Files
Adriano Dal Pastro 8f9ce89039 research: imposta sleeve OPZIONI VRP — infrastruttura + prima validazione (LEAD reale, non deploy)
fetch_dvol.py: storia DVOL (IV Deribit) BTC/ETH 2021-2026 -> data/raw/dvol_*. options_vrp_lab.py:
backtest CSP settimanale, premio BS su DVOL reale + calibrazione f (skew/spread), payoff sul path
realizzato, causale; gauntlet (VRP, sweep f/delta, per-anno, worst-weeks, corr+contributo vs TP01).

Esiti (book 50/50 put delta-0.28): VRP reale (BTC IV>RV 78% del tempo). Sharpe DIPENDE da f:
0.71 conservativo (IV-ATM) -> 1.70 a f=1.29 (skew reale calm). CODA severa (DD 30-33%, settimane
-15..-26% su LUNA/FTX/crash; 2022 -9%, 2026-YTD -14%). Scorrelato a TP01 (+0.07) -> migliora il
portafoglio anche a premio conservativo (TP01 70%+OPT 30%: Sh settimanale 0.71->0.97).

VERDETTO: lead reale e diversificante, MA premio modellato (non catena reale) + calibrazione
ottimistica + coda short-vol non catturata nello stress. Regola: mai short-vol da modello in
deploy. NON aggiunto. Portafoglio invariato TP01 70% + XS01 30%. Prossimo: accumulo quote reali
multi-regime + stress crash + daily-MTM + paper testnet. Diario 2026-06-19-options-vrp-lab.md.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-19 20:30:08 +00:00

59 lines
2.1 KiB
Python

"""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_<asset>.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()