Vasicek is the first interest rate model almost everyone meets. It is elegant, it has closed-form bond prices, and it is the natural place to start because it is just mean reversion with Gaussian noise.

It is also not used to price anything on a real desk. The usual explanation — that it produces negative rates — is the wrong one, and has been since about 2014. The real disqualification is different and more fundamental.

The model

    \[dr_t = \kappa(\theta - r_t)\,dt + \sigma\,dW_t\]

Three parameters. \kappa is the speed of mean reversion, \theta the long-run level, \sigma the volatility. The drift pulls the rate back toward \theta whenever it strays, and the pull is proportional to how far it has strayed.

What makes it tractable is that \sigma is **constant** — it does not depend on the level of rates. That makes r_t Gaussian, which in turn means everything has a closed form. The conditional distribution at any horizon is exactly

    \[r_t \mid r_0 \sim N\left(\theta + (r_0-\theta)e^{-\kappa t},\ \frac{\sigma^2}{2\kappa}\left(1-e^{-2\kappa t}\right)\right)\]

No simulation needed, ever. And bond prices come out in exponential-affine form:

    \[P(t,T) = A(t,T)\,e^{-B(t,T)r_t}, \qquad B(t,T) = \frac{1-e^{-\kappa(T-t)}}{\kappa}\]

That is genuinely elegant, and it is why the model survives in teaching.

The negative rates problem, which is overstated

Because r_t is Gaussian, it can go below zero. With \kappa = 0.15, \theta = 4\%, \sigma = 100bp, r_0 = 3\%:

Horizon \mathbb{E}[r_t] Std dev \mathbb{P}(r_t < 0)
1y 3.14% 0.93% 0.04%
5y 3.53% 1.61% 1.42%
10y 3.78% 1.78% 1.69%
30y 3.99% 1.83% 1.44%

The stationary standard deviation is \sigma/\sqrt{2\kappa} = 1.83\%, and the long-run probability of a negative rate settles around 1.4%. Small.

It scales badly with volatility, though:

\sigma Stationary sd \mathbb{P}(r < 0)
50bp 0.91% 0.00%
100bp 1.83% 1.42%
150bp 2.74% 7.21%
200bp 3.65% 13.67%

At 200bp of volatility, one path in seven goes negative. That is a real modelling issue.

But here is why this is not the reason nobody uses Vasicek: **negative rates turned out to be real.** EUR, CHF, JPY and SEK all traded below zero for years. A model that permits negative rates is describing something that happens. Post-2014, Gaussian short-rate models became *more* defensible, not less — and the industry moved toward shifted or normal models precisely because lognormal ones could not handle the regime at all.

So the standard criticism is dated. The actual problem is elsewhere.

The fatal problem: it cannot fit today’s curve

A pricing model has one non-negotiable job: **reprice the instruments you can already observe.** If your model cannot recover today’s quoted bond prices, every derivative price it produces is built on a curve that does not exist.

Vasicek has three parameters. The term structure it generates is therefore fixed the moment you choose them. With the parameters above:

Maturity Vasicek zero rate
1y 3.07%
2y 3.13%
5y 3.27%
10y 3.42%
20y 3.56%
30y 3.63%

Whatever the market curve is today, Vasicek gives you **that** one. A smooth, monotone, gently rising curve.

Real curves are not like that. They have humps, they invert, they kink around policy meeting dates, they have dozens of liquid quoted points. Three parameters cannot match dozens of observations — this is not a calibration difficulty, it is arithmetic. You are trying to fit a curve with a shape that has no freedom left in it.

And the consequence is immediate: if your model prices the 10-year bond at 3.42% while the market prices it at 4.10%, then any swaption you price off that model is inconsistent with the underlying you would hedge with. You have built an arbitrage into your own book before pricing anything.

What fixes it: Hull-White

The fix is to make \theta a function of time:

    \[dr_t = \left[\theta(t) - a\,r_t\right]dt + \sigma\,dW_t\]

This is the **Hull-White** model, also called extended Vasicek, and the extension is exactly what it sounds like. Instead of a constant long-run level, \theta(t) is a whole function — infinitely many degrees of freedom — and it is chosen so the model reproduces today’s initial forward curve f(0,t) exactly:

    \[\theta(t) = \frac{\partial f(0,t)}{\partial t} + a\,f(0,t) + \frac{\sigma^2}{2a}\left(1-e^{-2at}\right)\]

You do not calibrate \theta(t) in the usual sense. You read it off the curve. It is pinned, not fitted.

What remains free is a and \sigma, and those get calibrated to **volatility** instruments — caps, floors, swaptions. Which is the right division of labour: the curve tells you about levels, the option market tells you about volatility, and the model uses each for what it knows.

Everything else about Vasicek survives the extension. The rate is still Gaussian. Bond prices are still exponential-affine. The closed forms still work. You lose nothing analytically and gain the one property that makes a model usable.

So what is Vasicek actually for

Three genuine uses, none of them pricing.

**Teaching.** It is the cleanest possible example of an affine term structure model, and every piece of machinery you need for Hull-White, CIR and the multi-factor models is visible in it without the notation getting in the way.

**Real-world scenario generation.** For risk, capital projection or ALM you want a plausible description of how rates behave, not an exact fit to today’s curve. Vasicek under the physical measure is a perfectly reasonable rate process, and the missing curve fit does not matter because you are not pricing off it.

**Sanity checking.** It has closed forms for almost everything, which makes it the right benchmark to validate a more complex implementation against. If your Hull-White engine does not reduce to Vasicek when you flatten \theta(t) to a constant, something is wrong.

Code

import numpy as np
from scipy.stats import norm

kap, th, sig, r0 = 0.15, 0.04, 0.01, 0.03

def vasicek_moments(t, r0=r0):
    """Exact Gaussian transition -- no simulation required."""
    m = th + (r0 - th)*np.exp(-kap*t)
    v = sig**2/(2*kap)*(1 - np.exp(-2*kap*t))
    return m, np.sqrt(v)

for t in (1, 5, 10, 30):
    m, s = vasicek_moments(t)
    print(f"{t:>3}y  E[r]={m:.4f}  sd={s:.4f}  P(r<0)={norm.cdf(-m/s):.2%}")

def zero_rate(T, r=r0):
    B = (1 - np.exp(-kap*T))/kap
    A = np.exp((th - sig**2/(2*kap**2))*(B - T) - sig**2*B**2/(4*kap))
    return -np.log(A*np.exp(-B*r))/T

print("\nthe curve the model generates, regardless of the market:")
for T in (1, 5, 10, 30):
    print(f"  {T:>3}y  {zero_rate(T):.4%}")

Run that second block, then compare with today’s actual curve. The gap is the reason the model does not price anything.

The takeaway

Vasicek is mean reversion plus Gaussian noise, and it is worth learning properly because everything in short-rate modelling is built on its structure. Its Gaussian distribution allows negative rates, which after 2014 stopped being an objection.

What disqualifies it from pricing is arithmetic: three parameters cannot reproduce a curve with dozens of quoted points, and a model that cannot reprice what you can already observe cannot be trusted with what you cannot. Hull-White fixes exactly that by replacing the constant \theta with a function read off the curve, and keeps every analytical property intact.


Related: the Feller condition, which is the equivalent boundary question for CIR — the model that solves the negative-rate problem instead of the calibration one.


Short-rate models, affine term structures and the calibration machinery behind them are worked through from the ground up in the course modules.


Get the Quant Reference Card — four pages covering stochastic calculus, measure change, the models you’ll meet, discretisation, rates, credit and XVA. Free.