You found a 5-cent edge on a Polymarket contract. How many shares do you buy? A traditional trader's answer might be "2% of capital" or "$500, that's my standard size." Those answers waste your edge. The Kelly Criterion is the mathematically correct answer to exactly this question — and on prediction markets, it matters more than on almost any other trading venue.
This post derives the Kelly formula for prediction market contracts, walks through why full Kelly is rarely the right choice, and shows how to apply fractional Kelly to an automated trading bot with working Python.
What the Kelly Criterion Actually Does
The Kelly Criterion tells you the fraction of your bankroll to stake on a single bet to maximize the long-term geometric growth rate of your bankroll. Two critical words:
- Long-term. Over many bets. Any single bet can lose.
- Geometric. Not total profit — the compounding rate. Bankroll doubling, not dollars earned.
The insight: if your edge is small, you want to bet small. If your edge is large, you want to bet bigger — but never so big that a single loss destroys your bankroll. Kelly finds the sweet spot.
The Formula for Binary Contracts
Polymarket contracts are binary: they settle at $1 (your side wins) or $0 (your side loses). If you buy at price p and your estimated true probability is q, the Kelly fraction is:
Where:
- f* = fraction of bankroll to stake
- q = your true probability estimate
- p = market price (as a probability, 0.0 to 1.0)
In words: Kelly fraction equals your edge (q − p) divided by the payoff (1 − p) if you win.
Worked example
Polymarket has a contract trading at $0.60 for "Home team wins." Your calibrated model estimates the home team's true probability at 0.72. You have a $5,000 bankroll.
- p = 0.60, q = 0.72
- f* = (0.72 − 0.60) / (1 − 0.60) = 0.12 / 0.40 = 0.30
- Kelly stake = $5,000 × 0.30 = $1,500
That's a big stake. Which is why almost nobody actually uses full Kelly.
Why Full Kelly Is Too Aggressive
Full Kelly assumes you know q exactly. In practice, you have an estimate of q with some error. Even a calibrated model with Expected Calibration Error of 2% has real uncertainty on any single prediction. Small errors in q produce large errors in Kelly fraction.
Consider the previous example with slightly worse inputs:
| Your estimate (q) | Market (p) | Full Kelly f* | Stake (of $5k) |
|---|---|---|---|
| 0.72 | 0.60 | 30.0% | $1,500 |
| 0.68 | 0.60 | 20.0% | $1,000 |
| 0.64 | 0.60 | 10.0% | $500 |
| 0.60 | 0.60 | 0.0% | $0 |
| 0.56 | 0.60 | −10.0% | sell/skip |
A 4pp error in your probability estimate moves Kelly by 10pp of bankroll. If your model is even slightly miscalibrated, full Kelly can double the stake you should actually take.
Fractional Kelly: The Practical Answer
The industry standard is fractional Kelly: stake a constant fraction of what full Kelly suggests. Common fractions:
| Fraction | Name | Use case |
|---|---|---|
| 1.00 | Full Kelly | Theoretical only. Not recommended. |
| 0.50 | Half Kelly | Experienced traders with well-calibrated edge estimates. |
| 0.25 | Quarter Kelly | Standard starting point for automated bots. Industry default. |
| 0.10 | Tenth Kelly | Conservative. Early-stage model with uncertain calibration. |
Why fractions work: halving the Kelly fraction cuts your growth rate by only ~25% but halves your variance. On a real-world estimator with calibration error, the actual growth rate with half Kelly often exceeds full Kelly because you don't over-stake when q is overestimated.
Our own moneyline trading bot defaults to quarter Kelly with a hard cap at 5% of bankroll per trade. In six months of live data, this produces consistent positive growth rates without the 40-70% drawdowns full Kelly would induce.
Python: Fractional Kelly Sizing
def kelly_fraction(market_price: float, fair_prob: float) -> float:
"""Compute Kelly fraction for a binary contract.
Returns 0.0 if no edge (or negative edge — caller should sell/skip).
"""
if market_price >= 1.0 or market_price <= 0:
return 0.0
if fair_prob <= market_price:
return 0.0
return (fair_prob - market_price) / (1.0 - market_price)
def size_position(bankroll_usd: float,
market_price: float,
fair_prob: float,
kelly_fraction_mult: float = 0.25,
max_per_trade_pct: float = 0.05,
min_per_trade_usd: float = 1.0) -> float:
"""Returns USD to stake, respecting fractional Kelly + hard cap + min size."""
f_star = kelly_fraction(market_price, fair_prob)
if f_star <= 0:
return 0.0
stake_pct = min(f_star * kelly_fraction_mult, max_per_trade_pct)
stake_usd = bankroll_usd * stake_pct
if stake_usd < min_per_trade_usd:
return 0.0
return stake_usd
# Example
stake = size_position(
bankroll_usd=5000,
market_price=0.60, # market ask = 60c
fair_prob=0.72, # model fair = 72%
kelly_fraction_mult=0.25, # quarter Kelly
max_per_trade_pct=0.05, # hard cap 5%
)
# stake = $250 (quarter Kelly suggests 7.5%, capped at 5%)
Adjustments for Real Markets
Execution cost
Kelly assumes you get the quoted price. In reality, you'll pay slippage, taker fees, and lose to latency. Shrink your fair_prob by a small buffer (0.005-0.01) before computing Kelly. This correctly models "the edge I capture is smaller than the edge I calculate."
Correlation across positions
Kelly assumes your bets are independent. On prediction markets, they rarely are: two positions on different NBA games in the same slate have correlated model risk (if your NBA model is miscalibrated, both trades lose). Never let Kelly put more than ~15% of bankroll across all same-sport simultaneous positions, regardless of individual Kelly signals.
Maximum number of concurrent positions
If you have 20 open positions each sized at 2% Kelly, that's 40% of bankroll at risk simultaneously. Limit either per-position size or total concurrent exposure. A practical rule: max_concurrent_exposure_pct = 15% to 20%.
Skip the sizing math. ZenHodl's API delivers calibrated fair probabilities for 11 sports, and the included bot course shows how to size trades with Kelly-based risk management.
See ZenHodlWhen Kelly Is the Wrong Tool
- You're not compounding. If you're paying out profits to yourself, Kelly's optimality breaks down. Use fixed-fraction sizing.
- Your edge estimate is unstable. If q has high variance across similar trades, Kelly over-stakes on outliers.
- Path matters more than expected value. Kelly maximizes log-growth, which is indifferent to 40% drawdowns. If a 40% drawdown would bankrupt you operationally, use fractional Kelly or a hard drawdown limit.
Summary
- Kelly for binary contracts: f* = (q − p) / (1 − p)
- Use quarter Kelly as a default unless you have high confidence in your calibration
- Cap single trades at 5% of bankroll and total exposure at 15-20%
- Shrink your fair_prob by 0.5-1.0 cents before sizing to model execution cost
- When q is very uncertain, skip the trade — not every signal deserves capital
Further reading: Understanding Edge in Prediction Markets · Risk Management for Automated Bots · Reading Polymarket Order Books