"""CALIBRAZIONE VRP su quote REALI cerbero-bite — misura f e skew, non li assume.

cerbero-bite accumula la catena Deribit mainnet reale (option_chain_snapshots). Qui, per ogni
snapshot, prendo la put piu' vicina a delta -0.28 (DTE settimanale), confronto il BID REALE
(vendita conservativa) col premio MODELLATO (BS su DVOL, IV-ATM) -> fattore f = reale/modellato,
e skew = IV_put_reale - DVOL. Pinna empiricamente dove sta il VRP sleeve sullo sweep f.

Input: /tmp/cb_puts.csv (export da cerbero-bite). Finestra ~2026-05 -> oggi (un regime, mainnet).

    uv run python scripts/research/options_vrp_calibrate.py
"""
from __future__ import annotations
import sys
from pathlib import Path
PROJECT_ROOT = Path(__file__).resolve().parents[2]
sys.path.insert(0, str(PROJECT_ROOT))
import numpy as np, pandas as pd
from scripts.research.options_vrp_lab import bs_put
from scripts.analysis.research_lab import load_tf

CSV = "/tmp/cb_puts.csv"


def spot_series(asset):
    px = load_tf(asset, "1h")
    return pd.Series(px["close"].values.astype(float),
                     index=pd.to_datetime(px["timestamp"], unit="ms", utc=True)).sort_index()


def dvol_series(asset):
    d = pd.read_parquet(PROJECT_ROOT / "data" / "raw" / f"dvol_{asset.lower()}.parquet")
    return pd.Series(d["close"].values.astype(float),
                     index=pd.to_datetime(d["timestamp"], unit="ms", utc=True)).sort_index()


def main():
    df = pd.read_csv(CSV, names=["ts", "asset", "strike", "expiry", "bid", "mid", "iv", "delta"])
    df["ts"] = pd.to_datetime(df["ts"], utc=True, errors="coerce")
    df["expiry"] = pd.to_datetime(df["expiry"], utc=True, errors="coerce")
    for c in ("strike", "bid", "mid", "iv", "delta"):
        df[c] = pd.to_numeric(df[c], errors="coerce")
    df = df.dropna(subset=["ts", "expiry", "strike", "bid", "iv", "delta"])
    df["dte"] = (df["expiry"] - df["ts"]).dt.total_seconds() / 86400.0
    df = df[(df["dte"] >= 4) & (df["dte"] <= 10) & (df["bid"] > 0)]

    print("=" * 92)
    print("  CALIBRAZIONE VRP su QUOTE REALI (cerbero-bite mainnet) — put weekly ~delta -0.28")
    print("=" * 92)
    for asset in ("BTC", "ETH"):
        d = df[df["asset"] == asset].copy()
        if d.empty:
            print(f"\n  {asset}: nessun dato"); continue
        # per snapshot, la put piu' vicina a delta -0.28
        d["dd"] = (d["delta"] - (-0.28)).abs()
        pick = d.sort_values("dd").groupby("ts").first().reset_index().sort_values("ts")
        S = spot_series(asset); V = dvol_series(asset)
        Sdf = pd.DataFrame({"ts": S.index.as_unit("ns"), "spot": S.values}).sort_values("ts")
        Vdf = pd.DataFrame({"ts": V.index.as_unit("ns"), "dvol": V.values}).sort_values("ts")
        pick = pick.sort_values("ts").reset_index(drop=True)
        pts = pick[["ts"]].copy()
        pts["ts"] = pts["ts"].dt.as_unit("ns")
        pick["spot"] = pd.merge_asof(pts, Sdf, on="ts", direction="nearest", tolerance=pd.Timedelta("2h"))["spot"].values
        pick["dvol"] = pd.merge_asof(pts, Vdf, on="ts", direction="nearest", tolerance=pd.Timedelta("2D"))["dvol"].values
        pick = pick.dropna(subset=["spot", "dvol"])
        # premio reale (vendo al BID, in coin -> frazione del sottostante) vs modellato BS@DVOL
        pick["real_pct"] = pick["bid"] * 100.0
        pick["model_pct"] = pick.apply(lambda r: bs_put(r["spot"], r["strike"], r["dte"] / 365.25, r["dvol"] / 100.0) / r["spot"] * 100.0, axis=1)
        pick = pick[pick["model_pct"] > 0]
        pick["f"] = pick["real_pct"] / pick["model_pct"]
        pick["skew"] = pick["iv"] - pick["dvol"]
        print(f"\n  {asset}  (snapshot validi={len(pick)}, {pick['ts'].iloc[0].date()} -> {pick['ts'].iloc[-1].date()})")
        print(f"    delta medio {pick['delta'].mean():+.2f} | DTE medio {pick['dte'].mean():.1f}g | moneyness medio {(pick['strike']/pick['spot']).mean():.3f}")
        print(f"    IV put reale {pick['iv'].mean():.1f}% vs DVOL {pick['dvol'].mean():.1f}%  -> SKEW medio {pick['skew'].mean():+.1f} pt")
        print(f"    premio reale(BID) {pick['real_pct'].mean():.2f}% vs modellato(IV-ATM) {pick['model_pct'].mean():.2f}%")
        print(f"    FATTORE f = reale/modellato:  mediana {pick['f'].median():.2f}  IQR [{pick['f'].quantile(.25):.2f}, {pick['f'].quantile(.75):.2f}]  (range {pick['f'].min():.2f}-{pick['f'].max():.2f})")

    print("\n  -> f e' il punto reale sullo sweep di options_vrp_lab (Sh: f1.0=0.71, f1.29=1.70).")
    print("  CAVEAT: finestra mag-giu 2026 = UN regime (niente crash) -> f calmo. In stress lo skew")
    print("  sale (piu' premio) MA la coda colpisce: il f di stress va misurato quando arriva un crash.")


if __name__ == "__main__":
    main()
