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
+42
View File
@@ -423,6 +423,48 @@ dort bereits nachvalidiert, ØR +0,305.) **Eine** Oberfläche:
Richtungs-Trefferquote der „aktiv"-Anzeige ~50 % (Münzwurf), Ø-Vorlauf ~0×ATR über
alle TF & H1-Regime → reiner Überdehnungs-Kontext, KEIN Signal.** (Die früheren
„70 %" aus `backtest_bounce.py` waren exit-getrieben, nicht Richtungs-Vorhersage.)
- **⚠⚠ TF-CHURN-FIX (2026-07-31, zwei Eingriffe) — Ursache für „93 % WARTEN statt 43 %":**
Auslöser war die User-Frage „warum hat der Bot die Treppe nicht erkannt und long
eröffnet?" zur Rally am 31.07. (82,5 → 84,4 in 2 h). Befund: in dem Fenster gab es
**99× WARTEN und 1× SHORT** — und dieser SHORT wurde am Tief autonom eröffnet
(AUTOSIG, 26,31 €, per `adverse15` geschlossen); den LONG machte der User um 11:56
von Hand gegen die Empfehlung. **Der WARTEN-Anteil live ist strukturell zu hoch:**
| | WARTEN |
|---|---|
| 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 überdehnt ist (`raw = sep if (sep>=deadband and stretch<=_STRETCH_MAX)
else 0.0`) — genau das passiert M5 IM Trend. Real am 31.07.: M5 sprang zwischen
**0,00 und 1,93**, die TF wechselte **33× am Tag, Median-Abstand 5 min**. Die
vorhandene 1,2×-Hysterese ist dagegen wirkungslos (gegen 0,0 kommt jeder Wert durch).
Und `set_timeframe()` verwarf bei JEDEM Wechsel die laufende Breakout-Bestätigung
(`_pend = None`) und verankerte sie beim AKTUELLEN Kurs neu. Bei `breakout_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.** Dazu: landet die Heuristik im Trend auf M30,
braucht das EMA-Kreuz dort Stunden — eine 2-h-Bewegung wird nie zum Signal.
⚠ **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 zurückgesetzt.** Der Anker
gehört zum Signal, nicht zur Zeitebene; dreht die Richtung, verankert
`_confirm_breakout` ohnehin neu (`p.get("dir") != d`). Das Level behält den ATR der
alten TF — bewusst, eine Neuberechnung wäre wieder ein Reset.
**FIX 2 (`engine._tf_loop`): Mindest-Verweildauer `[trading] tf_min_dwell_s=900`**
(0 = aus). Gibt einer TF Zeit, ihr Signal überhaupt fertig zu bestätigen.
**Verifiziert mit synthetischen Szenarien:** Fix 1 — Bestätigung überlebt den Wechsel
M5→M30 und feuert LONG, Richtungswechsel verankert korrekt neu; Fix 2 — an der ECHTEN
Score-Folge vom 31.07. nachgespielt: 4 Wechsel → 2.
⚠ **Ehrlich zur Beweislage:** das ist **NICHT backtestbar** — Backtests laufen
grundsätzlich auf einer festen TF, das Churning existiert dort per Konstruktion nicht.
Begründung ist also nicht „gemessen besser", sondern „stellt die Bedingung her, unter
der die vorhandene Messung gilt". **Erfolgskontrolle = der WARTEN-Anteil**: er muss
sich Richtung der gemessenen ~43 % bewegen (Abfrage s. Tabelle oben).
⚠ **Nicht behoben (bewusst):** der 0,0-Einbruch des Scores bei Überdehnung selbst —
das wäre eine Änderung der TF-Bewertung und damit messpflichtig. Fix 2 halbiert das
Churning, verhindert aber nicht den ersten Absturz auf M30.
- **Timeframe:** `[trading] tf_select=heuristic` → `engine._choose_tf` wählt jede
Minute die TF mit klarstem Trend aus dem **Band `[tf_min … tf_max]`** (leichter
Höher-TF-Bias). **Einstellung: `tf_min=M5`, `tf_max=M30`** (M1 raus: gemessen