"""FETCH storia DVOL (Deribit Volatility Index) — input IV per lo sleeve opzioni VRP. DVOL = vol implicita 30d annualizzata di Deribit (l'IV "ATM" del mercato). Public API, no auth. Limite 1000 punti/richiesta -> paginazione all'indietro. Salva data/raw/dvol_.parquet (colonne: timestamp ms, close = DVOL%). Usato come IV per prezzare BS le opzioni nel backtest VRP; la RV viene dai nostri prezzi certificati. VRP = IV - RV. uv run python scripts/research/fetch_dvol.py """ from __future__ import annotations import sys, time from pathlib import Path PROJECT_ROOT = Path(__file__).resolve().parents[2] sys.path.insert(0, str(PROJECT_ROOT)) import requests, pandas as pd URL = "https://www.deribit.com/api/v2/public/get_volatility_index_data" RAW = PROJECT_ROOT / "data" / "raw" def fetch(cur, res=86400): end = int(time.time() * 1000) floor = int(pd.Timestamp("2020-06-01", tz="UTC").timestamp() * 1000) rows = {} guard = 0 while end > floor and guard < 60: guard += 1 r = requests.get(URL, params={"currency": cur, "start_timestamp": floor, "end_timestamp": end, "resolution": res}, timeout=40) data = r.json().get("result", {}).get("data", []) if not data: break for ts, o, h, l, c in data: rows[int(ts)] = float(c) earliest = min(int(x[0]) for x in data) if earliest >= end: break end = earliest - 1 if not rows: return pd.DataFrame() df = pd.DataFrame(sorted(rows.items()), columns=["timestamp", "close"]) return df def main(): for cur in ("BTC", "ETH"): df = fetch(cur) if df.empty: print(f"{cur}: VUOTO"); continue ts = pd.to_datetime(df["timestamp"], unit="ms", utc=True) df.to_parquet(RAW / f"dvol_{cur.lower()}.parquet", index=False) print(f"{cur}: {len(df)} giorni [{ts.iloc[0].date()} -> {ts.iloc[-1].date()}] " f"DVOL media {df['close'].mean():.1f} range [{df['close'].min():.1f}, {df['close'].max():.1f}] " f"-> data/raw/dvol_{cur.lower()}.parquet") if __name__ == "__main__": main()