Parece que tu enfoque para calcular la IV está generalmente en el camino correcto. Sin embargo, para garantizar precisión y abordar cualquier discrepancia en la "sonrisa de volatilidad implícita" que estás observando, te sugeriría refinar la metodología en dos áreas:
1. Integración para el Cálculo del Precio de la Llamada: El método que has descrito para calcular el precio de la llamada utilizando una función de densidad de probabilidad (PDF) (f(S)) parece sumar manualmente valores discretos. Para un cálculo más preciso, especialmente si (S) no está densamente muestreado, te sugeriría integrar sobre un rango continuo de (S) utilizando bibliotecas como scipy
:
import numpy as np
import scipy.stats as ss
import scipy.integrate as integrate
def f(S, pis, mus, sigmas):
"""Función de densidad de probabilidad para una mezcla de normales."""
result = 0
for pi, mu, sigma in zip(pis, mus, sigmas):
result += pi / (np.sqrt(2 * np.pi) * sigma) * np.exp(-((S - mu)**2) / (2 * sigma**2))
return result
def call_price(r, T, K, pis, mus, sigmas):
"""Calcular el precio de la llamada utilizando integración numérica."""
f_integrated = lambda S: np.exp(-r * T) * (S - K) * f(S, pis, mus, sigmas)
price, _ = integrate.quad(f_integrated, K, np.inf)
return price
# Parámetros de ejemplo para f(S)
pis = [0.5, 0.5] # Pesos
mus = [-0.05, 0.05] # Medias
sigmas = [0.02, 0.02] # Desviaciones estándar
# Ejemplo de cálculo de precio de llamada
r = 0.00 # Tasa libre de riesgo
T = 1/52 # Tiempo hasta vencimiento en años
K = 100 # Precio de ejercicio
# Ajusta pis, mus, sigmas según tus especificaciones
precio_ejemplo = call_price(r, T, K, pis, mus, sigmas)
print(f"Ejemplo de precio de la llamada: {precio_ejemplo}")
2. Cálculo de la Volatilidad Implícita: Tu enfoque iterativo para encontrar la IV utilizando el método de Newton-Raphson parece apropiado. La suposición inicial y el límite de iteraciones me parecen razonables, pero refinaría el cálculo del precio de la opción (price
) y la vega (vega
) están calculando con precisión el precio y la vega de Black-Scholes, respectivamente (ver Haug y Hull para explicaciones detalladas). La clave es asegurarse de que el cálculo del precio de la llamada (call_price
) coincida con los precios de mercado o teóricos que estás utilizando para inferir la IV:
import numpy as np
import scipy.stats as ss
def black_scholes_price(S, K, T, r, sigma):
"""Calcular el precio de la opción de Black-Scholes."""
d1 = (np.log(S / K) + (r + 0.5 * sigma ** 2) * T) / (sigma * np.sqrt(T))
d2 = d1 - sigma * np.sqrt(T)
precio_llamada = S * ss.norm.cdf(d1, 0.0, 1.0) - K * np.exp(-r * T) * ss.norm.cdf(d2, 0.0, 1.0)
return precio_llamada
def black_scholes_vega(S, K, T, r, sigma):
"""Calcular la Vega de Black-Scholes, la derivada del precio con respecto a la volatilidad."""
d1 = (np.log(S / K) + (r + 0.5 * sigma ** 2) * T) / (sigma * np.sqrt(T))
vega = S * ss.norm.pdf(d1) * np.sqrt(T)
return vega
def find_implied_volatility(target_price, S, K, T, r):
"""Encontrar la volatilidad implícita dada un precio objetivo de la opción."""
MAX_ITERATIONS = 200
PRECISION = 1.0e-5
sigma_guess = 0.5
for _ in range(MAX_ITERATIONS):
price = black_scholes_price(S, K, T, r, sigma_guess)
vega = black_scholes_vega(S, K, T, r, sigma_guess)
price_diff = target_price - price
if abs(price_diff) < PRECISION:
return sigma_guess
sigma_guess += price_diff / vega
# Evitar volatilidad negativa
if sigma_guess < 0:
sigma_guess = PRECISION
return sigma_guess
# Uso de ejemplo:
S = 100 # Precio del activo subyacente
K = 100 # Precio de ejercicio
T = 1/52 # Tiempo hasta vencimiento en años (1 semana)
r = 0.00 # Tasa de interés libre de riesgo
precio_objetivo = 2.5 # Precio objetivo de la llamada de mercado o modelo
volatilidad_implícita = find_implied_volatility(precio_objetivo, S, K, T, r)
print(f"Volatilidad implícita: {volatilidad_implícita}")
Referencias
Haug, E. G. (2007). The Complete Guide to Option Pricing Formulas (2a ed.). McGraw-Hill Education.
Hull, J. C. (2017). Options, Futures, and Other Derivatives (10a ed.). Pearson.