σμ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 AcademyRutas
Ctrl K
AO
+1,2 k estudiantes
Iniciar sesiónUnirse ↗
Rutas
AO
+1,2 k estudiantes
Iniciar sesión
  • English
  • Français
  • Español
  • العربية
  • Português
  • Deutsch
  • 日本語
  • 中文
Ruta de Python›Módulo 4 · Valoración de renta fija y opciones›Tema 4.4·~50 minIntermedio

Duración y convexidad

Posición en la rutaMódulo 4 de 11 · Tema 4 de 16
4.4 Duración y convexidad
—Puntuación del lab— / 100XP total—Racha—

¿Cuánto dura realmente un bono?

El vencimiento dice cuándo llega el último pago, pero un bono que paga cupones grandes devuelve gran parte de tu dinero antes. La duración de Macaulay es el tiempo medio hasta recibir los flujos, ponderando cada fecha de pago por su parte del precio: sum(t * PV(t)) / precio. Un bono cupón cero tiene una duración igual a su vencimiento; los cupones la reducen. Nuestro bono a 10 años del 5 % con rendimiento del 6 % tiene una duración de 7,9 años. La duración es la longitud real del bono en el tiempo.

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 duración al riesgo de precio

Dividir entre 1 + ytm / freq da la duración modificada, que tiene un significado directo: es la caída porcentual del precio para una subida de una unidad (100 puntos) del rendimiento; una duración modificada de 7,67 significa alrededor de -7,67 % por +1 punto porcentual, en primera aproximación: dP / P ≈ -D_mod * dy. Es la cifra que las mesas de riesgo citan como sensibilidad a tipos del bono. También explica por qué el bono largo del tema anterior cayó mucho más que el corto: su duración es mayor.

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

Convexidad: la curvatura

La relación precio-rendimiento es una curva, no una recta, y la duración es solo su tangente. La tangente subestima el precio para movimientos en ambos sentidos, porque la curva se dobla hacia arriba: un bono gana más cuando los rendimientos bajan de lo que pierde cuando suben la misma cantidad. La convexidad mide esa curvatura, a partir de la segunda derivada: sum(flujo * t * (t + 1/freq) / (1 + y/freq) ** (freq * t + 2)) / precio. Añadir el término 0.5 * convexidad * dy² a la estimación por duración da una previsión del precio mucho mejor, y importa más cuanto mayor es el movimiento.

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 duración es para movimientos pequeñosLa duración supone un movimiento paralelo de un único rendimiento; las curvas reales se retuercen y los grandes movimientos necesitan también la convexidad. Usa la duración para comparar el riesgo de tipos de los bonos y cubrir pequeños cambios. Para escenarios de varios puntos, revalora el bono por completo, que es justo lo que hace bond_price.
  • Duración de Macaulay = sum(t * PV) / precio, el tiempo medio hasta el dinero; la de un cupón cero es su vencimiento.
  • Duración modificada = Macaulay / (1 + ytm / freq): la caída relativa del precio por +1 de rendimiento, dP / P ≈ -D_mod * dy.
  • Estimación del precio = precio * (1 - D_mod * dy + 0.5 * convexidad * dy²); el término de convexidad corrige la tangente, sobre todo en grandes movimientos.

A continuación: las curvas de tipos y la interpolación, porque distintos vencimientos tienen distintos tipos.

Lab: qué se califica

  • Hallar el tiempo medio hasta recibir tu dinero con macaulay_duration25 pts
  • Convertirla en sensibilidad del precio con modified_duration25 pts
  • Capturar la curvatura con convexity25 pts
  • Prever el nuevo precio sin revalorar con price_estimate25 pts
Explorador · lab-69-1
▾ lab-69-1
…
bash · en el navegador
learner@quantcraft:~/lab-69-1$
Python aún no cargadoPythonLn 1, Col 1Spaces: 4UTF-8

¿Restablecer este tema?

Todo lo que hay en lab-69-1 vuelve a los archivos iniciales y se limpia el terminal. Tu solución actual se perderá: no se puede deshacer.

Se restablecerá
  • main.py → código inicial
  • Historial del terminal y salida de pruebas
  • Cambios sin enviar
Se conservará
  • Mejor puntuación del lab
  • Tu XP y tu racha
  • Progreso de la lección y notas

Inicia sesión para ejecutar tu código.

Todas las clases se pueden leer gratis. Crea una cuenta o inicia sesión para ejecutar código, lanzar las pruebas y enviar este lab.

  • IDE en el navegador con terminal bash — sin instalar nada
  • Corrección instantánea, XP y tu lugar en la ruta
Crear una cuentaIniciar sesión
O
Continuar con GitHub