Estoy intentando fijar el precio de una opción de compra sobre un cupón cero según el modelo Vasicek utilizando el método de Monte Carlo:
$$C_0 = B(0,\theta) \ \mathbb{E}^{\mathbb{Q}_T}[(B(\theta,T)-K)^{+}]$$
El problema es que el código que he escrito para esto está dando un precio demasiado diferente de la respuesta esperada que es 0,095 basado en las fórmulas cerradas.
¿Qué puedo estar haciendo mal?
Los supuestos subyacentes y las ecuaciones que estoy utilizando:
Sea $(, (\mathcal{F}_t)_t, \mathbb{Q})$ tal que $\mathbb{Q}$ es la probabilidad neutral al riesgo.
Modelo Vasicek: $dr_t = a(b - r_t ) dt + \sigma dW_t^{\mathbb{Q}}$
Precio del bono cupón cero: $B(T,S) = \tau(T,S) \ exp(-\eta(T,S)\ r_t)$
Desde $r_t$ es gaussiano bajo $\mathbb{Q}_t$ (medida de avance): $$r(t) \sim \mathcal{N}(r_0e^{-at} + b(1-e^{-at}) + \frac{\sigma(1 - e^{-at})}{a^2} - \frac{\sigma(1 - e^{-2at})}{2a^2} \ , \ \sigma^{2} \frac{1 - e^{-2at}}{2a}) $$
Y mi código basado en lo anterior: (uno puede simplemente copiar y pegar y luego ejecutar el código de abajo asumiendo que las librerías externas de Python requeridas ya están instaladas).
import numpy as np
import pylab as plt
from random import gauss
from math import exp, sqrt, log
from scipy.stats import norm
a = 0.2
b = 0.1
sigma = 0.02
r = 0.1
t = 0
theta = 0.5
T = 1
K = 0.9
#Distribution of rt
r_0 = r
m_rt = r * exp(-a*theta) + b * (1 - exp(-a*theta)) + sigma * ((1 - exp(-a*theta)) / a**2 ) - sigma * ((1 - exp(-2*a*theta))/2*(a**2))
v_rt = (sigma**2) * (1 - exp(2*a*theta))/ 2*a
eta = (1 - exp(-a*(T-theta)))/a
tau = np.exp( (b - (sigma**2)/(2*(a**2))) * (eta - T + theta) - (0.25 * (sigma**2) * (eta**2) / a) )
def VasicekZCPrice(t,T,a,b,sigma,r):
B = ( 1- exp( -a*(T-t) ) )/ a
A = exp( ( (b-(0.5*sigma**2)) / a**2 )*( B - T + t ) - ( 0.25*sigma**2 / a ) * B**2)
ZC = A*exp(-B*r)
return ZC
def monte_carlo_call(theta, T, a, b, sigma, r, K, nbSimul = 10000, steps = 100):
dt = (T-theta)/steps
r__T = r * np.exp(-a*dt) + b* (1-np.exp(-a*dt)) + (sigma*(1-exp(-a*dt))/a**2) - sigma * ((1-np.exp(-2*a*dt))/2*a**2) + sigma*np.sqrt((1-np.exp(-2*a*dt))/2*a) * np.random.normal(size=(steps,nbSimul))
B__T = tau * np.exp(-eta*r__T)
payoffs = np.maximum( B__T - K, 0 )
option_price = VasicekZCPrice(t, T,a,b,sigma,r) * np.mean(payoffs)
return option_price
monte_carlo_call(theta, T, a, b, sigma, r,K , nbSimul = 10000, steps = 100)
que me da:
0.03686737433679907
Se puede acceder a una versión ampliada del código y a más explicaciones a través de ce lien en Google Colab.
¡Muchas gracias!