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
+59 -1
View File
@@ -947,6 +947,13 @@ class TradingEngine:
# history.log_recommendation → flutet nicht).
try:
adv = (self.agent.snapshot() or {}).get("advisory") or {}
# News-Sentiment mitloggen (2026-07-24, Idee 6): war seit einer Weile
# None — wieder befüllt, damit die Prädiktivität in ein paar Monaten
# messbar ist (analyze_verdict_calibration.py fand H2 nur n=4/6).
try:
_news = float((self.news.sentiment or {}).get("score") or 0.0)
except Exception:
_news = None
self.history.log_recommendation(
signal=rec.get("signal"), score=float(rec.get("score") or 0.0),
conf_pct=int(rec.get("conf_pct") or 0),
@@ -954,10 +961,31 @@ class TradingEngine:
reversal=("rev" if "REV" in (rec.get("setup") or "") else None),
ai_sentiment=adv.get("bias"), ai_confidence=adv.get("confidence"),
setup=rec.get("setup"), regime=None, rsi=s.get("rsi_m15"),
news_score=None)
news_score=_news)
except Exception as e:
log.warning(f"log_recommendation: {e}")
# Verdict-Stimmen-Logging (2026-07-24, Idee 2b): Modul-Votes 1×/min in die
# DB (`verdict_votes`), damit die UNBELEGTEN Stimmen (KI-Copilot, Elliott)
# nach ein paar Wochen datenbasiert bewertet werden können (behalten /
# Gewicht senken / raus wie TU). Erste Messung (analyze_verdict_calibration.
# py, 2026-07-24): Copilot nicht robust prädiktiv, n aber klein → sammeln.
try:
vd = self._verdict(s, rec, self.wave.snapshot(), self.tu.snapshot(),
self.agent.snapshot(), self.elliott.snapshot())
vv = {v["name"]: v for v in vd.get("votes") or []}
def _v(name, key="vote"):
return (vv.get(name) or {}).get(key, 0)
self.history.log_verdict_votes(
headline=vd.get("headline") or "WARTEN",
conf=int(vd.get("conf") or 0), bias=float(vd.get("bias") or 0.0),
tf=vd.get("tf") or "", wave=_v("Welle"), m30=_v("M30"), h1=_v("H1"),
ki=_v("KI-Copilot"), ki_w=float(_v("KI-Copilot", "weight") or 0.0),
elliott=_v("Elliott"), elliott_w=float(_v("Elliott", "weight") or 0.0),
squeeze=_v("Squeeze"), news_score=_news)
except Exception as e:
log.debug(f"log_verdict_votes: {e}")
# Kontext für Trade-Logging (set_open_context beim Öffnen)
self._last_rec = {
"rec_signal": rec.get("signal"),
@@ -1651,6 +1679,21 @@ class TradingEngine:
# ══════════════════════════════════════════════════════════════════════
_SNAP_TTL_S = 0.8 # geteilter Snapshot gilt so lange als frisch
def _alignment_cached(self) -> dict | None:
"""Ausrichtungs-Split (mit/gegen/ohne Empfehlung, letzte 40 Trades) für den
Order-Bestätigungsdialog — ehrliche eigene Zahlen statt generischem Hinweis
(2026-07-24, Verhaltens-Hebel: Gegen-Signal-Trades sind die gemessene
Kern-Leckage). DB-Query gecacht (~120 s), Snapshot bleibt billig."""
now = time.time()
if now - getattr(self, "_align_ts", 0.0) > 120:
try:
self._align_cache = self.history.alignment_stats(40)
except Exception as e:
log.debug(f"alignment_stats: {e}")
self._align_cache = None
self._align_ts = now
return getattr(self, "_align_cache", None)
def snapshot_cached(self) -> dict:
"""Teilt EINEN frisch berechneten Snapshot über alle WS-Clients/HTTP-
Aufrufe (TTL ~0,8 s). Spart SQLite/Verdict-Last bei mehreren Geräten —
@@ -1903,6 +1946,21 @@ class TradingEngine:
"all": self._compact_stats("all")},
"close_alert_count": self._close_alert_count,
"news_storm": self.news.storm_state(),
# News-Sentiment-Score (1..+1) für den Konflikt-Chip (2026-07-24):
# steht der Headline-Flow stark gegen Signal/Position, zeigt das
# Frontend eine Warnung (reiner Kontext — Prädiktivität unbelegt,
# wird via recommendations.news_score gesammelt und später gemessen).
"news_sentiment": (lambda sc: round(float(sc), 2) if sc is not None else None)(
(self.news.sentiment or {}).get("score")),
"alignment": self._alignment_cached(),
# Live-Handelskosten relativ zur Vola (2026-07-24): Spread/ATR(M5).
# Gemessen (`backtest_realcosts.py`): Ø 0,265×ATR, Nacht 0,320,50 =
# Kostenfalle, 1517 Uhr ~0,13 = günstig. Reine Anzeige (Chip) — die
# informierende Alternative zum abgeschalteten Dead-Hours-Gate.
"cost_ratio": (lambda b, a, atr: round((a - b) / max(atr, 0.06), 2)
if (b and a and atr) else None)(
(market or {}).get("bid"), (market or {}).get("ask"),
((wave_snap or {}).get("pb_feats") or {}).get("atr")),
"sr_close_hint": sr_close_hint,
"stop_approach": stop_approach,
"auto_sr_close": self._auto_sr_close,