Download scripts/fetch_dvol.py from chonthichar/crypto-forecasting-ai: direct link, hf CLI and curl.
- Browser
- Download file 2.42 kB
-
https://huggingface.co/spaces/chonthichar/crypto-forecasting-ai/resolve/main/scripts/fetch_dvol.py
- Command line
-
hf download hf://spaces/chonthichar/crypto-forecasting-ai/scripts/fetch_dvol.py
-
curl -L -o fetch_dvol.py https://huggingface.co/spaces/chonthichar/crypto-forecasting-ai/resolve/main/scripts/fetch_dvol.py
2.42 kB
| """Download Deribit's BTC implied-volatility index (DVOL), hourly, full history. | |
| DVOL is the options market's own 30-day expectation of BTC volatility, in | |
| annualised percent, published since March 2021. It is information the price | |
| series does not contain directly: what option traders are paying for future | |
| movement. Public endpoint, no key needed. | |
| Rows are hourly OHLC of the index keyed by the hour's open time (UTC), the | |
| same convention as the Binance candles, so the close of row t is known when | |
| candle t closes and may be used for the forecast issued then. | |
| Writes outputs/volatility/btc_dvol_1h.csv. | |
| Usage: | |
| python scripts/fetch_dvol.py | |
| """ | |
| from __future__ import annotations | |
| import json | |
| import time | |
| import urllib.request | |
| from pathlib import Path | |
| import pandas as pd | |
| ROOT = Path(__file__).resolve().parents[1] | |
| OUT = ROOT / "outputs" / "volatility" / "btc_dvol_1h.csv" | |
| URL = ("https://www.deribit.com/api/v2/public/get_volatility_index_data" | |
| "?currency=BTC&start_timestamp={start}&end_timestamp={end}&resolution=3600") | |
| START_MS = 1609459200000 # 2021-01-01; the index begins in March 2021 | |
| def fetch() -> pd.DataFrame: | |
| end, rows = int(time.time() * 1000), [] | |
| while end > START_MS: | |
| with urllib.request.urlopen(URL.format(start=START_MS, end=end), timeout=30) as resp: | |
| result = json.load(resp)["result"] | |
| batch = result.get("data") or [] | |
| if not batch: | |
| break | |
| rows += batch | |
| nxt = result.get("continuation") | |
| if not nxt or nxt >= end: | |
| break | |
| end = nxt | |
| time.sleep(0.2) # be polite to a public endpoint | |
| df = pd.DataFrame(rows, columns=["ts", "open", "high", "low", "close"]) | |
| df["timestamp"] = pd.to_datetime(df["ts"], unit="ms", utc=True) | |
| return (df.drop(columns="ts").drop_duplicates("timestamp") | |
| .sort_values("timestamp").reset_index(drop=True)) | |
| def main() -> None: | |
| df = fetch() | |
| OUT.parent.mkdir(parents=True, exist_ok=True) | |
| df.to_csv(OUT, index=False) | |
| full = pd.date_range(df["timestamp"].min(), df["timestamp"].max(), freq="1h") | |
| print(f"{len(df):,} hours, {df['timestamp'].min()} -> {df['timestamp'].max()}; " | |
| f"{len(full) - len(df):,} missing hours; DVOL range {df['close'].min():.1f}-{df['close'].max():.1f}") | |
| print(f"written {OUT.relative_to(ROOT)}") | |
| if __name__ == "__main__": | |
| main() | |