Headless FastAPI-Backend (server.py + core/engine.py) mit Mobile-PWA (web/), Strategie-/Backtest-Suite und Doku. Secrets, DB, Logs und Laufzeit-State sind via .gitignore ausgeschlossen; Config-Vorlage: oil_widget_config.ini.example. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
83 lines
4.3 KiB
Python
83 lines
4.3 KiB
Python
#!/usr/bin/env python3
|
|
"""S/R-Close SIGNAL-gegated (User-Idee 2026-07-22): den S/R-Close (P(break)<0,60)
|
|
UNTERDRÜCKEN, solange die Empfehlung noch in Trade-Richtung zeigt — dann laufen
|
|
lassen (bis das Signal auf WARTEN dreht). Test-Frage: bringt „bei mit-Trend am
|
|
Level HALTEN statt schließen" mehr als der reine P(break)-Close?
|
|
|
|
Reuse der gemessenen S/R-Close-Mechanik aus `backtest_srclose_prob.py`:
|
|
R_run = laufen lassen (Trailing-Exit) · R_close = am Level schließen
|
|
feat[2] = 1.0 wenn EMA am Touch in Trade-Richtung (= „Empfehlung LONG/SHORT"),
|
|
0.0 sonst (= Empfehlung neutral/gegen → ~WARTEN).
|
|
|
|
Regeln je Level-Touch:
|
|
BASELINE = immer laufen lassen.
|
|
P(break) = close wenn P<0,60 (der aktuelle Live-Mechanismus).
|
|
USER-Regel = close wenn P<0,60 UND Empfehlung NICHT in Richtung (feat[2]==0);
|
|
bei mit-Trend HALTEN (laufen). Differenz nur bei den mit-Trend-Touches.
|
|
2 Halbjahre, Echtkosten. Verdict: USER-Regel nur besser, wenn ΣR in BEIDEN Hälften
|
|
über dem reinen P(break)-Close liegt.
|
|
"""
|
|
import sys
|
|
import numpy as np
|
|
import MetaTrader5 as mt5
|
|
from backtest_srclose_prob import collect, fit_logreg, _ema_series, _atr_series
|
|
from core.wave_rec import _EMA_FAST, _EMA_SLOW, _N_BARS
|
|
|
|
|
|
def main():
|
|
n = int(sys.argv[1]) if len(sys.argv) > 1 else 80000
|
|
mt5.initialize()
|
|
sym = next((c for c in ("SpotCrude", "USOIL", "WTI", "XTIUSD") if mt5.symbol_info(c)), None)
|
|
point = mt5.symbol_info(sym).point
|
|
bars = None
|
|
for req in (n, 80000, 60000, 40000):
|
|
bars = mt5.copy_rates_from_pos(sym, mt5.TIMEFRAME_M5, 0, req)
|
|
if bars is not None and len(bars) > 2000:
|
|
break
|
|
mt5.shutdown()
|
|
H = [float(b["high"]) for b in bars]; L = [float(b["low"]) for b in bars]
|
|
C = [float(b["close"]) for b in bars]; SP = [float(b["spread"])*point for b in bars]
|
|
EF = _ema_series(C, _EMA_FAST); ES = _ema_series(C, _EMA_SLOW); AT = _atr_series(H, L, C)
|
|
mid = len(C)//2
|
|
ev1 = collect(_N_BARS, mid, H, L, C, EF, ES, AT, SP, point)
|
|
ev2 = collect(mid, len(C), H, L, C, EF, ES, AT, SP, point)
|
|
# P(break)-Modell auf H1-Touches trainieren (wie im Original)
|
|
t1 = [e for e in ev1 if e["touched"]]
|
|
X1 = np.array([e["feat"] for e in t1]); y1 = np.array([e["brk"] for e in t1])
|
|
mu = X1.mean(0); sd = X1.std(0)+1e-9
|
|
w = fit_logreg((X1-mu)/sd, y1)
|
|
def pbreak(e):
|
|
x = (np.array(e["feat"])-mu)/sd
|
|
return 1/(1+np.exp(-(w@np.concatenate([[1.0], x]))))
|
|
|
|
X = 0.60
|
|
print("="*88)
|
|
print(f" S/R-Close SIGNAL-gegated (bei mit-Trend HALTEN) — {sym} M5, 2 Halbjahre, Echtkosten")
|
|
print(f" Vergleich: reiner P(break)-Close (P<{X}) vs. deine Regel (nur closen wenn Empf. NICHT in Richtung)")
|
|
print("="*88)
|
|
for lbl, ev in (("H1 (alt)", ev1), ("H2 (neu)", ev2)):
|
|
for e in ev:
|
|
if e["touched"]: e["_p"] = pbreak(e)
|
|
untouched = sum(e["R_run"] for e in ev if not e["touched"])
|
|
tset = [e for e in ev if e["touched"]]
|
|
base = sum(e["R_run"] for e in ev) # immer laufen
|
|
pbrule = sum((e["R_close"] if e["_p"] < X else e["R_run"]) for e in tset) + untouched
|
|
# USER: close nur wenn P<X UND Empfehlung NICHT in Richtung (feat[2]<0.5)
|
|
user = sum((e["R_close"] if (e["_p"] < X and e["feat"][2] < 0.5) else e["R_run"])
|
|
for e in tset) + untouched
|
|
# Die betroffenen Touches: P<X UND mit-Trend (die deine Regel jetzt HÄLT statt closed)
|
|
held = [e for e in tset if e["_p"] < X and e["feat"][2] >= 0.5]
|
|
gv_close = sum(e["R_close"] for e in held); gv_run = sum(e["R_run"] for e in held)
|
|
print(f"\n {lbl}: {len(ev)} Wellen · {len(tset)} Touches")
|
|
print(f" Baseline (immer laufen) ΣR = {base:+.0f}")
|
|
print(f" P(break)-Close (Live) ΣR = {pbrule:+.0f} (Δ Baseline {pbrule-base:+.0f})")
|
|
print(f" DEINE Regel (mit-Trend halten) ΣR = {user:+.0f} (Δ P(break) {user-pbrule:+.0f})")
|
|
print(f" → betroffen: {len(held)} mit-Trend-Touches. Wenn geHALTEN: ΣR {gv_run:+.0f} "
|
|
f"vs. geschlossen: ΣR {gv_close:+.0f} → Halten {'BESSER' if gv_run>gv_close else 'SCHLECHTER'} "
|
|
f"({gv_run-gv_close:+.0f})")
|
|
print(f"\n Verdict: deine Regel nur einbauen, wenn 'Halten BESSER' in BEIDEN Hälften.")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|