Kelly Criterion in Python: Calculate a Bankroll Fraction with Keeks¶
Quick answer¶
Given a win probability, a payoff multiplier, a loss multiplier, and a
normalized transaction cost, Keeks’ KellyCriterion.evaluate() returns the
fraction of the current bankroll to stake on a repeated binary bet:
from keeks.binary_strategies import KellyCriterion
bankroll = 1_000.0
strategy = KellyCriterion(
payoff=1.0,
loss=1.0,
transaction_cost_rate=0.01,
)
fraction = strategy.evaluate(probability=0.55, current_bankroll=bankroll)
print(f"Bankroll fraction: {fraction:.4%}")
Bankroll fraction: 9.0009%
This is a repeated-bet answer, not a one-time price. See Different problem: price a one-time gamble below if that is what you need.
Install Keeks¶
pip install keeks
Keeks supports Python 3.10 through 3.14.
Run the smallest complete example¶
from keeks.binary_strategies import KellyCriterion
bankroll = 1_000.0
strategy = KellyCriterion(
payoff=1.0,
loss=1.0,
transaction_cost_rate=0.01,
)
fraction = strategy.evaluate(probability=0.55, current_bankroll=bankroll)
amount = bankroll * fraction
print(f"Bankroll fraction: {fraction:.4%}")
print(f"Amount from a $1,000 bankroll: ${amount:.2f}")
Bankroll fraction: 9.0009%
Amount from a $1,000 bankroll: $90.01
Read the result¶
evaluate() returns a fraction of the bankroll, not a currency amount. The
example above multiplies that fraction by the current bankroll only to make
the result concrete — the fraction itself is what you should carry into a
simulation or your own accounting.
How Keeks handles payoff, loss, and cost¶
Keeks calculates:
p / (loss + cost) - (1 - p) / (payoff - cost)
where p is the win probability, payoff and loss are the
per-unit multipliers for a win and a loss, and cost is
transaction_cost_rate. The cost is added to the loss side and subtracted from
the payoff side before the ratio is taken, so it makes both a win pay a
little less and a loss cost a little more.
transaction_cost_rate is Keeks’ normalized, per-unit fractional model input —
not a synonym for a broker commission, a bid-ask spread, or slippage. It does
not model market impact, venue-specific fees, correlated positions, or
portfolio rebalancing. It is also not the same quantity as the keeks.simulators
classes’ fee_per_bet (plural): that one is a flat, absolute
bankroll amount charged once per settled bet, independent of stake size.
Passing the same number to both does not mean the same real-world cost, and
Keeks does not convert between them.
Why the result can be zero or capped¶
The raw formula above can be negative, and a raw fraction can also exceed
what the bankroll can safely support. KellyCriterion.evaluate() applies
two adjustments after the formula:
Zero floor. If the win probability is below the strategy’s
min_probability, or if the cost-adjusted payoff or loss is not positive, the strategy returns0.0rather than a negative or undefined fraction.min_probabilitydefaults toNone— the gate is edge-aware, so any bet the Kelly formula itself prices positively is placed. Setting an explicitmin_probabilityrefuses below-gate bets and emits aUserWarningnaming the suppressed fraction whenever the gate zeroes a bet the formula would size.Maximum-safe-bet clamp. The result is capped at
get_max_safe_bet(current_bankroll), the largest stake that cannot drive the bankroll negative givenlossandtransaction_cost_rate. A non-positive bankroll has no safe stake at all, so the clamp returns0.0in that case too.
Neither adjustment prevents a real loss on a given bet — they only keep the sizing from allocating more than the model can support.
Try fractional Kelly¶
Full Kelly is one specific scaling choice. If you want to bet a fraction of what full Kelly would allocate, see Full Kelly vs Fractional Kelly in Python for a side-by-side comparison with runnable code.
Different problem: price a one-time gamble¶
Everything above answers a repeated-bet question: given this binary model,
what fraction of the current bankroll should this rule allocate now? A
different question — what is the maximum price you would pay to enter a
single, one-time gamble with known outcomes and probabilities — is answered
by Utilities’s find_indifference_price() and the
calculate_max_entry_price() method that utility-based strategies
support. Do not blend the two: a bet-sizing fraction is not an entry price.
Limits and disclaimer¶
This page models a known win probability and a single binary outcome per bet. It does not model execution venues, order books, correlated positions, or promise investment performance. Keeks is an educational library; treat every number above as a property of the model, not a forecast.
Next steps¶
Getting Started — installation and the full bankroll/simulator flow.
Binary Strategies — constructor and method details for every strategy.
Bankroll —
bettable_funds, history, and drawdown protection.Utilities — one-time CRRA indifference pricing.
Full Kelly vs Fractional Kelly in Python — compare full Kelly against half and quarter Kelly with identical inputs.