Random walks & martingales
Start in discrete time. A drunkard stands on the integers and at each tick flips a fair coin: heads, step right; tails, step left. After \(n\) steps his position is a sum of independent \(\pm 1\) increments — a simple random walk. He has no memory and no destination; the best forecast of where he will be next is exactly where he is now. That property has a name, and it is the spine of mathematical finance.
A process \(M_t\) is a martingale if its expected future value, given everything known so far, equals its present value:
The increments of the walk are independent and identically distributed with mean zero and unit variance, so after \(n\) steps the position has mean \(0\) and variance \(n\) — variance accumulates linearly in the number of steps, and the typical distance travelled grows like \(\sqrt{n}\). This is the diffusive scaling that will reappear, unchanged, in continuous time: spread widens with the square root of elapsed time, never linearly. A walk that moved linearly with \(n\) would be a deterministic trend with noise; the \(\sqrt{n}\) law is the signature of pure randomness with no edge.
Now refine the clock. Take \(n\) steps in a fixed window of length \(t\), each of size \(\sqrt{t/n}\) so that variance is conserved at \(t\) regardless of \(n\). Let \(n \to \infty\). By the central limit theorem the rescaled walk converges to a continuous, Gaussian-distributed process — Brownian motion. The drunkard's discrete stagger becomes a path that is continuous everywhere yet jagged at every magnification, and the whole apparatus of §1.2 onward is the price we pay for that limit.
# A fair random walk converges to Brownian motion: variance grows like n
import numpy as np
rng = np.random.default_rng(0)
n_paths, n_steps = 20000, 400
steps = rng.choice([-1.0, 1.0], size=(n_paths, n_steps)) # fair +/-1 coin flips
walk = np.cumsum(steps, axis=1) # positions over time
ks = [25, 100, 400]
print(" step n sample Var theory (= n)")
for k in ks:
print(f" {k:5d} {walk[:, k-1].var():12.2f} {k:14d}")
# fair game: E[next | now] = now, so increments have zero conditional mean
incr = walk[:, 1:] - walk[:, :-1]
print(f"\nmean increment (should be ~0): {incr.mean():+.4f}")
print("variance = number of steps -> std grows like sqrt(n): the martingale walk")
plot_xy(list(range(1, n_steps + 1)), walk[:8].T.tolist()) # 8 sample paths
Brownian motion (the Wiener process)
The limit of the rescaled walk is standard Brownian motion \(W_t\), also called the Wiener process after Norbert Wiener, who first proved it exists as a rigorous mathematical object. It is defined by four axioms — every later equation in this volume is a consequence of them:
Two facts about \(W_t\) defy ordinary intuition, and both matter for what follows. First, the path is continuous but nowhere differentiable: there is no well-defined velocity at any instant, because over a tiny interval \(\mathrm{d}t\) the displacement is of order \(\sqrt{\mathrm{d}t}\), so the ratio \(\mathrm{d}W/\mathrm{d}t\) behaves like \(1/\sqrt{\mathrm{d}t} \to \infty\). You cannot zoom in until the wiggling smooths out — magnify any segment and it looks statistically identical to the whole, a self-similar fractal.
Second, and decisively, is the quadratic variation. Sum the squared increments of \(W\) over a partition of \([0,t]\); unlike a smooth curve, whose squared increments vanish in the limit, the sum converges to \(t\) itself — not to zero, and with no randomness left over:
One honest caveat. Real prices are not literally Brownian. They jump on news, their volatility clusters and spikes, and a strictly Brownian model gives prices that can go negative — which is why §1.3 works with the logarithm instead. Bachelier's 1900 thesis modelled prices as arithmetic Brownian motion and was decades ahead of its time; the modern repair, geometric Brownian motion, keeps the tractability while fixing the sign. Brownian motion is the idealization that makes the algebra possible, not a faithful portrait of a tape.
Geometric Brownian motion — the stock model
A stock cannot follow plain Brownian motion: prices would wander below zero, and a $5 stock and a $500 stock would feel the same dollar shocks rather than the same percentage shocks. The fix is to put the randomness on the returns, not the price level. The instantaneous return earns a drift \(\mu\) plus a noise \(\sigma\,\mathrm{d}W_t\):
Solving EQ Q1.4 requires applying calculus to \(\log S_t\), which is precisely where Itô's lemma enters (§1.4). The result — derived in full next section — is the closed-form solution:
The two moments of \(S_T\) follow from the lognormal law and are worth memorizing because every Monte-Carlo check reduces to them:
# Simulate Brownian & GBM paths; terminal mean/var vs theory (EQ Q1.5-Q1.6)
import numpy as np
rng = np.random.default_rng(1)
S0, mu, sig, T = 100.0, 0.08, 0.25, 1.0
n_paths, n_steps = 100000, 250
dt = T / n_steps
dW = rng.normal(0.0, np.sqrt(dt), size=(n_paths, n_steps)) # Brownian increments
W_T = dW.sum(axis=1) # W_T ~ N(0, T)
print(f"Brownian W_T : mean {W_T.mean():+.4f} (theory 0) var {W_T.var():.4f} (theory {T:.4f})")
# closed-form GBM terminal: log-drift carries the -1/2 sigma^2 correction
S_T = S0 * np.exp((mu - 0.5*sig**2)*T + sig*W_T)
mean_thy = S0*np.exp(mu*T)
var_thy = S0**2*np.exp(2*mu*T)*(np.exp(sig**2*T) - 1)
print(f"GBM E[S_T] : sim {S_T.mean():8.3f} theory {mean_thy:8.3f}")
print(f"GBM Var(S_T): sim {S_T.var():8.2f} theory {var_thy:8.2f}")
print(f"median S_T : sim {np.median(S_T):8.3f} theory {S0*np.exp((mu-0.5*sig**2)*T):8.3f}")
print("\nmean > median: the lognormal right tail drags the average up.")
plot_xy(sorted(S_T[:5000].tolist()), np.linspace(0,1,5000).tolist()) # empirical CDF
Itô's lemma
Here is the heart of the chapter. In ordinary calculus, the chain rule for a function \(f(x)\) of a smooth path keeps only the first derivative: \(\mathrm{d}f = f'(x)\,\mathrm{d}x\). The second-order term \(\tfrac12 f''(x)(\mathrm{d}x)^2\) is discarded because \((\mathrm{d}x)^2\) is negligible for a smooth curve. For a Brownian path it is not negligible — EQ Q1.3 says \((\mathrm{d}W)^2 = \mathrm{d}t\) — so that second-order term refuses to die. Keeping it gives Itô's lemma, the chain rule of stochastic calculus, proved by Kiyosi Itô in 1944:
The cleanest demonstration that ordinary calculus fails uses \(f(W) = W^2\). Naïve calculus would write \(\mathrm{d}(W^2) = 2W\,\mathrm{d}W\). Itô's lemma, with \(\mu = 0,\ \sigma = 1\), \(f' = 2W\), \(f'' = 2\), instead gives:
Stochastic differential equations
A stochastic differential equation (SDE) is the master template of every model in this volume. It writes the infinitesimal change of a process as a deterministic drift plus a random diffusion:
Most SDEs have no closed-form solution, so they are solved numerically. The simplest scheme is Euler–Maruyama: step forward by \(\Delta t\), adding a drift increment and a Gaussian noise of standard deviation \(b\sqrt{\Delta t}\) — note the \(\sqrt{\Delta t}\), the diffusive scaling of §1.1 made into code:
One mean-reverting SDE deserves a name now, because it powers the interest-rate models of Quant 04 and the volatility models of Quant 03. The Ornstein–Uhlenbeck process \(\mathrm{d}X_t = \kappa(\theta - X_t)\,\mathrm{d}t + \sigma\,\mathrm{d}W_t\) is pulled back toward a long-run level \(\theta\) at speed \(\kappa\): unlike Brownian motion, whose variance grows without bound, its variance saturates at \(\sigma^2/2\kappa\). It is the canonical model for anything that wanders but does not run away — spreads, rates, mean-reverting pairs.
Where the idealization leaks. Itô calculus assumes continuous paths and finite quadratic variation. Markets violate both: prices jump (the 1987 crash was a discontinuity no diffusion can produce), and tails are fatter than Gaussian. The honest repairs are jump-diffusions (a Poisson jump term added to EQ Q1.9), stochastic volatility (make \(b\) itself an SDE, as Heston does in Vol · EQ Q3.7), and rough-volatility models that replace \(W\) with fractional Brownian motion. None of these abandon Itô; they extend it. Brownian motion remains the load-bearing baseline precisely because its algebra is the one that closes.
# Verify the Ito drift correction: E[log S_T] uses mu - 0.5*sigma^2, not mu
import numpy as np
rng = np.random.default_rng(2)
S0, mu, sig, T = 100.0, 0.10, 0.40, 1.0
n_paths, n_steps = 200000, 200
dt = T / n_steps
# Euler-Maruyama on GBM: dS = mu*S dt + sig*S dW, noise scales with sqrt(dt)
S = np.full(n_paths, S0)
for _ in range(n_steps):
Z = rng.standard_normal(n_paths)
S += mu*S*dt + sig*S*np.sqrt(dt)*Z
log_ret = np.log(S / S0)
ito_drift = (mu - 0.5*sig**2) * T # correct: Ito's lemma
naive_drift = mu * T # wrong: ordinary calculus
print(f"simulated E[log S_T/S0] : {log_ret.mean():+.4f}")
print(f"Ito prediction (mu-.5s^2)T: {ito_drift:+.4f} <- matches")
print(f"naive prediction mu*T : {naive_drift:+.4f} <- off by 0.5*sig^2*T = {0.5*sig**2*T:.4f}")
print(f"\nmean price E[S_T] still grows at mu: sim {S.mean():.2f} vs S0*e^(muT) {S0*np.exp(mu*T):.2f}")
print("the half-sigma-squared lives in the LOG drift, not the price mean.")
You now have the engine; next we discretize it into something you can price on. Quant 02 collapses continuous GBM onto a recombining binomial tree: choose up/down moves and a risk-neutral probability so the tree's mean and variance match the SDE, then price any option by backward induction. It is Itô made arithmetic — and the most intuitive door into the Black–Scholes formula of Quant 03.
References
- Itô, K. (1944). Stochastic Integral.
- Bachelier, L. (1900). Théorie de la spéculation.
- Øksendal, B. (2003). Stochastic Differential Equations: An Introduction with Applications (6th ed.).
- Uhlenbeck, G. E. & Ornstein, L. S. (1930). On the Theory of the Brownian Motion.
- Einstein, A. (1905). Über die von der molekularkinetischen Theorie der Wärme geforderte Bewegung….
- Wiener, N. (1923). Differential Space.