Gesamtempfehlung-Paket: 2 Rollouts, 3 Anzeige-Features, 2 Messungen (v=114)

- Entry-Raum-Gate 0,6→1,0 (Messung lag vor: beide Hälften besser)
- Konfidenz-Kalibrierung gemessen (analyze_verdict_calibration.py): conf
  INVERTIERT zwischen Regimen → keine P(Erfolg)-Aufwertung, kein Konf-Sizing
- verdict_votes-Logging (1×/min) für spätere Copilot/Elliott-Entscheidung
- Order-Dialog zeigt eigenen Ausrichtungs-Split (36/40 Trades ohne Signal: −423€)
- Live-Kosten-Chip (Spread/ATR) im Verdict
- P(break)×Entry-Raum-Freigabe gemessen VERWORFEN (Flip in jeder Schwelle,
  backtest_entryroom_pbreak.py) — 13. verworfener Signal-Eingriff
- News-Konflikt-Chip + recommendations.news_score wieder befüllt

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Axel Hocks
2026-07-24 20:57:56 +02:00
co-authored by Claude Opus 4.8
parent c3c6a8ce5f
commit d61c4a3634
10 changed files with 544 additions and 21 deletions
+52 -6
View File
@@ -68,7 +68,7 @@ function beepRecommendation(sig, isNew) {
}
// ── Gesamtempfehlung: Konfidenz-Ring + Bias-Balken + Modul-Chips ───────────
function renderVerdict(v) {
function renderVerdict(v, snap) {
const sig = v.headline || "—";
const cls = sig === "LONG" ? "long" : sig === "SHORT" ? "short" : "";
const arr = sig === "LONG" ? "▲" : sig === "SHORT" ? "▼" : "◌";
@@ -89,9 +89,18 @@ function renderVerdict(v) {
const bias = typeof v.bias === "number" ? v.bias : 0;
const strength = Math.abs(bias) >= 0.5 ? "stark" : Math.abs(bias) >= 0.2 ? "leicht" : "gemischt";
const dir = bias > 0.05 ? "LONG" : bias < -0.05 ? "SHORT" : "neutral";
// Live-Kosten-Chip (Spread/ATR — gemessen Ø 0,265; Nacht 0,320,50 = Falle):
// reine Info, die die abgeschaltete Dead-Hours-Sperre ehrlich ersetzt.
const cr = snap && snap.cost_ratio;
let costTxt = "";
if (cr != null) {
const tag = cr < 0.20 ? "✅ günstig" : cr <= 0.32 ? "· normal" : "⚠ teuer";
costTxt = ` · Kosten ${fmt(cr, 2)}×ATR ${tag}`;
}
$("vd-consensus").textContent =
sig === "—" ? "keine Daten"
: `Modul-Konsens: ${strength} ${dir} · ${agree}/${total} Module für ${sig}`;
(sig === "—" ? "keine Daten"
: `Modul-Konsens: ${strength} ${dir} · ${agree}/${total} Module für ${sig}`)
+ costTxt;
$("vd-needle").style.left = ((bias + 1) / 2 * 100).toFixed(1) + "%";
// Modul-Chips
@@ -284,7 +293,7 @@ function render(d) {
}
// ── Gesamtempfehlung (aggregiert) ───────
renderVerdict(d.verdict || {});
renderVerdict(d.verdict || {}, d);
renderStructure(d.structure);
renderStatsCompact(d.stats_compact, d.market);
renderGaps(d.gaps, d.market);
@@ -518,6 +527,28 @@ function render(d) {
stopEl.textContent = "";
}
}
// News-Konflikt-Chip (2026-07-24, realer Auslöser 23.07.: zwei Shorts gegen einen
// +0,98-Sentiment-Burst): |Score|≥0,5 UND Richtung gegen offene Position bzw.
// gegen das aktive Signal → Warnung. Reiner Kontext, Prädiktivität unbelegt.
const ncEl = $("news-conflict");
if (ncEl) {
const ns = d.news_sentiment;
let txt = "";
if (ns != null && Math.abs(ns) >= 0.5) {
const newsDir = ns > 0 ? "LONG" : "SHORT";
const newsWord = ns > 0 ? "bullisch" : "bärisch";
if (hasPos) {
const posDir = posLong ? "LONG" : "SHORT";
if (posDir !== newsDir)
txt = `📰 News-Flow stark ${newsWord} (${ns > 0 ? "+" : ""}${fmt(ns, 2)}) — steht gegen deine ${posDir}-Position`;
} else if (w.signal === "LONG" || w.signal === "SHORT") {
if (w.signal !== newsDir)
txt = `📰 News-Flow stark ${newsWord} (${ns > 0 ? "+" : ""}${fmt(ns, 2)}) — steht gegen das ${w.signal}-Signal`;
}
}
if (txt) { ncEl.className = "news-conflict warn"; ncEl.textContent = txt; }
else { ncEl.className = "news-conflict hidden"; ncEl.textContent = ""; }
}
// Schalter-Zustand: Auto-Close am S/R an/aus + Mindestgewinn
const srBtn = $("srclose-btn");
if (srBtn) {
@@ -735,11 +766,26 @@ document.querySelectorAll(".btn[data-side]").forEach(btn => {
const info = recInfo(side); // WARTEN/Gegen-Signal → Hinweis, der
if (info.danger) { // bestätigt werden muss (kein Block)
const sig = (lastSnap.wave_signal || {}).signal || "WARTEN";
const head = (sig === "WARTEN" || sig === "—")
const isWait = (sig === "WARTEN" || sig === "—");
const head = isWait
? " Keine Empfehlung (WARTEN)"
: ` Empfehlung steht GEGEN dich (${sig})`;
// Ehrliche EIGENE Zahlen (letzte 40 Trades, Ausrichtungs-Split aus der DB):
// die gemessene Kern-Leckage sind genau diese diskretionären Abweichungen.
let statLine = "";
const al = lastSnap.alignment || null;
if (al) {
const grp = isWait ? al.none : al.against;
const ref = al.with;
const f = g => (g && g.n >= 5)
? `${g.wr}% Trefferquote · ${g.pnl >= 0 ? "+" : ""}${fmt(g.pnl, 0)} € (n${g.n})`
: null;
const own = f(grp), rf = f(ref);
if (own) statLine += `\n\n📊 Deine Trades ${isWait ? "OHNE Signal" : "GEGEN das Signal"}: ${own}`;
if (rf) statLine += `\n📊 Mit Signal: ${rf}`;
}
const ok = await modal(head,
info.line + `\n\n${side.toUpperCase()} trotzdem eröffnen?`,
info.line + statLine + `\n\n${side.toUpperCase()} trotzdem eröffnen?`,
"confirm", true);
if (!ok) return; // Abbrechen = doch nicht; sonst läuft er
}