"""S3-03: Ultimate Squeeze — combina TUTTI i filtri migliori.
Filtri che funzionano (testati singolarmente):
- Anti-fakeout (+1% acc)
- Long squeeze duration (+1% acc)
- Cross-asset squeeze simultaneo (+0.5%)
- Timing 4-16 UTC (+0.5%)
- Correlation ETH-BTC alta per ETH trades (+1%)
- Volume confirmation al breakout

Nuovi filtri da testare:
- Volume delta: up_volume - down_volume al breakout
- Momentum confirmation: breakout nella direzione del trend 1h
- Volatility regime: skip in regime estremo (RV > 100%)
"""
from __future__ import annotations
import sys
sys.path.insert(0, ".")

import numpy as np
import pandas as pd
from src.data.downloader import load_data

FEE_RT = 0.002
INITIAL = 1000
LEVERAGE = 3


def keltner_ratio(close, high, low, window=14):
    n = len(close)
    r = np.full(n, np.nan)
    for i in range(window, n):
        wc, wh, wl = close[i-window:i], high[i-window:i], low[i-window:i]
        ma = np.mean(wc)
        bb_std = np.std(wc)
        tr = np.maximum(wh-wl, np.maximum(np.abs(wh-np.roll(wc,1)), np.abs(wl-np.roll(wc,1))))
        atr = np.mean(tr[1:])
        kc = (ma+1.5*atr)-(ma-1.5*atr)
        bb = (ma+2*bb_std)-(ma-2*bb_std)
        if kc > 0: r[i] = bb/kc
    return r


def ema(arr, period):
    r = np.full(len(arr), np.nan)
    k = 2/(period+1)
    r[period-1] = np.mean(arr[:period])
    for i in range(period, len(arr)):
        r[i] = arr[i]*k + r[i-1]*(1-k)
    return r


def rv_ann(close, window):
    lr = np.diff(np.log(np.where(close == 0, 1e-10, close)))
    r = np.full(len(close), np.nan)
    for i in range(window, len(lr)):
        r[i+1] = np.std(lr[i-window:i]) * np.sqrt(24*365)
    return r


def run_ultimate(primary, tf="15m"):
    secondary = "ETH" if primary == "BTC" else "BTC"

    df = load_data(primary, tf)
    c, h, l, v = df["close"].values, df["high"].values, df["low"].values, df["volume"].values
    n = len(df)
    ts = pd.to_datetime(df["timestamp"], unit="ms", utc=True)

    df2 = load_data(secondary, tf)
    c2, ts2 = df2["close"].values, df2["timestamp"].values

    kcr = keltner_ratio(c, h, l, 14)
    kcr2 = keltner_ratio(c2, df2["high"].values, df2["low"].values, 14)

    ema_50 = ema(c, 50)
    rv_48 = rv_ann(c, 48)

    # Rolling correlation
    ret1 = np.diff(np.log(np.where(c == 0, 1e-10, c)))
    ret2 = np.diff(np.log(np.where(c2[:len(c)] == 0, 1e-10, c2[:len(c)])))
    min_len = min(len(ret1), len(ret2))
    ret1 = ret1[:min_len]
    ret2 = ret2[:min_len]
    corr = np.full(n, np.nan)
    for i in range(48, min_len):
        cv = np.corrcoef(ret1[i-48:i], ret2[i-48:i])[0,1]
        corr[i+1] = cv if np.isfinite(cv) else 0

    # Detect squeezes
    events = []
    in_sq = False
    sq_start = 0
    for i in range(15, n):
        if np.isnan(kcr[i]): continue
        is_sq = kcr[i] < 0.8
        if is_sq and not in_sq:
            in_sq = True
            sq_start = i
        elif not is_sq and in_sq:
            in_sq = False
            dur = i - sq_start
            if dur < 5 or i + 6 >= n:
                continue
            events.append({"idx": i, "dur": dur, "sq_start": sq_start})

    print(f"\n{'#'*70}")
    print(f"  {primary} {tf} — ULTIMATE SQUEEZE ({len(events)} squeeze events)")
    print(f"{'#'*70}")

    filters_map = {
        "antifake": lambda ev, i: not _antifake(c, h, l, i),
        "long_sq": lambda ev, i: ev["dur"] >= 10,
        "timing": lambda ev, i: 4 <= ts.iloc[i].hour <= 16,
        "cross": lambda ev, i: _cross_squeeze(kcr2, i, ts, ts2),
        "corr_high": lambda ev, i: not np.isnan(corr[i]) and abs(corr[i]) >= 0.6,
        "vol_confirm": lambda ev, i: _vol_confirm(v, i, ev["sq_start"]),
        "trend_align": lambda ev, i: _trend_align(c, ema_50, i),
        "low_rv": lambda ev, i: not np.isnan(rv_48[i]) and rv_48[i] < 1.5,
    }

    def _antifake(c, h, l, i):
        if i + 1 >= len(c): return False
        br = h[i] - l[i]
        if br <= 0: return False
        if c[i] > c[i-1]:
            return (h[i] - c[i]) / br > 0.6
        return (c[i] - l[i]) / br > 0.6

    def _cross_squeeze(kcr2, i, ts1, ts2_arr):
        i2 = np.searchsorted(ts2_arr, ts.values[i].astype("int64") // 10**6)
        i2 = min(i2, len(kcr2)-1)
        return any(not np.isnan(kcr2[j]) and kcr2[j] < 0.85 for j in range(max(0,i2-10), i2+1))

    def _vol_confirm(v, i, sq_start):
        avg = np.mean(v[sq_start:i])
        return avg > 0 and v[i] > avg * 1.3

    def _trend_align(c, ema_val, i):
        if np.isnan(ema_val[i]): return True
        first_ret = (c[i] - c[i-1]) / c[i-1] if c[i-1] > 0 else 0
        if first_ret > 0:
            return c[i] > ema_val[i]
        return c[i] < ema_val[i]

    # Test combinazioni incrementali
    combos = [
        ("BASE", []),
        ("antifake", ["antifake"]),
        ("long_sq", ["long_sq"]),
        ("antifake+long", ["antifake", "long_sq"]),
        ("antifake+timing", ["antifake", "timing"]),
        ("antifake+cross", ["antifake", "cross"]),
        ("antifake+corr", ["antifake", "corr_high"]),
        ("antifake+vol", ["antifake", "vol_confirm"]),
        ("antifake+trend", ["antifake", "trend_align"]),
        ("af+long+timing", ["antifake", "long_sq", "timing"]),
        ("af+long+cross", ["antifake", "long_sq", "cross"]),
        ("af+long+corr", ["antifake", "long_sq", "corr_high"]),
        ("af+long+trend", ["antifake", "long_sq", "trend_align"]),
        ("af+long+cross+time", ["antifake", "long_sq", "cross", "timing"]),
        ("af+long+corr+time", ["antifake", "long_sq", "corr_high", "timing"]),
        ("af+long+corr+trend", ["antifake", "long_sq", "corr_high", "trend_align"]),
        ("ALL_NO_VOL", ["antifake", "long_sq", "cross", "timing", "corr_high", "trend_align", "low_rv"]),
        ("ALL", ["antifake", "long_sq", "cross", "timing", "corr_high", "vol_confirm", "trend_align", "low_rv"]),
        ("BEST_5", ["antifake", "long_sq", "corr_high", "trend_align", "low_rv"]),
    ]

    results = []
    for combo_name, filter_names in combos:
        yearly = {}
        capital = float(INITIAL)
        peak = capital
        max_dd = 0

        for ev in events:
            i = ev["idx"]
            first_ret = (c[i] - c[i-1]) / c[i-1] if c[i-1] > 0 else 0
            if abs(first_ret) < 0.001:
                continue

            skip = False
            for fn in filter_names:
                if fn in filters_map and not filters_map[fn](ev, i):
                    skip = True
                    break
            if skip:
                continue

            direction = 1 if first_ret > 0 else -1
            entry = c[i-1]
            exit_price = c[min(i+2, n-1)]
            actual = (exit_price - entry) / entry * direction
            net = actual * LEVERAGE - FEE_RT * LEVERAGE

            capital += capital * 0.15 * net
            capital = max(capital, 10)
            if capital > peak: peak = capital
            dd = (peak - capital) / peak
            max_dd = max(max_dd, dd)

            year = ts.iloc[i].year
            if year not in yearly:
                yearly[year] = {"w": 0, "t": 0, "pnls": []}
            yearly[year]["t"] += 1
            if actual > 0: yearly[year]["w"] += 1
            yearly[year]["pnls"].append(net * INITIAL)

        all_t = sum(d["t"] for d in yearly.values())
        all_w = sum(d["w"] for d in yearly.values())
        if all_t < 20: continue

        acc = all_w / all_t * 100
        pnl = sum(p for d in yearly.values() for p in d["pnls"])
        worst = min(yearly.items(), key=lambda x: x[1]["w"]/x[1]["t"] if x[1]["t"]>0 else 0)
        wa = worst[1]["w"]/worst[1]["t"]*100 if worst[1]["t"]>0 else 0

        results.append({
            "name": combo_name, "trades": all_t, "acc": acc, "pnl": pnl,
            "dd": max_dd*100, "capital": capital, "worst": f"{worst[0]}({wa:.0f}%)",
            "yearly": yearly,
        })

    results.sort(key=lambda x: x["acc"], reverse=True)

    print(f"\n  {'Name':.<28s} {'Trades':>6s} {'Acc':>6s} {'PnL€':>9s} {'DD%':>5s} {'Worst':>12s}")
    print(f"  {'-'*70}")
    for r in results[:20]:
        tag = "✅✅" if r["acc"] >= 80 else "✅" if r["acc"] >= 78 else ""
        print(f"  {r['name']:.<28s} {r['trades']:>6d} {r['acc']:>5.1f}% €{r['pnl']:>+8.0f} {r['dd']:>4.1f}% {r['worst']:>12s} {tag}")

    # Dettaglio migliore
    if results:
        best = results[0]
        print(f"\n  MIGLIORE: {best['name']} → {best['acc']:.1f}% acc, DD {best['dd']:.1f}%")
        for y in sorted(best["yearly"]):
            d = best["yearly"][y]
            ya = d["w"]/d["t"]*100 if d["t"]>0 else 0
            tag = " ← CRASH" if y in [2020,2021,2022] else ""
            print(f"    {y}: {d['t']:4d}t {ya:5.1f}% €{sum(d['pnls']):+.0f}{tag}")

    return results


all_r = []
for asset in ["BTC", "ETH"]:
    for tf in ["15m", "1h"]:
        r = run_ultimate(asset, tf)
        for x in r:
            all_r.append({**x, "key": f"{asset}_{tf}"})

all_r.sort(key=lambda x: x["acc"], reverse=True)
print(f"\n\n{'='*70}")
print(f"  TOP 10 GLOBALE")
print(f"{'='*70}")
for r in all_r[:10]:
    tag = "✅✅" if r["acc"] >= 80 else "✅" if r["acc"] >= 78 else ""
    print(f"  {r['key']:.<10s} {r['name']:.<28s} {r['trades']:>5d} {r['acc']:>5.1f}% €{r['pnl']:>+8.0f} DD {r['dd']:.1f}% {r['worst']:>12s} {tag}")
