Hull-White Process
Table of Contents
Summary
The Hull-White (1990) model generalises
Vasicek by letting the
mean-reversion target become a function of time, \(\theta(t)\), instead of a
single constant. This one change solves Vasicek's biggest practical
limitation: a constant \(\theta\) cannot be tuned to make the model's
initial term structure match every observed market rate simultaneously,
whereas a piecewise-constant \(\theta(t)\) can, by construction, be chosen
to fit the curve exactly at every input pillar.
ores::analytics::quant::service::hull_white_process implements it, and
vasicek_process composes
it rather than being a separate implementation.
Layperson's mental model
Take the elastic band pulling toward a fixed resting length and let the resting length itself change over time, in steps, on a schedule chosen in advance — instead of one fixed target, the band is told "aim for this length for the first period, then this other length for the next period", and so on. That single change is what lets the model be tuned to match a whole observed curve, point by point, rather than being stuck approximating it with one fixed target.
double hull_white_process::next() { const double z = normal_(rng_); const double theta_i = theta_at(tick_); // this tick's target, from a schedule const double decay = std::exp(-kappa_); const double var = (1.0 - decay * decay) / (2.0 * kappa_); rate_ = theta_i + (rate_ - theta_i) * decay + sigma_ * std::sqrt(var) * z; ++tick_; return rate_; }
Detail
The SDE
\(\theta(t)\) is supplied to hull_white_process as a piecewise-constant
function (theta_path) rather than a single number — holding \(\theta(t)\)
constant reduces this SDE to exactly
Vasicek's, which is why
Vasicek is implemented as a thin wrapper around this class rather than
duplicated.
Why fit the initial curve exactly
A constant-\(\theta\) model like Vasicek has only three free parameters (\(\kappa\), \(\theta\), \(\sigma\)) to match an entire observed yield curve, which typically has far more independently-observed points than that — an exact fit is generically impossible. Letting \(\theta(t)\) vary in time adds one degree of freedom per time step, which is exactly enough freedom to force the model's implied curve through every observed input point exactly, while keeping \(\kappa\) and \(\sigma\) as the (still just two) parameters controlling the curve's dynamics — how it moves — rather than its shape today.
dt: an explicit, separate step-length parameter
\(\kappa\), \(\theta(t)\), \(\sigma\) are always expressed in the SDE's own
time unit (years); a tick is a purely internal simulation step whose
real-world length is a separate, explicit dt (year fraction per
tick) — a constructor parameter defaulting to 1.0 (one tick per
year), never something a caller pre-folds into kappa=/=sigma
themselves. Both next()'s transition and discount_factor()'s
recursion take dt into account:
and the backward recursion for \(B_i\) (see below) accumulates \(dt\) of
bond-time per tick, not a flat \(1\) — a tick spanning, say, one
calendar day (dt = 1/365) must integrate only \(1/365\) of a year's
discounting, not a full year's. Getting this wrong is not a cosmetic
error: at dt = 1/365 over a 730-tick (2-year) horizon, treating each
tick as a full year of bond-time computes \(e^{-730\, r}\) instead of
\(e^{-2\, r}\) — an astronomically over-discounted price, and the
concrete bug this dt parameter fixes (see
the task that found and
fixed it).
Cross-checked against QuantLib
(Engine.remote/QuantLib/ql/processes/ornsteinuhlenbeckprocess.cpp,
ql/models/shortrate/onefactormodels/vasicek.cpp): every QuantLib
short-rate formula keeps speed (kappa) and dt=/=Time arguments
always separate (exp(-speed*dt), never a pre-scaled composite), and
Vasicek/Hull-White's own bond pricing in QuantLib uses a genuine closed
form in real \((t,T)\) years, \(B(t,T) = (1-e^{-a(T-t)})/a\), rather than
an iterative per-tick recursion at all — a possible future
simplification for this class's own constant-\(\theta\) (Vasicek)
special case, not implemented here, since the general time-varying
\(\theta(t)\) case this class exists for still needs the recursion. Only
the domain knowledge (the \(dt\) discipline, the closed forms, the
degenerate small-\(\kappa\) algebraic-limit handling) is adopted from
QuantLib here, not its object-oriented shape (StochasticProcess1D
inheritance, observer-pattern term-structure handles) — this codebase
stays data-oriented, both by convention and because a future
GPU-batched simulation of many processes at once favours plain
parameter arrays over one object per process.
Two equivalent forms
Hull & White's original paper writes the SDE in "drift intercept" form,
\(dr = [\phi(t) - a r]\, dt + \sigma\, dW\) with \(\phi(t) =
\kappa\theta(t)\). hull_white_process instead uses the "target level"
form shown above, \(\kappa(\theta(t)-r)\), the same shape as
ornstein_uhlenbeck_process's SDE. The two
are algebraically equivalent (relabel \(\phi(t) = \kappa\theta(t)\) to move
between them), but the target-level form is chosen deliberately in this
codebase: it makes both the degenerate \(\kappa \le 0\) case and the
Vasicek special case (\(\theta(t)\) held constant) reduce to exactly
ornstein_uhlenbeck_process's formula, with no re-derivation or approximation needed —
a direct, mechanical consequence of the form chosen, not a coincidence of
the underlying mathematics.
See also
- Stochastic Processes — the hub, including the comparison table across all four mean-reverting processes.
- Ornstein-Uhlenbeck Process — the general process both the target-level form and the degenerate \(\kappa \le 0\) case reduce to.
- Vasicek Process — the constant-\(\theta(t)\) special case, implemented by composing this class.
- Cox-Ingersoll-Ross (CIR) Process — the alternative generalisation addressing non-negativity instead of curve-fitting.
Further reading
- Hull, J., & White, A. (1990). "Pricing Interest-Rate-Derivative Securities." The Review of Financial Studies, 3(4), 573-592. The original paper introducing the time-varying \(\theta(t)\) generalisation of Vasicek and its exact-curve-fitting property.
- Brigo, D., & Mercurio, F. (2006). Interest Rate Models — Theory and Practice (2nd ed.). Springer. Chapter 3 covers both SDE forms (drift intercept vs. target level) and their equivalence in detail.
- Wikipedia: Hull-White model.