Introduction aux surfaces de volatilité crypto
La construction d'une surface de volatilité pour les options sur cryptocurrency représente l'un des défis les plus stimulants en finance quantitative. Contrairement aux actifs traditionnels, les crypto-actifs présentent une volatilité implicite instable, des skews asymétriques prononcés et des surfaces qui évoluent de manière erratique au gré des événements macro-économiques et des cycles de marché.
Dans ce tutoriel pratique, nous allons explorer comment collecter des données historiques de qualité via l'API Tardis, puis comment construire une surface de volatilité tridimensionnelle en utilisant les techniques d'interpolation Scipy. Nous intégrerons également l'intelligence artificielle de HolySheep pour automatiser l'analyse et la détection des anomalies de pricing.
Architecture de la solution
Notre pipeline se compose de trois étapes principales. Premièrement, la collecte des données OHLCV et des Greek letters via l'API Tardis. Deuxièmement, le nettoyage et la transformation des données pour correspondre au format requis par notre modèle. Troisièmement, l'interpolation par splines cubiques et l'extrapolation pour les strikes manquants.
L'architecture repose sur Python 3.11+, pandas pour la manipulation des données, scipy pour l'interpolation numérique et l'API HolySheep pour l'analyse contextuelle. Le taux de change avantageux de HolySheep (1¥ = 1$ avec WeChat et Alipay) permet de réduire considérablement les coûts d'inférence IA lors des appels récurrents à notre modèle d'analyse.
Configuration de l'environnement
pip install tardis-python pandas numpy scipy matplotlib
pip install requests pandas-datareader
export HOLYSHEEP_API_KEY="your-key-here"
export TARDIS_API_KEY="your-tardis-key-here"
Récupération des données depuis l'API Tardis
L'API Tardis propose des données historiques de qualité institutionnelle pour plus de 30 exchanges crypto. Pour les options BTC et ETH, la couverture est particulièrement exhaustive avec des données degree-level pour les Greeks (delta, gamma, vega, theta).
import requests
import pandas as pd
from datetime import datetime, timedelta
Configuration de l'API Tardis
TARDIS_BASE_URL = "https://api.tardis.dev/v1"
def fetch_option_chain(symbol, expiry_date, exchange="deribit"):
"""Récupère la chaîne d'options pour un sous-jacent et une échéance donnée"""
url = f"{TARDIS_BASE_URL}/options/chain"
params = {
"exchange": exchange,
"symbol": symbol,
"expiry_date": expiry_date.strftime("%Y-%m-%d"),
"include_greeks": True,
"include_ohlcv": True
}
headers = {
"Authorization": f"Bearer {TARDIS_API_KEY}",
"Content-Type": "application/json"
}
response = requests.get(url, params=params, headers=headers, timeout=30)
response.raise_for_status()
data = response.json()
return pd.DataFrame(data['options'])
def fetch_historical_volatility(symbol, days=90):
"""Calcule la volatilité historique sur une période glissante"""
end_date = datetime.now()
start_date = end_date - timedelta(days=days)
url = f"{TARDIS_BASE_URL}/historical/{symbol}/ohlcv"
params = {
"exchange": "binance",
"timeframe": "1d",
"from": start_date.isoformat(),
"to": end_date.isoformat()
}
response = requests.get(url, params=params, timeout=30)
response.raise_for_status()
ohlcv = pd.DataFrame(response.json())
ohlcv['returns'] = ohlcv['close'].pct_change()
historical_vol = ohlcv['returns'].std() * np.sqrt(365)
return historical_vol, ohlcv
Exemple d'utilisation
btc_options = fetch_option_chain("BTC", datetime(2026, 3, 28))
print(f"Options BTC récupérées : {len(btc_options)} contracts")
print(btc_options[['strike', 'iv_bid', 'iv_ask', 'delta', 'gamma']].head())
Construction de la surface de volatilité avec Scipy
Une fois les données nettoyées, nous utilisons scipy.interpolate pour construire une surface lisse. La méthode RBF (Radial Basis Function) offre une flexibilité supérieure pour les données crypto présentant des irrégularités structurelles.
import numpy as np
from scipy.interpolate import RBFInterpolator, griddata, CloughTocher2DInterpolator
from scipy.spatial import ConvexHull
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
def build_volatility_surface(options_df, spot_price):
"""
Construit une surface de volatilité implicite
Paramètres:
options_df: DataFrame avec colonnes ['strike', 'time_to_expiry', 'iv_bid', 'iv_ask']
spot_price: Prix spot actuel du sous-jacent
Retourne:
Interpolateur RBF prêt à l'emploi
"""
# Calcul du moneyness (log-moneyness)
options_df['moneyness'] = np.log(options_df['strike'] / spot_price)
options_df['mid_iv'] = (options_df['iv_bid'] + options_df['iv_ask']) / 2
# Suppression des outliers (IV hors de [5%, 500%])
clean_df = options_df[
(options_df['mid_iv'] > 0.05) &
(options_df['mid_iv'] < 5.0) &
(options_df['time_to_expiry'] > 0) &
(options_df['time_to_expiry'] < 2)
].copy()
# Points d'observation
X = clean_df[['moneyness', 'time_to_expiry']].values
y = clean_df['mid_iv'].values
# Normalisation des features
X_mean = X.mean(axis=0)
X_std = X.std(axis=0)
X_norm = (X - X_mean) / X_std
# Construction de l'interpolateur RBF avec noyau gaussien
rbf = RBFInterpolator(X_norm, y, kernel='gaussian', smoothing=0.01)
return rbf, X_mean, X_std
def evaluate_surface(rbf, X_mean, X_std, spot_price,
strikes_range, tenors_range):
"""Évalue la surface sur une grille régulière"""
moneyness_grid = np.log(strikes_range / spot_price)
time_grid = tenors_range
# Création du maillage
M, T = np.meshgrid(moneyness_grid, time_grid)
points = np.column_stack([M.ravel(), T.ravel()])
# Normalisation et interpolation
points_norm = (points - X_mean) / X_std
iv_surface = rbf(points_norm).reshape(M.shape)
return M, T, iv_surface
def plot_vol_surface(M, T, iv_surface, spot_price):
"""Visualisation 3D de la surface de volatilité"""
fig = plt.figure(figsize=(14, 8))
ax = fig.add_subplot(111, projection='3d')
strikes = spot_price * np.exp(M)
surf = ax.plot_surface(strikes, T * 365, iv_surface * 100,
cmap='viridis', edgecolor='none', alpha=0.9)
ax.set_xlabel('Strike Price
Ressources connexes
Articles connexes