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
+79
View File
@@ -142,6 +142,84 @@ function beepRecommendation(sig, isNew) {
// · HL-Kontext (`#hl-note`) — schreibt in die Meldungen-Karte, nicht hierher
// 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) {
// ── Selbst-Kalibrierung: die Empfehlung zeigt ihre eigene Trefferquote ──
// ⚠ Gegen 50 % zu lesen, nicht gegen 0 — es ist eine Richtungsaussage.
@@ -609,6 +687,7 @@ function render(d) {
}
// ── Gesamtempfehlung (aggregiert) ───────
renderM15(d.m15_setup);
renderKontext(d);
renderCircuitBreaker(d.circuit_breaker);
renderPatterns(d.patterns);