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:
co-authored by
Claude Opus 5
parent
3e8fa9fea8
commit
908e20a9d0
@@ -4785,6 +4785,69 @@ Signal-Eingriffe sind gescheitert, und die gemessene Stärke des Users liegt in
|
||||
AUSWAHL, nicht in einer Regel. Ein Modul, das ihm seine eigene Historie zur aktuellen
|
||||
Lage zeigt, spielt auf diese Stärke; eines das für ihn einsteigt, ersetzt sie.
|
||||
|
||||
## ⚠⚠ P(break) v2 LIVE GEPRÜFT (2026-08-07) — KALIBRIERUNG DANEBEN, TRENNSCHÄRFE UNENTSCHIEDEN
|
||||
|
||||
Fällige B4-Messung nach dem Nachtrainieren vom 31.07. (`analyze_pbreak_live.py`,
|
||||
878 ausgewertete Vorhersagen ab 01.08.). Zwei Befunde, die auseinandergehalten
|
||||
gehören — und einer davon betrifft die Messung selbst.
|
||||
|
||||
⚠⚠ **ZUERST: DAS SKRIPT MISCHTE ZWEI MODELLE.** Es trennte bei der
|
||||
M30-Level-Umstellung (30.07.), **nicht** beim Nachtrainieren (31.07.); „GESAMT"
|
||||
las damit altes und neues Modell zusammen. Genau der Fehler, der am 02.08. in
|
||||
`analyze_divergence.py` schon behoben wurde (`_EPOCHS`) — hier stand er noch.
|
||||
Neu: `MODELL_V2` mit demselben Stichtag wie die Fälligkeitsbedingung (01.08.),
|
||||
plus eigener Abschnitt „NACHTRAINIERTES MODELL". Die alten Abschnitte bleiben.
|
||||
|
||||
**(1) KALIBRIERUNG — messbar daneben, und die Ursache ist benennbar.**
|
||||
| P(break) | n | vorhergesagt | real |
|
||||
|---|---|---|---|
|
||||
| 0–19 | 56 | 15,1 % | **53,6 %** |
|
||||
| 20–34 | 199 | 29,8 % | 43,2 % |
|
||||
| 35–49 | 414 | 42,2 % | 56,8 % |
|
||||
| 50–64 | 180 | 54,1 % | 61,7 % |
|
||||
| **65–100** | 29 | **69,0 %** | **17,2 %** ⚠ invertiert |
|
||||
⚠ **Die Basisrate ist gewandert** — Training **37,8 %**, live **53,2 %**, und das
|
||||
**stabil über vier volle Tage** (03.08. 51,4 % · 04.08. 54,1 % · 05.08. 56,4 % ·
|
||||
06.08. 53,8 %, je n=122–276). Das ist kein Rauschen. Ein Modell, dessen Niveau an
|
||||
einer 37,8-%-Basisrate verankert ist, muss in einem 53-%-Regime systematisch zu
|
||||
niedrig sagen — genau das steht in der Tabelle. Dieselbe Signatur wie beim alten
|
||||
Modell (alle unteren Klassen „zu niedrig", oberste invertiert).
|
||||
|
||||
**(2) TRENNSCHÄRFE — NICHT entscheidbar, und das ist der wichtigere Befund.**
|
||||
| | |
|
||||
|---|---|
|
||||
| AUC roh (n=878) | 0,541 |
|
||||
| **AUC entkoppelt (n=87)** | **0,556** |
|
||||
| **95-%-Bootstrap-KI** | **[0,434 … 0,674]** |
|
||||
Das Intervall enthält **den Zufall (0,50) UND die Messlatte (0,654)**. Es ist
|
||||
also **nicht** belegt, dass das Modell schlechter rankt als beim Nachtrainieren —
|
||||
es ist nur nichts belegt. „AUC 0,54" als Durchfall zu lesen wäre falsch.
|
||||
|
||||
⚠⚠ **DIE FÄLLIGKEITSBEDINGUNG ZÄHLTE DIE FALSCHE GRÖSSE — behoben.** Sie stand
|
||||
auf **800 ROHEN** Vorhersagen; die sind nicht unabhängig (dieselbe Position
|
||||
pendelt vielfach um dasselbe Level). Aus 878 rohen werden **87 entkoppelte** —
|
||||
die Bedingung hat die Beweismenge um **rund das Zehnfache** überschätzt und die
|
||||
Messung als „fällig" gemeldet, obwohl sie nichts entscheiden konnte. Die
|
||||
Abhängigkeit war im Skript seit jeher dokumentiert („entkoppelte Sicht"), nur die
|
||||
Fälligkeit zählte daran vorbei. **Jetzt: 350 ENTKOPPELTE** (halbiert die
|
||||
KI-Breite 0,12 → 0,06, erst dann sind 0,50 und 0,65 trennbar; bei ~17/Tag ≈ 3
|
||||
Wochen). Stand: **87/350**.
|
||||
⚠ Verwandt mit der Bootstrap-Grenze bei `backtest_cost_gate.ci95`
|
||||
(„überlappende Beobachtungen → effektives n ist ~n/24") — dieselbe Klasse Fehler,
|
||||
diesmal in einer Fälligkeitsbedingung statt in einem Konfidenzintervall.
|
||||
|
||||
✅ **Operativ kein Notfall:** `auto_sr_close = false` seit 06.08. — das Modell
|
||||
schliesst **keine** Trades. Es speist nur den Hinweis in der App, die
|
||||
Chart-Linien, den Copilot-Kontext und `stop_approach`. Die Fehlkalibrierung
|
||||
kostet damit aktuell **kein Geld**, sie macht nur die Anzeige zu pessimistisch
|
||||
(sie sagt „Level hält", wo es in 53 % der Fälle bricht).
|
||||
⚠ **Vor einem erneuten Nachtrainieren:** der letzte Versuch hat live auch nicht
|
||||
gehalten. Der Befund zeigt auf das **Niveau** (Basisrate/Achsenabschnitt), nicht
|
||||
zwingend auf die Rangfolge — ein drittes Fitten derselben Bauart würde denselben
|
||||
Weg gehen. Naheliegender wäre, das Niveau **laufend** an die jüngste Basisrate zu
|
||||
koppeln oder ein Vola-/Regime-Merkmal aufzunehmen. **Nicht gebaut, nicht
|
||||
gemessen.**
|
||||
|
||||
## ⚠⚠ LIVE-CODE HING AN EINEM BACKTEST-SKRIPT — behoben 2026-08-07
|
||||
|
||||
**Befund:** `core/engine.py` (`squeeze_monitor`) und `weekly_review.py` importierten
|
||||
|
||||
+37
-2
@@ -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 = []
|
||||
|
||||
+17
-3
@@ -62,9 +62,23 @@ CHECKS = [
|
||||
"backtest_srclose_prob.py aufnehmen und neu fitten (live in beiden "
|
||||
"Hälften +6/+4 Pp für die 2.–4. Berührung, 5.+ fällt zurück). "
|
||||
"Danach mit frischen Live-Daten gegenprüfen.",
|
||||
"have": lambda: _q("SELECT COUNT(*) FROM pbreak_predictions "
|
||||
"WHERE outcome IS NOT NULL AND ts >= strftime('%s','2026-08-01')"),
|
||||
"need": 800, "unit": "Vorhersagen seit 01.08.",
|
||||
# ⚠⚠ EINHEIT KORRIGIERT 2026-08-07 — die alte Bedingung zählte die FALSCHE
|
||||
# Größe. Sie stand auf 800 ROHEN Vorhersagen; die sind aber NICHT
|
||||
# unabhängig (dieselbe Position pendelt vielfach um dasselbe Level). Am
|
||||
# 07.08. war sie mit 878 „fällig" — entkoppelt (max. 1 je Level und
|
||||
# Stunde) waren es **87**, und das 95-%-Bootstrap-Intervall der AUC ging
|
||||
# von 0,434 bis 0,674: es enthält sowohl den Zufall (0,50) als auch die
|
||||
# Messlatte (0,654). Die Messung konnte also gar nichts entscheiden.
|
||||
# Die Abhängigkeit war im Skript seit jeher dokumentiert („entkoppelte
|
||||
# Sicht"), nur die Fälligkeit zählte daran vorbei — sie überschätzte die
|
||||
# Beweismenge um rund das Zehnfache.
|
||||
# 350 entkoppelte Zeilen ≈ halbe KI-Breite (0,12 → 0,06), erst dann sind
|
||||
# 0,50 und 0,65 überhaupt trennbar. Bei ~17/Tag sind das ~3 Wochen.
|
||||
"have": lambda: _q(
|
||||
"SELECT COUNT(*) FROM (SELECT DISTINCT ROUND(level,2), ts/3600 "
|
||||
"FROM pbreak_predictions WHERE outcome IS NOT NULL "
|
||||
"AND ts >= strftime('%s','2026-08-01'))"),
|
||||
"need": 350, "unit": "ENTKOPPELTE Vorhersagen seit 01.08. (max. 1 je Level und Stunde)",
|
||||
"cmd": "python analyze_pbreak_live.py",
|
||||
},
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user