Kelly Criterion
A mathematical framework for optimal bet sizing to maximise long‑run wealth growth. Derivation, interactive coin‑toss simulation, and continuous portfolio application.
Mathematical Foundation
Consider a binary bet with probability \(p\) of winning a fraction \(g\) of the stake, and probability \(q = 1-p\) of losing a fraction \(l\).
After \(n\) independent trials the wealth is
The exponential growth rate per trial is
Maximising \(G(f)\) w.r.t. \(f\) gives the optimal fraction
For the common case where you win or lose the full stake (\(g=l=1\)), this simplifies to
Interactive Coin‑Toss Simulation
Kelly fraction \(f^*\)
Wealth trajectories (10 paths)
Continuous Portfolio – Kelly for Stocks
For a risky asset with expected return \(\mu\) and volatility \(\sigma\) (risk‑free rate \(r\)), the optimal fraction is
| Fraction | Mean wealth | P(loss>50%) |
|---|---|---|
| 0.0 (cash) | — | — |
| Kelly | — | — |
| 1.0 (all stocks) | — | — |
Kelly Surface: Optimal Fraction vs \(\mu\) and \(\sigma\)
The red dot marks the current parameters \(\mu = 0.08,\ \sigma = 0.20\). Surface shows \(f^* = (\mu-r)/\sigma^2\) with \(r=0.02\).
Python Implementation – Vectorised Simulation
Efficient simulation of a continuously rebalanced Kelly portfolio using geometric Brownian motion.
import numpy as np
def simulate_kelly(mu, vol, rf, frac, sim=10000, n=252):
"""
Vectorised Kelly simulation with daily rebalancing.
Returns array of shape (sim, n+1), initial wealth = 1.
"""
dt = 1 / n
z = np.random.randn(sim, n)
port_mu = frac * mu + (1 - frac) * rf
port_vol = frac * vol
log_drift = (port_mu - 0.5 * port_vol**2) * dt
log_shocks = port_vol * np.sqrt(dt) * z
log_returns = log_drift + log_shocks
cum_log = np.cumsum(log_returns, axis=1)
wealth = np.exp(cum_log)
return np.column_stack([np.ones(sim), wealth])