Simulating the Hull–White Extension of the Vasicek Short-Rate Model
Summary
The document describes a question about extending a Vasicek short-rate simulation to the Hull–White model. It first presents the exact one-step normal transition for a constant-parameter Vasicek process: the conditional mean reverts toward a fixed long-run level, and the variance depends on the mean-reversion speed, volatility, and time step. A Python example applies that transition repeatedly to produce a path of short rates.
The author then gives the time-dependent mean expression for the Hull–White extension and asks how to adapt the simulation. The document does not provide a solution to that question, so it offers the Vasicek implementation and model equations as context rather than a complete Hull–White procedure. The sample path includes negative rates, consistent with the model’s unbounded normal rate distribution. It does not discuss calibration, fitting the time-varying drift to an initial yield curve, or validating simulated paths against market data.
Key ideas
- The Vasicek short rate has a normal conditional transition with a mean that reverts toward a constant level.
- Its exact transition variance depends on volatility, mean-reversion speed, and the simulation time step.
- The Hull–White extension replaces the constant long-run level with a time-varying function.
- The document poses, but does not answer, how to implement the time-varying drift in the simulation.
Tags
Full text
# Simulating Hull-White Model in Python
# Simulating Hull-White Model in Python
I first simulated the short rate in the Vasicek model using the following code, which is equivalent to simulating the following normal distribution $r_{t} \sim N\left(r_{0}e^{-at} + b\left(1-e^{-at}\right), \dfrac{\sigma^{2}}{2a}\left(1-e^{-2at}\right)\right)$ (code retrieved from https://github.com/open-source-modelling/vasicek_one_factor_python/blob/main/Vasicek_one_factor.py):
```
def simulate_Vasicek_One_Factor(r0: float = 0.1, a: float = 1.0, lam: float = 0.1, sigma: float = 0.2, T: int = 52, dt = 0.1) -> pd.DataFrame:
""" Simulates a temporal series of interest rates using the One Factor Vasicek model
interest_rate_simulation = simulate_Vasicek_One_Factor(r0, a, lam, sigma, T, dt)
Args:
r0 (float): starting interest rate of the Vasicek process
a (float): speed of reversion parameter that characterizes the velocity at which such trajectories will regroup around b in time
lam (float): long-term mean level that all future trajectories will evolve around
sigma (float): instantaneous volatility measures instant by instant the amplitude of randomness entering the system
T (integer): end modeling time. From 0 to T, the time series runs.
dt (float): increment of time that the process runs on. Ex. dt = 0.1 then the time series is 0, 0.1, 0.2,...
Returns:
N x 2 Pandas DataFrame where index is modelling time and values are a realisation of the underlying's price
Example:
Model the interest rate which is 10% today. The annualized instant volatility is 20%. The external analysis points out that the mean reversion parameter is 1 and the long-term interest rate level is 10 % therefore the mean reversion correction is theta = 10% * 1 = 10%. The user is interested in an interest rate projection of the next 10 years in increments of 6 months (0.5 years)
import pandas as pd
import numpy as np
simulate_Vasicek_One_Factor(0.1, 1.0, 0.1, 0.2, 10, 0.5)
[out] = Time Stock Price
0.000000 0.100000
0.526316 0.212055
1.052632 0.115934
1.578947 0.012870
2.105263 0.003295
2.631579 0.206635
3.157895 0.191319
3.684211 0.108299
4.210526 0.094983
4.736842 0.075903
5.263158 0.229143
5.789474 -0.111977
6.315789 0.120245
6.842105 0.116082
7.368421 0.230879
7.894737 0.266821
8.421053 0.229788
8.947368 0.304378
9.473684 0.217760
10.000000 0.217147
For more information see https://en.wikipedia.org/wiki/Vasicek_model
"""
N = int(T / dt) + 1 # number of end-points of subintervals of length 1/dt between 0 and max modelling time T
time, delta_t = np.linspace(0, T, num = N, retstep = True)
r = np.ones(N) * r0
for t in range(1,N):
r[t] = r[t-1] * np.exp(-a*dt)+lam*(1-np.exp(-a*dt))+sigma*np.sqrt((1-np.exp(-2*a*dt))/(2*a))* np.random.normal(loc = 0,scale = 1)
dict = {'Time' : time, 'Interest Rate' : r}
interest_rate_simulation = pd.DataFrame.from_dict(data = dict)
interest_rate_simulation.set_index('Time', inplace = True)
return interest_rate_simulation
```
I am now trying to simulate the short rate in the Vasicek Model with the Hull-White Extension , which is equivalent to simulating the following normal distribution $r_{t} \sim N\left(r_{0}e^{-at} + ae^{-at}\int_{0}^{t}b\left(s\right)e^{as}ds, \dfrac{\sigma^{2}}{2a}\left(1-e^{-2at}\right)\right)$. But I am currently struggling how to adjust the previous code in order to correctly simulate the short rate in the Vasicek Model with the Hull-White Extension.
Kind regards,
GuyonShown in full with attribution under the source's licence. Licence: CC BY-SA 4.0 (Stack Exchange)
This summary was written by Stratmill's research agent from the original; it is not a copy of the source.