σμimplied vol · KKmax(S−K,0)udβρᵢⱼfat tailsPnL · drawdownyield · TdSₜ = μSₜ dt + σSₜ dWₜC = S·N(d₁) − K·e⁻ʳᵀ·N(d₂)σₚ² = wᵀΣwd₁ = [ln(S/K) + (r + σ²⁄2)T] ⁄ σ√T∂V/∂t + ½σ²S²·∂²V/∂S² + rS·∂V/∂S − rV = 0Sharpe = (Rₚ − R_f) ⁄ σₚVaR₉₉ = μ − 2.33σρ = Cov(X,Y) ⁄ σₓσᵧE[Rₚ] = Σ wᵢ·E[Rᵢ]φ(x) = e^(−x²/2) ⁄ √2πE[Rᵢ] = R_f + βᵢ(E[Rₘ] − R_f)dXₜ = θ(μ − Xₜ)dt + σ dWₜσ²ₜ = ω + α·ε²ₜ₋₁ + β·σ²ₜ₋₁C − P = S − K·e⁻ʳᵀΔ = ∂V/∂S Γ = ∂²V/∂S²p = (e^(rΔt) − d) ⁄ (u − d)rₜ = ln(Pₜ ⁄ Pₜ₋₁)E[Xₜ₊₁ | ℱₜ] = Xₜf* = (bp − q) ⁄ bz = (x − μ) ⁄ σP(N=k) = λᵏe^(−λ) ⁄ k!Θ = −∂V/∂Tν = S·φ(d₁)·√Tmin wᵀΣw s.t. wᵀμ = μ*∫Σ∂∞λ
σμimplied vol · KKmax(S−K,0)udβρᵢⱼfat tailsPnL · drawdownyield · TdSₜ = μSₜ dt + σSₜ dWₜC = S·N(d₁) − K·e⁻ʳᵀ·N(d₂)σₚ² = wᵀΣwd₁ = [ln(S/K) + (r + σ²⁄2)T] ⁄ σ√T∂V/∂t + ½σ²S²·∂²V/∂S² + rS·∂V/∂S − rV = 0Sharpe = (Rₚ − R_f) ⁄ σₚVaR₉₉ = μ − 2.33σρ = Cov(X,Y) ⁄ σₓσᵧE[Rₚ] = Σ wᵢ·E[Rᵢ]φ(x) = e^(−x²/2) ⁄ √2πE[Rᵢ] = R_f + βᵢ(E[Rₘ] − R_f)dXₜ = θ(μ − Xₜ)dt + σ dWₜσ²ₜ = ω + α·ε²ₜ₋₁ + β·σ²ₜ₋₁C − P = S − K·e⁻ʳᵀΔ = ∂V/∂S Γ = ∂²V/∂S²p = (e^(rΔt) − d) ⁄ (u − d)rₜ = ln(Pₜ ⁄ Pₜ₋₁)E[Xₜ₊₁ | ℱₜ] = Xₜf* = (bp − q) ⁄ bz = (x − μ) ⁄ σP(N=k) = λᵏe^(−λ) ⁄ k!Θ = −∂V/∂Tν = S·φ(d₁)·√Tmin wᵀΣw s.t. wᵀμ = μ*∫Σ∂∞λ
uantCraft AcademyParcours
Ctrl K
AO
+1,2 k apprenants
ConnexionRejoindre ↗
Parcours
AO
+1,2 k apprenants
Connexion
  • English
  • Français
  • Español
  • العربية
  • Português
  • Deutsch
  • 日本語
  • 中文
Parcours Python›Module 11 · Systèmes de production et modèles de pointe›Sujet 11.9·~1 h 30 minExpert

Le modèle SABR

Position dans le parcoursModule 11 sur 11 · Sujet 9 sur 13
11.9 Le modèle SABR
—Score du lab— / 100XP total—Série—

Un smile en quatre nombres

Les options de taux et de change se négocient sur de nombreux strikes, et les salles ont besoin d'un moyen lisse et conscient des arbitrages d'interpoler et d'extrapoler les volatilités cotées. SABR (Hagan, Kumar, Lesniewski, Woodward, 2002) est le standard du marché. Il modélise un forward F avec sa propre volatilité aléatoire alpha : dF = alpha F^beta dW et d alpha = nu alpha dZ, avec une corrélation rho entre les chocs. Quatre paramètres façonnent le smile d'une échéance : alpha fixe le niveau global, beta la façon dont la volatilité dépend du niveau de prix (0 normal, 1 lognormal), rho l'inclinaison (skew) et nu la courbure (de combien les ailes montent).

# The four parameters of one expiry, for a rate forward of 3%
f, t = 0.03, 1.0                              # forward rate and expiry in years
alpha, beta, rho, nu = 0.035, 0.5, -0.3, 0.4
print(round(alpha / f ** (1 - beta), 4))      # 0.2021   alpha / f^(1-beta) is roughly the at-the-money volatility (before the correction)

La formule de Hagan

Le développement asymptotique de Hagan donne la volatilité implicite de Black sans simulation. À la monnaie (K = F), c'est alpha / F^(1-beta) fois une correction de temps 1 + (...) * T, où la parenthèse combine trois effets : la courbure beta de l'épine dorsale, le terme de skew rho * nu et le terme de smile nu^2. Hors de la monnaie, la même correction multiplie deux facteurs de plus : un dénominateur en log-moneyness L = ln(F/K) et le rapport z / chi(z), avec z = (nu/alpha) (FK)^((1-beta)/2) L et chi(z) = ln((sqrt(1 - 2 rho z + z^2) + z - rho) / (1 - rho)). Quand z tend vers 0 le rapport tend vers 1, donc la formule rejoint en douceur la valeur à la monnaie, mais calculer directement 0 / 0 échouerait : traitez un z minuscule comme une limite.

# The pieces of Hagan's formula: the time correction, the at-the-money volatility and z / chi(z)
import math

def sabr_correction(f, k, t, alpha, beta, rho, nu):
    fk = f * k
    return 1 + ((1 - beta) ** 2 / 24 * alpha ** 2 / fk ** (1 - beta) + rho * beta * nu * alpha / (4 * fk ** ((1 - beta) / 2)) + (2 - 3 * rho ** 2) * nu ** 2 / 24) * t

def sabr_atm_vol(f, t, alpha, beta, rho, nu):
    return alpha / f ** (1 - beta) * sabr_correction(f, f, t, alpha, beta, rho, nu)

def z_over_chi(z, rho):
    if abs(z) < 1e-7:
        return 1.0
    return z / math.log((math.sqrt(1 - 2 * rho * z + z ** 2) + z - rho) / (1 - rho))

print(round(sabr_atm_vol(0.03, 1.0, 0.035, 0.5, -0.3, 0.4), 6))      # 0.203877   the at-the-money volatility
print(round(z_over_chi(0.5, -0.3), 6), z_over_chi(0.0, -0.3))        # 1.103683 1.0   near 1, and exactly 1.0 at z = 0

Lire le smile et l'ajuster

Tracez la volatilité implicite en fonction du strike et les paramètres ont des signatures claires. Un rho négatif relève les strikes bas et abaisse les hauts (skew descendant, typique des actions et de nombreux taux) ; rho = 0 donne un smile symétrique. Un nu plus grand relève les deux ailes. beta déplace l'épine dorsale : de combien la volatilité à la monnaie change quand le forward bouge. Les praticiens fixent beta par convention ou d'après l'historique, puis calibrent le reste sur les volatilités cotées de chaque échéance (sujet suivant), en résolvant souvent alpha à partir de la cotation à la monnaie pour qu'elle colle exactement. Deux mises en garde : la formule est une approximation qui se dégrade pour les longues échéances et les très bas strikes, où elle peut impliquer des densités de probabilité négatives.

# The smile for three values of rho: a negative rho lifts the low strikes (downward skew)
import math

def sabr_vol(f, k, t, alpha, beta, rho, nu):
    fk = f * k
    log = math.log(f / k)
    mid = fk ** ((1 - beta) / 2)
    z = nu / alpha * mid * log
    ratio = 1.0 if abs(z) < 1e-7 else z / math.log((math.sqrt(1 - 2 * rho * z + z ** 2) + z - rho) / (1 - rho))
    denominator = mid * (1 + (1 - beta) ** 2 / 24 * log ** 2 + (1 - beta) ** 4 / 1920 * log ** 4)
    bracket = 1 + ((1 - beta) ** 2 / 24 * alpha ** 2 / fk ** (1 - beta) + rho * beta * nu * alpha / (4 * mid) + (2 - 3 * rho ** 2) * nu ** 2 / 24) * t
    return alpha / denominator * ratio * bracket

for rho in (-0.5, 0.0, 0.5):
    print(rho, [round(sabr_vol(0.03, k, 1.0, 0.035, 0.5, rho, 0.4), 4) for k in (0.02, 0.03, 0.04)])
# one line per rho: the first value (low strike) is the highest when rho is negative and the lowest when rho is positive
# A free sanity check: with beta = 1 and nu = 0 SABR is Black-Scholes, so the at-the-money volatility is alpha at every expiry
def atm(f, t, alpha, beta, rho, nu):
    fk = f * f
    bracket = 1 + ((1 - beta) ** 2 / 24 * alpha ** 2 / fk ** (1 - beta) + rho * beta * nu * alpha / (4 * fk ** ((1 - beta) / 2)) + (2 - 3 * rho ** 2) * nu ** 2 / 24) * t
    return alpha / f ** (1 - beta) * bracket

print(atm(100.0, 0.5, 0.2, 1.0, -0.3, 0.0), atm(100.0, 5.0, 0.2, 1.0, -0.3, 0.0))      # 0.2 0.2
Une approximation avec un point faible connuLa formule de Hagan est précise près de la monnaie et pour les courtes échéances, mais elle peut donner des prix de papillons négatifs aux bas strikes et aux longues échéances, ce qui signifie un arbitrage dans le smile ajusté. Vérifiez les volatilités ajustées en valorisant des papillons, limitez les plages de paramètres (rho strictement entre -1 et 1, nu pas énorme) et réajustez chaque échéance séparément et en douceur dans le temps. Pour des taux bas ou négatifs, utilisez la version normale (Bachelier) de la formule, qui ne s'effondre pas près de zéro.
  • SABR donne à chaque échéance un smile à partir de quatre paramètres : alpha (niveau), beta (épine dorsale), rho (skew) et nu (courbure).
  • Formule de Hagan = préfacteur x z / chi(z) x correction de temps ; à la monnaie elle se réduit à alpha / F^(1-beta) fois la correction, et z / chi(z) tend vers 1 quand z tend vers 0.
  • Un rho négatif incline le smile vers le bas, un nu plus grand relève les ailes ; ajustez chaque échéance séparément, vérifiez l'arbitrage aux ailes, et utilisez la version normale près de taux nuls.

À suivre : la calibration de modèles, ajuster les paramètres d'un modèle aux prix de marché.

Lab : ce qui est noté

  • Ajouter la correction de temps avec sabr_correction25 pts
  • Lire le point à la monnaie avec sabr_atm_vol25 pts
  • Maîtriser le 0 / 0 dans z_over_chi25 pts
  • Tracer le smile avec sabr_implied_vol25 pts
Explorateur · lab-138-1
▾ lab-138-1
…
bash · dans le navigateur
learner@quantcraft:~/lab-138-1$
Python pas encore chargéPythonLn 1, Col 1Spaces: 4UTF-8

Réinitialiser ce sujet ?

Tout le contenu de lab-138-1 revient aux fichiers de départ et le terminal est vidé. Votre solution actuelle sera perdue : cette action est irréversible.

Sera réinitialisé
  • main.py → code de départ
  • Historique du terminal et sortie des tests
  • Modifications non soumises
Sera conservé
  • Meilleur score du lab
  • Votre XP et votre série
  • Progression du cours et notes

Connectez-vous pour exécuter votre code.

Tous les cours sont gratuits à lire. Créez un compte ou connectez-vous pour exécuter du code, lancer les tests et soumettre ce lab.

  • IDE dans le navigateur avec terminal bash — rien à installer
  • Correction instantanée, XP et votre place dans le parcours
Créer un compteSe connecter
OU
Continuer avec GitHub