Monte Carlo Simulation
Exploring the stochastic nature of short-term interest rates.
Initialising Vasicek Model
Interactive Stochastic Interest Rate Simulation & Yield Curve Modelling
Created by Sajid Ahmed
Exploring the stochastic nature of short-term interest rates.
Adjust variables to recalculate the model.
The theoretical term structure for zero-coupon bonds based on the affine property of the Vasicek model.
Likelihood of the rate outcome using the Ornstein-Uhlenbeck transition density
The core logic driving the simulation.
The Vasicek model describes the evolution of interest rates as a Stochastic Differential Equation (SDE). It captures the tension between random market shocks and a long-term economic equilibrium.
This SDE is a specific case of the Ornstein-Uhlenbeck process and can be solved explicitly using Itō's Lemma:
The model produces a closed-form solution for bond prices. The price of a Zero-Coupon Bond $P(t,T)$ maturing at time $T$ is:
This relationship implies that the Yield Curve is determined entirely by the short rate $r_t$ and the model parameters.
The Python code constructing the models.
Since continuous time ($dt$) is impossible to model on a discrete computer, we approximate the Vasicek SDE using the Euler-Maruyama method.
def simulate_vasicek(r0, a, b, sigma, T=1.0, dt=0.01, num_sims=1):
.
.
.
# Scale random shocks by sqrt(dt) as variance grows linearly with time.
shocks = sigma * np.sqrt(dt) * np.random.normal(size=(N, num_sims))
# Iterate through time steps to apply the Euler-Maruyama update rule.
for t in range(1, N):
drift = a * (b - rates[t-1, :]) * dt
rates[t, :] = rates[t-1, :] + drift + shocks[t, :]
return time, rates
To generate the probability distributions, we do not need to run simulations. We use the statistical properties of the normal distribution derived directly from the model:
def calculate_future_distribution(r0, a, b, sigma, t):
expected_mean = r0 * np.exp(-a * t) + b * (1 - np.exp(-a * t))
# Variance (derived from Ito Isometry)
variance = (sigma**2 / (2 * a)) * (1 - np.exp(-2 * a * t))
std_dev = np.sqrt(variance)
return expected_mean, std_dev