P(break) v2 live geprueft: Kalibrierung daneben, Trennschaerfe unentschieden

Faellige B4-Messung nach dem Nachtrainieren vom 31.07. (878 Vorhersagen ab
01.08.). Drei Befunde.

1) Das Skript mischte zwei Modelle. Es trennte bei der M30-Umstellung (30.07.),
nicht beim Nachtrainieren (31.07.) - "GESAMT" las altes und neues Modell
zusammen. Derselbe Fehler wie am 02.08. in analyze_divergence.py. Neu:
MODELL_V2 mit demselben Stichtag wie die Faelligkeitsbedingung.

2) Kalibrierung messbar daneben. Die Basisrate ist gewandert: Training 37,8 %,
live 53,2 %, stabil ueber vier volle Tage (51,4 / 54,1 / 56,4 / 53,8 % bei
n=122-276). Ein Modell, dessen Niveau an 37,8 % verankert ist, muss in einem
53-%-Regime systematisch zu niedrig sagen - genau das passiert. Oberste Klasse
invertiert (69 % vorhergesagt, 17 % real).

3) Trennschaerfe NICHT entscheidbar - und das ist der wichtigere Befund.
Entkoppelt n=87, AUC 0,556, 95-%-Bootstrap-KI [0,434 ... 0,674]. Das Intervall
enthaelt den Zufall (0,50) UND die Messlatte (0,654).

Die Faelligkeitsbedingung zaehlte die falsche Groesse: 800 ROHE Vorhersagen,
die aber nicht unabhaengig sind (dieselbe Position pendelt um dasselbe Level).
Aus 878 rohen werden 87 entkoppelte - die Bedingung ueberschaetzte die
Beweismenge um rund das Zehnfache und meldete "faellig", obwohl die Messung
nichts entscheiden konnte. Jetzt 350 ENTKOPPELTE (halbiert die KI-Breite).
Stand 87/350.

Operativ kein Notfall: auto_sr_close ist seit 06.08. false, das Modell
schliesst keine Trades. Es speist nur Anzeige, Chart-Linien und
Copilot-Kontext.

Nichts umgestellt - ein drittes Fitten derselben Bauart wuerde denselben Weg
gehen; der Befund zeigt aufs Niveau, nicht zwingend auf die Rangfolge.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Axel Hocks
2026-08-07 07:43:24 +02:00
co-authored by Claude Opus 5
parent 3e8fa9fea8
commit 908e20a9d0
3 changed files with 117 additions and 5 deletions
+37 -2
View File
@@ -28,6 +28,17 @@ from datetime import datetime
DB = "oil_widget_history.db"
M30_SWITCH = datetime(2026, 7, 30).timestamp()
# ⚠⚠ MODELL-EPOCHE (ergänzt 2026-08-07). Am 31.07. wurde das P(break)-Modell
# NACHTRAINIERT (`backtest_pbreak_retrain.py`) und die Schwelle von 0,55 auf 0,35
# gesenkt. Die Tabelle `pbreak_predictions` enthält beides — Vorhersagen des ALTEN
# und des NEUEN Modells. Wer sie zusammen auswertet, misst eine Mischung und liest
# die Fehlkalibrierung des alten Modells als aktuellen Alarm.
# Derselbe Fehler wurde am 02.08. in `analyze_divergence.py` behoben (`_EPOCHS`);
# hier stand er noch. Stichtag identisch zur Fälligkeitsbedingung in
# `measurement_reminder.py` ("pbreak_accuracy_v2", ts >= 2026-08-01), damit
# Erinnerung und Auswertung dieselbe Grundmenge zählen.
MODELL_V2 = datetime(2026, 8, 1).timestamp()
def auc(ps, ys):
"""Rangbasiert, mit Bindungskorrektur."""
@@ -106,8 +117,32 @@ def main():
print(f" {len(rows)} ausgewertete Vorhersagen, {t0:%d.%m.%Y} bis {t1:%d.%m.%Y}")
print("=" * 84)
report(rows, "GESAMT")
calib(rows, "gesamt")
# ⚠ GESAMT mischt ALTES und NEUES Modell (s. MODELL_V2 oben) — bleibt als
# Historie stehen, ist aber NICHT der B4-Maßstab.
report(rows, "GESAMT ⚠ mischt altes + nachtrainiertes Modell")
calib(rows, "gesamt (gemischt)")
# ── DAS ist die fällige B4-Messung: nur das nachtrainierte Modell ──────
v2 = [(float(p), 1 if o == "break" else 0, pr)
for ts, _d, _l, p, pr, o in raw if ts >= MODELL_V2]
print("\n" + "=" * 84)
print(" NACHTRAINIERTES MODELL (ab 01.08.) — die fällige B4-Prüfung")
print(" Messlatte: AUC 0,654 (out-of-sample beim Nachtrainieren erreicht)")
print("=" * 84)
report(v2, "MODELL v2")
if len(v2) >= 30:
calib(v2, "Modell v2")
# entkoppelt auch hier — der Cluster-Effekt gilt unabhängig vom Modell
seen2 = set(); dd2 = []
for ts, _d, lvl, p, pr, o in raw:
if ts < MODELL_V2:
continue
key = (round(float(lvl or 0), 2), ts // 3600)
if key in seen2:
continue
seen2.add(key)
dd2.append((float(p), 1 if o == "break" else 0, pr))
report(dd2, "MODELL v2 · ENTKOPPELT (max. 1 je Level und Stunde)")
# ── entkoppelt: max. 1 Vorhersage je (Level, Stunde)
seen = set(); dedup = []