σμ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.3·~45 minIntermedio

Rendimiento al vencimiento

Posición en la rutaMódulo 4 de 11 · Tema 3 de 16
4.3 Rendimiento al vencimiento
—Puntuación del lab— / 100XP total—Racha—

Del precio de vuelta al rendimiento

En el mercado un bono se cotiza por su precio, pero los inversores comparan bonos por el rendimiento. El rendimiento al vencimiento (YTM) es la única tasa de descuento con la que el valor actual de todos los flujos del bono iguala su precio: el rendimiento anualizado que obtienes si compras ahora, mantienes hasta el vencimiento y se hacen todos los pagos. Para un bono a 10 años con precio 925,61 y cupón del 5 %, es el 6 %. A diferencia del precio, el YTM no tiene fórmula cerrada, porque la incógnita está dentro de un polinomio de grado alto.

import numpy as np

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

price = bond_price(1000, 0.05, 0.06, 10)
print(round(price, 4))                                       # 925.6126   the market price we pretend to observe

# A back-of-the-envelope yield: annual coupon plus the yearly share of the discount, over the average of price and par
coupon = 1000 * 0.05
print(round((coupon + (1000 - price) / 10) / ((1000 + price) / 2), 5))     # 0.05966   close to 6%, but not exact

Buscar: bisección

El precio cae de forma continua al subir el rendimiento, así que se puede buscar. Toma un intervalo [low, high] que seguro contenga la respuesta (0 % a 100 %). Valora el bono en el punto medio: si el precio está por encima del objetivo, el rendimiento debe ser mayor, así que sube low al punto medio; si no, baja high. Cada paso divide el intervalo por dos; 40 pasos lo reducen un billón de veces. La bisección es lenta comparada con otros métodos, pero no puede fallar mientras la respuesta esté dentro del intervalo, lo que la hace el recurso seguro.

low, high = 0.0, 1.0
for step in range(6):
    mid = (low + high) / 2
    price_mid = bond_price(1000, 0.05, mid, 10)
    print(step, round(mid, 5), round(price_mid, 2))
    if price_mid > price:      # priced too high: the yield must be higher
        low = mid
    else:
        high = mid
# 0 0.5 110.38
# 1 0.25 275.86
# 2 0.125 578.47
# 3 0.0625 908.08
# 4 0.03125 1159.97
# 5 0.04688 1024.72      the interval keeps shrinking around 6% (the target price is 925.61)

Buscar más rápido: Newton

El método de Newton usa la pendiente. Define f(y) = bond_price(y) - objetivo; queremos f(y) = 0. En la estimación actual, sigue la tangente hasta cero: y_new = y - f(y) / f'(y). La pendiente se estima numéricamente con un paso minúsculo h: (f(y + h) - f(y - h)) / (2h). Cerca de la respuesta el número de dígitos correctos se duplica aproximadamente en cada paso, así que bastan cuatro o cinco pasos donde la bisección necesita cuarenta. Newton puede fallar si se empieza mal o si la pendiente es plana, así que mantén un límite de pasos y recurre a la bisección si no converge.

y, h = 0.05, 1e-6                            # start at the coupon rate
for step in range(5):
    f = bond_price(1000, 0.05, y) - price
    slope = (bond_price(1000, 0.05, y + h) - bond_price(1000, 0.05, y - h)) / (2 * h)
    print(step, round(y, 8), round(f, 6))
    y = y - f / slope
# 0 0.05 74.387374
# 1 0.05954347 3.245932
# 2 0.05999903 0.006916
# 3 0.06 0.0
# 4 0.06 0.0        converged to 6% after 3 steps
# Check the answer by pricing the bond at the yield we found
print(round(bond_price(1000, 0.05, y, 10), 4), round(price, 4))      # 925.6126 925.6126   the same price: the yield is right
Los rendimientos se comparan, los precios noUn rendimiento al vencimiento supone que puedes reinvertir cada cupón al mismo rendimiento y que el emisor paga por completo: es una promesa, no una previsión. Un bono que cotiza a un rendimiento muy alto suele ser uno del que el mercado duda que se reembolse. Compara rendimientos solo entre bonos de riesgo y vencimiento similares.
  • El YTM es la tasa de descuento que iguala el valor actual del bono con su precio; no tiene fórmula cerrada, así que se busca.
  • Bisección: sigue partiendo [low, high] (precio sobre el objetivo: sube low); lenta pero segura.
  • Newton: y = y - f / slope, con pendiente numérica; converge en pocos pasos pero necesita un límite de pasos y un buen inicio.

A continuación: la duración y la convexidad, medir cuán sensible es el precio de un bono al rendimiento.

Lab: qué se califica

  • Estimar el rendimiento a ojo con approx_ytm25 pts
  • Hallar el rendimiento partiendo el intervalo con bisect_yield25 pts
  • Hallar el rendimiento más rápido con newton_yield25 pts
  • Nombrar la situación del bono con classify_price25 pts
Explorador · lab-68-1
▾ lab-68-1
…
bash · en el navegador
learner@quantcraft:~/lab-68-1$
Python aún no cargadoPythonLn 1, Col 1Spaces: 4UTF-8

¿Restablecer este tema?

Todo lo que hay en lab-68-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