Kelly Criterion
The mathematically optimal bet sizing formula for maximizing long-term growth. Critical for bankroll management, exposure limits, and pricing margin optimization.
๐ The Kelly Formula
Optimal fraction of bankroll to bet
Decimal odds - 1 (net odds)
Probability of winning
Probability of losing (1-p)
Bet Parameters
Kelly Adjustment
๐ Results
Bankroll Simulation (100 bets)
Key Insight: Full Kelly maximizes growth rate but has high variance. Double Kelly can lead to ruin. Half Kelly provides ~75% of full Kelly's growth with much less volatility.
Expected Growth Rate vs Bet Size
The peak of this curve is at 10.0% (Full Kelly). Betting more than Full Kelly actually decreases expected growth!
๐ Sports Pricing Applications
For the House (PrizePicks)
- โ Exposure Limits: Cap max bet on any single line using Kelly-based thinking
- โ Risk Budget: Allocate risk capital across different games/sports optimally
- โ Pricing Margins: Set vig/hold to ensure house always has positive Kelly
For Sharp Bettors (Detection)
- โ Syndicate Detection: Sharps bet Kelly-optimal amounts - watch for consistent sizing
- โ Line Movement: Price adjust based on Kelly-implied edge of sharp action
- โ CLV Tracking: Sharp bettors consistently beat closing lines
โ ๏ธ Common Pitfalls
Overestimating Edge
If your true probability estimate is wrong, Kelly can suggest dangerously large bets. Use fractional Kelly as insurance.
Ignoring Correlation
Multiple bets on correlated outcomes require adjusted Kelly sizing to avoid over-concentration.
Short-Term Variance
Kelly optimizes long-run growth. Short-term drawdowns can be severe even with correct Kelly.
R Code Equivalent
# Kelly Criterion Calculator
kelly_fraction <- function(win_prob, decimal_odds) {
b <- decimal_odds - 1 # Net odds
q <- 1 - win_prob # Loss probability
f <- (b * win_prob - q) / b
max(0, f) # Can't bet negative
}
# Simulate bankroll growth
simulate_kelly <- function(win_prob, odds, bankroll, kelly_mult = 1, n_bets = 100) {
f <- kelly_fraction(win_prob, odds) * kelly_mult
history <- numeric(n_bets + 1)
history[1] <- bankroll
for (i in 1:n_bets) {
bet <- f * history[i]
if (runif(1) < win_prob) {
history[i + 1] <- history[i] + bet * (odds - 1)
} else {
history[i + 1] <- history[i] - bet
}
}
history
}
# Example
f <- kelly_fraction(0.55, 2)
cat(sprintf("Optimal Kelly: %.1f%%\n", f * 100))
cat(sprintf("Bet size: $%.0f\n", f * 10000))