Il y a trois mois, j'ai passé quatre jours entiers à déboguer une RuntimeWarning: overflow encountered in exp qui corrompait mes calibrations de surface de volatilité implicite. Le problème ? Une interpolation CubiqueSpline standard qui générait des valeurs explosives pour les maturités longues avec des strikes extrêmes. Cette expérience m'a poussé à comparer systématiquement toutes les méthodes d'interpolation disponibles pour la construction de surfaces de volatilité implicite.
Comprendre le Problème de la Surface de Volatilité Implicite
La surface de volatilité implicite est une représentation tridimensionnelle de la volatilité implicite en fonction du strike et de la maturité. Elle est fondamentale pour :
- La tarification d'options exotiques
- La gestion des risques de volatilité
- L'arbitrage de volatilité
- La construction de courbes de volatilité smile/skew
Les 5 Méthodes d'Interpolation Comparées
1. Interpolation Linéaire
L'approche la plus simple et la plus robuste. Elle relie les points de données par des segments linéaires, garantissant la continuité mais pas la dérivabilité.
import numpy as np
from scipy.interpolate import interp1d
Construction d'une courbe de volatilité implicite
strikes = np.array([80, 90, 100, 110, 120])
vols = np.array([0.25, 0.22, 0.20, 0.19, 0.21])
Interpolation linéaire
vol_linear = interp1d(strikes, vols, kind='linear',
bounds_error=False, fill_value='extrapolate')
Évaluation en dehors des points known
test_strikes = np.linspace(75, 125, 50)
test_vols = vol_linear(test_strikes)
print(f"Vol à K=95: {vol_linear(95):.4f}")
print(f"Vol à K=115: {vol_linear(115):.4f}")
2. Splines Cubiques (Clamped)
Les splines cubiques offrent une continuité C² (fonction, dérivée première et seconde continues). Cependant, elles peuvent générer des oscillations parasites pour des données financières.
from scipy.interpolate import CubicSpline
Spline cubique avec conditions aux limites
cs = CubicSpline(strikes, vols, bc_type='clamped')
bc_type='clamped': dérivée première = 0 aux extrémités
Alternative: 'natural' pour seconde dérivée = 0
test_vols_spline = cs(test_strikes)
Dérivée du smile ( важный pour le skew )
smile_slope = cs(test_strikes, 1) # Première dérivée
print(f"Extrapolation K=130: {cs(130):.4f}") # Peut exploser!
3. Interpolation par Fonctions de Base Radiales (RBF)
Méthode particulièrement adaptée aux surfaces 2D avec une很好的 généralisation. Fonctionne bien même avec des données clairsemées.
from scipy.interpolate import RBFInterpolator
Données 2D: strikes et maturités
strikes_2d = np.array([80, 90, 100, 110, 120] * 3)
maturities = np.array([0.25]*5 + [0.5]*5 + [1.0]*5)
vols_2d = np.array([0.25, 0.22, 0.20, 0.19, 0.21, # T=0.25
0.24, 0.21, 0.19, 0.18, 0.20, # T=0.5
0.23, 0.20, 0.18, 0.17, 0.19]) # T=1.0
coords = np.column_stack([strikes_2d, maturities])
RBF avec noyau gaussien (_smooth=True pour lisser le bruit)
rbf_interp = RBFInterpolator(coords, vols_2d, kernel='gaussian',
smoothing=0.01)
Évaluation sur grille
eval_coords = np.array([[k, t] for k in test_strikes
for t in [0.3, 0.6, 0.9]])
surface_vols = rbf_interp(eval_coords)
4. Kriging (Krigeage)
Méthode géostatistique qui offre non seulement l'interpolation mais aussi une estimation de l'incertitude. Particulièrement utile pour le pricing d'options avec ajustements de convexité.
# Implémentation Kriging simplifiée
from scipy.linalg import solve
def kriging_interpolation(x_data, y_data, x_eval, sigma_nugget=0.01):
"""
Kriging ordinaire avec effet de pépite (nugget)
pour gérer le bruit de mesure
"""
n = len(x_data)
# Matrice de covariance (modèle gaussien)
def cov(h, l=10):
return np.exp(-3 * (h/l)**2)
# Construction de la matrice de covariance
H = np.zeros((n+1, n+1))
for i in range(n):
for j in range(n):
H[i,j] = cov(abs(x_data[i] - x_data[j]))
H[n,:n] = H[:n,n] = 1
H[n,n] = 0
# Résolution du système
y_aug = np.append(y_data, np.mean(y_data))
# Résolution avec gestion des erreurs numériques
try:
weights = solve(H, y_aug, assume_a='pos')
except np.linalg.LinAlgError:
# Ajout de régularisation numérique
H += np.eye(n+1) * 1e-8
weights = solve(H, y_aug)
return weights[:n]
Application aux données de volatilité
weights = kriging_interpolation(strikes, vols, test_strikes)
5. Interpolation Smoothing (SciPy UnivariateSpline)
Combine interpolation et lissage, idéal quand les données contiennent du bruit de marché ou des anomalies temporaires.
from scipy.interpolate import UnivariateSpline
Spline avec lissage automatique
s = nombre de points - sqrt(2) pour lisser le bruit
spline_smooth = UnivariateSpline(strikes, vols, s=len(vols)*0.5)
Évaluation
test_vols_smooth = spline_smooth(test_strikes)
Estimation de la qualité du lissage
residual = np.sum((spline_smooth(strikes) - vols)**2)
print(f"Résidu du lissage: {residual:.6f}")
print(f"Coefficient de lissage effectif: {spline_smooth.get_smoothing_factor():.4f}")
Benchmarks de Performance et Précision
| Méthode | Latence (ms) |
|---|