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,76 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Verlässlichkeit der Bounce-Anzeige ('aktiv'): Wenn _bounce_one(TF)=active feuert
|
||||
(überdehnt + Winkel gedreht), wie oft bewegt sich der Kurs in Bounce-Richtung?
|
||||
Aufgeschlüsselt nach TF (M1/M5/M15/M30) und nach H1-Regime (mit/gegen/flach zur
|
||||
Bounce-Richtung). Nur ONSET (Übergang nicht-aktiv→aktiv) = unabhängige Ereignisse.
|
||||
"""
|
||||
import sys, bisect
|
||||
import MetaTrader5 as mt5
|
||||
from core.wave_rec import WaveRecommender, _atr, _ema_last, _EMA_FAST, _EMA_SLOW, _HTF_DEADBAND
|
||||
K = 10 # Vorlauf in Bars der jeweiligen TF
|
||||
|
||||
def _ema_series(v,p):
|
||||
k=2.0/(p+1); o=[]; e=v[0]
|
||||
for i,x in enumerate(v): e=x if i==0 else x*k+e*(1-k); o.append(e)
|
||||
return o
|
||||
def _atr_series(H,L,C,p=14):
|
||||
t=[0.0]
|
||||
for i in range(1,len(C)): t.append(max(H[i]-L[i],abs(H[i]-C[i-1]),abs(L[i]-C[i-1])))
|
||||
return [(sum(t[max(1,i-p+1):i+1])/max(1,len(t[max(1,i-p+1):i+1]))) if i else None for i in range(len(C))]
|
||||
|
||||
def main():
|
||||
n=int(sys.argv[1]) if len(sys.argv)>1 else 40000
|
||||
mt5.initialize()
|
||||
sym=None
|
||||
for c in ("SpotCrude","USOIL","WTI","XTIUSD"):
|
||||
if mt5.symbol_info(c): sym=c; break
|
||||
# H1-Regime vorbereiten
|
||||
h1=mt5.copy_rates_from_pos(sym,mt5.TIMEFRAME_H1,0,20000)
|
||||
hT=[int(b["time"]) for b in h1]; hc=[float(b["close"]) for b in h1]
|
||||
hh=[float(b["high"]) for b in h1]; hl=[float(b["low"]) for b in h1]
|
||||
hEf=_ema_series(hc,_EMA_FAST); hEs=_ema_series(hc,_EMA_SLOW); hA=_atr_series(hh,hl,hc)
|
||||
def h1_sign(ts):
|
||||
idx=bisect.bisect_right(hT,ts)-1
|
||||
if idx<_EMA_SLOW or hA[idx] is None or hA[idx]<=0: return 0
|
||||
d=hEf[idx]-hEs[idx]
|
||||
return 0 if abs(d)<_HTF_DEADBAND*hA[idx] else (1 if d>0 else -1)
|
||||
|
||||
tfs=[("M1",mt5.TIMEFRAME_M1),("M5",mt5.TIMEFRAME_M5),
|
||||
("M15",mt5.TIMEFRAME_M15),("M30",mt5.TIMEFRAME_M30)]
|
||||
print("="*86)
|
||||
print(f" Bounce-Anzeige 'aktiv' — Verlässlichkeit je TF & H1-Regime ({sym}, Vorlauf {K} Bars)")
|
||||
print(" Treffer = Kurs bewegt sich in Bounce-Richtung · Ø = Ø-Bewegung in ATR")
|
||||
print("="*86)
|
||||
for lbl,tf in tfs:
|
||||
r=mt5.copy_rates_from_pos(sym,tf,0,n)
|
||||
if r is None or len(r)<200: print(f"{lbl}: zu wenig Bars"); continue
|
||||
T=[int(b["time"]) for b in r]; H=[float(b["high"]) for b in r]
|
||||
L=[float(b["low"]) for b in r]; C=[float(b["close"]) for b in r]
|
||||
buckets={"mit":[], "gegen":[], "flach":[], "alle":[]}
|
||||
prev=False
|
||||
for i in range(120, len(C)-K):
|
||||
wc=C[i-119:i+1]; wh=H[i-119:i+1]; wl=L[i-119:i+1]
|
||||
atr=_atr(wh,wl,wc)
|
||||
if not atr or atr<=0: prev=False; continue
|
||||
b=WaveRecommender._bounce_one(wc,atr)
|
||||
active = bool(b and b["state"]=="active")
|
||||
if active and not prev:
|
||||
d=1 if b["dir"]=="LONG" else -1
|
||||
fwd=(C[i+K]-C[i])*d/atr # in ATR, Bounce-Richtung
|
||||
reg=h1_sign(T[i])
|
||||
cls = "mit" if reg==d else "gegen" if reg==-d else "flach"
|
||||
buckets[cls].append(fwd); buckets["alle"].append(fwd)
|
||||
prev=active
|
||||
print(f"\n{lbl} ({len(buckets['alle'])} aktive Bounce-Signale)")
|
||||
for cls in ("alle","mit","gegen","flach"):
|
||||
v=buckets[cls]
|
||||
if not v: print(f" {cls:<6} -"); continue
|
||||
hit=100*sum(1 for x in v if x>0)/len(v)
|
||||
print(f" {cls:<6} n={len(v):>4} Treffer={hit:>3.0f}% Ø={sum(v)/len(v):+.2f}×ATR")
|
||||
mt5.shutdown()
|
||||
print("\n 'mit' = H1-Trend in Bounce-Richtung (Trend-Fortsetzung)")
|
||||
print(" 'gegen' = H1-Trend GEGEN den Bounce (Gegen-Trend-Fade)")
|
||||
print(" 'flach' = H1 neutral (reine Range/Mean-Reversion)")
|
||||
|
||||
if __name__=="__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user