#!/usr/bin/env python3 """Prüft die TRAILING-Logik und Optimierungen über 2 Zeiträume (Track B). Bildet die ECHTE Phasen-Mechanik nach (Init→Trail→Lock, HW-Ratsche, Breakeven-Boden) und variiert die Schlüsselparameter: - trail_start (ab welchem Profit der SL zu ratchen beginnt; live 0,3×ATR) - mult (Trail-Abstand HW−mult×ATR; live M5=1,5) plus Baseline 'Fix-Stop' (SL 2×ATR, kein Trailing) und 'Breakeven-only'. Signal-Set = Reversal + Trend (wie backtest_hourly). Metrik: Ø-R/PF/WR/ΣR je Hälfte. Robust nur, wenn eine Variante in BEIDEN Hälften besser ist. """ 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; _TP_INIT=3.5; _LOCK_START=3.5; _LOCK_SCALE=0.6; _LOCK_MIN=1.2 _BE=1.3 # Breakeven-Boden (live) 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(entry,d,atr,H,L,C,j0, trail_start, mult, breakeven=_BE, trail=True): """Echte Phasen-Trailing-Sim. trail=False → fixer Stop entry−mult×ATR (kein Ratchen).""" sl = entry - d*mult*atr tp = entry + d*_TP_INIT*atr hw = entry; rank = 0 end=min(j0+_MAXH, len(C)-1) for j in range(j0, end+1): hi,lo=H[j],L[j] hit_sl = (lo<=sl) if d>0 else (hi>=sl) hit_tp = (hi>=tp) if d>0 else (lo<=tp) if hit_sl: return (sl-entry)*d/atr # pessimistisch: SL vor TP im selben Bar if hit_tp: return (tp-entry)*d/atr hw = max(hw,hi) if d>0 else min(hw,lo) if not trail: continue profit=(hw-entry)*d ph = 0 if profit=breakeven*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 def st(Rs): if not Rs: return " -" n=len(Rs); w=sum(1 for r in Rs if r>0) g=sum(r for r in Rs if r>0); ls=-sum(r for r in Rs if r<0) return f"WR={100*w/n:>3.0f}% Ø-R={sum(Rs)/n:+.3f} PF={(g/ls if ls>0 else 99):>4.2f} Worst={min(Rs):+.2f} ΣR={sum(Rs):+.0f}" def signals(H,L,C,ES,EF,AT,lo,hi,step): TH=_REVERSAL_STRETCH; out=[] for i in range(max(lo,_N_BARS), min(hi,len(C)-_MAXH-1), step): 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 ef1 else 60000 step=int(sys.argv[2]) if len(sys.argv)>2 else 2 mt5.initialize(); sym=None for c in ("SpotCrude","USOIL","WTI","XTIUSD"): if mt5.symbol_info(c): sym=c; break bars=None for req in (n,100000,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] EF=_ema_series(C,_EMA_FAST); ES=_ema_series(C,_EMA_SLOW); AT=_atr_series(H,L,C) mid=len(C)//2 halves=[("H1 (alt)",_N_BARS,mid),("H2 (neu)",mid,len(C))] print("="*94) print(f" TRAILING-Optimierung — {sym} M5 ({len(C)} Bars, step {step}) Signal=Trend+Reversal") print(f" Live-Basis: trail_start=0,3 · mult=1,5 (M5) · Breakeven=1,3 · Lock ab 3,5×ATR") print("="*94) SIG={lbl: signals(H,L,C,ES,EF,AT,a,b,step) for lbl,a,b in halves} for lbl,_,_ in halves: print(f" {lbl}: {len(SIG[lbl])} Signale") variants = [("FIX-Stop 2,0 (kein Trail)", dict(trail_start=99, mult=2.0, trail=False)), ("Breakeven-only (mult=2,0)", dict(trail_start=_BE, mult=2.0, breakeven=_BE)), ("LIVE start0,3 mult1,5", dict(trail_start=0.3, mult=1.5)), ("start0,6 mult1,5", dict(trail_start=0.6, mult=1.5)), ("start1,0 mult1,5", dict(trail_start=1.0, mult=1.5)), ("start0,3 mult2,0", dict(trail_start=0.3, mult=2.0)), ("start1,0 mult2,0", dict(trail_start=1.0, mult=2.0)), ("start0,3 mult2,5", dict(trail_start=0.3, mult=2.5)), ("start1,3 mult2,5", dict(trail_start=1.3, mult=2.5))] for name,kw in variants: print(f"\n{name}") for lbl,_,_ in halves: Rs=[sim(C[i],d,atr,H,L,C,i+1, **kw) for (i,d,atr) in SIG[lbl]] print(f" {lbl} {st(Rs)}") if __name__=="__main__": main()