Vollpruefung aller 87 Skripte + Nachrechnung der verworfenen Modelle
Phase 1 - Lauffaehigkeit: 87 von 87 Skripten laufen fehlerfrei (8000 Bars, Timeout 900 s). Kein Defekt durch die heutigen wave_rec-Aenderungen. Werkzeug: run_all_backtests.py, probiert die uneinheitlichen Aufruf-Signaturen adaptiv durch (Bar-Zahl / TF+Bars / zwei TFs+Bars). Phase 2a - breakout_k: die dokumentierte Begruendung REPRODUZIERT NICHT. k=0,3 war mit dem LEGACY_BE10-Exit (Breakeven 1,0) validiert. Erstmals mit dem kanonischen Exit nachgerechnet (backtest_breakout_canon.py, echte _confirm_breakout-Mechanik, 80k M5, 2 Halbjahre, Echtkosten): k=0,0 H1 -0,180/-569 H2 -0,054/-250 k=0,3 H1 -0,170/-356 H2 -0,069/-217 (LIVE) k=0,5 H1 -0,142/-262 H2 -0,074/-208 k=0,8 H1 -0,112/-166 H2 -0,032/ -73 k=1,0 H1 -0,101/-130 H2 -0,004/ -8 k=0,5/0,8/1,0 schlagen den Live-Wert in BEIDEN Haelften (bis +226/+209 SR). TROTZDEM keine Aenderung empfohlen: (a) alle Werte negativ (PF 0,70-0,99), es ist eine Wahl zwischen Verlusten; (b) Optimum lag am Rand -> Gegenprobe bis k=3,0 zeigt kein sauberes Optimum (H2: -8 -> -17 -> -20 -> -19); (c) gemessen wurde das UNGEGATETE Signal, live laufen min_conf/HTF/Entry-Raum davor. Naechster Schritt waere eine gegatete Neumessung, bevor ein Gate angefasst wird, das 63 % der WARTEN erzeugt. Phase 2b - verworfene Modelle bei vollen Bars: ALLE bleiben verworfen. 14 Klassen (ORB, Doppeltop, Volume Profile, Liquidity Sweeps, Konsolidierung, Handbuch-Level, Marktstruktur, Momentum, Inter-Market, Chop-Gate, Reversal-Lockout, S/R-Close-Signal, MACD/ADX/RSI, HTF-Winkel) - keine kippt ins Positive. Bei ~14 Tests waere bei 5 % Fehlalarmquote ein falsch-positives Ergebnis zu erwarten gewesen; es gab keins. Regel vorab fixiert. Kein Freibrief fuer regelmaessiges Nachrechnen - die Begruendung gegen woechentliche Laeufe steht unveraendert. Anlass war die einmalige Signalaenderung. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
9e6e81dd34
commit
80a5be7fe5
@@ -0,0 +1,103 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Führt ALLE Backtest-/Analyse-Skripte aus und protokolliert das Ergebnis.
|
||||
|
||||
Zweck (User-Auftrag 2026-08-04): nach den Änderungen am Signal (Reversal aus,
|
||||
`angle=`-Befund) prüfen, ob die Skripte noch laufen UND ob ihre Aussagen halten.
|
||||
|
||||
⚠ Die Aufruf-Signaturen sind NICHT einheitlich. Die meisten nehmen eine Bar-Zahl
|
||||
als erstes Argument, einige aber einen Timeframe (`backtest_signal.py M5 3000`,
|
||||
`backtest_htf_filter.py M5 M30 3000`). Ein Aufruf mit der falschen Signatur
|
||||
quittiert mit `KeyError`/`ValueError` — das ist KEIN Defekt und darf nicht als
|
||||
solcher gezählt werden. Deshalb probiert der Runner adaptiv mehrere Varianten
|
||||
und meldet erst dann einen Fehler, wenn KEINE davon durchläuft.
|
||||
|
||||
Aufruf: python run_all_backtests.py [bars] [--only muster]
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import pathlib
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
|
||||
PY = sys.executable
|
||||
HERE = pathlib.Path(__file__).parent
|
||||
|
||||
# Skripte, die kein eigenständiger Lauf sind (Bibliothek/Helfer) oder extrem lange
|
||||
# laufen und separat gefahren werden.
|
||||
SKIP = {
|
||||
"run_all_backtests.py",
|
||||
}
|
||||
|
||||
|
||||
def varianten(n: int) -> list[list[str]]:
|
||||
"""Aufruf-Varianten in der Reihenfolge, in der sie probiert werden."""
|
||||
return [
|
||||
[str(n)], # Standard: Bar-Zahl
|
||||
["M5", str(n)], # TF + Bar-Zahl
|
||||
["M5", "M30", str(n)], # zwei TFs + Bar-Zahl
|
||||
[], # ohne Argumente (Defaults)
|
||||
]
|
||||
|
||||
|
||||
def main() -> None:
|
||||
n = 6000
|
||||
only = None
|
||||
args = sys.argv[1:]
|
||||
if args and args[0].isdigit():
|
||||
n = int(args[0]); args = args[1:]
|
||||
if len(args) >= 2 and args[0] == "--only":
|
||||
only = args[1]
|
||||
|
||||
files = sorted(set(list(HERE.glob("backtest_*.py")) + list(HERE.glob("analyze_*.py"))))
|
||||
files = [f for f in files if f.name not in SKIP]
|
||||
if only:
|
||||
files = [f for f in files if only in f.name]
|
||||
|
||||
print(f"{len(files)} Skripte · {n} Bars · Start {time.strftime('%H:%M:%S')}")
|
||||
print("=" * 96)
|
||||
ok, fail, slow = [], [], []
|
||||
for i, f in enumerate(files, 1):
|
||||
t0 = time.time()
|
||||
erfolg = None
|
||||
letzter_fehler = ""
|
||||
for v in varianten(n):
|
||||
try:
|
||||
r = subprocess.run([PY, "-X", "utf8", f.name] + v, cwd=HERE,
|
||||
capture_output=True, text=True, timeout=900,
|
||||
encoding="utf-8", errors="replace")
|
||||
except subprocess.TimeoutExpired:
|
||||
letzter_fehler = "TIMEOUT (>900 s)"
|
||||
continue
|
||||
if r.returncode == 0:
|
||||
erfolg = (v, r.stdout or "")
|
||||
break
|
||||
tail = [x for x in (r.stderr or "").splitlines() if x.strip()]
|
||||
letzter_fehler = tail[-1][:110] if tail else f"exit {r.returncode}"
|
||||
dt = time.time() - t0
|
||||
if erfolg:
|
||||
v, out = erfolg
|
||||
zeilen = [x for x in out.splitlines() if x.strip()]
|
||||
sig = " ".join(v) or "(ohne)"
|
||||
print(f"[{i:>2}/{len(files)}] OK {f.name:<36} {dt:>6.1f}s args={sig}")
|
||||
ok.append((f.name, sig, dt, zeilen[-1][:100] if zeilen else ""))
|
||||
if dt > 120:
|
||||
slow.append((f.name, dt))
|
||||
else:
|
||||
print(f"[{i:>2}/{len(files)}] FEHLER {f.name:<36} {dt:>6.1f}s {letzter_fehler}")
|
||||
fail.append((f.name, letzter_fehler))
|
||||
|
||||
print("=" * 96)
|
||||
print(f"OK: {len(ok)} FEHLER: {len(fail)} (Ende {time.strftime('%H:%M:%S')})")
|
||||
if fail:
|
||||
print("\nFEHLGESCHLAGEN:")
|
||||
for name, err in fail:
|
||||
print(f" {name:<36} {err}")
|
||||
if slow:
|
||||
print("\nLangsam (>120 s):")
|
||||
for name, dt in sorted(slow, key=lambda x: -x[1]):
|
||||
print(f" {name:<36} {dt:.0f}s")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user