σμ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.8·~55 minIntermedio

La fórmula de Black–Scholes

Posición en la rutaMódulo 4 de 11 · Tema 8 de 16
4.8 La fórmula de Black–Scholes
—Puntuación del lab— / 100XP total—Racha—

Una fórmula para una opción

En 1973 Black y Scholes mostraron que, si una acción sigue el modelo lognormal con volatilidad constante, una opción se puede replicar negociando la acción y un bono, de modo que su precio no depende de lo probable que los inversores crean una subida. El precio de un call europeo es S * N(d1) - K * exp(-rT) * N(d2): la acción que recibes si la opción acaba en el dinero, ponderada por un número tipo probabilidad, menos el strike descontado que pagas, ponderado por la probabilidad neutral al riesgo N(d2) de ejercer. El put se deduce de la paridad.

d1 = (ln(S/K) + (r + sigma^2/2) T) / (sigma sqrt(T)) d2 = d1 - sigma sqrt(T) C = S N(d1) - K e^(-rT) N(d2)
import math

def norm_cdf(x):
    return 0.5 * (1 + math.erf(x / math.sqrt(2)))      # N(x): the probability that a standard normal is below x

print(round(norm_cdf(0.0), 4), round(norm_cdf(1.96), 4))      # 0.5 0.975

def d1_d2(spot, strike, rate, sigma, t):
    d1 = (math.log(spot / strike) + (rate + 0.5 * sigma ** 2) * t) / (sigma * math.sqrt(t))
    return d1, d1 - sigma * math.sqrt(t)

d1, d2 = d1_d2(100, 100, 0.05, 0.2, 1)
print(round(d1, 4), round(d2, 4))                               # 0.35 0.15

El call y el put

N es la función de distribución normal estándar, que math.erf de Python da como 0.5 * (1 + erf(x / sqrt(2))). d1 y d2 combinan la posición ln(S/K), la deriva y la volatilidad durante la vida de la opción. Con ellos: call = S * N(d1) - K * exp(-rT) * N(d2) y put = K * exp(-rT) * N(-d2) - S * N(-d1). Para spot 100, strike 100, tipo del 5 %, volatilidad del 20 % y un año, el call cuesta 10,45 y el put 5,57, y la diferencia 4,88 es exactamente el valor de paridad S - K * exp(-rT).

def bs_call(spot, strike, rate, sigma, t):
    d1, d2 = d1_d2(spot, strike, rate, sigma, t)
    return spot * norm_cdf(d1) - strike * math.exp(-rate * t) * norm_cdf(d2)

def bs_put(spot, strike, rate, sigma, t):
    d1, d2 = d1_d2(spot, strike, rate, sigma, t)
    return strike * math.exp(-rate * t) * norm_cdf(-d2) - spot * norm_cdf(-d1)

call, put = bs_call(100, 100, 0.05, 0.2, 1), bs_put(100, 100, 0.05, 0.2, 1)
print(round(call, 4), round(put, 4))                            # 10.4506 5.5735
print(round(call - put, 4), round(100 - 100 * math.exp(-0.05), 4))   # 4.8771 4.8771   put-call parity holds

Qué mueve el precio

Cinco parámetros determinan el precio. Un strike mayor abarata el call (80: 24,59; 100: 10,45; 120: 3,25). Una volatilidad mayor encarece ambas opciones, ya que más incertidumbre solo añade alza para el titular (10 %: 6,81; 20 %: 10,45; 40 %: 18,02). Un plazo mayor hasta el vencimiento también sube el precio (3 meses: 4,62; 1 año: 10,45; 4 años: 25,21). Observa que el rendimiento esperado de la acción no aparece en absoluto en la fórmula: solo hay que estimar la volatilidad, por eso los precios de opciones cotizados se expresan a menudo como una volatilidad.

for strike in (80, 100, 120):
    print("strike", strike, round(bs_call(100, strike, 0.05, 0.2, 1), 4))      # 24.5888, 10.4506, 3.2475
for sigma in (0.1, 0.2, 0.4):
    print("sigma", sigma, round(bs_call(100, 100, 0.05, sigma, 1), 4))         # 6.805, 10.4506, 18.023
for t in (0.25, 1, 4):
    print("t", t, round(bs_call(100, 100, 0.05, 0.2, t), 4))                   # 4.615, 10.4506, 25.2133
# Time value: the call is worth more than its intrinsic value (what it would pay if it expired today)
intrinsic = max(100 - 100 * math.exp(-0.05), 0)
print(round(intrinsic, 4), round(bs_call(100, 100, 0.05, 0.2, 1) - intrinsic, 4))     # 4.8771 5.5735   intrinsic value and time value
Un modelo, con supuestosBlack–Scholes supone volatilidad constante, precios lognormales sin saltos, sin dividendos, ejercicio europeo y negociación sin fricciones. Los mercados reales muestran una volatilidad que cambia con el strike y la fecha (la sonrisa de volatilidad), saltos y colas gruesas. La fórmula sigue siendo el lenguaje común del mercado, por eso los precios se cotizan como volatilidad implícita, tema de un próximo tema.
  • N(x) = 0.5 * (1 + erf(x / sqrt(2))), y d1 = (ln(S/K) + (r + sigma²/2) T) / (sigma sqrt(T)), d2 = d1 - sigma sqrt(T).
  • Call = S N(d1) - K e^(-rT) N(d2); put = K e^(-rT) N(-d2) - S N(-d1); su diferencia es el valor de paridad S - K e^(-rT).
  • Los precios suben con la volatilidad y el plazo y bajan con el strike del call; el rendimiento esperado de la acción no está, solo hace falta la volatilidad.

A continuación: la delta, cuánto se mueve el precio de la opción cuando la acción se mueve un dólar.

Lab: qué se califica

  • Construir la probabilidad acumulada de la campana con norm_cdf25 pts
  • Calcular las dos cantidades de Black–Scholes con d1_d225 pts
  • Valorar un call con bs_call25 pts
  • Valorar un put con bs_put25 pts
Explorador · lab-73-1
▾ lab-73-1
…
bash · en el navegador
learner@quantcraft:~/lab-73-1$
Python aún no cargadoPythonLn 1, Col 1Spaces: 4UTF-8

¿Restablecer este tema?

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