# Trouble Calibrating a Vasicek Model

I have simulated some data according to a Vasicek process and I am then trying to apply ordinary least squares (OLS) regression analysis to see how accurate the estimated model parameters are from the estimation. However, my estimated model parameters do not even seem close to what they should be. I have tried letting T get very large, and I have even simulated 100,000 paths and estimated the model for each path, and then averaged the estimates. Yet the results still look awry. So either I am simulating my data wrong, or the regression I am doing is somehow wrong. I have attached my python code below, so if anybody can take a look and let me know why my model parameters are off I would appreciate it very much.

The form of the model I am using is:

$$dr_t = (a - b r_t) dt + \sigma dW.$$

To estimate my model parameters I am fitting a regression on the discrete data that gives me the following model:

$$r_{t+1} - r_{t} = (a - b r_t) \Delta t + \sigma Z_t$$

where $$Z_t \sim N(0,\Delta t)$$ (i.e. mean 0, variance $$\Delta t$$). From this setup I know that my estimated intercept will be $$a\Delta t$$ and my estimated slope will be $$-1 * b \Delta t$$. Therefore, in my fit_vasicek_model function, I make the necessary transformation to recover "a" and "b".

Here is my code ( I have omitted some portions that are irrelevant to this question )

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)
model = sm.OLS(y,X)
results = model.fit()
a, b1 = results.params / self.dt
b = -1 * b1
return a, b


So now when I create an instance and simulate a bunch of paths, then fit the model I parameters for a and b that are not even close to their true value. Here is my guess as to why: There needs to be a long enough of a period (i.e, T is large enough), relative to the reversion parameter, b. Meaning if b is large, T can be small. If b is small, T must be large.

# 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: 7.0396842314975165


Notice that the mean of b is 7.03, not 4. So now when I let T=1000 this is what I see.

np.mean(b_lst)
Out: 7.538313498938557


This is still a bit off. I did look at the plot of the rate curves and they don't totally look stationary. So letting b get really big (i.e. b=30), even for a smaller T=30 I get the following result

np.mean(b_lst)
Out: 31.078385891056488


This looks like what I would expect. So, what is the general rule for reasonable convergence? I have read somewhere that we must have $$\mid 1 - b \Delta t \mid <= 1$$, though when $$\Delta t = 1/30$$ and $$b=4$$, this still holds true, yet the results look awful. Thanks for reading this, and I appreciate any help you filks might give.

• Your SDE simulation is using Euler approximation, but with Vasicek we have the exact terminal distribution available. You might as well use that. Or at least use Milstein. I'm not saying the simulation accuracy is at fault here for sure, but with such unusual parameter values it might well be. Jun 20 at 13:22

dr_t = (a − b*r_t)*dt + σ * dBt

However, the Vasicek model is:

dr_t = a(b - r_t)*dt + σ * dBt

Can you update the equation and try again?

Typically, a is the mean reversion speed and b is the mean reversion level

https://en.wikipedia.org/wiki/Vasicek_model

• Thanks, I will try this. Although, in my parameterization the mean is b/a, so my initial guess is that by changing how I simulate my data I will just be changing the interpretation of the regression parameters. May 31, 2021 at 20:51
• Did this end up helping? Jun 29, 2021 at 22:57