#!/usr/bin/env python3 """R-Ertrag der P(break)-Schwellen-Regel messen (Track B, Echtkosten, 2 Hälften): Regel: erreicht die Welle das gegenüberliegende Level, berechne P(Durchbruch) mit dem kalibrierten Logit-Modell (auf H1 trainiert). Ist P < Schwelle X → am Level CLOSEN; sonst laufen lassen (Live-Trailing). Baseline = immer laufen lassen. Findet das R-Optimum und prüft die User-Schwelle 60 % (= closen wenn P<0,60). """ import sys import numpy as np 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): sl=entry-d*_SL_ATR*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] if (lo<=sl) if d>0 else (hi>=sl): return (sl-entry)*d/atr if (hi>=tp) if d>0 else (lo<=tp): return (tp-entry)*d/atr 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 def collect(a,b,H,L,C,EF,ES,AT,SP,point): """→ Liste dicts: R_run (baseline), touched, break, feat, R_close (bei Touch).""" TH=_REVERSAL_STRETCH; out=[] 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 else 0.0225)/atr R_run=sim_run(entry,d,atr,H,L,C,i+1)-cost rec={"R_run":R_run,"touched":False} phis,plos=[],[] for j in range(i-_LOOKBACK+_PIV_K, i-_PIV_K): if H[j]==max(H[j-_PIV_K:j+_PIV_K+1]): phis.append(H[j]) if L[j]==min(L[j-_PIV_K:j+_PIV_K+1]): plos.append(L[j]) if d>0: cands=[p for p in phis if p>entry+0.3*atr]; level=min(cands) if cands else None else: cands=[p for p in plos if p=level) if d>0 else (L[j]<=level)): jt=j; break if ((entry-L[j]) if d>0 else (H[j]-entry)) >= 2.0*atr: break if jt is not None: up=level+d*_BRK_ATR*atr; dn=level-d*_BRK_ATR*atr; brk=False for j in range(jt, min(jt+_BRK_W, len(H))): if (H[j]>=up) if d>0 else (L[j]<=up): brk=True; break if (L[j]<=dn) if d>0 else (H[j]>=dn): brk=False; break rec.update(touched=True, brk=1.0 if brk else 0.0, R_close=(level-entry)*d/atr-cost, feat=[(C[jt]-C[max(0,jt-6)])*d/atr,(C[jt]-C[max(0,jt-3)])*d/atr, 1.0 if (EF[jt]-ES[jt])*d>0 else 0.0, abs(level-entry)/atr]) out.append(rec) return out def fit_logreg(X,y,iters=3000,lr=0.3): n,m=X.shape; Xb=np.hstack([np.ones((n,1)),X]); w=np.zeros(m+1) for _ in range(iters): p=1/(1+np.exp(-(Xb@w))); w-=lr*(Xb.T@(p-y))/n return w 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] 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) # Modell auf H1-Touches trainieren 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])))) print("="*94) print(f" P(break)-Close-Regel — R-Ertrag (Echtkosten, Trailing-Baseline) — {sym} M5") print(f" Modell auf H1 trainiert · Koeff mom6={w[1]:+.2f} mom3={w[2]:+.2f} wt={w[3]:+.2f} dist={w[4]:+.2f}") print("="*94) for lbl,ev in (("H1 (alt)",ev1),("H2 (neu)",ev2)): base=sum(e["R_run"] for e in ev) tset=[e for e in ev if e["touched"]] for e in tset: e["_p"]=pbreak(e) print(f"\n{lbl}: {len(ev)} Wellen · {len(tset)} Level-Touches · Baseline (immer laufen) ΣR={base:+.0f}") print(f" {'Schwelle X':<12}{'%laufen':>9}{'ΣR Regel':>10}{'Δ vs Baseline':>15}") for X in (0.30,0.35,0.40,0.45,0.50,0.55,0.60,0.70): run=sum(1 for e in tset if e["_p"]>=X) total=sum((e["R_close"] if e["_p"]7.0f}%{total:>10.0f}{total-base:>+15.0f}{mark}") # Mindestgewinn-Variante (User-Frage): am Level nur closen, wenn der Close # mindestens minR (netto, ×ATR) bringt — sonst weiterlaufen lassen. print(f" {'Mindestgewinn (P<0.60)':<24}{'%geclosed':>10}{'ΣR Regel':>10}{'Δ vs minR=0':>13}") base_rule=sum((e["R_close"] if e["_p"]<0.60 else e["R_run"]) for e in tset) \ + sum(e["R_run"] for e in ev if not e["touched"]) for minR in (0.0,0.1,0.2,0.3,0.5,0.8): closed=sum(1 for e in tset if e["_p"]<0.60 and e["R_close"]>=minR) total=sum((e["R_close"] if (e["_p"]<0.60 and e["R_close"]>=minR) else e["R_run"]) for e in tset) + sum(e["R_run"] for e in ev if not e["touched"]) print(f" minR={minR:.1f}×ATR {100*closed/max(1,len(tset)):>8.0f}%{total:>10.0f}{total-base_rule:>+13.0f}") if __name__=="__main__": main()