Cox-Ingersoll-Ross (CIR) Process

Table of Contents

Summary

The Cox-Ingersoll-Ross (CIR, 1985) model keeps Vasicek's mean-reverting drift shape but replaces its constant volatility with a state-dependent sigma*sqrt(r) term, which shrinks toward zero as the rate itself approaches zero and rules out the negative rates Vasicek and Hull-White can produce. That same volatility term is also what breaks the closed-form Gaussian transition the other two share: a CIR rate's next value follows a non-central chi-squared distribution, not a Normal one, requiring a genuinely different simulation technique. ores::analytics::quant::service::cox_ingersoll_ross_process implements the exact (non-approximated) transition via the standard Poisson-mixture-of-central-chi-squared construction, not an Euler discretisation.

Layperson's mental model

Same elastic band as Vasicek, pulling the rate back toward a resting level — but now the jitter added each tick shrinks as the rate gets close to zero, and vanishes entirely exactly at zero. That single change is what keeps the rate from ever crossing into negative territory: right at the boundary, there is no randomness left to push it over, only the band's steady pull back up. The cost is that the maths describing "how big is the next jump" is no longer the plain bell-curve (Normal) distribution Vasicek uses — it becomes a different, more intricate distribution that itself has to be sampled correctly, not approximated.

double cox_ingersoll_ross_process::next_stochastic() {
    const double decay = std::exp(-kappa_);
    const double c = sigma_ * sigma_ * (1.0 - decay) / (4.0 * kappa_);
    const double d = 4.0 * kappa_ * theta_ / (sigma_ * sigma_);
    const double lambda = rate_ * decay / c;      // shrinks toward 0 as rate_ -> 0
    // Simplified for clarity: the real code guards this draw for lambda == 0
    // (rate_ touching the zero boundary this section discusses), since
    // std::poisson_distribution asserts on a zero mean.
    const int n = std::poisson_distribution<int>(lambda / 2.0)(rng_);
    std::chi_squared_distribution<double> chi2(d + 2.0 * n);
    return c * chi2(rng_);
}

Detail

The SDE

\begin{equation} dr = \kappa(\theta - r)\, dt + \sigma\sqrt{r}\, dW \end{equation}

identical to Vasicek's drift, \(\kappa(\theta-r)\), with the volatility term changed from a constant \(\sigma\) to \(\sigma\sqrt{r}\). As \(r \to 0\), the volatility term vanishes too, which is exactly the mechanism keeping \(r\) from crossing zero: the closer the rate gets to zero, the less randomness is left to push it further down, leaving the positive drift term \(\kappa\theta\, dt\) to pull it back up.

The Feller condition

Whether \(r\) can ever touch zero (as opposed to merely staying close to it) depends on the Feller condition: \(2\kappa\theta \ge \sigma^2\). When it holds, \(r\) stays strictly positive for all time; when it does not, \(r\) can touch zero (but never go negative) before being pulled back up by the drift term. This makes CIR's non-negativity guarantee genuinely stronger than Vasicek's total absence of one, but not an unconditional "always strictly positive" guarantee independent of parameter choice — the guarantee's strength depends on which side of the Feller condition the chosen \((\kappa, \theta, \sigma)\) fall on.

The exact transition

Because the SDE above is nonlinear in \(r\) (via \(\sqrt{r}\)), it has no closed-form solution the way Vasicek's linear SDE does — but the exact transition distribution from one tick to the next is still known in closed form, as a Poisson mixture of central chi-squared distributions (Glasserman, 2003, section 3.4):

\begin{align} c &= \frac{\sigma^2 (1 - e^{-\kappa})}{4\kappa} \\ d &= \frac{4\kappa\theta}{\sigma^2} \quad \text{(degrees of freedom)} \\ \lambda &= \frac{r_t e^{-\kappa}}{c} \quad \text{(non-centrality)} \\ N &\sim \mathrm{Poisson}(\lambda/2) \\ r_{t+1} &= c X, \quad X \sim \chi^2(d + 2N) \end{align}

cox_ingersoll_ross_process draws this transition exactly, tick by tick, rather than approximating it via an Euler scheme (which for CIR specifically can produce negative simulated rates — the very defect the model was designed to avoid — unless a more careful discretisation is used; drawing the exact transition sidesteps that problem entirely). \(\kappa\) must be strictly positive for this construction (\(c\) above divides by \(\kappa\)) — unlike Vasicek and Hull-White, which tolerate \(\kappa \le 0\) as a degenerate driftless case, CIR has no such fallback since the \(\sqrt{r}\) volatility term makes a non-mean-reverting CIR process ill-posed. The \(\sigma = 0\) edge case is likewise handled separately, as the deterministic mean-reversion ODE \(dr = \kappa(\theta-r)\, dt\), since both the transition formulas above and the closed-form bond price below divide by \(\sigma\).

The closed-form bond price

CIR also supplies a closed-form affine zero-coupon bond price, derived the same way as Vasicek's — applying Ito's lemma to the SDE above to obtain the bond's own dynamics — despite the SDE itself having no closed-form path solution:

\begin{align} \gamma &= \sqrt{\kappa^2 + 2\sigma^2} \\ B(\tau) &= \frac{2(e^{\gamma\tau} - 1)}{(\gamma+\kappa)(e^{\gamma\tau}-1) + 2\gamma} \\ A(\tau) &= \left[ \frac{2\gamma\, e^{(\kappa+\gamma)\tau/2}} {(\gamma+\kappa)(e^{\gamma\tau}-1) + 2\gamma} \right]^{2\kappa\theta/\sigma^2} \\ P(\tau) &= A(\tau)\, e^{-B(\tau)\, r_t} \end{align}

dt: an explicit, separate step-length parameter

As with Vasicek/ Hull-White, \(\kappa\), \(\theta\), \(\sigma\) are always in the SDE's own (annual) time unit; a tick's real-world length is a separate, explicit dt — a constructor parameter defaulting to 1.0. Both the exact transition and the closed-form bond price need it: decay=/=c=/=lambda in the transition use \(e^{-\kappa\, dt}\) in place of \(e^{-\kappa}\), and \(\tau\) in the bond price is \(\text{ticks\_ahead} \times dt\), not the raw tick count. Because CIR's bond price is already a closed form (no iterative recursion the way Hull-White's time-varying-\(\theta\) case needs), this dt fix is a single substitution once dt is threaded through — but omitting it has the same failure mode as Hull-White's uncorrected recursion: \(\tau\) used as a raw tick count silently treats each tick as a full year, over-discounting by a factor of \(1/dt\) at fine tick granularities (e.g. daily ticks, dt = 1/365). See the task that found and fixed this for the concrete numbers, and Hull-White's own doc for the cross-check against QuantLib's identical speed=/=dt separation convention.

See also

  • Stochastic Processes — the hub, including the comparison table across all four mean-reverting processes.
  • Ornstein-Uhlenbeck Process — the drift shape CIR shares with Vasicek and Hull-White.
  • Vasicek Process — the constant-volatility model whose main criticised weakness (negative rates) CIR addresses.
  • Ito's Lemma — used to derive the closed-form bond price above.

Further reading

  • Cox, J. C., Ingersoll, J. E., & Ross, S. A. (1985). "A Theory of the Term Structure of Interest Rates." Econometrica, 53(2), 385-407. The original paper: the SDE, the Feller condition, and the closed-form affine bond price.
  • Feller, W. (1951). "Two Singular Diffusion Problems." Annals of Mathematics, 54(1), 173-182. The earlier, purely mathematical paper establishing the boundary-behaviour condition later named after Feller and applied to the CIR process above.
  • Glasserman, P. (2003). Monte Carlo Methods in Financial Engineering. Springer. Section 3.4 gives the Poisson-mixture-of-chi-squared exact simulation scheme cox_ingersoll_ross_process implements directly.
  • Wikipedia: Cox-Ingersoll-Ross model.

Emacs 29.3 (Org mode 9.6.15)