He simulado algunos datos según un proceso de Vasicek y luego estoy intentando aplicar un análisis de regresión por mínimos cuadrados ordinarios (MCO) para ver la exactitud de los parámetros del modelo estimado a partir de la estimación. Sin embargo, mis parámetros estimados del modelo no parecen ni siquiera acercarse a lo que deberían ser. He intentado dejar que T sea muy grande, e incluso he simulado 100.000 trayectorias y he estimado el modelo para cada trayectoria, y luego he promediado las estimaciones. Sin embargo, los resultados siguen siendo erróneos. Así que o bien estoy simulando mis datos mal, o la regresión que estoy haciendo es de alguna manera incorrecta. He adjuntado mi código python a continuación, así que si alguien puede echar un vistazo y decirme por qué los parámetros de mi modelo están mal, se lo agradecería mucho.
La forma del modelo que estoy utilizando es:
$$ dr_t = (a - b r_t) dt + \sigma dW.$$
Para estimar los parámetros de mi modelo estoy ajustando una regresión sobre los datos discretos que me da el siguiente modelo:
$$ r_{t+1} - r_{t} = (a - b r_t) \Delta t + \sigma Z_t$$
donde $ Z_t \sim N(0,\Delta t)$ (es decir, media 0, varianza $\Delta t$ ). A partir de esta configuración sé que mi intercepción estimada será $ a\Delta t$ y mi pendiente estimada será $-1 * b \Delta t$ . Por lo tanto, en mi función fit_vasicek_model, hago la transformación necesaria para recuperar "a" y "b".
Aquí está mi código ( he omitido algunas partes que son irrelevantes para esta pregunta )
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import random
import statsmodels.formula.api as smf
import statsmodels.api as sm
import statsmodels.tools as sm_tools
class InterestRateModels:
def __init__(self, nsim, T, Vas = None):
self.N = nsim
self.T = T
self.dt = 1/T
self.Vas = Vas
def sim_vasicek(self, r0, a, b, sigma):
"""
Inputs:
-------
N = number of paths to simulate
T = number of time steps to take
r0 = initial (current) short-term rate
a, b, sigma = parameters of the model
The Model:
----------
dr_t = (a b*r_t)*dt + * dBt
r_t = short rate
a = long-run average rate, a in Real Numbers
b = speed of reversion, b > 0
sigma = volatility of short rate
Bt = Gaussian (0 mean, 1 sigma) process
Returns:
--------
Creates an object attribute that is a matrix of simulated short rate paths.
"""
dt = 1.0/self.T
X = np.random.normal(0,np.sqrt(dt),size=(self.N,self.T))
self.Vas = np.zeros((self.N,self.T)); self.Vas[:,0] = r0;
for i in range(self.N):
for j in range(1,self.T):
self.Vas[i,j] = self.Vas[i,j-1] + (a-b*self.Vas[i,j-1]) * dt + sigma * X[i,j]
return
def plot_vasicek(self):
for i in range(self.N):
plt.plot(self.Vas[i,:])
return
def fit_vasicek_model(self, rate_path):
"""
Inputs:
-------
rate_path is a single interest rate path.
Returns:
--------
Parameters of the model (not the regression paraneters, as they get transformed)
Intercept = a * dt
Slope = -1 * b * dt (The slope needs to be multiplied by negative 1)
"""
n = len(rate_path)
X = rate_path[:n-1]
y = np.diff(rate_path)
X = sm_tools.tools.add_constant(X)
model = sm.OLS(y,X)
results = model.fit()
a, b1 = results.params / self.dt
b = -1 * b1
return a, b
Así que ahora, cuando creo una instancia y simulo un montón de trayectorias, y luego ajusto el modelo, tengo parámetros para a y b que ni siquiera se acercan a su valor real. Aquí está mi conjetura en cuanto a por qué: Tiene que haber un período lo suficientemente largo (es decir, T es lo suficientemente grande), en relación con el parámetro de reversión, b. Significa que si b es grande, T puede ser pequeño. Si b es pequeño, T debe ser grande.
# nsim=1000, T=30, a=1, b=4 #
rates_sim = InterestRateModels(nsim=1000, T=30)
rates_sim.sim_vasicek(.02, a=1, b=4, sigma=.3)
rates_sim.plot_vasicek()
b_lst = []
a_lst = []
for i in range(rates_sim.N):
rate_path = rates_sim.Vas[i,:]
a, b = rates_sim.fit_vasicek_model(rate_path)
a_lst.append(a)
b_lst.append(b)
np.mean(b_lst)
Out[273]: 7.0396842314975165
Observa que la media de b es 7,03, no 4. Así que ahora cuando dejo T=1000 esto es lo que veo.
np.mean(b_lst)
Out[275]: 7.538313498938557
Esto sigue siendo un poco fuera de lugar. He mirado el gráfico de las curvas de velocidad y no parecen totalmente estacionarias. Así que dejando que b sea realmente grande (es decir, b=30), incluso para un T=30 más pequeño obtengo el siguiente resultado
np.mean(b_lst)
Out[277]: 31.078385891056488
Esto parece lo que yo esperaría. Entonces, ¿cuál es la regla general para una convergencia razonable? He leído en alguna parte que debemos tener $\mid 1 - b \Delta t \mid <= 1$ aunque cuando $\Delta t = 1/30$ y $b=4$ Esto sigue siendo cierto, pero los resultados son horribles. Gracias por leer esto, y aprecio cualquier ayuda que los filks puedan dar.