Rates, Control & Data
Three more jobs for stochastic calculus: pricing bonds when the interest rate itself is random, choosing an investment strategy optimally, and confronting the models with real market data.
11.1Short-Rate Models (Vasicek)
Until now the interest rate has been a constant. In reality it moves, and every bond price depends on how. The simplest serious model makes the short-term interest rate an Ornstein–Uhlenbeck process (section 5.2), pulled toward a long-run level. It then has something remarkable: a closed-form price for every bond, and therefore a whole yield curve from three parameters.
Predict first: Today's short rate is below its long-run level. The yield curve will slope…
Move today's rate, the speed of mean reversion and the rate volatility. Left: short-rate paths over 10 years. Right: the yield curve from the exact formula, with Monte Carlo bond prices as dots.
- $r_t$
- The short rate: the interest rate for borrowing over the next instant.
- $a,\ b,\ \sigma$
- Mean-reversion speed, long-run level (5%) and volatility of the rate.
- $P(0, T)$
- Today's price of one dollar paid at time $T$ (a zero-coupon bond): the average, under risk-neutral probabilities, of discounting at the realized path of rates.
- $A(T),\ B(T)$
- Explicit functions of the parameters. $B$ is the bond's sensitivity to today's rate (its "duration" in this model).
- yield $y(T)$
- The constant rate that gives the same price: $y(T) = -\ln P(0, T)/T$. Plotted against $T$ it is the yield curve.
In plain words: a bond's price averages the discount factor over every path the rate might take. Because the Vasicek rate is normally distributed, so is $\int r\,dt$, and the average of $e^{-\text{normal}}$ has a formula. That is where $A$ and $B$ come from. Rates below the long-run level mean an upward-sloping curve, and above it a downward one (inverted, as before recessions). Volatility pulls long yields down through convexity: $e^{-x}$ is curved, so uncertainty makes bonds more valuable. The flaw: a normally distributed rate can go negative. At the starting settings the chance is under 1%, but it grows quickly when today's rate is near zero or volatility is high (the stats line shows it). Once seen as absurd, negative rates happened in Europe and Japan in the 2010s.
One SDE for the short rate gives prices for bonds of every maturity. Vasicek is affine: yields are linear in today's rate, which makes calibration and risk simple. CIR (section 5.2) keeps rates positive with a similar formula. Modern desks model the whole curve at once (Heath–Jarrow–Morton, or LIBOR/SOFR market models) so they can match today's curve exactly.
Going deeper: the precise statement
Bond price. Under $Q$, $\int_0^T r_t\,dt$ is normal with mean $bT + (r_0 - b)B(T)$ and a known variance, so $P = e^{-\text{mean} + \text{variance}/2}$. This gives $\ln A(T) = \big(B(T) - T\big)\frac{a^2b - \sigma^2/2}{a^2} - \frac{\sigma^2B(T)^2}{4a}$. Equivalently, $P(t, T)$ solves the PDE $\partial_tP + a(b - r)\partial_rP + \tfrac12\sigma^2\partial_{rr}P - rP = 0$ (Feynman–Kac with discounting, section 6.3).
Affine models. Whenever drift and variance are affine in $r$ (Vasicek, CIR), bond prices are exponential-affine, $P = e^{A(T) - B(T)r}$, with $A$ and $B$ solving Riccati ODEs (the same equation type as the Kalman filter in section 8.2).
Market price of risk. The parameters here are risk-neutral. Real-world rates can drift differently, and the gap is the term premium.
References: O. Vasicek, "An equilibrium characterization of the term structure", J. Financial Economics 5 (1977), 177–188. D. Brigo & F. Mercurio, Interest Rate Models: Theory and Practice (2nd ed., Springer, 2006), ch. 3. Shreve, Stochastic Calculus for Finance II, §10.2.
Show the code (Python + NumPy)
import numpy as np
from math import exp, log, sqrt
a, b, sigma, r0, T = 0.5, 0.05, 0.02, 0.02, 5.0 # Vasicek: dr = a(b - r)dt + sigma dW
B = (1 - exp(-a * T)) / a
lnA = (B - T) * (a * a * b - sigma ** 2 / 2) / a ** 2 - sigma ** 2 * B ** 2 / (4 * a)
exact = exp(lnA - B * r0) # closed-form zero-coupon bond price
rng, n, steps = np.random.default_rng(32), 20_000, 500
dt, r, integral = T / steps, np.full(n, r0), np.zeros(n)
for _ in range(steps):
integral += r * dt # accumulate the integral of r dt
r += a * (b - r) * dt + sigma * sqrt(dt) * rng.normal(size=n)
mc = np.exp(-integral)
print(f"5-year bond: closed form {exact:.5f} Monte Carlo {mc.mean():.5f} +- {mc.std() / sqrt(n):.5f}")
print(f"5-year yield {-log(exact) / T * 100:.3f}% (short rate today {r0 * 100:.1f}%, long-run level {b * 100:.1f}%)")
Output when we ran it:
5-year bond: closed form 0.82443 Monte Carlo 0.82477 +- 0.00036
5-year yield 3.861% (short rate today 2.0%, long-run level 5.0%)
11.2Merton's Portfolio Problem
How much of your wealth should be in stocks? Merton answered it in 1969 with stochastic calculus. Suppose you rebalance continuously, keeping a fixed fraction π in the stock and the rest in cash, and judge outcomes with a utility function that dislikes risk to a degree γ. Then the best fraction has a one-line formula.
Predict first: If an investor becomes twice as risk-averse (γ doubles), the optimal fraction in stocks will…
Choose the stock fraction and the risk aversion. Left: 40 possible 10-year wealth paths for that fraction (log scale). Right: the certainty-equivalent growth rate for every fraction. The dashed line marks Merton's optimum.
- $X_t$
- Your wealth at time $t$.
- $\pi$
- The fraction of wealth kept in the stock (above 100% means borrowing to invest more).
- $\mu,\ \sigma,\ r$
- The stock's expected return (8%) and volatility (20%), and the cash rate (2%).
- $\gamma$
- Relative risk aversion, in the utility $U(x) = x^{1-\gamma}/(1-\gamma)$. Larger means more afraid of losses.
- certainty equivalent
- The guaranteed growth rate you would accept instead of the risky strategy: $r + \pi(\mu - r) - \tfrac12\gamma\pi^2\sigma^2$.
- $\pi^*$
- The fraction that maximizes it: the risk premium $\mu - r$ divided by the risk ($\sigma^2$) times the aversion ($\gamma$).
In plain words: more stock adds expected return in a straight line, $\pi(\mu - r)$, but adds risk as a square, $\tfrac12\gamma\pi^2\sigma^2$. A straight line minus a parabola peaks where the two slopes balance: at $\pi^* = (\mu - r)/(\gamma\sigma^2)$. Too little stock leaves return on the table. Too much, and the volatility eats the growth: the typical path of an over-leveraged portfolio falls even though its average rises. That's the $-\tfrac12\pi^2\sigma^2$ Itô term. With log utility ($\gamma = 1$) this is the Kelly criterion, which maximizes long-run growth.
The optimal portfolio keeps a constant fraction in stocks: buy after falls and sell after rises, to rebalance. The fraction is set by the risk premium, the risk and your aversion to it. The same Itô correction that makes $W^2$ drift (section 4.2) is why leverage beyond Kelly lowers long-run growth: a classic trading-interview point.
Going deeper: the precise statement
Hamilton–Jacobi–Bellman equation. The value function $V(t, x) = \sup_\pi\mathbb E[U(X_T) \mid X_t = x]$ satisfies $\partial_tV + \sup_\pi\big\{x(r + \pi(\mu - r))\partial_xV + \tfrac12\pi^2\sigma^2x^2\partial_{xx}V\big\} = 0$. Maximizing the quadratic in $\pi$ gives $\pi^* = -\frac{(\mu - r)\,\partial_xV}{\sigma^2 x\,\partial_{xx}V}$. For CRRA utility, $V = f(t)\,x^{1-\gamma}$, so $-x\partial_{xx}V/\partial_xV = \gamma$ and $\pi^* = (\mu - r)/(\gamma\sigma^2)$.
Growth and Kelly. With log utility, $\mathbb E[\ln X_T] = \ln X_0 + (r + \pi(\mu - r) - \tfrac12\pi^2\sigma^2)T$ is maximized at $\pi = (\mu - r)/\sigma^2$. Twice that leverage gives a long-run growth rate of $r$: the same as holding cash, with far more risk.
Assumptions. Constant $\mu$ and $\sigma$, frictionless trading and a known risk premium. In practice $\mu$ is estimated so poorly that fractional Kelly and robust versions are used.
References: R. Merton, "Lifetime portfolio selection under uncertainty: the continuous-time case", Review of Economics and Statistics 51 (1969), 247–257. Øksendal, Stochastic Differential Equations, ch. 11.
Show the code (Python + NumPy)
import numpy as np
from math import sqrt
mu, r, sigma, gamma, T = 0.08, 0.02, 0.2, 3.0, 1.0
pi_star = (mu - r) / (gamma * sigma ** 2) # Merton's optimal stock fraction
W = np.random.default_rng(33).normal(size=400_000) * sqrt(T)
def certainty_equivalent(pi): # wealth level with the same expected utility
wealth = np.exp((r + pi * (mu - r) - pi ** 2 * sigma ** 2 / 2) * T + pi * sigma * W)
return np.mean(wealth ** (1 - gamma)) ** (1 / (1 - gamma)) # CRRA utility x^(1-gamma)/(1-gamma)
grid = np.linspace(0, 1.5, 31)
best = grid[np.argmax([certainty_equivalent(p) for p in grid])]
print(f"pi* formula {pi_star:.2f} best on a simulated grid {best:.2f}")
print(f"certainty equivalent at pi*: {certainty_equivalent(pi_star):.4f} all cash: {np.exp(r * T):.4f} all stock: {certainty_equivalent(1.0):.4f}")
Output when we ran it:
pi* formula 0.50 best on a simulated grid 0.50
certainty equivalent at pi*: 1.0359 all cash: 1.0202 all stock: 1.0207
11.3Models Meet Data
Every model on this site makes testable claims. GBM says daily log returns are independent and normally distributed, and Vasicek says rates revert to a fixed level at a fixed speed. Here are two real daily series from the Federal Reserve: the euro–dollar exchange rate (1999–2025) and the 10-year US Treasury yield (1990–2025). Test the models against them.
Predict first: For daily EUR/USD returns, what do you expect from the correlation between one day and the next?
Pick a series and a range of years. For EUR/USD: the distribution of daily returns on a log scale against the normal curve (left), and how returns and their sizes correlate with past days (right). For the yield: the series with a fitted Ornstein–Uhlenbeck mean and ±2 standard-deviation band.
- $r$
- A daily log return, $\ln(S_{t+1}/S_t)$.
- kurtosis
- The average fourth power of standardized returns. It measures how heavy the tails are. A bell curve has 3 (section 8.1).
- autocorrelation
- The correlation between a quantity today and the same quantity some days later (the lag).
- volatility clustering
- Calm days follow calm days and turbulent days follow turbulent ones: the size of moves is predictable even though their direction is not.
- $\alpha,\ \beta,\ \varepsilon$
- A regression of tomorrow's yield on today's, which is the discrete-time version of an OU process. $\beta$ close to 1 means slow mean reversion.
- half-life
- How long a deviation from the long-run mean takes to shrink by half.
In plain words: GBM gets one thing right: the direction of tomorrow's move is unpredictable. It gets two things wrong. Tails are fat (kurtosis about 5.5, and 4-standard-deviation days about 37 times more common than a bell curve allows), and volatility clusters. That is the empirical case for jumps (section 8.1) and stochastic volatility (section 10.2). For the yield, the OU fit changes dramatically with the years you pick: the half-life ranges from months to years. Part of that is real (monetary regimes change). Part is statistics: the "Show the code" panel shows that even on data that truly is OU, this estimator sees too much mean reversion in short samples. Knowing how an estimator misleads is as important as knowing the model.
Data: Board of Governors of the Federal Reserve System (US), U.S. Dollars to Euro Spot Exchange Rate [DEXUSEU] and Market Yield on U.S. Treasury Securities at 10-Year Constant Maturity [DGS10], retrieved from FRED, Federal Reserve Bank of St. Louis (public domain).
Models are maps, not territory. GBM's independence holds for directions but fails for sizes, and its normality fails in the tails. A mean-reversion fit on a few years of data is mostly noise plus a known bias. A quant researcher's job is to know which assumptions matter for the question at hand, and to test them before trusting a price or a strategy.
Going deeper: the precise statement
Stylized facts. Across asset classes, returns show heavy tails, near-zero autocorrelation of returns, slowly decaying autocorrelation of absolute returns, and a negative correlation between returns and future volatility (the leverage effect, section 10.2's ρ). GARCH models and stochastic volatility reproduce clustering. Jumps and fat-tailed innovations reproduce the tails.
OU estimation. The regression estimate of $\beta$ is biased toward zero in finite samples (Kendall's bias, roughly $-(1 + 3\beta)/n$ for $n$ observations), so the mean-reversion speed $a$ is overestimated and the half-life underestimated. The bias matters most for slowly mean-reverting series, where $\beta$ is close to 1. With a unit root ($\beta = 1$) there is no mean reversion at all, and standard confidence intervals fail (Dickey–Fuller).
Regimes. A long-run "mean" fitted over 1990–2025 averages over very different monetary policy regimes. Regime-switching models and time-varying parameters address this.
References: R. Cont, "Empirical properties of asset returns: stylized facts and statistical issues", Quantitative Finance 1 (2001), 223–236. M. Kendall, "Note on bias in the estimation of autocorrelation", Biometrika 41 (1954), 403–404. Data: FRED, Federal Reserve Bank of St. Louis.
Show the code (Python + NumPy)
import numpy as np
from math import log, sqrt
a, mean, sigma, dt = 0.3, 0.04, 0.01, 1 / 252 # a true OU process: half-life 2.3 years
rng = np.random.default_rng(34)
def fitted_half_life(years):
x = np.empty(int(years / dt)); x[0] = mean
shocks = sigma * sqrt(dt) * rng.normal(size=len(x) - 1)
for i in range(1, len(x)):
x[i] = x[i - 1] + a * (mean - x[i - 1]) * dt + shocks[i - 1]
beta, alpha = np.polyfit(x[:-1], x[1:], 1) # regression x[t+1] = alpha + beta x[t]
return log(2) / (-log(beta) / dt) if beta < 1 else np.inf
for years in (5, 10, 30):
hl = np.array([fitted_half_life(years) for _ in range(100)])
print(f"{years:2d}-year windows: median fitted half-life {np.median(hl):.1f} y, "
f"middle 80% {np.percentile(hl, 10):.1f} to {np.percentile(hl, 90):.1f} y (true {log(2) / a:.1f} y)")
Output when we ran it:
5-year windows: median fitted half-life 0.6 y, middle 80% 0.3 to 1.5 y (true 2.3 y)
10-year windows: median fitted half-life 1.0 y, middle 80% 0.5 to 3.0 y (true 2.3 y)
30-year windows: median fitted half-life 1.6 y, middle 80% 0.9 to 2.6 y (true 2.3 y)
Chapter recap
Quick questions on this chapter's big ideas. Each answer is explained as soon as you choose.
1. In the Vasicek model, today's short rate is above its long-run level. The yield curve slopes…
2. In Merton's problem, doubling the stock's volatility σ changes the optimal stock fraction by a factor of…
3. Daily returns of real exchange rates are…