Anlass war die Frage nach numpy. Statt zu vermuten wurde profiliert — und das
Ergebnis war ein anderes als erwartet: von 10,07 s Gesamtlaufzeit steckten
8,17 s in der EIGENZEIT der Backtest-Schleife, nur 0,44 s in _build.
Ursache:
[C[j] for j in PH if i - _PIV_LOOK <= j <= i - _PIV_K] # je BAR, ganze Liste
Das ist O(Bars x Pivots) — bei 80k Bars hunderte Millionen Vergleiche, und
genau daher kamen die 9-20-Minuten-Laeufe. PH/PL sind sortiert, also genuegen
zwei Binaersuchen fuer dieselbe Menge in O(log n).
Gemessen: backtest_signal_touchfill.py ueber 80k Bars von ~9 min auf 8,9 s
(~60x), bei 8k Bars 10,07 s -> 1,43 s. Das Ergebnis bleibt inhaltlich
identisch (alle sechs Felder negativ); die Handvoll Trades Unterschied ist die
bekannte Live-Bar-Drift, nicht der Umbau.
MIGRATIONS-REGEL ERNST GENOMMEN: ein Vorher/Nachher-Vergleich zweier LAEUFE
taugt hier nicht, weil copy_rates_from_pos am neuesten Bar ankert und
eintreffende Live-Bars das Fenster verschieben. Die Gleichheit wird deshalb
DIREKT auf der Datenstruktur bewiesen — tests/test_pivotfenster.py mit vier
Faellen: 4.000 Bars x 400 Pivots, Randfaelle, leere Liste, beidseitig
inklusive Grenzen.
Angewandt auf 7 Skripte (auto_signal_v3, breakout_gated, dist_gated, htf_vola,
metalabel, sl_width, trail_be) — mechanisch identische Transformation, alle
kompilieren, Stichprobe gegengelaufen (dist_gated 20k in 1,1 s).
Lehre: die naheliegende Antwort (numpy) war die falsche. Ein Profil kostet zwei
Minuten und haette diese Bremse jederzeit gezeigt — sie lag seit Monaten in
jedem gegateten Backtest.
17 Tests gruen, n-Falle-Scan sauber.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Nachgeholt, was in der Vollpruefung offen blieb: die ungegatete Messung zeigte
k=0,5/0,8/1,0 besser als den Live-Wert 0,3 - aber ohne min_conf, HTF-Filter und
Entry-Raum. backtest_breakout_gated.py schliesst die Luecke mit den ECHTEN
Methoden (_build, _confirm_breakout-Mechanik, _room_gate mit kausalen M5-Pivots).
k=0,0 H1 -0,173/-193 H2 +0,003/ +7
k=0,2 H1 -0,185/-149 H2 -0,012/ -16
k=0,3 H1 -0,160/-122 H2 -0,036/ -47 (LIVE)
k=0,5 H1 -0,127/ -85 H2 -0,041/ -47
k=0,8 H1 -0,101/ -54 H2 -0,012/ -11
k=1,0 H1 -0,096/ -45 H2 -0,016/ -12
Bestaetigt: k=0,5/0,8/1,0 schlagen 0,3 in BEIDEN Haelften, die Nachbarn halten
mit, und die OR verbessert sich in H1 monoton - also nicht nur
Handelsvermeidung. Die vorab fixierte Regel ist erfuellt.
TROTZDEM keine Umstellung empfohlen, und der Grund ist kein Messfehler sondern
eine Zweckfrage: alle Werte bleiben negativ (PF 0,70-1,01), das Gate begrenzt
Schaden statt Edge zu erzeugen; der Auto-Signal-Pfad ist ohnehin aus, das Signal
ist ein Vorschlag fuer den Menschen, und dessen gemessener Vorteil entstand auf
der k=0,3-Population; k=0,8 kuerzt die Empfehlungen um ~39 % und treibt den
WARTEN-Anteil weiter hoch, der mit 93 % ohnehin im Fokus steht.
Zwei benannte Abweichungen der Simulation:
- _confirm_breakout misst seinen Timeout mit time.time() gegen 3600 s. Im
Bar-Loop vergeht keine Wall-Clock-Zeit, der Timeout wuerde nie feuern. 3600 s
sind auf M5 exakt 12 Bars, so wird gezaehlt. Merke: jede time.time()-Messung
im Live-Code ist in einer Bar-Simulation stumm.
- hour=None, weil die EIA-Pruefung in _build ueber datetime.now(_BERLIN) laeuft -
mit Bar-Stunde wuerde ein Lauf am Mittwoch 15:30-16:30 alle Bars blocken.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>