#!/usr/bin/env python3
"""H1-Stärke-Filter (Diagnose: SHORT-Empfehlungen verlieren 31 % WR in Aufwärts-Regime):
Verwirft ein Signal, das GEGEN einen STARKEN H1-Trend läuft (|H1 EMA12−EMA50| > thr×ATR_H1).
Das ist NICHT der schon verworfene H1-WINKEL-Filter, sondern die EMA-Trend-STÄRKE.
Signale kommen aus der echten `_build`-Logik (wie live). Exit = live-Modell (SL 2,0×ATR
+ Trailing 1,5, Breakeven 1,3). Kosten = echter Bar-Spread/ATR. 2 Halbjahre.

Entscheidung: Filter NUR bauen, wenn die WEGGEFILTERTEN Signale in BEIDEN Hälften
negativen Ø-R haben UND der Gesamt-ΣR in beiden steigt. Haben sie positiven Edge
(wie 6× zuvor), macht der Filter den Bot schlechter → verwerfen.
"""
import sys, bisect
import MetaTrader5 as mt5
from core.analysis import calc_trend_angle
from core.wave_rec import (WaveRecommender, _atr, _ema_last, _ema_series,
                           _EMA_FAST, _EMA_SLOW, _N_BARS, _HTF_DEADBAND, _ANGLE_LR)
_MAXH = 288; _ATRMIN = 0.12


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, sl_atr=2.0, trail=1.5, trail_on=0.3, be_on=1.3):
    eff = entry - d*sl_atr*atr; hw = entry
    end = min(j0+_MAXH, len(C)-1); exit_px = C[end]
    for j in range(j0, end+1):
        hi, lo = H[j], L[j]
        if (lo <= eff) if d > 0 else (hi >= eff): exit_px = eff; break
        hw = max(hw, hi) if d > 0 else min(hw, lo)
        prof = (C[j]-entry)*d
        if prof >= trail_on*atr:
            cand = hw - d*trail*atr
            if prof >= be_on*atr: cand = max(cand, entry) if d > 0 else min(cand, entry)
            eff = max(eff, cand) if d > 0 else min(eff, cand)
    return (exit_px-entry)*d/atr


def st(Rs):
    if not Rs: return None
    n = len(Rs); w = sum(1 for x in Rs if x > 0); s = sum(Rs)
    up = sum(x for x in Rs if x > 0); dn = -sum(x for x in Rs if x < 0)
    return dict(n=n, wr=100*w/n, oR=s/n, pf=(up/dn if dn > 0 else 99.9), sum=s)


def line(lbl, s):
    if not s: return f"    {lbl:<24} —"
    return (f"    {lbl:<24} n={s['n']:>4} WR={s['wr']:>3.0f}% ØR={s['oR']:+.3f} "
            f"PF={s['pf']:>4.2f} ΣR={s['sum']:>+6.0f}")


def main():
    n = int(sys.argv[1]) if len(sys.argv) > 1 else 80000
    mt5.initialize()
    sym = next((c for c in ("SpotCrude", "USOIL", "WTI", "XTIUSD") if mt5.symbol_info(c)), None)
    bars = mt5.copy_rates_from_pos(sym, mt5.TIMEFRAME_M5, 0, n+_N_BARS+_MAXH+5)
    m30 = mt5.copy_rates_from_pos(sym, mt5.TIMEFRAME_M30, 0, n//6+500)
    h1  = mt5.copy_rates_from_pos(sym, mt5.TIMEFRAME_H1, 0, n//12+500)
    si = mt5.symbol_info(sym); point = si.point
    mt5.shutdown()
    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]
    SP = [float(b["spread"])*point for b in bars]

    def series(rr):
        t = [int(b["time"]) for b in rr]; c = [float(b["close"]) for b in rr]
        hh = [float(b["high"]) for b in rr]; ll = [float(b["low"]) for b in rr]
        return t, _ema_series(c, _EMA_FAST), _ema_series(c, _EMA_SLOW), _atr_series(hh, ll, c)
    mT, mEf, mEs, mA = series(m30)
    hT, hEf, hEs, hA = series(h1)

    def m30s(ts):
        i = bisect.bisect_right(mT, ts)-1
        if i < _EMA_SLOW or mA[i] is None or mA[i] <= 0: return 0
        dd = mEf[i]-mEs[i]
        return 0 if abs(dd) < _HTF_DEADBAND*mA[i] else (1 if dd > 0 else -1)

    def h1_strength(ts):
        """H1-EMA-Abstand in ATR (signiert; >0 = aufwärts)."""
        i = bisect.bisect_right(hT, ts)-1
        if i < _EMA_SLOW or hA[i] is None or hA[i] <= 0: return 0.0
        return (hEf[i]-hEs[i])/hA[i]

    w = WaveRecommender(type("T", (), {"snapshot": lambda s: {"intervals": {}}})(), mt5.TIMEFRAME_M5)
    sigs = []   # (idx, d, atr, h1_strength)
    def cost(i, atr): return (SP[i] if SP[i] > 0 else 0.0225)/atr
    for i in range(_N_BARS, len(C)-_MAXH-1):
        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)
        a5 = calc_trend_angle(C[i-_ANGLE_LR-2:i], _ANGLE_LR)
        rec, _ = w._build(ef, es, C[i-1], atr, "M5", 0, htf_trend=m30s(T[i]), angle=a5)
        if rec["signal"] == "WARTEN": continue
        d = 1 if rec["signal"] == "LONG" else -1
        sigs.append((i, d, max(atr, _ATRMIN), h1_strength(T[i])))
    mid = len(C)//2

    print("="*82)
    print(f"  H1-Stärke-Filter — {sym} M5  ({len(sigs)} Signale · Exit live · Echtkosten · 2 Halbjahre)")
    print(f"  Filter verwirft Signal, wenn es GEGEN einen H1-Trend > thr×ATR läuft.")
    print("="*82)
    for lbl, lo, hi in (("H1 (alt)", 0, mid), ("H2 (neu)", mid, len(C))):
        seg = [(i, d, a, h1) for (i, d, a, h1) in sigs if lo <= i < hi]
        base = [sim(C[i], d, a, H, L, C, i+1) - cost(i, a) for (i, d, a, h1) in seg]
        print(f"\n{lbl}:")
        print(line("BASIS (alle Signale)", st(base)))
        for thr in (0.5, 1.0, 1.5):
            # gegen starken H1: SHORT & H1 stark auf  ODER  LONG & H1 stark ab
            drop = [(i, d, a) for (i, d, a, h1) in seg
                    if (d < 0 and h1 > thr) or (d > 0 and h1 < -thr)]
            keep = [(i, d, a) for (i, d, a, h1) in seg
                    if not ((d < 0 and h1 > thr) or (d > 0 and h1 < -thr))]
            dR = [sim(C[i], d, a, H, L, C, i+1) - cost(i, a) for (i, d, a) in drop]
            kR = [sim(C[i], d, a, H, L, C, i+1) - cost(i, a) for (i, d, a) in keep]
            sd = st(dR); sk = st(kR)
            print(f"  thr={thr}×ATR:")
            print(line("  WEGGEFILTERT (drop)", sd) + ("   <- Edge<0 = Filter OK" if sd and sd["oR"] < 0 else ""))
            print(line("  BEHALTEN (keep)", sk))
    print(f"\n  Filter NUR bauen, wenn 'drop' ØR<0 & ΣR<0 in BEIDEN Hälften (dann hebt")
    print(f"  Entfernen den Gesamt-ΣR). Positiver drop-Edge = die Pullbacks tragen → verwerfen.")

if __name__ == "__main__":
    main()
