σμ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 4 · Valorisation des produits de taux et d'options›Sujet 4.4·~50 minIntermédiaire

Duration et convexité

Position dans le parcoursModule 4 sur 11 · Sujet 4 sur 16
4.4 Duration et convexité
—Score du lab— / 100XP total—Série—

Quelle est la vraie longueur d'une obligation ?

L'échéance dit quand arrive le dernier paiement, mais une obligation qui verse de gros coupons restitue une grande part de votre argent plus tôt. La duration de Macaulay est le délai moyen pour recevoir les flux, chaque date de paiement étant pondérée par sa part du prix : sum(t * PV(t)) / prix. Une obligation zéro-coupon a une duration égale à son échéance ; les coupons la réduisent. Notre obligation à 10 ans, 5 %, à 6 % de rendement, a une duration de 7,9 ans. La duration est la vraie longueur de l'obligation dans le temps.

import numpy as np

def bond_cashflows(face, coupon_rate, years, freq):
    n = int(round(years * freq))
    times = np.arange(1, n + 1) / freq
    flows = np.full(n, face * coupon_rate / freq)
    flows[-1] += face
    return times, flows

times, flows = bond_cashflows(1000, 0.05, 10, 2)
pv = flows / (1 + 0.06 / 2) ** (2 * times)           # present value of each payment
price = pv.sum()
macaulay = (times * pv).sum() / price                # the average time, weighted by present value
print(round(price, 4), round(macaulay, 4))           # 925.6126 7.895   shorter than the 10-year maturity

De la duration au risque de prix

Diviser par 1 + ytm / freq donne la duration modifiée, qui a un sens direct : c'est la baisse en pourcentage du prix pour une hausse d'une unité (100 points) du rendement ; une duration modifiée de 7,67 signifie environ -7,67 % pour +1 point de pourcentage, en première approximation : dP / P ≈ -D_mod * dy. C'est le chiffre que les salles de risque citent comme la sensibilité de taux de l'obligation. Il explique aussi pourquoi l'obligation longue du sujet précédent a tant plus baissé que la courte : sa duration est plus élevée.

modified = macaulay / (1 + 0.06 / 2)
print(round(modified, 4))                       # 7.6654   about -7.67% of price for +1 percentage point of yield

dy = 0.01
print(round(price * (1 - modified * dy), 2))    # 854.66   the first-order estimate after a rise to 7%
# the exact price at 7% is 857.88: duration alone underestimates it

Convexité : la courbure

La relation prix-rendement est une courbe, pas une droite, et la duration n'en est que la tangente. La tangente sous-estime le prix pour un mouvement dans les deux sens, car la courbe se redresse : une obligation gagne plus quand les rendements baissent qu'elle ne perd quand ils montent du même montant. La convexité mesure cette courbure, à partir de la dérivée seconde : sum(flux * t * (t + 1/freq) / (1 + y/freq) ** (freq * t + 2)) / prix. Ajouter le terme 0.5 * convexité * dy² à l'estimation par la duration donne une bien meilleure prévision du prix, et cela compte d'autant plus que le mouvement est grand.

convexity = (flows * times * (times + 1 / 2) / (1 + 0.06 / 2) ** (2 * times + 2)).sum() / price
print(round(convexity, 3))                                   # 71.785

for dy in (0.01, -0.01, 0.03):
    exact = bond_price(1000, 0.05, 0.06 + dy, 10)
    duration_only = price * (1 - modified * dy)
    with_convexity = price * (1 - modified * dy + 0.5 * convexity * dy ** 2)
    print(dy, round(exact, 2), round(duration_only, 2), round(with_convexity, 2))
# 0.01 857.88 854.66 857.99
# -0.01 1000.0 996.56 999.88
# 0.03 739.84 712.77 742.67      for a big move convexity matters most
# Duration by maturity for a 5% bond at a 6% yield: it grows with maturity, but slower than one for one
for years in (1, 5, 10, 30):
    t_, f_ = bond_cashflows(1000, 0.05, years, 2)
    p_ = f_ / (1 + 0.06 / 2) ** (2 * t_)
    print(years, round((t_ * p_).sum() / p_.sum(), 3))
# 1 0.988
# 5 4.472
# 10 7.895
# 30 14.77
La duration est pour les petits mouvementsLa duration suppose un déplacement parallèle d'un rendement unique ; les courbes réelles se tordent et les grands mouvements demandent aussi la convexité. Utilisez la duration pour comparer le risque de taux des obligations et couvrir de petites variations. Pour des scénarios de plusieurs points, revalorisez complètement l'obligation, ce que fait précisément bond_price.
  • Duration de Macaulay = sum(t * PV) / prix, le délai moyen pour l'argent ; la duration d'un zéro-coupon est son échéance.
  • Duration modifiée = Macaulay / (1 + ytm / freq) : la baisse relative du prix pour +1 de rendement, dP / P ≈ -D_mod * dy.
  • Estimation du prix = prix * (1 - D_mod * dy + 0.5 * convexité * dy²) ; le terme de convexité corrige la tangente, surtout pour les grands mouvements.

À suivre : les courbes de taux et l'interpolation, car des échéances différentes ont des taux différents.

Lab : ce qui est noté

  • Trouver le délai moyen pour récupérer son argent avec macaulay_duration25 pts
  • En faire une sensibilité du prix avec modified_duration25 pts
  • Capturer la courbure avec convexity25 pts
  • Prévoir le nouveau prix sans revaloriser avec price_estimate25 pts
Explorateur · lab-69-1
▾ lab-69-1
…
bash · dans le navigateur
learner@quantcraft:~/lab-69-1$
Python pas encore chargéPythonLn 1, Col 1Spaces: 4UTF-8

Réinitialiser ce sujet ?

Tout le contenu de lab-69-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