#!/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)<dead*ATR[idx] else (1 if 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()
