"""S2-05: Gap fade + overnight reversal.
Crypto non ha gap di apertura classici, ma ha "gap di sessione":
- Asia open (00 UTC): tende a continuare il trend USA precedente
- EU open (07 UTC): spesso corregge eccessi notturni
- USA open (13-14 UTC): alta volatilità, breakout o reversal

Strategia: fai fade dell'overextension al cambio sessione.
Se il prezzo ha fatto >1.5% nella sessione precedente, aspettati reversal.
"""
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 = 0.001
INITIAL = 1000
LEVERAGE = 3


def run_gap_fade(asset, tf="1h"):
    print(f"\n{'#'*60}")
    print(f"  {asset} {tf} — GAP FADE / SESSION REVERSAL")
    print(f"{'#'*60}")

    df = load_data(asset, tf)
    close = df["close"].values
    high = df["high"].values
    low = df["low"].values
    n = len(close)
    split = int(n * 0.7)
    timestamps = pd.to_datetime(df["timestamp"], unit="ms", utc=True)
    hours = timestamps.dt.hour.values

    session_opens = {
        "asia": 0,
        "eu": 7,
        "usa": 14,
    }

    configs = [
        # (session_name, lookback_hours, entry_thr, hold_hours, stop_pct, name)
        ("eu", 7, 0.015, 4, 0.012, "eu_fade_1.5pct"),
        ("eu", 7, 0.02, 4, 0.015, "eu_fade_2pct"),
        ("eu", 7, 0.01, 6, 0.01, "eu_fade_1pct_6h"),
        ("usa", 7, 0.015, 4, 0.012, "usa_fade_1.5pct"),
        ("usa", 7, 0.02, 4, 0.015, "usa_fade_2pct"),
        ("asia", 8, 0.02, 6, 0.015, "asia_fade_2pct"),
        ("eu", 7, 0.025, 3, 0.015, "eu_fade_2.5pct_fast"),
        ("usa", 6, 0.015, 3, 0.01, "usa_fade_fast"),
    ]

    for session, lookback, entry_thr, hold, stop, name in configs:
        capital = float(INITIAL)
        correct = 0
        total = 0
        daily_trades = {}

        session_hour = session_opens[session]

        for i in range(max(split, lookback + 1), n - hold):
            if hours[i] != session_hour:
                continue

            day = timestamps.iloc[i].strftime("%Y-%m-%d")
            if daily_trades.get(day, 0) >= 1:
                continue

            prev_ret = (close[i] - close[i - lookback]) / close[i - lookback]

            direction = None
            if prev_ret > entry_thr:
                direction = "short"  # fade the rally
            elif prev_ret < -entry_thr:
                direction = "long"  # fade the dump

            if direction is None:
                continue

            entry = close[i]
            exit_price = close[min(i + hold, n - 1)]

            for j in range(i + 1, min(i + hold + 1, n)):
                if direction == "long":
                    if (close[j] - entry) / entry >= stop * 2:
                        exit_price = close[j]
                        break
                    if (entry - close[j]) / entry >= stop:
                        exit_price = close[j]
                        break
                else:
                    if (entry - close[j]) / entry >= stop * 2:
                        exit_price = close[j]
                        break
                    if (close[j] - entry) / entry >= stop:
                        exit_price = close[j]
                        break
                exit_price = close[j]

            if direction == "long":
                trade_ret = (exit_price - entry) / entry
            else:
                trade_ret = (entry - exit_price) / entry

            net = trade_ret * LEVERAGE - FEE * 2 * LEVERAGE
            capital += capital * 0.2 * net
            capital = max(capital, 0)

            total += 1
            if trade_ret > 0:
                correct += 1
            daily_trades[day] = daily_trades.get(day, 0) + 1

        if total < 15:
            continue

        acc = correct / total * 100
        ret = (capital - INITIAL) / INITIAL * 100
        test_days = (n - split) / 24
        test_years = test_days / 365.25
        ann = ((capital / INITIAL) ** (1 / test_years) - 1) * 100 if test_years > 0 and capital > 0 else -100
        dpnl = (capital - INITIAL) / test_days if test_days > 0 else 0
        days_active = len(daily_trades)

        tag = "✅" if acc >= 58 and ann >= 30 else ""
        print(f"  {name:25s}: trades={total:4d} acc={acc:.1f}% ret={ret:+.1f}% ann={ann:+.1f}% €/day={dpnl:.2f} active={days_active} {tag}")


for asset in ["ETH", "BTC"]:
    run_gap_fade(asset)
