Initial commit: Oil Trading Bot (MT5, WTI)
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>
This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
#!/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()
|
||||
Reference in New Issue
Block a user