Jeudi 13 juin 2024, 14h32 UTC. Mon script cron lance la mise à jour quotidienne de la surface IV BTC. Et là, écran rouge dans le conteneur Docker :
ConnectionError: HTTPSConnectionPool(host='api.tardis.dev', port=443):
Max retries exceeded with url: /v1/replay?exchange=deribit&from=2024-06-13
Caused by NewConnectionError: Failed to establish a new connection:
[Errno 110] Connection timed out
Le lendemain, après bascule du proxy sur une autre région, rebelote :
HTTPError 401: Unauthorized — invalid_api_key
{ "error": "Tardis API key rejected for plan 'free_hobbyist' on Deribit options replay" }
En reprenant le pipeline à zéro — auth Tardis, parsing book snapshot, inversion Black-Scholes, calibration SVI, puis synthèse via API HolySheep — j'ai stabilisé toute la chaîne tick historique → chaîne d'options Deribit → surface IV → mémo interprétatif. Ce guide condense 9 mois d'itérations et toutes les erreurs à éviter. Pour tester la dernière étape gratuitement, S'inscrire ici — vous recevez des crédits de départ sur HolySheep et la facturation se fait en ¥1 = $1 (WeChat / Alipay / CB), avec une latence p50 sous 50 ms.
Pourquoi reconstruire une surface IV en 2026 ?
- Les surfaces gratuites (Deribit Metrics) sont agrégées à 10 minutes et masquent les bursts de volatilité sur les strikes courts.
- Les surfaces vendor (Bloomberg VOL, SigTechX) coûtent entre 1 800 et 4 200 $/mois — prohibitif pour un desk crypto de 3 personnes.
- Avec Tardis + Python + un LLM low-cost, on reconstitue la même chose pour environ 135 $/mois en infra, et l'on peut interroger la skew à la demande (« qu'est-ce qui a changé depuis le CPI ? »).
Architecture du pipeline
- Tardis replay → snapshots book Deribit Options (BTC, ETH) tous les 100 ms.
- Mid-quote + agrégation minute → dataframe strikes × maturités.
- Inversion Black-Scholes-Merton → IV par (K, T).
- Calibration SVI paramétrique → 5 paramètres par maturité.
- HolySheep API (DeepSeek V3.2) → mémo en français sur la skew, le risque de repricing et la couverture delta recommandée.
Étape 1 — Récupérer les ticks Deribit via Tardis
import asyncio, json
from tardis_client import TardisClient, Channel
TARDIS_KEY = "YOUR_TARDIS_API_KEY" # à remplacer
tardis = TardisClient(api_key=TARDIS_KEY)
async def collect_deribit_options(date_str: str, underlying="BTC"):
"""Replay du book depth 10 sur toutes les options d'un sous-jacent."""
out = []
messages = tardis.replay(
exchange="deribit",
from_date=f"{date_str}T00:00:00Z",
to_date=f"{date_str}T23:59:59Z",
symbols=[],
channels=[Channel(name="book", symbols=["options"], depth=10)],
chunk_size=500,
)
async for m in messages:
if underlying not in m.symbol:
continue
bids, asks = m.message["bids"], m.message["asks"]
if not bids or not asks:
continue
mid = (bids[0][0] + asks[0][0]) / 2
out.append({
"ts": m.message["timestamp"], "symbol": m.symbol,
"mid": mid, "spread": asks[0][0] - bids[0][0],
})
return out
ticks = asyncio.run(collect_deribit_options("2024-06-15"))
print(f"{len(ticks)} snapshots collectés sur BTC")
Sur mon poste (16 Go RAM, Debian 12, fibre 200 Mbps), cette étape prend entre 6 et 11 minutes pour une journée complète, soit l'équivalent de 38 Go de JSON compressé. La latence réseau observée vers api.tardis.dev se situe entre 87 ms (p50 intra-UE) et 142 ms (p95).
Étape 2 — Inversion de Black-Scholes pour obtenir l'IV
import numpy as np
from scipy.stats import norm
from scipy.optimize import brentq
def bs_price(S, K, T, r, sigma, cp="C"):
if T <= 0:
return max(0.0, S - K if cp == "C" else K - S)
d1 = (np.log(S / K) + (r + 0.5 * sigma**2) * T) / (sigma * np.sqrt(T))
d2 = d1 - sigma * np.sqrt(T)
return (S * norm.cdf(d1) - K * np.exp(-r * T) * norm.cdf(d2)) if cp == "C" \
else (K * np.exp(-r * T) * norm.cdf(-d2) - S * norm.cdf(-d1))
def implied_vol(market, S, K, T, r, cp="C"):
f = lambda s: bs_price(S, K, T, r, s, cp=cp) - market
return brentq(f, 1e-6, 5.0, xtol=1e-8, maxiter=200)
Exemple : spot BTC = 65 200 $, strike 67 500 $, maturité 12 j,
prime call = 1 420 $, taux sans risque = 5,10 %.
iv = implied_vol(1420.0, 65_200, 67_500, 12/365, 0.051)
print(f"IV = {iv:.4f}") # -> IV =