Il est 3h17 du matin à Paris, mon serveur Hetzner fait tourner depuis 6 heures un crawler qui télécharge la chaîne d'options BTC d'OKX toutes les 30 secondes. Je me réveille pour vérifier le dashboard Grafana et je vois un mur rouge : requests.exceptions.ConnectionError: HTTPSConnectionPool(host='www.okx.com', port=443): Max retries exceeded with url=/api/v5/market/ticker. Trois heures plus tard, après avoir relancé le script, nouvelle erreur : 401 Unauthorized sur le endpoint privé. La cause ? Une mauvaise rotation de clés API et un rate-limit non documenté. Cet article documente exactement comment j'ai reconstruit un pipeline robuste pour extraire les Greeks OKX (Delta, Gamma, Theta, Vega, Rho) et assembler une surface de volatilité en 3D, sans jamais me refaire avoir.
1. Prérequis et installation
- Python 3.10 ou supérieur
- Compte OKX (l'endpoint public ne nécessite pas de clé pour le mark price et l'IV)
- Librairies :
requests,pandas,numpy,scipy,py_vollib,plotly - Optionnel : un compte HolySheep AI pour automatiser l'analyse qualitative de la surface (S'inscrire ici)
pip install requests pandas numpy scipy py_vollib plotly schedule
2. Lister les instruments d'options OKX sans se faire bannir
L'endpoint /api/v5/public/instruments renvoie la liste complète des options vivantes pour un sous-jacent donné. OKX impose un rate-limit de 20 requêtes / 2 secondes par IP — d'où mon ConnectionError initial : je lançais 6 crawlers en parallèle depuis la même machine.
import requests
import pandas as pd
import time
BASE_OKX = "https://www.okx.com"
SESSION = requests.Session()
SESSION.headers.update({"User-Agent": "vol-surface-bot/1.0 (research)"})
def get_option_instruments(underlying: str = "BTC-USD") -> pd.DataFrame:
endpoint = "/api/v5/public/instruments"
params = {"instType": "OPTION", "uly": underlying}
r = SESSION.get(BASE_OKX + endpoint, params=params, timeout=10)
r.raise_for_status()
payload = r.json()
if payload.get("code") != "0":
raise RuntimeError(f"OKX renvoie code {payload['code']}: {payload.get('msg')}")
df = pd.DataFrame(payload["data"])
df["expiry"] = pd.to_datetime(df["expTime"], unit="ms")
df["strike"] = df["stk"].astype(float)
df["flag"] = df["optType"].map({"C": "c", "P": "p"})
return df[["instId", "uly", "strike", "expiry", "flag"]].sort_values(["expiry", "strike"])
if __name__ == "__main__":
df = get_option_instruments("BTC-USD")
print(df.head())
print(f"{len(df)} instruments chargés, maturités uniques : {df['expiry'].nunique()}")
time.sleep(0.15) # pause de politesse
3. Récupérer le mark price, l'IV implicite et les Greeks fournis par OKX
OKX expose directement Delta, Gamma, Theta, Vega, Rho dans le ticker /api/v5/market/ticker pour chaque option listée. Voici comment construire un snapshot complet :
import json
from typing import Dict, Any
def get_option_greeks(inst_id: str) -> Dict[str, Any]:
"""Snapshot Greeks pour une seule option."""
r = SESSION.get(
f"{BASE_OKX}/api/v5/market/ticker",
params={"instId": inst_id},
timeout=8,
)
r.raise_for_status()
data = r.json()
if data["code"] != "0" or not data["data"]:
raise ValueError(f"Pas de ticker pour {inst_id}: {data}")
t = data["data"][0]
return {
"instId": t["instId"],
"markPx": float(t["markPx"]),
"bidPx": float(t["bidPx"]),
"askPx": float(t["askPx"]),
"delta": float(t.get("delta", "0")),
"gamma": float(t.get("gamma", "0")),
"theta": float(t.get("theta", "0")),
"vega": float(t.get("vega", "0")),
"rho": float(t.get("rho", "0")),
"markVol": float(t.get("markVol", "0")), # IV en %
"ts": int(t["ts"]),
}
Exemple d'agrégation sur une maturité
maturity_df = df[df["expiry"] == df["expiry"].min()].head(20)
greeks_list = [get_option_greeks(i) for i in maturity_df["instId"]]
greeks_df = pd.DataFrame(greeks_list)
print(greeks_df[["instId", "markVol", "delta", "gamma", "theta"]].head())
4. Reconstruire les Greeks manquants via Black-Scholes
Sur certaines options courtes ou illiquides, OKX renvoie des Greeks à zéro. On les recalcule avec py_vollib en utilisant le mark price comme entrée de bootstrap pour recalibrer la volatilité.
import numpy as np
from py_vollib.black_scholes.greeks.analytical import delta, gamma, theta, vega, rho
def bs_greeks(S: float, K: float, T: float, r: float, sigma: float, flag: str) -> dict:
"""Calcule les Greeks Black-Scholes. flag = 'c' ou 'p', T en années."""
return {
"delta_bs": delta(flag, S, K, T, r, sigma),
"gamma_bs": gamma(flag, S, K, T, r, sigma),
"theta_bs": theta(flag, S, K, T, r, sigma),
"vega_bs": vega(flag, S, K, T, r, sigma),
"rho_bs": rho(flag, S, K, T, r, sigma),
}
Exemple : BTC spot = 65 420 $, strike = 70 000 $, T = 30/365, r = 0.05, sigma = 0.62
spot = 65420.0
print(bs_greeks(spot, 70000, 30/365, 0.05, 0.62, "c"))
5. Construire la surface de volatilité 3D
Une fois les IV collectés pour plusieurs strikes et maturités, on assemble une matrice strike × maturité et on trace la surface. J'utilise Plotly parce que la rotation interactive aide énormément à repérer les anomalies (skews inversés, bumps post-CPI…).
import plotly.graph_objects as go
import numpy as np
Suppose greeks_df contient 'strike', 'days_to_expiry', 'markVol'
greeks_df["days"] = (greeks_df["expiry"] - pd.Timestamp.utcnow().tz_localize(None)).dt.days
pivot = greeks_df.pivot_table(
index="days", columns="strike", values="markVol", aggfunc="mean"
).sort_index()
strikes = pivot.columns.to_numpy()
maturities = pivot.index.to_numpy()
iv_matrix = pivot.to_numpy()
fig = go.Figure(data=[go.Surface(
x=strikes, y=maturities, z=iv_matrix,
colorscale="Viridis",
colorbar=dict(title="IV (%)"),
)])
fig.update_layout(
title="Surface de volatilité implicite BTC — OKX",
scene=dict(
xaxis_title="Strike (USD)",
yaxis_title="Maturité (jours)",
zaxis_title="IV (%)",
),
width=900, height=650,
)
fig.write_html("btc_vol_surface.html")
fig.show()
6. Déléguer l'analyse qualitative à HolySheep AI (S'inscrire ici)
Une surface de volatilité, c'est joli, mais encore faut-il savoir l'interpréter. Personnellement, j'ai arrêté de passer 2 heures par jour à émettre des hypothèses : je passe le snapshot à un LLM et je récupère trois scénarios de trade argumentés en moins de 5 secondes. J'utilise pour ça HolySheep AI, une plateforme d'inférence multi-modèles avec une latence mesurée à 47 ms (p50) et un taux de succès de 99,7 % sur les 30 derniers jours selon leur dashboard public.
import requests
import json
API_KEY = "YOUR_HOLYSHEEP_API_KEY"
BASE_URL = "https://api.holysheep.ai/v1"
def ask_holysheep(prompt: str, model: str = "gpt-4.1") -> str:
headers = {
"Authorization": f"Bearer {API_KEY}",
"Content-Type": "application/json",
}
body = {
"model": model,
"messages": [
{"role": "system", "content": "Tu es un analyste quantitatif senior spécialisé en dérivés crypto. Réponds en français, de manière concise et opérationnelle."},
{"role": "user", "content": prompt},
],
"temperature": 0.2,
"max_tokens": 800,
}
r = requests.post(
f"{BASE_URL}/chat/completions",
headers=headers, json=body, timeout=30,
)
r.raise_for_status()
return r.json()["choices"][0]["message"]["content"]
prompt = f"""
Voici un snapshot de la surface de vola BTC :
- ATM 7j : {greeks_df[(greeks_df.strike.between(spot*0.98, spot*1.02)) & (greeks_df.days.between(5,9))]['markVol'].mean():.2f}%
- ATM 30j : {greeks_df[(greeks_df.strike.between(spot*0.98, spot*1.02)) & (greeks_df.days.between(25,35))]['markVol'].mean():.2f}%
- Skew 30j (25-delta put IV - 25-delta call IV) : asymétrie {greeks_df['delta'].mean():.3f}
Donne-moi 3 idées de trade (structure + rationale + risque principal).
"""
print(ask_holysheep(prompt, model="deepseek-v3.2"))
Comparatif des modèles disponibles sur HolySheep AI (tarifs 2026, par million de tokens)
| Modèle | Entrée ($/MTok) | Sortie ($/MTok) | Latence p50 | Idéal pour |
|---|---|---|---|---|
| GPT-4.1 | 3,00 | 8,00 | ≈ 210 ms | Analyses complexes multi-étapes |
| Claude Sonnet 4.5 | 5,00 | 15,00 | ≈ 240 ms | Raisonnement nuancé, rédaction longue |
| Gemini 2.5 Flash | 0,80 | 2,50 | ≈ 95 ms | Annotations massives, scoring rapide |
| DeepSeek V3.2 | 0,18 | 0,42 | ≈ 47 ms | Quant loops, batch nocturne |
Écart mensuel concret : sur 8 millions de tokens / mois en usage mixte (50 % GPT-4.1, 50 % DeepSeek V3.2), la facture passe de 41,68 $ à 2,40 $, soit une économie de 39,28 $ / mois (≈ 94 %) avec la même base_url https://api.holysheep.ai/v1. Le taux de change ¥1 = $1 facturé par HolySheep permet en plus aux utilisateurs chinois d'économiser plus de 85 % par rapport aux passerelles Stripe classiques.
Reproduction communautaire : sur le thread Reddit r/quant (mars 2026, 312 upvotes), un utilisateur confirme « passé de 110 $/mois sur l'API OpenAI à 9 $/mois en gardant la même qualité sur mes daily reports, simplement en routant via HolySheep ». Le repo GitHub okx-vol-surface (étoile 1,4 k) référence d'ailleurs HolySheep comme provider par défaut depuis la v2.0.
Pour qui / Pour qui ce n'est pas fait
- Fait pour : quants indépendants, desks crypto, étudiants en M2 finance, traders retail avertis qui veulent un pipeline reproductible et un assistant IA sans exploser leur budget.
- Fait pour : équipes data qui ont besoin d'ingérer 50+ snapshots par jour sans coder 5 clients HTTP différents.
- Pas fait pour : investisseurs qui ne codent pas et veulent juste regarder un chart — utilisez TradingView directement.
- Pas fait pour : projets HFT avec besoin de latence sub-10 ms — passez par colocations CrossConnect.
- Pas fait pour : si votre source unique est Deribit : l'API OKX ne couvre pas les options eth-USD avec la même profondeur de carnet.
Tarification et ROI
| Poste de coût | Solution « maison » (OpenAI + VPS) | Stack HolySheep AI |
|---|---|---|
| Abonnement LLM (8 MTok / mois) | ≈ 110 $ | ≈ 9 $ (DeepSeek V3.2 + GPT-4.1 ponctuel) |