"""PD01 — Price-Volume Divergence Squeeze.

Estende SQ02 con volume TREND come filtro:
  - Breakout UP con volume CRESCENTE (ultimi 3 bar vs media squeeze) → ENTRA
  - Breakout UP con volume CALANTE → SALTA (divergenza bearish)
  - Viceversa per short

Logica anti-fakeout:
  1. Squeeze rilascio (come SQ02)
  2. Anti-fakeout candela (come SQ02)
  3. Volume al breakout > media squeeze (come SQ02)
  4. NUOVO: volume trending UP nelle ultime 3 barre prima del breakout

Parametri semplici, nessun overfitting.
"""
from __future__ import annotations
import sys
sys.path.insert(0, ".")

import numpy as np
import pandas as pd

from src.strategies.base import Strategy, Signal
from src.strategies.indicators import keltner_ratio, detect_squeezes


class PriceVolumeDivergence(Strategy):
    name = "PD01_price_vol_div"
    description = "Squeeze + antifakeout + volume trend confirmation"
    default_assets = ["BTC", "ETH"]
    default_timeframes = ["15m", "1h"]
    fee_rt = 0.002
    leverage = 3.0
    position_size = 0.15
    initial_capital = 1000.0

    def generate_signals(self, df: pd.DataFrame, ts: pd.DatetimeIndex,
                         **params) -> list[Signal]:
        c = df["close"].values
        h = df["high"].values
        l = df["low"].values
        v = df["volume"].values
        n = len(c)

        bb_w = params.get("bb_window", 14)
        sq_thr = params.get("sq_threshold", 0.8)
        retrace_limit = params.get("retrace_limit", 0.6)
        vol_mult = params.get("vol_multiplier", 1.3)
        vol_trend_bars = params.get("vol_trend_bars", 3)  # barre per trend volume

        kcr = keltner_ratio(c, h, l, bb_w)
        events = detect_squeezes(c, h, l, kcr, sq_thr)

        signals = []
        for ev in events:
            i = ev["idx"]
            if i < vol_trend_bars + 1 or i >= n:
                continue

            # Direzione breakout
            first_ret = (c[i] - c[i - 1]) / c[i - 1] if c[i - 1] > 0 else 0
            if abs(first_ret) < 0.001:
                continue
            direction = 1 if first_ret > 0 else -1

            # Anti-fakeout
            br = h[i] - l[i]
            if br > 0:
                if direction == 1 and (h[i] - c[i]) / br > retrace_limit:
                    continue
                elif direction == -1 and (c[i] - l[i]) / br > retrace_limit:
                    continue

            # Volume al breakout > media squeeze
            sq_start = ev["sq_start"]
            avg_sq_v = np.mean(v[sq_start:i])
            if avg_sq_v <= 0 or v[i] <= avg_sq_v * vol_mult:
                continue

            # Volume TREND: slope delle ultime vol_trend_bars barre
            # Usa regressione lineare semplice (rank correlation del volume)
            recent_v = v[i - vol_trend_bars:i + 1]  # include breakout bar
            if len(recent_v) < vol_trend_bars:
                continue
            # slope: media seconda metà vs prima metà
            mid = len(recent_v) // 2
            v_early = np.mean(recent_v[:mid])
            v_late = np.mean(recent_v[mid:])
            vol_trending_up = v_late > v_early
            vol_trending_down = v_early > v_late

            # Concordanza: long richiede volume trending up, short trending down
            if direction == 1 and not vol_trending_up:
                continue
            if direction == -1 and not vol_trending_down:
                continue

            signals.append(Signal(
                idx=i,
                direction=direction,
                entry_price=c[i - 1],
                metadata={
                    "dur": ev["dur"],
                    "vol_ratio": v[i] / avg_sq_v if avg_sq_v > 0 else 0,
                    "vol_trend": v_late / v_early if v_early > 0 else 1,
                },
            ))
        return signals


if __name__ == "__main__":
    strategy = PriceVolumeDivergence()

    configs = [
        {"bb_window": 14, "sq_threshold": 0.8, "retrace_limit": 0.6,
         "vol_multiplier": 1.3, "vol_trend_bars": 3},
        {"bb_window": 14, "sq_threshold": 0.8, "retrace_limit": 0.6,
         "vol_multiplier": 1.2, "vol_trend_bars": 3},
        {"bb_window": 14, "sq_threshold": 0.8, "retrace_limit": 0.6,
         "vol_multiplier": 1.3, "vol_trend_bars": 5},
        {"bb_window": 14, "sq_threshold": 0.8, "retrace_limit": 0.5,
         "vol_multiplier": 1.3, "vol_trend_bars": 3},
        {"bb_window": 14, "sq_threshold": 0.75, "retrace_limit": 0.6,
         "vol_multiplier": 1.3, "vol_trend_bars": 3},
        {"bb_window": 20, "sq_threshold": 0.8, "retrace_limit": 0.6,
         "vol_multiplier": 1.3, "vol_trend_bars": 3},
    ]

    all_results = []
    for cfg in configs:
        for asset in ["BTC", "ETH"]:
            for tf in ["15m", "1h"]:
                for hold in [3, 6]:
                    r = strategy.backtest(asset, tf, hold=hold, **cfg)
                    if r and r.trades >= 20:
                        lbl = (f"PD01 vtb={cfg['vol_trend_bars']} "
                               f"vm={cfg['vol_multiplier']} "
                               f"sq={cfg['sq_threshold']} h={hold}")
                        r.strategy_name = lbl
                        all_results.append(r)

    all_results.sort(key=lambda r: r.accuracy, reverse=True)

    print(f"\n{'=' * 130}")
    print("  PD01 PRICE-VOLUME DIVERGENCE — TOP 20")
    print(f"{'=' * 130}")
    print(f"  {'Nome':<50s} {'A/T':>7s} {'Trades':>6s} {'Acc':>6s} "
          f"{'PnL€':>10s} {'DD%':>6s} {'€/day':>7s} "
          f"{'Mkt%':>5s} {'Dur':>5s} {'Anni':>4s}")
    print(f"  {'─' * 120}")
    for r in all_results[:20]:
        r.print_summary()

    if all_results:
        all_results[0].print_yearly()

    print(f"\n  BENCHMARK SQ02: 79.7% acc, 1250t, DD 6.5%, €5.23/day, 9 anni")
    print(f"  BENCHMARK MT01: 82.7% acc, 503t, DD 5.9%")
