A trader can be right more often than wrong and still lose money.
Suppose a strategy wins 60% of its trades and produces twice as much profit when it wins as it loses when it loses. On the surface, this looks like an unusually strong system. But the correct position size is not automatically 100%, nor is it some arbitrary fraction determined by intuition.
Kelly sizing turns the win rate, payoff ratio, and bankroll into a mathematical position-size decision. For the example above, the unconstrained Kelly fraction is 40% of the bankroll per trade. That result is mathematically correct, but it is not automatically prudent to deploy.
This article derives the formula, explains why fractional Kelly is often more defensible, quantifies the trade-off between growth and volatility, and provides a runnable implementation for calculating and simulating position sizes.
1. First, Define the Payoff Ratio Precisely
The phrase “a 2:1 payoff ratio” is used inconsistently.
This article defines it as follows:
- A winning trade produces a net gain of 2 units for every 1 unit risked.
- A losing trade loses 1 unit for every 1 unit risked.
If the account has a risk budget of $1,000:
- A win produces a net profit of $2,000.
- A loss produces a net loss of $1,000.
The relevant variable in the Kelly formula is therefore:
[
b = 2
]
where (b) is the ratio of net profit to net loss.
This definition is different from saying that a winning trade returns two times the initial stake, including the returned stake. For example, a contract that returns three dollars for every one dollar staked has a net profit-to-loss ratio of (2:1), not (3:1). Confusing gross returns and net profit changes the position size.
The calculation also assumes that the $1,000 risk amount is the maximum loss associated with the trade. If the strategy can lose more because of gaps, slippage, or discontinuous price moves, the effective payoff ratio must be adjusted downward.
2. The Core Question
Consider a repeated binary outcome:
- Win probability: (p = 0.60)
- Loss probability: (q = 1-p = 0.40)
- Profit per unit risked when winning: (b = 2)
- Loss per unit risked when losing: (1)
- Current bankroll: (B)
If the trader risks a fraction (f) of the bankroll on each trade, the account value changes as follows:
| Outcome | Probability | New bankroll |
|---|---|---|
| Win | 60% | (B(1+2f)) |
| Loss | 40% | (B(1-f)) |
The question is not simply:
Which fraction maximizes the expected dollar profit?
The Kelly criterion maximizes the expected growth rate of the logarithm of wealth, or equivalently the expected growth rate of capital:
[
G(f) = p \ln(1+bf) + q \ln(1-f)
]
This distinction matters. The strategy that maximizes expected arithmetic profit is not always the strategy that maximizes long-run compound growth.
A strategy that occasionally suffers a severe loss may deliver a high expected dollar return while eventually destroying the account through compounding. Logarithmic growth penalizes that outcome because a negative return cannot fall below (-100%), while positive returns can compound over time.
3. Deriving the Kelly Formula
The expected log growth function is:
[
G(f) = p\ln(1+bf) + q\ln(1-f)
]
The first derivative is:
[
G'(f) = \frac{pb}{1+bf} - \frac{q}{1-f}
]
Set the derivative to zero:
[
\frac{pb}{1+bf} = \frac{q}{1-f}
]
Cross-multiplying gives:
[
pb(1-f) = q(1+bf)
]
Expanding:
[
pb-pbf = q+qbf
]
Collecting the terms containing (f):
[
pb-q = bf(p+q)
]
Because (p+q=1):
[
f^* = pb-q
]
Since (q=1-p):
[
f^* = pb-(1-p)
]
The standard form is:
[
f^* = p-\frac{q}{b}
]
For the example:
[
f^* = 0.60-\frac{0.40}{2}
]
[
f^* = 0.60-0.20 = 0.40
]
Therefore, full Kelly sizing would risk:
[
f = 40%
]
of the current bankroll on each trade.
For a $100,000 account, that means a $40,000 risk amount. The resulting outcomes would be:
| Outcome | Kelly stake | Win amount | Loss amount |
|---|---|---|---|
| Win | $40,000 | +$80,000 | — |
| Loss | $40,000 | — | −$40,000 |
This is the raw mathematical answer to the topic question.
However, it is not yet a complete risk-management decision.
4. Why 40% Feels Aggressive
Kelly assumes that the trader knows the win probability and payoff ratio accurately, that the bets are repeatable, and that capital can be continuously redeployed. Real trading rarely satisfies all these assumptions perfectly.
The most important weakness is estimation error.
Suppose the measured win rate is 60%, but the true win rate could be 55% or 50%. Full Kelly based on the measured value may produce a much larger position than the strategy can support.
Consider three estimates of the same strategy:
| Assumed win rate | Payoff ratio | Full Kelly | Risk on $100,000 |
|---|---|---|---|
| 50% | 2:1 | 0% | $0 |
| 55% | 2:1 | 35% | $35,000 |
| 60% | 2:1 | 40% | $40,000 |
The change from 55% to 60% appears small, but it increases the Kelly stake by five percentage points.
The correct response is not to abandon Kelly mathematics. It is to distinguish between:
- The mathematically optimal fraction under specified assumptions.
- The fraction that is appropriate under parameter uncertainty.
- The fraction that fits the trader’s drawdown tolerance and operational constraints.
5. Fractional Kelly
Fractional Kelly scales the full-Kelly result by a multiplier (k):
[
f_{\text{actual}} = k f^*
]
The multiplier is usually chosen from the range 0 to 1.
For the example:
[
f^* = 40%
]
The resulting position sizes are:
| Kelly multiplier | Fraction risked | Risk on $100,000 |
|---|---|---|
| 0.25 | 10% | $10,000 |
| 0.50 | 20% | $20,000 |
| 0.75 | 30% | $30,000 |
| 1.00 | 40% | $40,000 |
Half Kelly would therefore risk 20% of the account per trade:
[
f_{\text{actual}} = 0.5 \times 0.40 = 0.20
]
Fractional Kelly is not mathematically optimal if the estimated parameters are perfectly accurate. Its purpose is to reduce the damage caused by:
- Overestimated win rates.
- Underestimated loss tails.
- Incorrect payoff assumptions.
- Correlation between trades.
- Gap risk and execution slippage.
- Regime changes.
- Emotional interference with a system that otherwise works.
A reasonable implementation often uses a conservative estimate of both edge components rather than applying an arbitrary haircut after the fact. For example:
[
p_{\text{conservative}} = 0.55
]
[
b_{\text{conservative}} = 1.8
]
Then:
[
f^*_{\text{conservative}}
=0.55-\frac{0.45}{1.8}
=0.55-0.25
=0.30
]
Applying half Kelly to that conservative estimate produces:
[
f_{\text{actual}} = 0.5 \times 0.30 = 0.15
]
This approach reduces the risk of using an overconfident parameter set.
6. Growth Versus Drawdown
The arithmetic expected return of a binary strategy is:
[
E[R] = pb f-qf
]
For (p=0.60), (b=2), and (q=0.40):
[
E[R] = (0.60 \times 2 - 0.40)f = 0.80f
]
The expected logarithmic growth rate is different:
| Fraction risked | Expected arithmetic return per trade | Expected log growth |
|---|---|---|
| 5% | 4.0% | 3.66% |
| 10% | 8.0% | 3.10% |
| 20% | 16.0% | 12.06% |
| 25% | 20.0% | 12.82% |
| 40% | 32.0% | 14.84% |
| 50% | 40.0% | 14.38% |
At 50% Kelly sizing, expected log growth begins to decline because the account is exposed to increasingly severe drawdowns.
For example, a 50% loss reduces the bankroll by half. Recovering from that loss requires a 100% gain. A sufficiently large sequence of losses can permanently impair the compounding process even if the average trade remains profitable.
This is why full Kelly often produces a steeper historical equity curve than fractional Kelly. It also explains why the full-Kelly result can be mathematically attractive while being operationally difficult to hold.
A useful practical distinction is:
- Kelly answers: How much can I risk if the edge is real and stable?
- Risk management answers: How much can I risk if the edge is uncertain, execution is imperfect, and I must continue trading?
7. A Runnable Kelly Calculator
The following Python implementation validates inputs, computes full and fractional Kelly, and runs a reproducible Monte Carlo simulation.
It uses only the Python standard library and treats each trade as an independent binary outcome. The simulation is illustrative, not a substitute for testing the strategy’s actual trade sequence.
from __future__ import annotations
import argparse
import math
import random
from dataclasses import dataclass
@dataclass(frozen=True)
class KellyPlan:
win_probability: float
payoff_ratio: float
edge: float
full_kelly: float
fractional_kelly: float
risk_fraction: float
win_multiplier: float
loss_multiplier: float
@property
def expected_log_growth(self) -> float:
return (
self.win_probability * math.log(self.win_multiplier)
+ (1.0 - self.win_probability) * math.log(self.loss_multiplier)
)
def build_kelly_plan(
win_probability: float,
payoff_ratio: float,
kelly_multiplier: float = 0.5,
) -> KellyPlan:
"""Calculate a validated Kelly position-sizing plan.
payoff_ratio is net profit divided by net loss.
kelly_multiplier must be between 0 and 1.
"""
if not 0.0 < win_probability < 1.0:
raise ValueError("win_probability must be strictly between 0 and 1")
if payoff_ratio <= 0.0:
raise ValueError("payoff_ratio must be positive")
if not 0.0 <= kelly_multiplier <= 1.0:
raise ValueError("kelly_multiplier must be between 0 and 1")
loss_probability = 1.0 - win_probability
edge = win_probability * payoff_ratio - loss_probability
if edge <= 0.0:
full_kelly = 0.0
else:
full_kelly = edge / payoff_ratio
risk_fraction = full_kelly * kelly_multiplier
return KellyPlan(
win_probability=win_probability,
payoff_ratio=payoff_ratio,
edge=edge,
full_kelly=full_kelly,
fractional_kelly=risk_fraction,
risk_fraction=risk_fraction,
win_multiplier=1.0 + payoff_ratio * risk_fraction,
loss_multiplier=1.0 - risk_fraction,
)
def simulate_wealth(
plan: KellyPlan,
initial_bankroll: float,
number_of_trades: int,
seed: int = 7,
) -> dict[str, float | int]:
"""Simulate independent trades using a fixed random seed."""
if initial_bankroll <= 0.0:
raise ValueError("initial_bankroll must be positive")
if number_of_trades <= 0:
raise ValueError("number_of_trades must be positive")
rng = random.Random(seed)
bankroll = initial_bankroll
peak = bankroll
max_drawdown = 0.0
for _ in range(number_of_trades):
if rng.random() < plan.win_probability:
bankroll *= plan.win_multiplier
else:
bankroll *= plan.loss_multiplier
peak = max(peak, bankroll)
drawdown = 1.0 - bankroll / peak
max_drawdown = max(max_drawdown, drawdown)
return {
"final_bankroll": bankroll,
"total_return": bankroll / initial_bankroll - 1.0,
"max_drawdown": max_drawdown,
"number_of_trades": number_of_trades,
}
def main() -> None:
parser = argparse.ArgumentParser(
description="Calculate and simulate fractional Kelly position sizing."
)
parser.add_argument("--win-probability", type=float, default=0.60)
parser.add_argument("--payoff-ratio", type=float, default=2.0)
parser.add_argument("--kelly-multiplier", type=float, default=0.50)
parser.add_argument("--bankroll", type=float, default=100_000.0)
parser.add_argument("--trades", type=int, default=1_000)
parser.add_argument("--seed", type=int, default=7)
args = parser.parse_args()
plan = build_kelly_plan(
win_probability=args.win_probability,
payoff_ratio=args.payoff_ratio,
kelly_multiplier=args.kelly_multiplier,
)
simulation = simulate_wealth(
plan=plan,
initial_bankroll=args.bankroll,
number_of_trades=args.trades,
seed=args.seed,
)
print(f"Full Kelly: {plan.full_kelly:.2%}")
print(f"Fractional Kelly: {plan.risk_fraction:.2%}")
print(f"Expected log growth: {plan.expected_log_growth:.4%}")
print(f"Final bankroll: ${simulation['final_bankroll']:,.2f}")
print(f"Total return: {simulation['total_return']:.2%}")
print(f"Maximum drawdown: {simulation['max_drawdown']:.2%}")
if __name__ == "__main__":
main()
Running the script with the default parameters produces a 40% full-Kelly fraction and a 20% half-Kelly risk fraction:
python kelly_plan.py \
--win-probability 0.60 \
--payoff-ratio 2.0 \
--kelly-multiplier 0.50 \
--bankroll 100000 \
--trades 1000 \
--seed 7
The exact simulation output depends on the random seed and should not be interpreted as a performance claim. Its purpose is to make the consequences of a position-size rule visible.
8. Adding Parameter Uncertainty
A production system should not treat a single estimated win rate as exact. One simple sensitivity method is to sample the win rate and payoff ratio from plausible ranges.
from statistics import mean
def conservative_kelly_plan(
win_probability_low: float,
win_probability_high: float,
payoff_ratio_low: float,
payoff_ratio_high: float,
kelly_multiplier: float = 0.5,
simulations: int = 10_000,
seed: int = 11,
) -> dict[str, float]:
"""Estimate a Kelly fraction over uncertain strategy parameters."""
if simulations <= 0:
raise ValueError("simulations must be positive")
if not 0.0 < win_probability_low < win_probability_high < 1.0:
raise ValueError("invalid win probability range")
if payoff_ratio_low <= 0.0 or payoff_ratio_high < payoff_ratio_low:
raise ValueError("invalid payoff ratio range")
rng = random.Random(seed)
fractions: list[float] = []
for _ in range(simulations):
probability = rng.uniform(win_probability_low, win_probability_high)
payoff = rng.uniform(payoff_ratio_low, payoff_ratio_high)
plan = build_kelly_plan(
win_probability=probability,
payoff_ratio=payoff,
kelly_multiplier=kelly_multiplier,
)
fractions.append(plan.risk_fraction)
return {
"mean_fraction": mean(fractions),
"minimum_fraction": min(fractions),
"maximum_fraction": max(fractions),
"simulations": float(simulations),
}
This does not prove that the uncertainty ranges are correct. It only prevents the calculation from implicitly assuming that the point estimate is exact.
A stronger approach combines:
- Out-of-sample trade results.
- Confidence intervals for the win rate.
- Slippage-adjusted loss estimates.
- Tail-loss analysis.
- Regime-based parameter estimates.
- Explicit caps based on maximum acceptable drawdown.
9. Kelly Does Not Apply Directly to Every Portfolio
The simple formula assumes that each trade is a binary, repeatable opportunity with the same probability and payoff ratio.
That assumption becomes problematic when positions are correlated. If ten trades all depend on the same market factor, they may look like ten independent bets in a spreadsheet while behaving like one concentrated bet.
For multiple assets, the general portfolio-growth problem is expressed as:
[
\mathbf{w}^* = \Sigma^{-1}\mu
]
subject to portfolio constraints, where:
- (\mathbf{w}) is the vector of position weights.
- (\mu) is the vector of expected excess returns.
- (\Sigma) is the covariance matrix of returns.
The scalar Kelly formula is therefore not a general portfolio construction rule. It is a special case for a single binary payoff structure.
The practical lesson remains useful: estimate the edge, measure covariance, and avoid treating a collection of correlated trades as independent diversification.
10. Common Mistakes
Mistake 1: Using Arithmetic Expected Return Instead of Log Growth
A strategy with a high expected percentage return can still experience ruin if its loss distribution is too severe. Kelly’s use of logarithmic growth reflects this compounding constraint.
Mistake 2: Confusing Gross and Net Payoff
If a trade wins $2 for every $1 risked and loses $1, the net profit-to-loss ratio is 2:1. If the contract returns $3 in total, the net ratio is 2:1. State which convention the code uses.
Mistake 3: Treating the Estimated Win Rate as Exact
A point estimate is not a parameter guarantee. Use conservative values, uncertainty ranges, and drawdown limits.
Mistake 4: Ignoring Execution Costs
Commissions, spread, slippage, and market impact reduce the realized payoff ratio. If the average win becomes $1.90 after costs while the average loss becomes $1.10, the effective ratio is approximately 1.73 rather than 2.00.
Mistake 5: Forgetting Correlation
Ten positions with similar exposure do not provide ten independent opportunities.
Mistake 6: Using Kelly as a Reason to Remove Risk Limits
Kelly is a sizing method, not a complete operating system. It does not replace stop rules, exposure limits, liquidity checks, execution safeguards, or a plan for discontinuous losses.
11. A Practical Decision Procedure
A disciplined implementation can use the following sequence:
- Define the payoff ratio net of expected costs.
- Estimate the win rate from out-of-sample or live data.
- Apply a conservative adjustment for estimation uncertainty.
- Calculate the full-Kelly fraction.
- Apply a fractional-Kelly multiplier.
- Cap the result by maximum account drawdown and concentration limits.
- Recalculate when the strategy’s statistics change materially.
- Monitor realized outcomes rather than changing the rule after every trade.
For the motivating example, the calculation is:
[
f^* = 0.60-\frac{0.40}{2}=0.40
]
A half-Kelly implementation would use:
[
f = 0.50 \times 0.40=0.20
]
That means risking 20% of the bankroll per trade under the stated assumptions, subject to additional operational caps.
The answer is not “always risk 20%.” The answer is:
The mathematical full-Kelly estimate is 40%. Fractional Kelly converts that estimate into a more survivable risk budget, while conservative parameters and portfolio constraints determine whether the final size should be lower.
Next Steps
Implement the calculator with the exact net payoff definition used by your strategy. Test it against historical trades, including spread, commission, slippage, and gap losses. Compare full Kelly with 0.5-Kelly and 0.25-Kelly across different win-rate estimates, then choose a rule that remains acceptable during prolonged losing streaks.
Track the realized win rate, average win, average loss, maximum drawdown, and recovery time. If the strategy’s statistics change, revisit the assumptions rather than changing the position size emotionally.
This article does not constitute investment advice. Markets involve risk; past performance does not guarantee future results.