TF-Churn-Fix: Breakout-Bestaetigung ueberlebt TF-Wechsel + Verweildauer

Auslöser: User-Frage warum der Bot die Rally am 31.07. (82,5 -> 84,4 in 2 h)
nicht gehandelt hat. Befund: in dem Fenster 99x WARTEN und 1x SHORT - und
dieser SHORT wurde am Tief autonom eroeffnet (AUTOSIG, -26,31 EUR, per
adverse15 geschlossen). Den LONG machte der User um 11:56 von Hand.

Der WARTEN-Anteil ist strukturell zu hoch:
   Backtest-Erwartung (backtest_dist.py)   ~43 %
   Live letzte 24 h                         93,2 %
   Live letzte 7 Tage                       88,0 %
   Live gesamt (93.599 Zeilen)              78,6 %

MECHANISMUS (im Log belegt): _choose_tf setzt den Score einer TF hart auf
0,0, sobald sie ueberdehnt ist - genau das passiert M5 IM Trend. Real am
31.07.: M5 sprang zwischen 0,00 und 1,93, die TF wechselte 33x am Tag
(Median-Abstand 5 min). Die 1,2x-Hysterese ist dagegen wirkungslos. Und
set_timeframe() verwarf bei JEDEM Wechsel die laufende Breakout-
Bestaetigung und verankerte sie beim aktuellen Kurs neu. Bei k=0,3 und
ATR_M30~0,53 braucht sie ~0,16 $, der Kurs lief ~0,08 $ je 5 min -> die
Bestaetigung konnte rechnerisch nie fertig werden.

Gleicher Fehlertyp wie beim P(break)-Modell am selben Tag:
backtest_breakout.py hat k=0,3 auf einer FESTEN Zeitebene validiert; live
wandert sie - die Bedingung, unter der die Messung gilt, existiert im
Betrieb nicht.

FIX 1 (wave_rec.set_timeframe): _pend wird nicht mehr zurueckgesetzt. Der
Anker gehoert zum Signal, nicht zur Zeitebene; bei Richtungswechsel
verankert _confirm_breakout ohnehin neu.
FIX 2 (engine._tf_loop): Mindest-Verweildauer [trading] tf_min_dwell_s=900.

Verifiziert mit synthetischen Szenarien: Fix 1 - Bestaetigung ueberlebt
M5->M30 und feuert LONG, Richtungswechsel verankert korrekt neu; Fix 2 -
an der ECHTEN Score-Folge vom 31.07. nachgespielt: 4 Wechsel -> 2.

NICHT backtestbar (Backtests laufen auf fester TF, das Churning existiert
dort nicht). Begruendung ist "stellt die Bedingung her, unter der die
Messung gilt", nicht "gemessen besser". Erfolgskontrolle = WARTEN-Anteil
muss sich Richtung ~43 % bewegen.

Bewusst nicht behoben: der 0,0-Einbruch des Scores bei Ueberdehnung selbst
- das waere eine Aenderung der TF-Bewertung und damit messpflichtig.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Axel Hocks
2026-07-31 12:37:54 +02:00
co-authored by Claude Opus 5
parent 0944b1c13a
commit 0208101707
3 changed files with 79 additions and 2 deletions
+14 -1
View File
@@ -237,7 +237,20 @@ class WaveRecommender:
self._tf = tf
self._rec = None # alte Welle verwerfen — TF gewechselt
self._ts = 0.0
self._pend = None # Breakout-Bestätigung zurücksetzen
# ⚠ `_pend` wird BEWUSST NICHT MEHR zurückgesetzt (Fix 2026-07-31).
# Vorher: `self._pend = None`. Real beobachtet an der Rally vom 31.07.
# (82,5 → 84,4 in 2 h): die TF-Heuristik wechselte 33× am Tag (Median-
# Abstand 5 min), weil der Score einer TF hart auf 0,0 fällt, sobald sie
# überdehnt ist (`_choose_tf`: `raw = sep if … stretch <= _STRETCH_MAX
# else 0.0`) — genau das passiert M5 IM Trend. Jeder Wechsel verwarf die
# laufende Breakout-Bestätigung und verankerte sie beim AKTUELLEN Kurs neu.
# Bei k=0,3 und ATR_M30≈0,53 braucht sie ~0,16 $; der Kurs lief ~0,08 $
# je 5 min → die Bestätigung konnte RECHNERISCH nie fertig werden. Folge:
# live 93 % WARTEN gegen ~43 % Backtest-Erwartung (`backtest_dist.py`).
# Der Anker gehört zum SIGNAL, nicht zur Zeitebene; dreht die Richtung,
# verankert `_confirm_breakout` ohnehin neu (`p.get("dir") != d`).
# ⚠ Das Level wurde mit dem ATR der alten TF gesetzt — bewusst behalten:
# eine Neuberechnung wäre wieder ein Reset und damit derselbe Fehler.
log.info(f"Wellen-TF: {_TF_LABELS.get(tf, str(tf))}")
# ── TU als Konfidenz-Faktor (kein harter Blocker mehr) ───────────────────