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
|
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.
|
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
|
## ⚠⚠ LIVE-CODE HING AN EINEM BACKTEST-SKRIPT — behoben 2026-08-07
|
||||||
|
|
||||||
**Befund:** `core/engine.py` (`squeeze_monitor`) und `weekly_review.py` importierten
|
**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"
|
DB = "oil_widget_history.db"
|
||||||
M30_SWITCH = datetime(2026, 7, 30).timestamp()
|
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):
|
def auc(ps, ys):
|
||||||
"""Rangbasiert, mit Bindungskorrektur."""
|
"""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(f" {len(rows)} ausgewertete Vorhersagen, {t0:%d.%m.%Y} bis {t1:%d.%m.%Y}")
|
||||||
print("=" * 84)
|
print("=" * 84)
|
||||||
|
|
||||||
report(rows, "GESAMT")
|
# ⚠ GESAMT mischt ALTES und NEUES Modell (s. MODELL_V2 oben) — bleibt als
|
||||||
calib(rows, "gesamt")
|
# 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)
|
# ── entkoppelt: max. 1 Vorhersage je (Level, Stunde)
|
||||||
seen = set(); dedup = []
|
seen = set(); dedup = []
|
||||||
|
|||||||
+17
-3
@@ -62,9 +62,23 @@ CHECKS = [
|
|||||||
"backtest_srclose_prob.py aufnehmen und neu fitten (live in beiden "
|
"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). "
|
"Hälften +6/+4 Pp für die 2.–4. Berührung, 5.+ fällt zurück). "
|
||||||
"Danach mit frischen Live-Daten gegenprüfen.",
|
"Danach mit frischen Live-Daten gegenprüfen.",
|
||||||
"have": lambda: _q("SELECT COUNT(*) FROM pbreak_predictions "
|
# ⚠⚠ EINHEIT KORRIGIERT 2026-08-07 — die alte Bedingung zählte die FALSCHE
|
||||||
"WHERE outcome IS NOT NULL AND ts >= strftime('%s','2026-08-01')"),
|
# Größe. Sie stand auf 800 ROHEN Vorhersagen; die sind aber NICHT
|
||||||
"need": 800, "unit": "Vorhersagen seit 01.08.",
|
# 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",
|
"cmd": "python analyze_pbreak_live.py",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user