P(break) neu trainiert auf live-spiegelnder Stichprobe (Weg b) - eingebaut

Behebt die am selben Tag gefundene Merkmals-Diskrepanz: das alte Modell war
auf "Anlauf zu einem beim Entry FIXIERTEN Level" trainiert, live waehlt
_draw_levels das Level jede Sekunde neu -> mom3 live 0,15 statt 1,45 ->
Ausgabe immer ~23 % -> Gate seit Inbetriebnahme faktisch nie aktiv.

backtest_pbreak_retrain.py: Stichprobe spiegelt den Live-Pfad (Level
dynamisch mit Hysterese, gesampelt an JEDEM Bar im 0,15xATR-Band, keine
Anlauf-Bedingung). Kontrolle: Merkmalsmittel der Stichprobe (mom6 0,203 /
mom3 0,202) treffen die live rekonstruierten Werte (0,181 / 0,149).

  AUC auf dieser Stichprobe (H2, out-of-sample):
      ALT-Modell  0,368   (schlechter als Zufall, 19,2 % vs real 39,4 %)
      NEU-Modell  0,654   kalibriert

backtest_pbreak_rvalue.py (R-Ertrag, Echtkosten, Baseline = nur Trailing):
NEU schlaegt ALT in BEIDEN Haelften bei JEDER Schwelle. Gegen die Baseline
gewinnt es bei 0,35/0,45/0,55 in beiden (bei 0,60 kippt H1).
Bestwert 0,35: H1 -149 vs -506 (+357), H2 +1308 vs -110 (+1418).
Nebenbefund: das ALTE Modell war in H1 schlechter als gar kein Auto-Close.

EINGEBAUT: neue _PB_MU/_SD/_W (final auf allen 80k gefittet, n=76.542,
Basisrate 37,8 %, nach H1->H2-Validierung; alte Werte als Kommentar) +
sr_close_pbreak 0,55 -> 0,35, Config-Waechter-Anker mitgezogen.
Verifiziert: Chart-Linien zeigen 43 %/36 % statt 8-15 %.

ACHTUNG - invertiert eine alte Projekt-Regel: mom3-Gewicht dreht das
Vorzeichen (+1,4330 -> -0,5420). Alt: "kriecht ans Level -> 26 % Bruch, mit
Schwung -> laufen lassen". Neu: Anlauf-Schub -> 26,5 % (Level absorbiert
ihn und haelt), Schwung weg vom Level -> 51 %. Beides gilt in seiner
Population (fixiertes vs. dynamisches Level); fuer den Live-Pfad gilt die
neue Lesart.

Offen: auch NEU schliesst bei 0,35 noch ~94-97 % der Positionen (waehlt vor
allem den besseren Moment). Touch-Zahl bringt im neuen Modell nichts mehr
(0,652 vs 0,654) - die dynamische Level-Wahl erfasst den Effekt bereits.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Axel Hocks
2026-07-31 08:57:16 +02:00
co-authored by Claude Opus 5
parent b137967a68
commit 0944b1c13a
5 changed files with 557 additions and 11 deletions
+29 -3
View File
@@ -100,9 +100,35 @@ _STARTUP_GRACE_S = 60.0 # nach Bot-Start schließt der Bot 60 s lang KE
# ⚠ Die Merkmale bleiben M5-basiert (mom6/mom3 auf M5-Bars) — nur die LEVEL sind M30.
# Alte M5-Werte (falls je zurück): MU (0.7482,0.7036,0.9112,0.7072) ·
# SD (1.1597,0.9687,0.2844,0.6403) · W (-0.5853,0.1192,0.7820,0.1204,-0.2994).
_PB_MU = (1.6565, 1.4523, 0.9465, 1.9133)
_PB_SD = (2.5291, 2.4177, 0.2250, 2.1257)
_PB_W = (-0.3264, 0.4719, 1.4330, 0.0943, -0.1885) # [b0, mom6, mom3, wt, dist]
# ⚠⚠ NEU TRAINIERT 2026-07-31 auf einer LIVE-SPIEGELNDEN Stichprobe
# (`backtest_pbreak_retrain.py` + `backtest_pbreak_rvalue.py`). GRUND: die alten
# Werte waren auf einer Situation trainiert, die live gar nicht vorkommt.
# Training ALT: Level beim Entry FIXIERT (≥0,3×ATR weg), warten auf den ersten
# Touch nach einem echten ANLAUF → mom3 ≈ 1,45×ATR (ein Schub)
# LIVE: `_draw_levels` wählt das nächste Level JEDE SEKUNDE NEU (Hysterese)
# → der Kurs steht neben einem Level, das gerade erst das nächste
# wurde, ohne Anlauf → mom3 ≈ 0,15×ATR
# Gemessen (aus `candles_m1` rekonstruiert, n=2275): mom3 live 0,149 vs. ALT-µ 1,4523
# (1,303) · mom6 0,181 vs 1,6565 (1,476). Der daraus folgende z-Versatz (1,05)
# erklärt die gesamte Fehlkalibrierung: das Modell sagte live IMMER ~23 % (real 41 %),
# lag damit stets unter der Schwelle → **das Gate war seit Inbetriebnahme nie aktiv**
# (91 % aller Berührungen geschlossen = der 2× verworfene pauschale S/R-Close).
# KONTROLLE auf der live-spiegelnden Stichprobe: ALT erreicht dort **AUC 0,368**
# (schlechter als Zufall!), NEU **0,654** out-of-sample (Fit H1 → H2).
# R-Ertrag (Echtkosten, Baseline = nur Trailing): NEU schlägt ALT in BEIDEN Hälften
# bei JEDER Schwelle; gegen die Baseline gewinnt es bei 0,35/0,45/0,55 in beiden
# (bei 0,60 kippt H1). Bestwert **0,35** (H1 +357, H2 +1418 gegen Baseline) →
# `sr_close_pbreak` entsprechend auf 0,35 gesetzt.
# ⚠ Das Gewicht von mom3 DREHT das Vorzeichen (+1,4330 → 0,5420): im Anlauf-Kontext
# hieß Schwung „Level bricht", im Klebe-am-Level-Kontext heißt er „Level hält".
# Deshalb war ALT live schlechter als eine Münze und nicht bloß nutzlos.
# Final auf allen 80k Bars gefittet (n=76.542 Events, Basisrate 37,8 %), nachdem
# H1→H2 out-of-sample validiert war — gleiches Vorgehen wie beim ersten Modell.
# Alte M30-Anlauf-Werte (Rückweg): MU (1.6565,1.4523,0.9465,1.9133) ·
# SD (2.5291,2.4177,0.2250,2.1257) · W (-0.3264,0.4719,1.4330,0.0943,-0.1885).
_PB_MU = (0.1962, 0.2071, 0.5300, 3.2624)
_PB_SD = (1.3109, 0.9579, 0.4991, 3.5649)
_PB_W = (-0.5216, 0.0712, -0.5420, 0.0047, 0.0386) # [b0, mom6, mom3, wt, dist]
def _p_break(mom6: float, mom3: float, wt: float, dist: float) -> float:
"""P(Level-Durchbruch) ∈ (0,1) aus den 4 standardisierten Merkmalen."""