"""IB01 — Inside Bar Breakout.

Pattern di compressione a singola candela: quando una barra ha high < prev high
E low > prev low, il prezzo si sta comprimendo. Al breakout del range della
inside bar, segui la direzione.

17% delle candele 15m sono inside bars → frequenza altissima.

IN:
    - OHLCV DataFrame
    - Parametri: min_consecutive (N inside bars consecutivi),
                 volume_filter, breakout_confirm

OUT:
    - Signal al breakout del range dell'inside bar
    - BacktestResult

Logica:
    1. Identifica N inside bars consecutivi (compressione)
    2. Quando il prezzo rompe il range → entra nella direzione del breakout
    3. Filtro: volume al breakout > media
    4. Hold fisso
"""
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


class InsideBarBreakout(Strategy):
    name = "IB01_inside_bar"
    description = "Inside bar breakout — compressione a singola candela"
    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)

        min_consec = params.get("min_consecutive", 2)
        use_vol = params.get("vol_filter", False)
        min_range_pct = params.get("min_range_pct", 0.002)

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

        signals = []
        consec = 0
        mother_high = 0.0
        mother_low = 0.0

        for i in range(1, n - 1):
            is_inside = h[i] <= h[i - 1] and l[i] >= l[i - 1]

            if is_inside:
                if consec == 0:
                    mother_high = h[i - 1]
                    mother_low = l[i - 1]
                consec += 1
            else:
                if consec >= min_consec:
                    range_pct = (mother_high - mother_low) / mother_low if mother_low > 0 else 0
                    if range_pct < min_range_pct:
                        consec = 0
                        continue

                    # Breakout detection sulla barra corrente
                    if c[i] > mother_high:
                        direction = 1
                    elif c[i] < mother_low:
                        direction = -1
                    else:
                        consec = 0
                        continue

                    # Volume filter
                    if use_vol and not np.isnan(vol_ma[i]):
                        if v[i] < vol_ma[i] * 1.2:
                            consec = 0
                            continue

                    signals.append(Signal(
                        idx=i, direction=direction, entry_price=c[i],
                        metadata={"consec": consec, "range_pct": round(range_pct * 100, 3)},
                    ))

                consec = 0

        return signals


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

    configs = [
        ("2ib", {"min_consecutive": 2}),
        ("3ib", {"min_consecutive": 3}),
        ("4ib", {"min_consecutive": 4}),
        ("2ib+vol", {"min_consecutive": 2, "vol_filter": True}),
        ("3ib+vol", {"min_consecutive": 3, "vol_filter": True}),
        ("2ib r>0.3%", {"min_consecutive": 2, "min_range_pct": 0.003}),
        ("3ib r>0.3%", {"min_consecutive": 3, "min_range_pct": 0.003}),
    ]

    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"IB01 {label} h={hold}"
                        all_results.append(r)

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