Kelly criterion in trading: why traders use half-Kelly

5 min readMetaKit

"How much should I risk per trade?" usually gets one of two answers: "1–2%", with no reason given, or "use the Kelly criterion", with a formula and a warning not to actually use it. Both are right in their way. The Kelly criterion tells you the maximum growth-optimal bet for an edge you know exactly, and the reason nobody bets it is that nobody knows their edge exactly.

The Kelly formula for trading

For a strategy with win rate W and an average win that's R times the average loss:

Kelly % = W − (1 − W) ÷ R

The result is the fraction of your account to risk per trade: the amount you'd lose if the trade hits its stop, not the position's notional size.

Example: a strategy that wins 53% of the time, with average wins 1.41 times average losses.

Kelly = 0.53 − 0.47 ÷ 1.41 = 0.53 − 0.333 = 0.197, about 19.7% of the account at risk per trade.

If that number made you flinch, good. Hold that thought.

A negative Kelly means the strategy has no edge: the formula is telling you the optimal bet is not to trade it. A Kelly of exactly zero is break-even, the same point the break-even win rate describes.

What Kelly actually optimises

Kelly maximises the long-run growth rate of the account: if you could trade the same edge forever, betting the Kelly fraction grows money faster than any other fixed fraction. Bet less and you grow more slowly. Bet more and you grow more slowly and take bigger drawdowns. Bet twice Kelly and the expected growth rate falls to zero.

That's the important asymmetry: overbetting is much worse than underbetting. Going over Kelly costs you growth and adds risk; going under costs you a little growth and removes a lot of risk.

Why full Kelly is too aggressive

Even if your inputs were perfect, full Kelly is a rough ride. Drawdowns of half the account are routine at full Kelly over a long series of trades. For a 19.7% risk per trade, five losses in a row, not unusual at a 47% loss rate, takes the account down about 67%.

And your inputs aren't perfect:

  • Win rate and win/loss ratio are estimates from a finite number of trades. With 100 trades, the true win rate behind a measured 53% could plausibly be anywhere from the low 40s to the low 60s. At 45%, the same strategy's Kelly is 0.45 − 0.55 ÷ 1.41 = 6%, not 19.7%.
  • Markets change. The edge you measured last year isn't guaranteed next year.
  • Trades aren't independent. Losses cluster in bad regimes, which is exactly when an oversized bet hurts most.

Overestimating your edge pushes you past true Kelly into the zone where you lose growth and gain risk. Since you will sometimes overestimate it, the sensible thing is to bet well below your estimate.

Half-Kelly and fractional Kelly

Half-Kelly bets half the Kelly fraction. It keeps about three-quarters of full Kelly's long-run growth rate while cutting volatility roughly in half, and it leaves room for your estimate to be wrong. Quarter-Kelly goes further. Many systematic traders treat Kelly as a ceiling and run a small fraction of it.

For the example strategy:

FractionRisk per trade
Full Kelly19.7%
Half-Kelly9.9%
Quarter-Kelly4.9%
Tenth-Kelly2.0%

Notice where the familiar "risk 1–2% per trade" rule lands: around a tenth of Kelly for a decent strategy. That's not an accident. The 1–2% rule is what fractional Kelly looks like once you admit you don't know your edge precisely and want to survive long losing streaks, and on a prop firm account with a 5% daily loss limit it's often the most the rules allow anyway; see the drawdown rules post.

Getting your inputs from your trade history

Kelly needs two numbers: win rate and win/loss ratio. Your account statement has both. Over the MetaKit API, the performance endpoint returns them directly:

import os
 
import requests
 
r = requests.get(
    "https://api.metakit.cloud/v1/accounts/2/performance",
    params={"range": "12m"},
    headers={"Authorization": f"Bearer {os.environ['METAKIT_KEY']}"},
).json()
 
w = r["win_rate"] / 100            # 53.21 -> 0.5321
ratio = r["win_loss_ratio"]        # average win / |average loss|
kelly = w - (1 - w) / ratio
print(f"trades: {r['closed_trades']}  win rate: {w:.1%}  W/L: {ratio:.2f}")
print(f"full Kelly: {kelly:.1%}  half: {kelly / 2:.1%}  quarter: {kelly / 4:.1%}")

Use a long window: Kelly from 30 trades is mostly noise. closed_trades tells you how much data you're working from. The expectancy post explains why win rate and win/loss ratio have to be read together.

From a Kelly fraction to a lot size

Kelly gives you a percentage of the account to risk. To trade it, convert it to lots using the stop distance:

lots = (account equity × risk fraction) ÷ (stop distance in pips × pip value per lot)

With a $20,000 account at quarter-Kelly (4.9%) and a 25-pip stop on EURUSD (about $10 per pip per lot): 20,000 × 0.049 ÷ (25 × 10) = 3.92 lots, risking $980. At tenth-Kelly (2%), the same trade is 1.6 lots risking $400.

Then round down to the symbol's volume step. The lot size post covers pip value for other pairs and account currencies, and the position sizing API post does the whole calculation from the symbol spec in code.

Kelly in practice

  1. Compute Kelly from a long history, hundreds of trades if you have them.
  2. Treat it as a ceiling, not a target. Never risk more than full Kelly.
  3. Bet a fraction, half at most, a quarter or less if your data is thin.
  4. Recompute periodically, and cut size when the estimate falls.
  5. If Kelly is near zero or negative, stop trading the strategy, don't size it smaller.

Kelly sizing scales with the account: as equity grows the risk per trade grows, and after losses it shrinks. That's the opposite of a martingale, and it's why fractional Kelly can survive losing streaks that martingale can't.