"""LADDER SL/TP STUDY (2026-06-18) — i 3 passi pre-deploy + studio di SL e TP da aggiungere.

Contesto: dopo clean_feed.py i Price Ladder BTC/ETH sono candidati VERI (PROMOSSO, DD gate
2021+ ~11-15%), MA il tail REALE e' il 2018 (-44/-52%) che il gate (IDX 2021+) NON vede. SL/TP
sono la leva per domarlo. Prior del progetto: gli stop su mean-reversion sono falsi negativi
(EXIT-16/SH01/pairs z-stop) -> ma un grid in un BEAR sostenuto (2018, niente rimbalzo) e' il
caso in cui un catastrophe-SL genuinamente aiuta. Questo studio distingue i due regimi.

Fa i 3 passi:
  1. VALUTAZIONE 2018-INCLUSIVE: metriche standalone su TUTTA la storia (2018+) + DD per anno
     (il gate del progetto e' cieco al 2018; qui no).
  2. FILL maker vs taker: il grid e' LIMIT -> su Deribit fill MAKER ~0%; confronto 0% vs 0.10%
     RT (la harness e' conservativa). E' la preparazione backtest dello shadow ledger (la parte
     live = deploy operativo a parte).
  3. HALF-SIZE: il candidato finale a meta' size (prudenza coda).
E studia SL (sl_buf, = catastrophe stop sotto il range) x TP (tp_buf) sul tail 2018 vs edge 2021+.

    uv run python scripts/analysis/ladder_sltp_study.py
"""
from __future__ import annotations

import sys
from pathlib import Path

import numpy as np
import pandas as pd

PROJECT_ROOT = Path(__file__).resolve().parents[2]
sys.path.insert(0, str(PROJECT_ROOT))

from scripts.analysis.ladder_search import regime_mask, _gate
from scripts.analysis.grid_game_gate import grid_mtm

OOS_DATE = pd.Timestamp("2024-10-12", tz="UTC")


def fm(eqd: pd.Series) -> dict:
    """Metriche su TUTTA la storia (2018+), niente reindex a IDX 2021+."""
    def sh(s):
        r = s.pct_change().fillna(0.0)
        return float(r.mean() / r.std() * np.sqrt(365)) if r.std() > 0 else 0.0

    def dd(s):
        c = s / s.iloc[0]
        return float(((c - c.cummax()) / c.cummax()).min() * 100)
    oos = eqd[eqd.index >= OOS_DATE]
    peryear = {int(y): round(dd(g), 1) for y, g in eqd.groupby(eqd.index.year)}
    return {"full_sh": round(sh(eqd), 2), "full_dd": round(dd(eqd), 1),
            "oos_sh": round(sh(oos), 2) if len(oos) > 5 else 0.0,
            "dd2018": peryear.get(2018, 0.0), "dd2022": peryear.get(2022, 0.0),
            "peryear": peryear}


def run(asset, tf, rd, ru, levels, sl_buf, tp_buf, max_bars, regime, tmax, fee_side=0.0005):
    mask = regime_mask(asset, tf, trend_max=tmax) if regime == "range" else None
    eqd, st = grid_mtm(asset, tf=tf, range_down=rd, range_up=ru, levels=levels,
                       sl_buf=sl_buf, tp_buf=tp_buf, max_bars=max_bars,
                       deploy_mask=mask, fee_side=fee_side)
    m = fm(eqd); m["trades"] = st["trades"]; m["eqd"] = eqd
    return m


# candidati base (i migliori del re-gate pulito)
BASES = {
    "BTC 1h L6 range1.5": dict(asset="BTC", tf="1h", rd=0.20, ru=0.06, levels=6,
                               max_bars=720, regime="range", tmax=1.5),
    "BTC 1h L3 none":     dict(asset="BTC", tf="1h", rd=0.08, ru=0.06, levels=3,
                               max_bars=720, regime="none", tmax=2.0),
}


def sltp_sweep(name, base):
    print(f"\n{'='*104}\n  SL/TP SWEEP — {name}  (full=2018+, dd2018=tail vero, oos=2024-10+; fee 0.10% RT)\n{'='*104}")
    print(f"  {'sl_buf':>7}{'tp_buf':>7}{'trades':>8}{'full_sh':>9}{'full_dd':>9}{'dd2018':>8}{'dd2022':>8}{'oos_sh':>8}")
    best = None
    for slb in (0.06, 0.08, 0.10, 0.12, 0.15, 0.20):
        for tpb in (0.03, 0.05, 0.08):
            m = run(**base, sl_buf=slb, tp_buf=tpb)
            star = ""
            # criterio: tail 2018 contenuto (>-25%) E oos edge preservato (sh>3) E full edge ok
            if m["dd2018"] > -25 and m["oos_sh"] > 3 and m["full_sh"] > 1.5:
                star = "  <-- tail-capped + edge"
                if best is None or m["dd2018"] > best[1]["dd2018"]:
                    best = ((slb, tpb), m)
            print(f"  {slb:>7.2f}{tpb:>7.2f}{m['trades']:>8}{m['full_sh']:>9.2f}"
                  f"{m['full_dd']:>9.1f}{m['dd2018']:>8.1f}{m['dd2022']:>8.1f}{m['oos_sh']:>8.2f}{star}")
    return best


def main():
    print("LADDER SL/TP STUDY — 3 passi pre-deploy + SL/TP da aggiungere\n")
    # passo 1: valutazione 2018-inclusive dei due base (sl/tp correnti)
    print("[1] VALUTAZIONE 2018-INCLUSIVE (sl/tp correnti) — DD per anno (il gate IDX2021+ e' cieco al 2018):")
    for name, base in BASES.items():
        m = run(**base, sl_buf=0.12, tp_buf=0.05)
        print(f"  {name:<22} full_sh {m['full_sh']:>5.2f}  full_dd {m['full_dd']:>6.1f}  "
              f"oos_sh {m['oos_sh']:>5.2f}  | DD/anno {m['peryear']}")

    # passo SL/TP: sweep su entrambi
    winners = {}
    for name, base in BASES.items():
        winners[name] = sltp_sweep(name, base)

    # passo 2+3: maker vs taker + half-size + gate 2021+, sul miglior (sl,tp) del candidato regime-gated
    name = "BTC 1h L6 range1.5"
    w = winners.get(name)
    print(f"\n{'='*104}\n  [2+3] FILL maker/taker + HALF-SIZE + GATE 2021+ — {name}\n{'='*104}")
    if w is None:
        print("  nessun (sl,tp) ha cappato il tail 2018 sotto -25% mantenendo l'edge: vedi sweep sopra.")
        # usa comunque lo sl piu' stretto per il confronto fill
        (slb, tpb) = (0.06, 0.05)
    else:
        (slb, tpb), _ = w
        print(f"  miglior (sl_buf,tp_buf) per tail 2018 + edge = ({slb}, {tpb})")
    base = BASES[name]
    for fee, lab in ((0.0005, "taker 0.10% RT"), (0.0, "maker 0% (Deribit limit)")):
        m = run(**base, sl_buf=slb, tp_buf=tpb, fee_side=fee)
        g = _gate(m["eqd"])
        print(f"  fee={lab:<26} oos_sh {m['oos_sh']:>5.2f}  dd2018 {m['dd2018']:>6.1f}  "
              f"gate½ {g['verdict_half']}  (OOS {g['base_oos_sh']}->{g['half_oos_sh']}, corr {g['max_corr_existing']})")
    print("\n  NB half-size: il gate 'half' E' gia' a meta' size (vedi grid_game_gate). La coda 2018")
    print("  standalone va dimezzata sul book a half. Lo shadow ledger reale (fill intrabar/maker)")
    print("  resta il passo OPERATIVO finale, non backtestabile qui.")


if __name__ == "__main__":
    main()
