#!/usr/bin/env python3 """Misst vier Verbesserungs-Ideen in einem Lauf (Live-Konfig: M5 + M30-Filter): A) Multi-TF-Konfluenz: Edge wenn nur M30 vs M30+H1 einig B) Exit nach Qualitaet: MAE/MFE (max Gegen-/Mitlauf in ATR) je Pullback-Bucket C) Tageszeit-Edge: Edge je Berliner Stunde D) Vola-Gate: Edge je ATR-Band """ from __future__ import annotations import sys from datetime import datetime, timezone, timedelta import MetaTrader5 as mt5 from core.wave_rec import (WaveRecommender, _atr, _ema_last, _EMA_FAST, _EMA_SLOW, _N_BARS, _HTF_DEADBAND) _TF = {"M1": mt5.TIMEFRAME_M1, "M5": mt5.TIMEFRAME_M5, "M15": mt5.TIMEFRAME_M15, "M30": mt5.TIMEFRAME_M30, "H1": mt5.TIMEFRAME_H1} _BERLIN = timezone(timedelta(hours=2)) # Juni = CEST (broker-epoch ist UTC+3 → -3+2) class _NeutralTU: def snapshot(self): return {"intervals": {}} def _ema_series(vals, period): k = 2.0/(period+1); out=[]; e=vals[0] for i,v in enumerate(vals): e = v if i==0 else v*k + e*(1-k); out.append(e) return out def _atr_series(H,L,C,period=14): trs=[0.0] for i in range(1,len(C)): trs.append(max(H[i]-L[i], abs(H[i]-C[i-1]), abs(L[i]-C[i-1]))) out=[] for i in range(len(C)): w=trs[max(1,i-period+1):i+1]; out.append(sum(w)/len(w) if w else None) return out def _rep(name, rets): if not rets: print(f" {name:<20} -"); return n=len(rets); win=sum(1 for x in rets if x>0) print(f" {name:<20} n={n:>4} Treffer={100*win/n:>3.0f}% Oe-Edge={sum(rets)/n:+.4f}") def _sign_at(ts, T, Ef, Es, ATR, dead): lo,hi,idx=0,len(T)-1,-1 while lo<=hi: m=(lo+hi)//2 if T[m]<=ts: idx=m; lo=m+1 else: hi=m-1 if idx<_EMA_SLOW or ATR[idx] is None or ATR[idx]<=0: return 0 d=Ef[idx]-Es[idx] return 0 if abs(d)0 else -1) def main(): n_bars = int(sys.argv[1]) if len(sys.argv)>1 else 8000 K = 10 if not mt5.initialize(): print("init", mt5.last_error()); sys.exit(1) sym=None for c in ("SpotCrude","USOIL","WTI","XTIUSD"): if mt5.symbol_info(c): sym=c; break sym=sym or "SpotCrude" bars = mt5.copy_rates_from_pos(sym, mt5.TIMEFRAME_M5, 0, n_bars+_N_BARS+K+5) m30b = mt5.copy_rates_from_pos(sym, mt5.TIMEFRAME_M30, 0, n_bars//6+400) h1b = mt5.copy_rates_from_pos(sym, mt5.TIMEFRAME_H1, 0, n_bars//12+400) mt5.shutdown() if bars is None or m30b is None or h1b is None: print("Bars fehlen"); sys.exit(1) T=[int(b["time"]) for b in bars] H=[float(b["high"]) for b in bars]; L=[float(b["low"]) for b in bars]; C=[float(b["close"]) for b in bars] def prep(bb): t=[int(x["time"]) for x in bb]; h=[float(x["high"]) for x in bb] l=[float(x["low"]) for x in bb]; c=[float(x["close"]) for x in bb] return t, _ema_series(c,_EMA_FAST), _ema_series(c,_EMA_SLOW), _atr_series(h,l,c) m30 = prep(m30b); h1 = prep(h1b) w=WaveRecommender(_NeutralTU(), mt5.TIMEFRAME_M5) confl={"nur M30":[], "M30+H1 einig":[]} mae={"near<0":[], "0-0.3":[], "0.3-1":[], "1-2":[], "2+":[]} mfe={k:[] for k in mae} by_hour={}; atr_vals=[]; rows=[] for i in range(_N_BARS, len(C)-K): wc=C[i-_N_BARS:i]; wh=H[i-_N_BARS:i]; wl=L[i-_N_BARS:i] atr=_atr(wh,wl,wc) if not atr or atr<=0: continue ef=_ema_last(wc,_EMA_FAST); es=_ema_last(wc,_EMA_SLOW) m=_sign_at(T[i], *m30, _HTF_DEADBAND) rec,_=w._build(ef,es,C[i-1],atr,"M5",5,htf_trend=m) if rec["signal"]=="WARTEN": continue d=1 if rec["signal"]=="LONG" else -1 fwd=C[i+K]-C[i]; r=fwd*d rows.append((r,atr,T[i])) # A) Konfluenz h=_sign_at(T[i], *h1, _HTF_DEADBAND) (confl["M30+H1 einig"] if h==d else confl["nur M30"]).append(r) # B) MAE/MFE in ATR seg_h=H[i+1:i+K+1]; seg_l=L[i+1:i+K+1] if d>0: adv=(min(seg_l)-C[i])/atr; fav=(max(seg_h)-C[i])/atr else: adv=(C[i]-max(seg_h))/atr; fav=(C[i]-min(seg_l))/atr near=(C[i-1]-es)/atr*d b = "near<0" if near<0 else "0-0.3" if near<0.3 else "0.3-1" if near<1 else "1-2" if near<2 else "2+" mae[b].append(adv); mfe[b].append(fav) # C) Stunde hr=datetime.fromtimestamp(T[i]-10800, timezone.utc).astimezone(_BERLIN).hour by_hour.setdefault(hr,[]).append(r) atr_vals.append((atr,r)) print("="*60); print(f" {sym} M5+M30 n_bars={len(C)} Vorlauf={K}"); print("="*60) print("\nA) Multi-TF-Konfluenz:") _rep("nur M30", confl["nur M30"]); _rep("M30+H1 einig", confl["M30+H1 einig"]) print("\nB) Exit: MAE/MFE (in ATR) je Pullback-Bucket [MAE=Gegenlauf, MFE=Mitlauf]:") for k in ["near<0","0-0.3","0.3-1","1-2","2+"]: a=mae[k]; f=mfe[k] if a: print(f" {k:<8} n={len(a):>4} Oe-MAE={sum(a)/len(a):+.2f} Oe-MFE={sum(f)/len(f):+.2f} MFE/|MAE|={ (sum(f)/len(f))/abs(sum(a)/len(a)+1e-9):.2f}") print("\nC) Tageszeit-Edge (Berliner Stunde):") for hr in sorted(by_hour): _rep(f"{hr:02d}:00", by_hour[hr]) print("\nD) Vola-Gate (ATR-Terzile):") atr_vals.sort() n=len(atr_vals); t1=atr_vals[:n//3]; t2=atr_vals[n//3:2*n//3]; t3=atr_vals[2*n//3:] for nm,seg in [("niedrig ATR",t1),("mittel ATR",t2),("hoch ATR",t3)]: rr=[r for _,r in seg]; lo=seg[0][0]; hi=seg[-1][0] _rep(f"{nm} ({lo:.2f}-{hi:.2f})", rr) if __name__ == "__main__": main()