diff --git a/core/engine.py b/core/engine.py index f720d62..c99034b 100644 --- a/core/engine.py +++ b/core/engine.py @@ -5006,6 +5006,40 @@ class TradingEngine: "conf_pct": wsig.get("conf_pct"), "raum": raum} + # ── 3c) M5-KONTEXT — reine ANZEIGE, KEINE Richtung, KEIN Banner + # (User-Entscheidung 2026-08-19 gegen eine eigene M5-Karte). + # ⚠⚠ Warum KEINE zweite Setup-Karte: die entkoppelte Selbstmessung + # dieser Karte steht bei n=342 auf 53,5 % [48,2 .. 58,8] (30 min) und + # 49,3 % (60 min) — die am 12.08. VORAB fixierte Bedingung ("bei + # >=350 Faellen ueber 50 % UND KI ohne die 50") ist damit bei + # vorhandener Stichprobe NICHT erfuellt. Dazu faellt die Karte als + # Handelsregel durch (`backtest_m15_auto.py`: OeR -0,162/-0,094, + # beide KI ohne Null). Eine zweite Karte derselben Bauart wuerde ein + # als Signal gemessen NEGATIVES Muster vervielfachen — und die + # Veto->Richtung-Falle, die in EINER Woche dreimal zuschlug, auf eine + # zweite Flaeche ausdehnen. + # ⚠ Deshalb bewusst nur ZUSTAND, kein Urteil: Squeeze-Lage, Kosten, + # ATR. Der M5-RAUM steht bereits in `motor.raum` (Gate 3b rechnet + # ohnehin auf M5) und wird hier NICHT wiederholt. + # ⚠ NUR ZUSAMMENGESETZT, nichts neu gerechnet — `wave.squeeze` und + # `cost_ratio` stehen im Snapshot ohnehin. Ein zweiter Rechenweg war + # der Fehler des Konsens-Pfeils (komplettes zweites `_verdict` im + # 5-s-Takt) und die Quelle jeder Divergenz zwischen Karte und Chart. + try: + _sq = (wave_snap or {}).get("squeeze") or {} + _atr5 = ((wave_snap or {}).get("pb_feats") or {}).get("atr") + out["m5"] = { + "squeeze": _sq.get("state"), + "squeeze_dir": _sq.get("dir"), + "box_atr": _sq.get("box_atr"), + "atr": _atr5, + # Spread/ATR_M5 — Schwellen aus `backtest_realcosts.py`: + # Median 0,193 · ab 0,32 die dokumentierte Kostenfalle. + "kosten": (round((ask - bid) / _atr5, 3) + if (bid and ask and _atr5 and _atr5 > 0) else None)} + except Exception: + out["m5"] = None + # ── 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] diff --git a/web/app.js b/web/app.js index 48e0689..f8011a5 100644 --- a/web/app.js +++ b/web/app.js @@ -364,6 +364,34 @@ function renderM15(s) { + "gedeckelt, der Verlust laeuft bis zum Stop. Reine Anzeige."; } + // --- M5-Kontext: reine ZUSTANDS-Zeile, keine Richtung, kein Banner ------ + // Bewusst KEINE eigene M5-Karte (User-Entscheidung 19.08.): die entkoppelte + // Selbstmessung dieser Karte steht bei n=342 auf 53,5 % [48,2 .. 58,8] und + // schliesst die 50 nicht aus; als Handelsregel faellt sie durch. Hier steht + // deshalb nur, WIE der M5-Markt gerade aussieht -- ohne Urteil. + const m5El = $("m15-m5"); + const m5 = s.m5; + if (m5) { + const t = []; + if (m5.squeeze === "active") { + t.push(`Squeeze AUSBRUCH ${m5.squeeze_dir || ""}`.trim()); + } else if (m5.squeeze === "armed") { + t.push("Squeeze armiert" + (m5.box_atr != null ? ` (Box ${m5.box_atr}×ATR)` : "")); + } else { + t.push("keine Kompression" + + (m5.box_atr != null ? ` (Box ${m5.box_atr}×ATR)` : "")); + } + if (m5.kosten != null) { + // Schwellen aus backtest_realcosts.py: Median 0,193 - ab 0,32 Kostenfalle. + const k = m5.kosten; + t.push(`Kosten ${k.toFixed(2)}×ATR_M5 ${k <= 0.20 ? "günstig" : k < 0.32 ? "normal" : "⚠ teuer"}`); + } + if (m5.atr != null) t.push(`ATR ${Number(m5.atr).toFixed(3)}`); + m5El.textContent = "M5 · " + t.join(" · "); + } else { + m5El.textContent = "M5 · —"; + } + const moEl = $("m15-motor"); const seite = (o, lbl) => { if (!o) return null; diff --git a/web/index.html b/web/index.html index b6822ba..4e30886 100644 --- a/web/index.html +++ b/web/index.html @@ -12,7 +12,7 @@ ⚠ LOKAL eingebunden, kein CDN: die PWA laeuft ueber WireGuard und muss offline funktionieren. --> - + @@ -122,6 +122,7 @@ gemessen, aber ueber verschiedene Trades. Diese Zeile schliesst die Luecke. REINE ANZEIGE, blockt nichts. -->
+