#!/usr/bin/env python3
"""Flatter-Analyse der Durchbruchs-Empfehlung (letzte 2 Tage, M1-Auflösung):
Rekonstruiert P(break) minütlich WIE DIE ENGINE (M5-Serie inkl. LAUFENDER Kerze,
deren Close = aktueller Kurs — genau das lässt mom3/mom6 im Bar springen) und misst
in Level-Nähe (≤0,6×ATR):
  - P-Spanne innerhalb einzelner M5-Kerzen (wie stark springt P intra-Bar)
  - Schwellen-Kreuzungen (close↔laufen bei 60 %) je Annäherungs-Episode
  - Zerlegung: Sprünge durch mom3 (laufende Kerze) vs. Level-Wechsel
"""
import sys, math
import MetaTrader5 as mt5
from core.engine import _p_break
from core.wave_rec import _EMA_FAST, _EMA_SLOW
_PIV_K=3; _LOOKBACK=300; _THR=0.60

def ema_last(vals,p):
    k=2.0/(p+1); e=vals[0]
    for x in vals[1:]: e=x*k+e*(1-k)
    return e
def atr14(H,L,C):
    tr=[max(H[i]-L[i],abs(H[i]-C[i-1]),abs(L[i]-C[i-1])) for i in range(1,len(C))]
    return sum(tr[-14:])/14

def main():
    days=int(sys.argv[1]) if len(sys.argv)>1 else 2
    mt5.initialize(); sym='SpotCrude'
    m1=mt5.copy_rates_from_pos(sym,mt5.TIMEFRAME_M1,0,days*1440+50)
    m5=mt5.copy_rates_from_pos(sym,mt5.TIMEFRAME_M5,0,days*288+_LOOKBACK+60)
    mt5.shutdown()
    T5=[int(b["time"]) for b in m5]
    O5=[float(b["open"]) for b in m5]; H5=[float(b["high"]) for b in m5]
    L5=[float(b["low"]) for b in m5]; C5=[float(b["close"]) for b in m5]
    T1=[int(b["time"]) for b in m1]; C1=[float(b["close"]) for b in m1]

    import bisect
    ep=[]            # aktive Annäherungs-Episode: Liste von (P, level, mom3)
    episodes=[]      # abgeschlossene Episoden
    per_bar={}       # (m5-index) -> [P...] für Intra-Bar-Spanne
    n_eval=0
    for i1 in range(30, len(m1)):
        t=T1[i1]; px=C1[i1]
        j=bisect.bisect_right(T5,t)-1          # laufende/letzte M5-Kerze
        if j < _LOOKBACK+10: continue
        # M5-Serie wie die Engine sie sieht: abgeschlossene Bars + laufende Kerze
        # mit Close = aktuellem M1-Kurs
        closes=C5[j-_LOOKBACK:j]+[px]
        highs =H5[j-_LOOKBACK:j]+[max(px,O5[j])]
        lows  =L5[j-_LOOKBACK:j]+[min(px,O5[j])]
        atr=max(atr14(highs,lows,closes),0.12)
        mom6=(closes[-1]-closes[-7])/atr
        mom3=(closes[-1]-closes[-4])/atr
        ediff=(ema_last(closes,_EMA_FAST)-ema_last(closes,_EMA_SLOW))/atr
        # Pivot-Level aus abgeschlossenen Bars
        ph=[H5[k] for k in range(j-_LOOKBACK+_PIV_K, j-_PIV_K)
            if H5[k]==max(H5[k-_PIV_K:k+_PIV_K+1])]
        # LONG-Sicht: nächster Widerstand über Kurs (analog gilt Short symmetrisch)
        cands=[p for p in ph if p>px]
        level=min(cands) if cands else None
        if level is None or (level-px) > 0.6*atr:
            if ep: episodes.append(ep); ep=[]
            continue
        wt=1.0 if ediff>0 else 0.0
        dist=abs(level-px)/atr
        P=_p_break(mom6,mom3,wt,dist)
        ep.append((P,level,mom3)); n_eval+=1
        per_bar.setdefault(j,[]).append(P)
    if ep: episodes.append(ep)

    print("="*84)
    print(f"  P(break)-Flattern — letzte {days} Tage, {n_eval} Minuten in Level-Nähe (≤0,6×ATR)")
    print("="*84)
    # Intra-Bar-Spanne
    spans=[max(v)-min(v) for v in per_bar.values() if len(v)>=3]
    if spans:
        spans.sort()
        print(f"\nP-Spanne INNERHALB einer M5-Kerze (n={len(spans)} Kerzen):")
        print(f"  Median {100*spans[len(spans)//2]:.0f} Pp · P90 {100*spans[int(len(spans)*0.9)]:.0f} Pp · Max {100*max(spans):.0f} Pp")
    # Episoden: Schwellen-Flips
    flips=[]; levsw=[]
    for e in episodes:
        if len(e)<3: continue
        f=sum(1 for k in range(1,len(e)) if (e[k][0]<_THR)!=(e[k-1][0]<_THR))
        sw=sum(1 for k in range(1,len(e)) if abs(e[k][1]-e[k-1][1])>1e-9)
        flips.append(f); levsw.append(sw)
    if flips:
        flips.sort()
        print(f"\nAnnäherungs-Episoden: {len(flips)} · Ø-Dauer "
              f"{sum(len(e) for e in episodes if len(e)>=3)/len(flips):.0f} min")
        print(f"  close↔laufen-Flips (60%-Schwelle) je Episode: "
              f"Median {flips[len(flips)//2]} · P90 {flips[int(len(flips)*0.9)]} · Max {max(flips)}")
        print(f"  Episoden mit ≥2 Flips: {100*sum(1 for f in flips if f>=2)/len(flips):.0f}% "
              f"· Level-Wechsel je Episode Ø {sum(levsw)/len(levsw):.1f}")
    # mom3-Beitrag: P-Änderung je Minute vs mom3-Änderung
    dP=[]; dM=[]
    for e in episodes:
        for k in range(1,len(e)):
            if abs(e[k][1]-e[k-1][1])<1e-9:      # gleiches Level → reiner Feature-Effekt
                dP.append(abs(e[k][0]-e[k-1][0])); dM.append(abs(e[k][2]-e[k-1][2]))
    if dP:
        print(f"\nMinuten-Sprünge bei GLEICHEM Level (n={len(dP)}):")
        print(f"  Ø |ΔP|/min = {100*sum(dP)/len(dP):.1f} Pp · Ø |Δmom3|/min = {sum(dM)/len(dM):.2f}×ATR")
        big=[p for p,m in zip(dP,dM) if m>0.3]
        print(f"  bei |Δmom3|>0,3: Ø |ΔP| = {100*sum(big)/max(1,len(big)):.1f} Pp "
              f"({100*len(big)/len(dP):.0f}% der Minuten) → mom3 (laufende Kerze) ist der Treiber")

if __name__=="__main__":
    main()
