Etapa 2 de 4 · Fundamentos en Python
El modelo de Black-Scholes explicado desde la intuición (con Python)
Entiende el modelo de Black-Scholes sin perderte en las ecuaciones: la idea de la cobertura, la fórmula de una call y una put, las griegas, la volatilidad implícita y su implementación en Python.
En este artículo
La fórmula de Black-Scholes es probablemente la ecuación más famosa de las finanzas. Le valió el Nobel de Economía de 1997 a Scholes y Merton (Black había fallecido dos años antes) y cambió para siempre los mercados de derivados. Pero lo realmente brillante no es la fórmula, sino la idea que hay detrás, y esa se puede entender sin cálculo estocástico.
En este artículo vamos de la intuición a la fórmula, y de la fórmula al código: precio de calls y puts, las griegas y la volatilidad implícita, todo en Python.
Qué es una opción, en dos minutos
- Una call te da el derecho (no la obligación) a comprar una acción a un precio fijo \( K \), el strike, en una fecha \( T \). Al vencimiento paga \( \max(S_T - K, 0) \).
- Una put te da el derecho a vender a \( K \). Paga \( \max(K - S_T, 0) \).
Por ese derecho se paga una prima hoy. La pregunta que resuelve Black-Scholes es: ¿cuál es la prima justa?
La idea clave: cubrir el riesgo
Antes de 1973, la respuesta intuitiva era «depende de lo que creas que va a subir la acción». Black, Scholes y Merton demostraron algo sorprendente: no depende.
El argumento es este. Si vendes una call, pierdes dinero si la acción sube. Pero puedes protegerte comprando una cierta cantidad de acciones, \( \Delta \). Si ajustas esa cantidad continuamente a medida que el precio se mueve, la combinación «opción vendida + \( \Delta \) acciones» deja de tener riesgo: lo que pierdes por un lado lo ganas por el otro.
Y una cartera sin riesgo solo puede rendir el tipo de interés sin riesgo \( r \); si rindiera más, habría una oportunidad de ganar dinero sin riesgo (un arbitraje) que el mercado eliminaría enseguida. Esa condición basta para fijar el precio de la opción, y en ella no aparece la rentabilidad esperada \( \mu \) de la acción.
La consecuencia práctica: para valorar una opción podemos hacer como si todos los activos rindieran \( r \). Es el mundo neutral al riesgo, y es exactamente lo que usamos en el artículo de Monte Carlo al sustituir \( \mu \) por \( r \).
La fórmula de Black-Scholes
Con los supuestos del modelo (precio con movimiento browniano geométrico, volatilidad y tipos constantes, sin costes de transacción y cobertura continua), el precio de una call europea es:
\[ C = S_0\,N(d_1) - K e^{-rT} N(d_2) \]
y el de una put:
\[ P = K e^{-rT} N(-d_2) - S_0\,N(-d_1) \]
con
\[ d_1 = \frac{\ln(S_0/K) + \left(r + \tfrac12\sigma^2\right)T}{\sigma\sqrt{T}}, \qquad d_2 = d_1 - \sigma\sqrt{T} \]
donde \( N(\cdot) \) es la función de distribución de la normal estándar. Cómo leerla:
- \( N(d_2) \) es la probabilidad (en el mundo neutral al riesgo) de que la call acabe ejerciéndose, es decir, \( S_T > K \).
- \( K e^{-rT} N(d_2) \) es lo que esperas pagar por el strike, traído a hoy.
- \( S_0 N(d_1) \) es el valor actual de la acción que esperas recibir si se ejerce.
Una call vale, por tanto, «lo que recibes menos lo que pagas», ponderado por probabilidades y descontado.
Calculadora de Black-Scholes interactiva
Precio de la call hoy Pago al vencimiento
Black-Scholes en Python
import numpy as np
from scipy.stats import norm
def black_scholes(S, K, T, r, sigma, tipo="call"):
d1 = (np.log(S / K) + (r + 0.5 * sigma**2) * T) / (sigma * np.sqrt(T))
d2 = d1 - sigma * np.sqrt(T)
if tipo == "call":
return S * norm.cdf(d1) - K * np.exp(-r * T) * norm.cdf(d2)
return K * np.exp(-r * T) * norm.cdf(-d2) - S * norm.cdf(-d1)
call = black_scholes(100, 105, 1, 0.03, 0.25, "call")
put = black_scholes(100, 105, 1, 0.03, 0.25, "put")
print(f"Call: {call:.4f} € Put: {put:.4f} €")La call sale en torno a 9,1 €. Si leíste el artículo anterior, compárala con el resultado de Monte Carlo: coinciden dentro del margen de error de la simulación. Dos métodos completamente distintos, el mismo número.
Comprobación: la paridad put-call
Existe una relación entre call y put que no depende de ningún modelo, solo de que no haya arbitraje:
\[ C - P = S_0 - K e^{-rT} \]
print(f"C - P = {call - put:.6f}")
print(f"S0 - K e^(-rT) = {100 - 105 * np.exp(-0.03):.6f}")Es un buen test para cualquier implementación: si no se cumple, hay un error.
Las griegas: la sensibilidad de la opción
A quien gestiona opciones le importa tanto el precio como cómo cambia ese precio cuando se mueve algo. Esas sensibilidades son derivadas parciales y se llaman griegas:
| Griega | Mide la sensibilidad a… | Call |
|---|---|---|
| Delta \( \Delta \) | el precio de la acción | \( N(d_1) \) |
| Gamma \( \Gamma \) | cómo cambia la delta | \( \dfrac{N'(d_1)}{S\sigma\sqrt{T}} \) |
| Vega | la volatilidad | \( S\,N'(d_1)\sqrt{T} \) |
| Theta \( \Theta \) | el paso del tiempo | \( -\dfrac{S N'(d_1)\sigma}{2\sqrt{T}} - rKe^{-rT}N(d_2) \) |
| Rho \( \rho \) | el tipo de interés | \( K T e^{-rT} N(d_2) \) |
\( N'(x) \) es la densidad de la normal. La delta es precisamente la cantidad de acciones que hay que tener para cubrir la opción: la misma \( \Delta \) del argumento de cobertura.
def griegas_call(S, K, T, r, sigma):
d1 = (np.log(S / K) + (r + 0.5 * sigma**2) * T) / (sigma * np.sqrt(T))
d2 = d1 - sigma * np.sqrt(T)
return {
"delta": norm.cdf(d1),
"gamma": norm.pdf(d1) / (S * sigma * np.sqrt(T)),
"vega": S * norm.pdf(d1) * np.sqrt(T) / 100, # por 1 punto de vol
"theta": (-S * norm.pdf(d1) * sigma / (2 * np.sqrt(T))
- r * K * np.exp(-r * T) * norm.cdf(d2)) / 365, # por día
"rho": K * T * np.exp(-r * T) * norm.cdf(d2) / 100, # por 1 punto de tipo
}
for nombre, valor in griegas_call(100, 105, 1, 0.03, 0.25).items():
print(f"{nombre:>6}: {valor: .4f}")Una forma rápida de comprobar las fórmulas es con diferencias finitas: mover un poco el precio y ver cuánto cambia la opción.
h = 0.01
delta_num = (black_scholes(100 + h, 105, 1, 0.03, 0.25)
- black_scholes(100 - h, 105, 1, 0.03, 0.25)) / (2 * h)
print(f"Delta analítica: {griegas_call(100, 105, 1, 0.03, 0.25)['delta']:.6f}")
print(f"Delta numérica: {delta_num:.6f}")Cómo se interpretan
- Delta 0,52: si la acción sube 1 €, la call sube unos 0,52 €. También se lee, de forma aproximada, como la probabilidad de acabar dentro del dinero.
- Gamma alta: la delta cambia deprisa y hay que reajustar la cobertura a menudo. Es máxima cerca del strike y del vencimiento.
- Vega positiva: más volatilidad, opción más cara. Tener una opción es, en el fondo, estar «largo» de volatilidad.
- Theta negativa: cada día que pasa la opción pierde valor si nada más cambia.
Volatilidad implícita
De los cinco datos de la fórmula, cuatro se observan directamente: precio, strike, plazo y tipo de interés. La volatilidad, no. Por eso en los mercados se hace al revés: se toma el precio de mercado de la opción y se busca qué \( \sigma \) lo reproduce. Esa es la volatilidad implícita.
Como la fórmula no se puede despejar para \( \sigma \), se resuelve numéricamente. Al ser el precio creciente en \( \sigma \), un método de búsqueda de raíces como Brent funciona muy bien:
from scipy.optimize import brentq
def vol_implicita(precio_mercado, S, K, T, r, tipo="call"):
f = lambda s: black_scholes(S, K, T, r, s, tipo) - precio_mercado
return brentq(f, 1e-6, 5.0)
iv = vol_implicita(10.50, S=100, K=105, T=1, r=0.03)
print(f"Volatilidad implícita: {iv:.2%}")Los traders cotizan las opciones directamente en volatilidad implícita: dicen «esta opción está a 28 de vol» en lugar de dar un precio. Y el índice VIX, el famoso «índice del miedo», es en esencia una volatilidad implícita del S&P 500 a 30 días.
Las limitaciones del modelo
Black-Scholes se sigue usando en todas partes, pero todo quant conoce sus supuestos y dónde fallan:
- Volatilidad constante. Si el modelo fuera cierto, todas las opciones sobre una acción tendrían la misma volatilidad implícita. En la realidad varía con el strike: es la sonrisa (o skew) de volatilidad. Las puts muy fuera del dinero cotizan más caras porque el mercado teme las caídas bruscas.
- Rentabilidades normales. Los mercados tienen colas mucho más gruesas: los movimientos extremos son más frecuentes de lo que predice la normal.
- Cobertura continua y sin costes. En la práctica se reajusta a intervalos y cada operación cuesta dinero.
Por eso existen modelos más ricos: volatilidad local, volatilidad estocástica (Heston), saltos… Pero todos se construyen sobre la misma idea de cobertura y neutralidad al riesgo. Entender bien Black-Scholes es la base para todos ellos.
Resumen
- Una opción se puede cubrir con la acción; la cartera cubierta no tiene riesgo y rinde \( r \).
- Por eso el precio no depende de \( \mu \) y se calcula en el mundo neutral al riesgo.
- Las griegas miden las sensibilidades; la delta es la cantidad de acciones de la cobertura.
- La volatilidad implícita es la \( \sigma \) que reproduce el precio de mercado.
Hasta ahora hemos valorado productos. En el siguiente artículo pasamos al otro gran problema del quant: medir cuánto puede perder una cartera con el Value at Risk.