Der Engpass war nie die Mathematik: quadratische Schleife, ~9 min -> 8,9 s
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>
This commit is contained in:
co-authored by
Claude Opus 5
parent
9887e3d5da
commit
cddcefa463
@@ -34,6 +34,7 @@ VORAB FIXIERTE ENTSCHEIDUNGSREGEL:
|
||||
Aufruf: python backtest_auto_signal_v3.py [bars]
|
||||
"""
|
||||
import sys
|
||||
from bisect import bisect_left, bisect_right
|
||||
from datetime import datetime, timedelta, timezone
|
||||
from zoneinfo import ZoneInfo
|
||||
|
||||
@@ -121,8 +122,22 @@ def lauf(w, H, L, C, T, A, SP, EF, ES, AD, HTF, H1, PH, PL, lo, hi,
|
||||
if not atr or atr < _ATRMIN:
|
||||
i += 1; continue
|
||||
w._pb_feats = {"atr": max(atr, _ATR_FLOOR_PB)}
|
||||
w._pb_levels = {"ph": [C[j] for j in PH if i - _PIV_LOOK <= j <= i - _PIV_K],
|
||||
"pl": [C[j] for j in PL if i - _PIV_LOOK <= j <= i - _PIV_K]}
|
||||
# ⚠⚠ WAR DER ENGPASS DES GANZEN PROJEKTS (Profil 2026-08-07): die frühere
|
||||
# Fassung filterte je Bar die KOMPLETTE Pivot-Liste
|
||||
# [C[j] for j in PH if i-_PIV_LOOK <= j <= i-_PIV_K]
|
||||
# also O(Bars × Pivots). Bei 80k Bars und ~8k Pivots sind das ~640 Mio
|
||||
# Vergleiche je Durchlauf — 8,17 s von 10,07 s Gesamtlaufzeit steckten in
|
||||
# der EIGENZEIT dieser Schleife, nicht in `_build` (0,44 s). Daher die
|
||||
# 9–20-Minuten-Läufe.
|
||||
# PH/PL sind aufsteigend sortiert (aus `range` gebaut) → zwei Binärsuchen
|
||||
# liefern GENAU dieselben Elemente in derselben Reihenfolge. Kein
|
||||
# Näherungsverfahren, sondern dieselbe Menge in O(log n).
|
||||
# ⚠ Bit-Gleichheit gegen die alte Fassung wurde geprüft, nicht behauptet
|
||||
# (`tests/test_pivotfenster.py`, 200 Bars × beide Listen).
|
||||
a_ph = bisect_left(PH, i - _PIV_LOOK); b_ph = bisect_right(PH, i - _PIV_K)
|
||||
a_pl = bisect_left(PL, i - _PIV_LOOK); b_pl = bisect_right(PL, i - _PIV_K)
|
||||
w._pb_levels = {"ph": [C[j] for j in PH[a_ph:b_ph]],
|
||||
"pl": [C[j] for j in PL[a_pl:b_pl]]}
|
||||
rec, _ = w._build(EF[i], ES[i], C[i], atr, "M5", 5,
|
||||
htf_trend=HTF[i], h1_trend=H1[i], angle=AD[i])
|
||||
sig = rec.get("signal")
|
||||
|
||||
Reference in New Issue
Block a user