"""MR01 — Mean Reversion da estremi RSI.

Approccio opposto allo squeeze: quando il prezzo va troppo lontano troppo veloce,
scommetti che torni indietro. Autocorrelazione lag-1 negativa (-0.21 BTC, -0.35 ETH)
conferma che il mercato a 15m è mean-reverting.

IN:
    - OHLCV DataFrame
    - Parametri: rsi_period, rsi_oversold, rsi_overbought, hold_bars,
                 volume_filter (volume > N× media), atr_filter (move > N×ATR)

OUT:
    - Signal: long quando RSI < oversold, short quando RSI > overbought
    - BacktestResult con metriche

Logica:
    1. RSI scende sotto soglia oversold → LONG (prezzo tornerà su)
    2. RSI sale sopra soglia overbought → SHORT (prezzo tornerà giù)
    3. Filtro opzionale: volume spike conferma l'eccesso
    4. Filtro opzionale: move recente > N×ATR (eccesso di prezzo)
    5. Hold fisso, poi chiudi
"""
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


def rsi(close, period=14):
    delta = np.diff(close)
    gain = np.where(delta > 0, delta, 0)
    loss = np.where(delta < 0, -delta, 0)
    result = np.full(len(close), 50.0)
    if len(gain) < period:
        return result
    ag = np.mean(gain[:period])
    al = np.mean(loss[:period])
    for i in range(period, len(delta)):
        ag = (ag * (period - 1) + gain[i]) / period
        al = (al * (period - 1) + loss[i]) / period
        result[i + 1] = 100 if al == 0 else 100 - 100 / (1 + ag / al)
    return result


class MeanReversionRSI(Strategy):
    name = "MR01_mean_reversion_rsi"
    description = "Mean reversion da estremi RSI — fade eccessi direzionali"
    default_assets = ["BTC", "ETH"]
    default_timeframes = ["15m", "1h"]
    fee_rt = 0.002

    def generate_signals(self, df, ts, **params):
        c = df["close"].values
        h = df["high"].values
        l = df["low"].values
        v = df["volume"].values
        n = len(c)

        rsi_period = params.get("rsi_period", 14)
        oversold = params.get("rsi_oversold", 25)
        overbought = params.get("rsi_overbought", 75)
        use_vol_filter = params.get("vol_filter", False)
        use_atr_filter = params.get("atr_filter", False)
        cooldown = params.get("cooldown", 4)

        rsi_vals = rsi(c, rsi_period)

        # Volume media rolling
        vol_ma = np.full(n, np.nan)
        for i in range(20, n):
            vol_ma[i] = np.mean(v[i - 20:i])

        # ATR
        tr = np.maximum(h[1:] - l[1:],
                        np.maximum(np.abs(h[1:] - c[:-1]), np.abs(l[1:] - c[:-1])))
        atr_vals = np.full(n, np.nan)
        for i in range(15, len(tr)):
            atr_vals[i + 1] = np.mean(tr[i - 14:i])

        signals = []
        last_signal_idx = -cooldown

        for i in range(20, n):
            if i - last_signal_idx < cooldown:
                continue

            direction = 0
            if rsi_vals[i] < oversold:
                direction = 1  # oversold → long
            elif rsi_vals[i] > overbought:
                direction = -1  # overbought → short

            if direction == 0:
                continue

            # Volume filter
            if use_vol_filter and not np.isnan(vol_ma[i]):
                if v[i] < vol_ma[i] * 1.5:
                    continue

            # ATR filter: il move recente deve essere > 1.5× ATR
            if use_atr_filter and not np.isnan(atr_vals[i]):
                recent_move = abs(c[i] - c[max(0, i - 3)]) / c[max(0, i - 3)]
                if recent_move < atr_vals[i] / c[i] * 1.5:
                    continue

            signals.append(Signal(
                idx=i, direction=direction, entry_price=c[i],
                metadata={"rsi": float(rsi_vals[i])},
            ))
            last_signal_idx = i

        return signals


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

    configs = [
        ("RSI25/75", {}),
        ("RSI20/80", {"rsi_oversold": 20, "rsi_overbought": 80}),
        ("RSI25/75+vol", {"vol_filter": True}),
        ("RSI20/80+vol", {"rsi_oversold": 20, "rsi_overbought": 80, "vol_filter": True}),
        ("RSI25/75+atr", {"atr_filter": True}),
        ("RSI20/80+vol+atr", {"rsi_oversold": 20, "rsi_overbought": 80, "vol_filter": True, "atr_filter": True}),
    ]

    all_results = []
    for label, params in configs:
        for asset in ["BTC", "ETH"]:
            for tf in ["15m", "1h"]:
                for hold in [3, 6]:
                    r = strategy.backtest(asset, tf, hold=hold, **params)
                    if r and r.trades >= 30:
                        r.strategy_name = f"MR01 {label} h={hold}"
                        all_results.append(r)

    all_results.sort(key=lambda r: r.accuracy, reverse=True)
    print(f"\n{'=' * 120}")
    print(f"  MR01 MEAN REVERSION RSI — TOP 20")
    print(f"{'=' * 120}")
    for r in all_results[:20]:
        r.print_summary()
    if all_results:
        all_results[0].print_yearly()
