Skip to content
All library documents

Simulating the Hull–White Extension of the Vasicek Short-Rate Model

Article Quant Q&A · Author: Guyon Van Rooij

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,

Guyon

Shown 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.