M15-Karte "Setup-Bereitschaft" gebaut - Ersatz der Gesamtempfehlung (v=153)

Nach drei negativen M15-Messungen (Squeeze-Einstieg, VWAP-Baender, Exit-ATR)
steht fest: auf M15 traegt keine Richtungsquelle. Gebaut ist deshalb bewusst
KEINE Empfehlung, sondern eine sequenzielle Gate-Kette:

  [1 HTF-BIAS M30/H1] -> [2 KOSTEN Spread/ATR_M15] -> [3 LEVEL & KEGEL]
  -> Order AM LEVEL

Der Unterschied zur alten Karte ist grundsaetzlich: dort wurden Stimmen zu einem
Bias VERRECHNET (gemessen 48-51 % Treffer), hier muss jedes Gate EINZELN
passieren. Ein gefallenes Gate laesst sich nicht durch ein anderes ausgleichen.

Nur belegte Bausteine: HTF-Trend (einziger robuster Filter, Edge x2), Kosten
(M15 gemessen 0,104 gegen M5 0,193), naechstes stehendes Level + P(break),
Kegel (out-of-sample kalibriert, 80-%-Band trifft 77 %), Veto (-6,60 EUR/Lot).

Status-Banner: SETUP BEREIT / WARTEN AUF LEVEL / KEIN TRADE. Es bestaetigt
ausdruecklich auch das NICHT-Handeln - die gemessene Kern-Leckage sind
diskretionaere Abweichungen.

Die Order-Buttons werden BEWUSST NICHT gesperrt (gegen den Vorschlag
"ausgrauen"): hartes Blockieren wurde im Projekt verworfen, und
User-Uebersteuerungen liefen gemessen 68 % WR.

Umsetzung: engine._m15_setup() setzt nur zusammen, was der Snapshot ohnehin
erzeugt. Neu gerechnet wird allein das M15-Kosten-Verhaeltnis und P(break) fuer
das naechste Level. Dafuer veroeffentlicht wave_rec jetzt tf_atr (ADDITIV) - der
ATR je Zeitebene wurde im Turn-Fetch laengst berechnet, war aber nirgends
abrufbar.

P(break)-Merkmale bleiben auf M5 (Modell ist darauf trainiert, Fix 2026-07-13).

Mit 5 Szenarien getestet (alles passt, Bias uneinig, Kosten teuer, Level zu
weit, Kaltstart ohne ATR_M15 -> kein Absturz), live verifiziert ueber
deploy.py --feld m15_setup.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Axel Hocks
2026-08-08 15:18:29 +02:00
co-authored by Claude Opus 5
parent 010007f7a3
commit 44955bf70a
6 changed files with 259 additions and 3 deletions
+40 -1
View File
@@ -4182,7 +4182,7 @@ dort bereits nachvalidiert, ØR +0,305.) **Eine** Oberfläche:
(„⚠ die Welle (steuert die Order) schweigt"). („⚠ die Welle (steuert die Order) schweigt").
Live gegengerechnet, beide Zeilen erscheinen wie beabsichtigt. Live gegengerechnet, beide Zeilen erscheinen wie beabsichtigt.
⚠ Reine Anzeige — an Gewichten, Gates und Order-Logik ist nichts geändert. ⚠ Reine Anzeige — an Gewichten, Gates und Order-Logik ist nichts geändert.
- Asset-Version aktuell **v=151** (in `web/index.html` hochzählen, siehe Workflows). - Asset-Version aktuell **v=153** (in `web/index.html` hochzählen, siehe Workflows).
Schriftgrößen 2026-07-24 global **+4px** (2× je +2px auf User-Wunsch; Body-Basis Schriftgrößen 2026-07-24 global **+4px** (2× je +2px auf User-Wunsch; Body-Basis
14→18px). ⚠ Betrifft in `style.css` sowohl `font-size:Npx` (71×) ALS AUCH die 14→18px). ⚠ Betrifft in `style.css` sowohl `font-size:Npx` (71×) ALS AUCH die
`font:<weight> Npx/…`-**Shorthand** (3×: `.ms-chip`/`.ms-bos-lbl`/`.sqm-badge` `font:<weight> Npx/…`-**Shorthand** (3×: `.ms-chip`/`.ms-bos-lbl`/`.sqm-badge`
@@ -4942,6 +4942,45 @@ Modell schliesst keine Trades.
„die Rangfolge ist kaputt" ist **nicht** belegt; belegt ist nur die „die Rangfolge ist kaputt" ist **nicht** belegt; belegt ist nur die
Basisraten-/Kalibrierungslücke. Basisraten-/Kalibrierungslücke.
## ✅ M15-KARTE „SETUP-BEREITSCHAFT" GEBAUT (2026-08-08, v=153) — Ersatz der Gesamtempfehlung
Nach dem Entfernen der Gesamtempfehlung und drei negativen M15-Messungen
(Squeeze-Einstieg, VWAP-Bänder, Exit-ATR) steht fest: **auf M15 trägt keine
Richtungsquelle.** Gebaut ist deshalb bewusst **keine Empfehlung**, sondern eine
**sequenzielle Gate-Kette** nach dem Schema des Users:
```
[① HTF-BIAS M30/H1] → [② KOSTEN Spread/ATR_M15] → [③ LEVEL & KEGEL] → Order AM LEVEL
```
**Der Unterschied zur alten Karte ist grundsätzlich**: dort wurden Stimmen zu
einem Bias **verrechnet** (gemessen 4851 % Treffer über 1.071 Episoden), hier
muss jedes Gate **einzeln** passieren. Ein gefallenes Gate lässt sich nicht durch
ein anderes ausgleichen.
**Nur BELEGTE Bausteine:** ① HTF-Trend (einziger robuster Filter, Edge ×2) ·
② Kosten (M15 gemessen **0,104** gegen M5 0,193 — hier gewinnt M15 wirklich) ·
③ nächstes STEHENDES Level aus `_draw_levels` + P(break) · ④ Kegel
(out-of-sample kalibriert, 80 %-Band trifft 77 %) · ⑤ Veto (gegen das Signal
6,60 €/Lot, beidhälftig).
**Status-Banner:** 🟢 SETUP BEREIT @ Level · 🟡 WARTEN AUF LEVEL · 🔴 KEIN TRADE.
⚠ Das Banner bestätigt ausdrücklich auch das **Nicht**-Handeln — die gemessene
Kern-Leckage sind diskretionäre Abweichungen, nicht verpasste Gelegenheiten.
⚠⚠ **Die Order-Buttons werden BEWUSST NICHT gesperrt** (gegen den Vorschlag
„ausgrauen"): hartes Blockieren wurde im Projekt verworfen, und
User-Übersteuerungen liefen gemessen **68 % WR**. Sichtbar machen, nicht
bevormunden.
**Umsetzung:** `engine._m15_setup()` setzt nur zusammen, was der Snapshot ohnehin
erzeugt; NEU gerechnet wird allein das M15-Kosten-Verhältnis und P(break) für das
nächste Level. ⚠ Dafür veröffentlicht `wave_rec` jetzt **`tf_atr`** (ADDITIV) —
der ATR je Zeitebene wurde im Turn-Fetch längst berechnet, war aber nirgends
abrufbar; ihn neu zu holen wäre ein zweiter MT5-Fetch für vorhandene Zahlen
(derselbe Fehler wie beim Konsens-Pfeil).
⚠ P(break)-Merkmale bleiben auf **M5** — das Modell ist darauf trainiert (Fix
2026-07-13); auf M15 umzustellen würde es falsch skalieren.
Mit **5 Szenarien getestet** (alles passt · Bias uneinig · Kosten teuer · Level
zu weit · Kaltstart ohne ATR_M15 → kein Absturz), live verifiziert über
`deploy.py --feld m15_setup`.
## ⚠⚠ EXIT-ABSTAND AUS M15-ATR = FÄLLT DURCH (2026-08-08) ## ⚠⚠ EXIT-ABSTAND AUS M15-ATR = FÄLLT DURCH (2026-08-08)
Zweiter Teil der M15-Idee: M5-Einstieg behalten, nur den EXIT gröber führen. Zweiter Teil der M15-Idee: M5-Einstieg behalten, nur den EXIT gröber führen.
+84
View File
@@ -3795,6 +3795,12 @@ class TradingEngine:
if (b and a and atr) else None)( if (b and a and atr) else None)(
(market or {}).get("bid"), (market or {}).get("ask"), (market or {}).get("bid"), (market or {}).get("ask"),
((wave_snap or {}).get("pb_feats") or {}).get("atr")), ((wave_snap or {}).get("pb_feats") or {}).get("atr")),
# M15-SETUP-BEREITSCHAFT (2026-08-08) — Ersatz fuer die entfernte
# Gesamtempfehlung. ⚠ KEINE Richtungsaussage: auf M15 traegt gemessen
# keine (Squeeze n=33/Nachbarn kippen, VWAP-Baender ohne Edge).
# Zeigt Bedingungen, nicht Prognosen.
"m15_setup": self._m15_setup(market, wave_snap, _cone,
self._alignment_cached()),
"sr_close_hint": sr_close_hint, "sr_close_hint": sr_close_hint,
"stop_approach": stop_approach, "stop_approach": stop_approach,
"auto_sr_close": self._auto_sr_close, "auto_sr_close": self._auto_sr_close,
@@ -3968,6 +3974,84 @@ class TradingEngine:
log.debug(f"sr_close_hint: {e}") log.debug(f"sr_close_hint: {e}")
return None return None
def _m15_setup(self, market, wave_snap, cone, alignment) -> dict | None:
"""SETUP-BEREITSCHAFT auf M15 — der Ersatz für die entfernte Gesamtempfehlung.
⚠⚠ BEWUSST KEINE RICHTUNGS-EMPFEHLUNG. Gemessen (2026-08-08) trägt auf
M15 KEINE Richtungsquelle: der Squeeze fällt dort durch (n=33 in H1,
Nachbarn kippen), VWAP-Bänder ebenso (Zufallslinie hält gleich gut, alle
Konfidenzintervalle enthalten die Null), und 24 Signal-Eingriffe sind
insgesamt gescheitert. Was BELEGT ist, sind Bedingungen — nicht Prognosen.
Die Karte zeigt deshalb das Schema des Users (Bias → Zone → Reichweite →
Veto) und überlässt den Auslöser dem Menschen, dessen Auswahl-Vorteil
unabhängig belegt ist.
Zusammengesetzt aus bereits berechneten Teilen — NEU gerechnet wird nur
das Kosten-Verhältnis auf M15 und P(break) für das nächste Level. Der
Konsens-Pfeil hat einmal ein zweites `_verdict()` gezogen; das ist die
Lehre daraus.
"""
try:
bid = (market or {}).get("bid"); ask = (market or {}).get("ask")
ws = wave_snap or {}
atr15 = (ws.get("tf_atr") or {}).get("M15")
out: dict = {"atr_m15": round(atr15, 4) if atr15 else None}
# ── 1) BIAS — der einzige belegte Filter (M30-Gegen-Trend: Edge ×2)
h30 = ws.get("htf_trend"); h1 = ws.get("h1_trend")
einig = (h30 and h1 and h30 == h1)
out["bias"] = {"m30": h30, "h1": h1,
"richtung": h30 if einig else None,
"einig": bool(einig)}
# ── 2) KOSTEN auf M15 — hier gewinnt M15 wirklich (gemessen 0,104
# gegen M5 0,193). Schwellen wie beim M5-Chip (0,20 / 0,32).
kr = None
if bid and ask and atr15 and atr15 > 0:
kr = round((ask - bid) / atr15, 3)
out["kosten"] = {"ratio": kr,
"stufe": (None if kr is None else
"guenstig" if kr < 0.20 else
"normal" if kr < 0.32 else "teuer")}
# ── 3) ZONE — nächstes STEHENDES Level (M30-Pivots, dieselbe Quelle
# wie Chart und S/R-Close) + P(break). ⚠ Die P(break)-Merkmale
# kommen aus M5, weil das Modell darauf trainiert ist (Fix
# 2026-07-13) — NICHT auf M15 umstellen.
dl = self._draw_levels() or {}
res = (dl.get("res") or [None])[0]
sup = (dl.get("sup") or [None])[0]
pf = ws.get("pb_feats") or {}
a5 = pf.get("atr") or 0.2
zonen = []
for lvl, seite in ((res, "res"), (sup, "sup")):
if not lvl or not bid or not atr15:
continue
d = 1 if seite == "res" else -1
gap = abs(lvl - bid)
wt = 1.0 if (pf.get("ema_diff", 0.0) or 0.0) * d > 0 else 0.0
p = _p_break(pf.get("mom6", 0.0) * d, pf.get("mom3", 0.0) * d,
wt, gap / max(a5, 0.06))
zonen.append({"seite": seite, "level": round(lvl, 3),
"gap_atr15": round(gap / atr15, 2),
"p_break": round(100 * p)})
out["zonen"] = zonen
# ── 4) REICHWEITE — der Kegel (kalibriert: 80 %-Band trifft 77 %)
lv = (cone or {}).get("levels") or []
b80 = [x for x in lv if x.get("band") == 80]
out["reichweite"] = [{"minutes": x.get("minutes"),
"lo": x.get("lo"), "hi": x.get("hi")}
for x in b80] or None
# ── 5) VETO — die eigene Bilanz, je Lot (absolute Euro sind bei
# wechselnder Positionsgröße ungültig, Lehre vom 04.08.)
out["veto"] = alignment or None
return out
except Exception as e:
log.debug(f"m15_setup: {e}")
return None
def _stop_approach_hint(self, market, position, wave_snap) -> dict | None: def _stop_approach_hint(self, market, position, wave_snap) -> dict | None:
"""REINE ANZEIGE: P(Durchbruch) für das Level, dem sich der Kurs auf der """REINE ANZEIGE: P(Durchbruch) für das Level, dem sich der Kurs auf der
**Gegen-/Stop-Seite** der offenen Position nähert (LONG → Support darunter, **Gegen-/Stop-Seite** der offenen Position nähert (LONG → Support darunter,
+9
View File
@@ -398,6 +398,14 @@ class WaveRecommender:
if turn_data: # frisch geholt → neu berechnen, sonst letzten Stand halten if turn_data: # frisch geholt → neu berechnen, sonst letzten Stand halten
self._last_tf_turns = {lbl: self._turn_state(c, a) self._last_tf_turns = {lbl: self._turn_state(c, a)
for lbl, (c, a) in turn_data.items()} for lbl, (c, a) in turn_data.items()}
# ⚠ ADDITIV (2026-08-08): den ATR je Zeitebene MITNEHMEN. Er wird im
# Turn-Fetch ohnehin berechnet (`turn_data[lbl] = (closes, atr)`),
# war aber nirgends abrufbar — die M15-Setup-Karte braucht ihn fuer
# das Kosten-Gate (Spread/ATR_M15) und die Abstandsangaben. Ihn dort
# neu zu holen waere ein zweiter MT5-Fetch fuer Zahlen, die schon da
# sind (derselbe Fehler wie beim Konsens-Pfeil, der ein zweites
# `_verdict()` rechnete).
self._tf_atr = {lbl: a for lbl, (c, a) in turn_data.items() if a}
# P(break)-Features IMMER aus M5 (Modell wurde auf M5 trainiert/kalibriert # P(break)-Features IMMER aus M5 (Modell wurde auf M5 trainiert/kalibriert
# — die Wave-TF wechselt per Heuristik bis M30; damit wäre mom6 ein 3-h- # — die Wave-TF wechselt per Heuristik bis M30; damit wäre mom6 ein 3-h-
# statt 30-min-Momentum und der ATR 23× größer → P(break) völlig falsch # statt 30-min-Momentum und der ATR 23× größer → P(break) völlig falsch
@@ -484,6 +492,7 @@ class WaveRecommender:
else: else:
self._last_bounce = {"state": None, "dir": None, "tf": None} self._last_bounce = {"state": None, "dir": None, "tf": None}
snap["tf_turns"] = dict(self._last_tf_turns) snap["tf_turns"] = dict(self._last_tf_turns)
snap["tf_atr"] = dict(getattr(self, "_tf_atr", {}) or {})
snap["bounce"] = dict(self._last_bounce) # Multi-TF überschreibt Basis-TF snap["bounce"] = dict(self._last_bounce) # Multi-TF überschreibt Basis-TF
snap["pb_feats"] = dict(self._pb_feats) if getattr(self, "_pb_feats", None) else None snap["pb_feats"] = dict(self._pb_feats) if getattr(self, "_pb_feats", None) else None
snap["pb_levels"] = dict(self._pb_levels) if getattr(self, "_pb_levels", None) else None snap["pb_levels"] = dict(self._pb_levels) if getattr(self, "_pb_levels", None) else None
+79
View File
@@ -142,6 +142,84 @@ function beepRecommendation(sig, isNew) {
// · HL-Kontext (`#hl-note`) — schreibt in die Meldungen-Karte, nicht hierher // · HL-Kontext (`#hl-note`) — schreibt in die Meldungen-Karte, nicht hierher
// Entfallen ist die Block-Grund-Zeile (`#vd-blocks`). // Entfallen ist die Block-Grund-Zeile (`#vd-blocks`).
// ══════════════════════════════════════════════════════════════════════════ // ══════════════════════════════════════════════════════════════════════════
// ══════════════════════════════════════════════════════════════════════════
// M15 SETUP-BEREITSCHAFT — sequenzielle GATE-KETTE, keine Score-Aggregation.
// [HTF-BIAS] → [KOSTEN] → [LEVEL & KEGEL] → AUSFÜHRUNG NUR AM LEVEL
// ⚠ Bewusst KEINE Richtungsaussage. Auf M15 trägt gemessen keine (Squeeze
// n=33/Nachbarn kippen, VWAP-Bänder ohne Edge). Die Karte sagt, ob die
// BEDINGUNGEN stimmen — der Auslöser bleibt beim Menschen.
// ⚠ Der Unterschied zur entfernten Gesamtempfehlung ist grundsätzlich: dort
// wurden Stimmen zu einem Bias VERRECHNET (gemessen 4851 % Treffer), hier
// muss jedes Gate EINZELN passieren. Ein Gate, das fällt, lässt sich nicht
// durch ein anderes ausgleichen.
// ══════════════════════════════════════════════════════════════════════════
function renderM15(s) {
const st = $("m15-status");
if (!s) { st.className = "m15-status"; st.textContent = "— keine Daten"; return; }
const f = (v, d = 2) => (v == null ? "—" : (+v).toFixed(d));
// ── Gate 1: HTF-Bias (der einzige belegte Filter, Edge ×2) ───────────
const b = s.bias || {};
const bOk = !!b.einig;
$("m15-bias").className = "m15-item " + (bOk ? "ok" : "fail");
$("m15-bias").textContent = bOk
? `① Bias ${b.richtung === "LONG" ? "▲ LONG" : "▼ SHORT"} · M30+H1 einig`
: `① Bias unklar · M30 ${b.m30 || "—"} / H1 ${b.h1 || "—"}`;
// ── Gate 2: Kosten auf M15 ───────────────────────────────────────────
const k = s.kosten || {};
const kOk = k.stufe === "guenstig" || k.stufe === "normal";
$("m15-kosten").className = "m15-item " + (k.ratio == null ? "" : kOk ? "ok" : "fail");
$("m15-kosten").textContent = k.ratio == null
? "② Kosten —"
: `② Kosten ${f(k.ratio, 3)}×ATR · ${
k.stufe === "guenstig" ? "günstig" : k.stufe === "normal" ? "normal" : "TEUER"}`;
// ── Gate 3: Level in Reichweite ──────────────────────────────────────
const z = (s.zonen || []);
const nah = z.filter(x => x.gap_atr15 != null && x.gap_atr15 <= 0.5);
const zOk = nah.length > 0;
$("m15-zone").className = "m15-item " + (z.length ? (zOk ? "ok" : "warn") : "");
$("m15-zone").textContent = z.length
? "③ " + z.map(x => `${x.seite === "res" ? "Widerstand" : "Support"} ${f(x.level, 3)}`
+ ` (${f(x.gap_atr15)}×ATR, Bruch ${x.p_break} %)`).join(" · ")
: "③ kein Level in Sicht";
// ── Reichweite (Kegel) — sagt WIE WEIT, nicht wohin ──────────────────
const r = s.reichweite || [];
$("m15-reich").className = "m15-item";
$("m15-reich").textContent = r.length
? "④ erwartete Spanne · " + r.map(x => `${x.minutes} ${f(x.lo, 2)}${f(x.hi, 2)}`).join(" · ")
: "④ erwartete Spanne —";
// ── Veto: die eigene Bilanz, JE LOT ──────────────────────────────────
const v = s.veto || {};
const g = v.against || {};
$("m15-veto").className = "m15-item " + (g.n >= 5 ? "warn" : "");
$("m15-veto").textContent = g.n >= 5
? `⑤ gegen das Signal: ${g.n} Trades, ${f(g.pnl_lot, 2)} € je Lot`
: "⑤ Veto: noch zu wenige Trades";
// ── Status: die Kette wird der Reihe nach ausgewertet ────────────────
let cls, txt;
if (!bOk) { cls = "rot"; txt = "🔴 KEIN TRADE · Bias unklar (M30/H1 uneinig)"; }
else if (!kOk && k.ratio != null) { cls = "rot"; txt = "🔴 KEIN TRADE · Kosten zu hoch"; }
else if (!zOk) { cls = "gelb"; txt = "🟡 WARTEN AUF LEVEL · Bias und Kosten passen"; }
else {
const nn = nah[0];
cls = "gruen";
txt = `🟢 SETUP BEREIT @ ${f(nn.level, 3)} · ${b.richtung === "LONG" ? "▲" : "▼"} `
+ `${b.richtung} · Order ANS LEVEL legen, nicht zum Markt`;
}
st.className = "m15-status " + cls;
st.textContent = txt;
st.title = "Sequenzielle Kette: Bias → Kosten → Level. Ein gefallenes Gate lässt "
+ "sich NICHT durch ein anderes ausgleichen. ⚠ Die Order-Buttons bleiben "
+ "bewusst bedienbar — hartes Blockieren wurde im Projekt verworfen, und "
+ "Übersteuerungen des Users liefen gemessen 68 % Trefferquote.";
}
function renderKontext(snap) { function renderKontext(snap) {
// ── Selbst-Kalibrierung: die Empfehlung zeigt ihre eigene Trefferquote ── // ── Selbst-Kalibrierung: die Empfehlung zeigt ihre eigene Trefferquote ──
// ⚠ Gegen 50 % zu lesen, nicht gegen 0 — es ist eine Richtungsaussage. // ⚠ Gegen 50 % zu lesen, nicht gegen 0 — es ist eine Richtungsaussage.
@@ -609,6 +687,7 @@ function render(d) {
} }
// ── Gesamtempfehlung (aggregiert) ─────── // ── Gesamtempfehlung (aggregiert) ───────
renderM15(d.m15_setup);
renderKontext(d); renderKontext(d);
renderCircuitBreaker(d.circuit_breaker); renderCircuitBreaker(d.circuit_breaker);
renderPatterns(d.patterns); renderPatterns(d.patterns);
+28 -2
View File
@@ -6,7 +6,7 @@
<meta name="theme-color" content="#0d1117"> <meta name="theme-color" content="#0d1117">
<title>Oil · MT5</title> <title>Oil · MT5</title>
<link rel="manifest" href="manifest.json"> <link rel="manifest" href="manifest.json">
<link rel="stylesheet" href="style.css?v=152"> <link rel="stylesheet" href="style.css?v=153">
</head> </head>
<body> <body>
<!-- Modul-Menü (ganz oben) --> <!-- Modul-Menü (ganz oben) -->
@@ -87,6 +87,32 @@
GEBLIEBEN sind drei Dinge, die dort nur geparkt waren und je eine GEBLIEBEN sind drei Dinge, die dort nur geparkt waren und je eine
eigene, unabhaengige Beleglage haben (s. CLAUDE.md). eigene, unabhaengige Beleglage haben (s. CLAUDE.md).
══════════════════════════════════════════════════════════════════ --> ══════════════════════════════════════════════════════════════════ -->
<!-- ══════════════════════════════════════════════════════════════════
M15 SETUP-BEREITSCHAFT (2026-08-08) — Ersatz fuer die entfernte
Gesamtempfehlung. ⚠ KEINE Richtungsaussage: auf M15 traegt gemessen
KEINE (Squeeze n=33/Nachbarn kippen, VWAP-Baender ohne Edge, 24
Signal-Eingriffe gescheitert). Gezeigt werden BEDINGUNGEN nach dem
Schema Bias -> Zone -> Reichweite -> Veto; den Ausloeser gibt der
Mensch, dessen Auswahl-Vorteil unabhaengig belegt ist.
══════════════════════════════════════════════════════════════════ -->
<section class="card wide" id="card-m15">
<h2 title="Setup-Bereitschaft auf M15. Zeigt BEDINGUNGEN, keine Richtungsprognose - auf M15 traegt gemessen kein Richtungssignal. Der Ausloeser bleibt beim Menschen.">M15 · Setup-Bereitschaft</h2>
<!-- Status-Banner: die wichtigste Zeile. Sie bestaetigt ausdruecklich
auch das NICHT-Handeln - die gemessene Kern-Leckage sind
diskretionaere Abweichungen, nicht fehlende Gelegenheiten.
⚠ Die Order-Buttons werden BEWUSST NICHT gesperrt: hartes Blockieren
wurde im Projekt verworfen, und User-Uebersteuerungen liefen
gemessen 68 % WR. Sichtbar machen, nicht bevormunden. -->
<div class="m15-status" id="m15-status"></div>
<div class="m15-grid">
<div class="m15-item" id="m15-bias" title="Uebergeordneter Trend M30 + H1. Der EINZIGE belegte Filter: gegen den HTF zu handeln halbiert den Edge (gemessen ×2)."></div>
<div class="m15-item" id="m15-kosten" title="Spread geteilt durch ATR_M15. Auf M15 gemessen 0,104 gegen 0,193 auf M5 - hier ist die groebere Zeitebene echt im Vorteil. Schwellen 0,20 / 0,32 aus backtest_realcosts.py."></div>
<div class="m15-item" id="m15-zone" title="Naechstes STEHENDES Level (M30-Pivots, dieselbe Quelle wie Chart und S/R-Close) mit Abstand und Durchbruchwahrscheinlichkeit. ⚠ P(break) ist live derzeit rund 7 Pp zu niedrig kalibriert."></div>
<div class="m15-item" id="m15-reich" title="Erwartete Spanne aus core/cone.py - out-of-sample geprueft, die 80-%-Baender treffen real 77 %. Sagt WIE WEIT, nicht wohin."></div>
<div class="m15-item" id="m15-veto" title="Deine eigene Bilanz mit/ohne/gegen Signal, je Lot gerechnet. Gegen das Signal zu handeln kostet gemessen 6,60 EUR je Lot - beidhaelftig robust."></div>
</div>
</section>
<section class="card wide" id="card-kontext"> <section class="card wide" id="card-kontext">
<h2 title="Drei unabhaengige Kontext-Anzeigen. KEINE Empfehlung und keine Richtungsaussage - die Aggregation zu einer Gesamtempfehlung wurde am 08.08. entfernt.">Marktkontext</h2> <h2 title="Drei unabhaengige Kontext-Anzeigen. KEINE Empfehlung und keine Richtungsaussage - die Aggregation zu einer Gesamtempfehlung wurde am 08.08. entfernt.">Marktkontext</h2>
<!-- Zeitebenen-Ampel (M1/M5/M15/M30/H1) --> <!-- Zeitebenen-Ampel (M1/M5/M15/M30/H1) -->
@@ -314,6 +340,6 @@
</div> </div>
<div id="toast" class="toast hidden"></div> <div id="toast" class="toast hidden"></div>
<script src="app.js?v=152"></script> <script src="app.js?v=153"></script>
</body> </body>
</html> </html>
+19
View File
@@ -489,3 +489,22 @@ main{padding-bottom:74px} /* Platz für die fixe Leiste */
.hl-note{font-size:13px;color:var(--dim);font-family:var(--mono); .hl-note{font-size:13px;color:var(--dim);font-family:var(--mono);
padding:5px 0;border-top:1px solid var(--line);margin-top:5px} padding:5px 0;border-top:1px solid var(--line);margin-top:5px}
.hl-note.hidden{display:none} .hl-note.hidden{display:none}
/* ── M15 Setup-Bereitschaft (2026-08-08, Ersatz der Gesamtempfehlung) ──────
Sequenzielle Gate-Kette statt Score-Aggregation. Das Status-Banner ist
bewusst das groesste Element der Karte: die gemessene Kern-Leckage sind
diskretionaere Abweichungen, nicht verpasste Gelegenheiten - deshalb muss
auch das NICHT-Handeln ausdruecklich bestaetigt werden. */
#card-m15{border-color:var(--accent)}
.m15-status{font-size:19px;font-weight:700;letter-spacing:.3px;
padding:10px 12px;border-radius:var(--r);margin-bottom:10px;
background:var(--surface-2);border:1px solid var(--border);color:var(--dim)}
.m15-status.gruen{color:var(--up);border-color:#1d5c2a;background:#0e2413}
.m15-status.gelb {color:var(--accent);border-color:#4a3600;background:#241d05}
.m15-status.rot {color:var(--down);border-color:#5c1a1a;background:#240f0f}
.m15-grid{display:flex;flex-direction:column;gap:5px}
.m15-item{font-size:15px;color:var(--dim);padding:4px 8px;border-radius:var(--r-sm);
background:var(--surface-2);border:1px solid var(--line)}
.m15-item.ok {color:var(--bright);border-color:#1d5c2a}
.m15-item.warn{color:var(--accent);border-color:#4a3600}
.m15-item.fail{color:var(--down);border-color:#5c1a1a}