#!/usr/bin/env python3 """User-Regel messen: „P(Level-Durchbruch) > 60 % → laufen lassen, sonst close." Dazu 2 Fragen (Track B, Echtkosten, 2 Hälften): (1) Wie hoch ist die Basisrate P(Durchbruch) beim ERSTEN Touch des Ziel-Levels — und können Merkmale am Touch (Trend, Momentum, Touch-Zahl, Tick-Volumen) sie robust über/unter 60 % schieben? Break = nach Touch +0,5×ATR JENSEITS des Levels binnen 12 Bars, bevor 0,5×ATR zurückfällt. (2) Entscheidungs-relevant: Ø(R_run − R_close) je Merkmal-Segment — gibt es ein Segment, in dem CLOSE am Level das Weiterlaufen (Trailing) robust schlägt? Wenn kein Merkmal P(break) verlässlich trennt bzw. kein Segment robust pro-Close ist, kollabiert die Regel zu „immer laufen lassen" (= Trailing, schon gemessen). """ import sys import MetaTrader5 as mt5 from core.analysis import calc_trend_angle from core.wave_rec import (_EMA_FAST, _EMA_SLOW, _N_BARS, _ANGLE_LR, _ANGLE_DEAD, _REVERSAL_STRETCH, _STRETCH_MAX) _MAXH=200; _ATRMIN=0.12; _SL_ATR=2.0; _TRAILON=0.3; _MULT=1.5; _BE=1.3 _LOCK_START=3.5; _LOCK_SCALE=0.6; _LOCK_MIN=1.2; _TP_INIT=3.5 _PIV_K=3; _LOOKBACK=300; _BRK_W=12; _BRK_ATR=0.5 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 sim_run(entry,d,atr,H,L,C,j0,level): """Baseline-Trailing bis Ende; liefert (R_final, j_touch|None) — Touch = erstes Erreichen des Levels, solange der Trade offen ist.""" sl=entry-d*_SL_ATR*atr; tp=entry+d*_TP_INIT*atr hw=entry; rank=0; jt=None end=min(j0+_MAXH,len(C)-1) for j in range(j0,end+1): hi,lo=H[j],L[j] if (lo<=sl) if d>0 else (hi>=sl): return (sl-entry)*d/atr, jt if jt is None and level is not None and ((hi>=level) if d>0 else (lo<=level)): jt=j if (hi>=tp) if d>0 else (lo<=tp): return (tp-entry)*d/atr, jt hw=max(hw,hi) if d>0 else min(hw,lo) profit=(hw-entry)*d ph=0 if profit<_TRAILON*atr else (1 if profit<_LOCK_START*atr else 2) if ph=_BE*atr: cand=max(cand,entry) if d>0 else min(cand,entry) sl=max(sl,cand) if d>0 else min(sl,cand) elif ph==2: tm=max(_LOCK_MIN,_MULT*_LOCK_SCALE) cand=hw-d*tm*atr cand=max(cand,entry) if d>0 else min(cand,entry) sl=max(sl,cand) if d>0 else min(sl,cand) return (C[end]-entry)*d/atr, jt def is_break(level,d,atr,H,L,jt): up=level+d*_BRK_ATR*atr; dn=level-d*_BRK_ATR*atr for j in range(jt, min(jt+_BRK_W, len(H))): if (H[j]>=up) if d>0 else (L[j]<=up): return True if (L[j]<=dn) if d>0 else (H[j]>=dn): return False return False def main(): n=int(sys.argv[1]) if len(sys.argv)>1 else 80000 mt5.initialize(); sym=None for c in ("SpotCrude","USOIL","WTI","XTIUSD"): if mt5.symbol_info(c): sym=c; break si=mt5.symbol_info(sym); point=si.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]; V=[float(b["tick_volume"]) 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; TH=_REVERSAL_STRETCH print("="*96) print(f" P(Level-Durchbruch) & Close-vs-Run am Touch — {sym} M5 ({len(C)} Bars, Echtkosten)") print("="*96) for lbl,a,b in (("H1 (alt)",_N_BARS,mid),("H2 (neu)",mid,len(C))): ev=[] # (break?, dR = R_run − R_close, feature-dict) for i in range(max(a,_N_BARS,_LOOKBACK), min(b,len(C)-_MAXH-1)): atr=AT[i] if not atr or atr<=0: continue atr=max(atr,_ATRMIN); es=ES[i]; ef=EF[i] stretch=(C[i]-es)/atr ang=calc_trend_angle(C[i-_ANGLE_LR-2:i],_ANGLE_LR); ad=ang-90.0 d=0 if stretch<=-TH and ad>=_ANGLE_DEAD: d=1 elif stretch>=TH and ad<=-_ANGLE_DEAD: d=-1 elif abs(stretch)<_STRETCH_MAX: d=1 if ef>es else -1 if ef0: cands=[p for p in phis if p>entry+0.3*atr] level=min(cands) if cands else None near=phis else: cands=[p for p in plos if p0 else 0 ev.append((brk, R_run-R_close, {"mom":mom,"touch":touches,"vol":volr,"wt":withtrend})) n_ev=len(ev); pb=100*sum(1 for e in ev if e[0])/max(1,n_ev) dall=sum(e[1] for e in ev)/max(1,n_ev) print(f"\n{lbl}: {n_ev} Level-Touches · Basisrate P(break)={pb:.0f}% · Ø(R_run−R_close)={dall:+.3f}") segs=[("mit Trend",lambda f:f["wt"]==1),("gegen Trend",lambda f:f["wt"]==0), ("Momentum ≥0,3",lambda f:f["mom"]>=0.3),("Momentum <0,3",lambda f:f["mom"]<0.3), ("Level ≥2 Touches",lambda f:f["touch"]>=2),("Level 1 Touch",lambda f:f["touch"]<2), ("Volumen-Spike ≥1,5×",lambda f:f["vol"]>=1.5),("Volumen normal",lambda f:f["vol"]<1.5)] print(f" {'Segment':<20}{'n':>7}{'P(break)':>10}{'Ø(run−close)':>14}") for name,fn in segs: sub=[e for e in ev if fn(e[2])] if not sub: continue p=100*sum(1 for e in sub if e[0])/len(sub) dd=sum(e[1] for e in sub)/len(sub) mark=" ← CLOSE besser" if dd<0 else "" print(f" {name:<20}{len(sub):>7}{p:>9.0f}%{dd:>+14.3f}{mark}") print("\n Die Regel trägt nur, wenn ein Segment in BEIDEN Hälften Ø(run−close)<0 zeigt") print(" (= dort wäre Close besser) UND P(break) dort klar unter der Basisrate liegt.") if __name__=="__main__": main()