In 1956, a Bell Labs scientist named John Larry Kelly Jr. published a single-page paper in the Bell System Technical Journal. His problem was deceptively simple: if you know the odds of a bet and the payout ratio, what fraction of your bankroll should you wager to maximize long-term growth? The answer he derived — now known universally as the Kelly Criterion — would go on to underpin everything from blackjack card counting to Black-Scholes options pricing to modern hedge fund portfolio construction.

Fifty-eight years later, a quant trader sits at a Bloomberg terminal, staring at a strategy that wins 60% of the time and delivers a 2:1 reward-to-risk ratio. The question is the same one Kelly faced: how much should I bet? This article derives the Kelly formula from first principles, applies it to this specific scenario, explores the critical gap between theory and practice, and provides production-grade Python code for systematic implementation.


1. Why "Bet It All" Is Never Optimal

Before diving into the math, it is worth understanding why naive intuition fails on this problem.

Consider three strategies for a +EV (positive expected value) bet:

Strategy Fraction Bet (f) Outcome if Win Outcome if Loss Expected Growth
Conservative 10% +0.2 units −0.1 units +2.1% per round
Kelly ~27% +0.54 units −0.27 units +5.8% per round
Aggressive 50% +1.0 units −0.5 units +1.2% per round
All-in 100% +2.0 units −1.0 units 0% per round

The all-in strategy, despite being +EV, yields zero long-term growth in expectation — because a single loss wipes out the entire bankroll. The Kelly fraction sits at the maximum of the growth function. The aggressive 50% bet grows more slowly than Kelly because variance compounds against you faster than edge compounds for you.

This asymmetry is the core insight: optimal bet sizing maximizes geometric mean returns, not arithmetic mean returns. The difference is critical. Arithmetic mean tells you average outcome; geometric mean tells you actual compounded growth over time.


2. Deriving the Kelly Criterion from First Principles

2.1 The Setup

Define the problem precisely:

  • $f$ = fraction of bankroll wagered (the quantity we want to solve for)
  • $b$ = net payout ratio (profit / risk), e.g., $b = 2$ means you win 2 units for every 1 unit risked
  • $p$ = probability of winning (e.g., $p = 0.60$)
  • $q = 1 - p$ = probability of losing

If you bet a fraction $f$ of your bankroll $B$, then:

  • Win outcome: Bankroll becomes $B(1 + bf)$
  • Lose outcome: Bankroll becomes $B(1 - f)$

2.2 Expected Growth Rate

After $N$ bets, if you win $W$ times and lose $L$ times ($W + L = N$), your bankroll is:

$$B_N = B_0 \cdot (1 + bf)^W \cdot (1 - f)^L$$

Taking the $N$th root to get the growth rate per bet:

$$G(f) = [(1 + bf)^p \cdot (1 - f)^q]^{1/N}$$

This is the geometric mean of the two outcomes. Maximizing $G(f)$ is equivalent to maximizing its logarithm, which is easier to differentiate:

$$\ln G(f) = p \ln(1 + bf) + q \ln(1 - f)$$

2.3 First-Order Condition

Take the derivative and set it to zero:

$$\frac{d}{df} \ln G(f) = \frac{bp}{1 + bf} - \frac{q}{1 - f} = 0$$

Cross-multiply:

$$bp(1 - f) = q(1 + bf)$$

$$bp - bpf = q + qbf$$

$$bp - q = f(bp + qb)$$

$$f^* = \frac{bp - q}{bp + qb} = \frac{bp - (1-p)}{bp + b(1-p)} = \frac{bp - q}{b(p + q)} = \frac{bp - q}{b}$$

The Kelly formula:

$$f^* = \frac{bp - q}{b}$$

Equivalently, using $q = 1 - p$:

$$f^* = p - \frac{q}{b}$$

2.4 Special Case: Even Odds ($b = 1$)

When the payout is 1:1 (you win as much as you risk), the formula simplifies to the classic Kelly fraction:

$$f^* = 2p - 1$$

This is often called the "edge over even" formula — you bet twice your edge. If $p = 0.55$ (55% win rate), you bet $f^* = 2(0.55) - 1 = 0.10$, or 10% of bankroll.


3. Applying Kelly to Our 60% / 2:1 Strategy

3.1 Numerical Calculation

For our specific example:

  • $p = 0.60$
  • $q = 0.40$
  • $b = 2$ (2:1 reward-to-risk ratio)

Plug into the formula:

$$f^* = \frac{(2)(0.60) - 0.40}{2} = \frac{1.20 - 0.40}{2} = \frac{0.80}{2} = 0.40$$

The Kelly fraction is 40%. This means for a $100,000 account, the optimal single-trade risk is $40,000 — not $10,000, and certainly not $100,000.

3.2 Verification via Growth Rate Calculation

To confirm, compute the expected growth rate at $f = 0.40$:

$$G(0.40) = (1 + 2 \cdot 0.40)^{0.60} \cdot (1 - 0.40)^{0.40}$$

$$G(0.40) = (1.80)^{0.60} \cdot (0.60)^{0.40}$$

$$\ln G(0.40) = 0.60 \ln(1.80) + 0.40 \ln(0.60)$$

$$\ln G(0.40) = 0.60 \times 0.5878 + 0.40 \times (-0.5108)$$

$$\ln G(0.40) = 0.3527 - 0.2043 = 0.1484$$

$$G(0.40) = e^{0.1484} \approx 1.160$$

This means each bet, on average, multiplies your bankroll by a factor of 1.16 — a 16% growth rate per round. To put this in perspective: starting with $100,000, after 100 identical independent bets:

$$B_{100} = 100{,}000 \cdot (1.16)^{100} \approx $21.6 \text{ million}$$

The geometric compounding is explosive.

3.3 Growth Rate as a Function of $f$

The relationship between $f$ and $G(f)$ is concave — it rises to a maximum at $f^*$ and then declines:

Fraction ($f$) Growth Rate $G(f) - 1$ Interpretation
0.05 +2.1% Suboptimal — leaving money on the table
0.15 +8.2%
0.25 +13.1%
0.40 +16.0% Kelly optimum
0.55 +14.7% Diminishing returns, variance rising
0.70 +10.2% Volatility erodes gains
1.00 0.0% Break-even despite +EV — no compounding

The steepness of the curve near $f^*$ reveals an important practical fact: small deviations from Kelly are not catastrophic. A 20% Kelly (half-Kelly) reduces the growth rate from 16.0% to roughly 9.2% — worse, but not ruinous. This provides justification for the fractional Kelly approaches discussed later.


4. The Kelly Paradox: Why Full Kelly Is Dangerous in Practice

4.1 The Estimation Problem

Kelly assumes you know $p$ and $b$ with perfect accuracy. In trading, you estimate them from historical data — and estimates are always wrong.

Suppose your true win rate is 58%, not 60%. Running the calculation:

$$f^* = \frac{2(0.58) - 0.42}{2} = \frac{1.16 - 0.42}{2} = 0.37$$

A 2% error in win rate estimation produces a 3% error in optimal Kelly fraction. Now consider the tail risk: if your actual win rate is 52% (still plausible given estimation noise), Kelly tells you to bet 4% of bankroll — a dramatically different outcome than 40%.

The Kelly formula amplifies estimation error. The more aggressive your Kelly fraction, the more sensitive your outcomes are to $p$ and $b$ estimation errors.

4.2 The Volatility Problem

Kelly maximizes long-run geometric growth. But "long-run" can require thousands of bets. In the short run, high Kelly fractions produce enormous variance:

Kelly Fraction Expected Return per Bet Standard Deviation Sharpe-like Ratio
10% +2.1% ±4.6% 0.46
40% +16.0% ±32.0% 0.50
80% +24.8% ±88.0% 0.28

At 40% Kelly, you are accepting a standard deviation that is twice your expected return. In practice, this means drawdowns of 40–60% are expected outcomes, not worst-case scenarios. A trader who cannot stomach a 50% drawdown cannot use full Kelly — even if the math says they should.

4.3 The Regime Change Problem

Markets are non-stationary. A strategy with $p = 0.60$ and $b = 2$ over a 5-year backtest may reflect a regime (e.g., a trending market) that will not persist. If the regime shifts and $p$ drops to 0.48, the Kelly formula yields a negative fraction — it tells you to not trade at all. But if you have been betting 40% of bankroll based on stale estimates, you will face catastrophic losses.


5. Fractional Kelly: Bridging Theory and Practice

5.1 Why Fractional?

Rather than bet the full Kelly fraction, practitioners commonly bet half-Kelly, quarter-Kelly, or an arbitrary fraction calibrated to their risk tolerance. Fractional Kelly reduces both expected growth and variance — but it dramatically reduces the probability of catastrophic drawdown.

The key insight: fractional Kelly achieves roughly 75% of the growth of full Kelly with less than 50% of the variance. The variance reduction is disproportionate to the growth reduction — a highly favorable trade-off for most traders.

Fraction Growth Rate Variance Growth-to-Variance Ratio
Full Kelly (1.0x) +16.0% +32.0% 0.50
Half Kelly (0.5x) +9.2% +16.0% 0.58
Quarter Kelly (0.25x) +5.1% +8.0% 0.64

5.2 Choosing Your Fraction

Selecting a Kelly fraction is not purely mathematical — it is a function of three factors:

  1. Confidence in estimates: Higher confidence → closer to full Kelly.
  2. Drawdown tolerance: Lower tolerance → lower fraction.
  3. Position count: A strategy that runs 20 concurrent positions should use lower per-position Kelly than a strategy with one position at a time.

A practical starting point is half-Kelly, which provides a reasonable balance between growth and drawdown protection. For high-frequency strategies with high position counts, quarter-Kelly or lower may be appropriate.


6. Multi-Position Kelly: The Continuous Case

6.1 Simultaneous Bets

The single-bet Kelly formula assumes bets are independent and sequential. When you have multiple simultaneous bets (e.g., a portfolio of 20 stocks), the math becomes a portfolio optimization problem.

For a portfolio of $n$ independent bets, the Kelly fraction for each position must be scaled such that the sum of all fractions does not exceed 1 (or some target portfolio leverage $L$):

$$\sum_{i=1}^{n} f_i \leq L$$

If all bets share the same $p$ and $b$, the Kelly algorithm allocates equally:

$$f_i = \frac{L}{n}$$

For a portfolio with 20 positions and target leverage $L = 1.0$ (no leverage), each position receives $f_i = 5%$ Kelly. For a 2x leveraged portfolio ($L = 2.0$), each position receives $f_i = 10%$.

6.2 Correlated Bets

Real portfolios have correlations. Two positions in the same sector are not independent — a sector-wide shock hits both simultaneously. The full Kelly treatment for correlated assets requires the covariance matrix $\Sigma$:

$$\mathbf{f}^* = \Sigma^{-1} \mathbf{\mu}$$

Where $\mathbf{\mu}$ is the vector of expected returns (in Kelly units: $bp_i - q_i$) and $\Sigma^{-1}$ is the precision matrix. This is equivalent to the mean-variance optimization of Markowitz, but maximizing geometric rather than arithmetic mean.

For most systematic traders, the complexity of full covariance-based Kelly is unnecessary. A simpler approximation — reducing the Kelly fraction by the square root of the average pairwise correlation — is often sufficient:

$$f_{\text{correlated}} = \frac{f_{\text{independent}}}{\sqrt{1 + \rho_{\text{avg}} \cdot (n - 1)}}$$


7. Production-Grade Python Implementation

7.1 Core Kelly Functions

"""
TickDB Knowledge Base: Kelly Criterion Implementation
Provides production-grade position sizing for systematic trading strategies.
Supports single-bet Kelly, fractional Kelly, and multi-position Kelly.
"""

import numpy as np
from typing import Optional, Union


def single_kelly_fraction(win_rate: float, reward_risk_ratio: float) -> float:
    """
    Calculate the full Kelly fraction for a single bet.
    
    Parameters
    ----------
    win_rate : float
        Probability of winning (p), must be in (0, 1).
    reward_risk_ratio : float
        Net payout ratio (b), defined as profit / risk.
        Example: b=2 means you win 2 units for every 1 unit risked.
    
    Returns
    -------
    float
        Optimal Kelly fraction (f*) in (0, 1).
        Returns 0.0 if the bet is negative expected value.
    
    Raises
    ------
    ValueError
        If win_rate is not in (0, 1) or reward_risk_ratio <= 0.
    
    Example
    -------
    >>> single_kelly_fraction(0.60, 2.0)
    0.40
    """
    if not 0 < win_rate < 1:
        raise ValueError(f"win_rate must be in (0, 1), got {win_rate}")
    if reward_risk_ratio <= 0:
        raise ValueError(f"reward_risk_ratio must be positive, got {reward_risk_ratio}")
    
    loss_rate = 1.0 - win_rate
    
    # Kelly formula: f* = (bp - q) / b
    kelly = (reward_risk_ratio * win_rate - loss_rate) / reward_risk_ratio
    
    # Return 0 for negative EV bets (Kelly tells you not to bet)
    return max(0.0, kelly)


def expected_growth_rate(
    kelly_fraction: float,
    win_rate: float,
    reward_risk_ratio: float
) -> float:
    """
    Calculate the expected geometric growth rate for a given Kelly fraction.
    
    Returns
    -------
    float
        Growth rate G(f) - 1, expressed as a decimal.
        e.g., 0.16 means 16% expected growth per bet.
    
    Note
    ----
    For small f or large N, the arithmetic approximation:
    E[G] ≈ p*ln(1 + b*f) + q*ln(1 - f)
    is used to avoid numerical underflow in extreme cases.
    """
    if kelly_fraction <= 0:
        return 0.0
    
    loss_rate = 1.0 - win_rate
    growth_rate = (
        win_rate * np.log(1 + reward_risk_ratio * kelly_fraction) +
        loss_rate * np.log(1 - kelly_fraction)
    )
    
    return np.exp(growth_rate) - 1.0


def fractional_kelly(
    win_rate: float,
    reward_risk_ratio: float,
    fraction: float = 0.5
) -> float:
    """
    Calculate a fractional Kelly position size.
    
    Parameters
    ----------
    win_rate : float
        Estimated win rate (p).
    reward_risk_ratio : float
        Reward-to-risk ratio (b).
    fraction : float, optional
        Fraction of full Kelly to use. Default is 0.5 (half-Kelly).
        Common values: 0.25 (quarter), 0.5 (half), 0.75 (three-quarters).
    
    Returns
    -------
    float
        Adjusted Kelly fraction.
    """
    full_kelly = single_kelly_fraction(win_rate, reward_risk_ratio)
    return full_kelly * fraction


def multi_position_kelly(
    n_positions: int,
    target_leverage: float = 1.0,
    kelly_fraction: float = 0.5
) -> float:
    """
    Calculate per-position Kelly allocation for a portfolio of simultaneous bets.
    
    Parameters
    ----------
    n_positions : int
        Number of concurrent positions.
    target_leverage : float, optional
        Total portfolio leverage. 1.0 = no leverage, 2.0 = 2x leverage.
        Default is 1.0.
    kelly_fraction : float, optional
        Fraction of full Kelly to apply. Default is 0.5 (half-Kelly).
    
    Returns
    -------
    float
        Kelly fraction for each individual position.
    
    Example
    -------
    >>> multi_position_kelly(n_positions=20, target_leverage=1.0, kelly_fraction=0.5)
    0.025  # Each of 20 positions gets 2.5% Kelly risk
    """
    if n_positions <= 0:
        raise ValueError(f"n_positions must be positive, got {n_positions}")
    
    # Full Kelly per position (assuming equal allocation)
    per_position_full = target_leverage / n_positions
    
    # Apply fractional Kelly
    return per_position_full * kelly_fraction

7.2 Position Size Calculator with Risk Management

from dataclasses import dataclass
from typing import List, Dict


@dataclass
class PositionSpec:
    """Specification for a single position."""
    symbol: str
    entry_price: float
    stop_loss_price: float
    win_rate: float
    reward_risk_ratio: float


@dataclass
class PositionSizeResult:
    """Result of position sizing calculation."""
    symbol: str
    kelly_fraction: float
    risk_amount: float
    position_value: float
    shares: int
    units_to_risk: float  # in account currency


def calculate_position_size(
    account_balance: float,
    spec: PositionSpec,
    kelly_fraction: float = 0.5,
    max_position_pct: float = 0.20
) -> PositionSizeResult:
    """
    Calculate position size based on Kelly Criterion with safeguards.
    
    Parameters
    ----------
    account_balance : float
        Total account equity.
    spec : PositionSpec
        Position specification including entry, stop, win rate, R/R.
    kelly_fraction : float, optional
        Fraction of full Kelly. Default 0.5.
    max_position_pct : float, optional
        Maximum position size as a fraction of account. Default 20%.
        Prevents over-concentration in single positions.
    
    Returns
    -------
    PositionSizeResult
        Calculated position size with dollar risk and share count.
    
    Engineering Notes
    -----------------
    - Uses ceiling division for share counts to ensure stop loss is hit exactly.
    - Enforces maximum position cap to prevent catastrophic single-trade losses.
    - Converts Kelly fraction to dollar risk based on stop-loss distance.
    """
    # Calculate full Kelly
    full_kelly = single_kelly_fraction(spec.win_rate, spec.reward_risk_ratio)
    
    # Apply fractional Kelly
    effective_kelly = full_kelly * kelly_fraction
    
    # Enforce maximum position cap
    effective_kelly = min(effective_kelly, max_position_pct)
    
    # Calculate risk amount
    risk_amount = account_balance * effective_kelly
    
    # Calculate distance to stop loss (risk per share)
    risk_per_share = abs(spec.entry_price - spec.stop_loss_price)
    
    if risk_per_share == 0:
        raise ValueError(f"Stop loss is identical to entry for {spec.symbol}")
    
    # Calculate position value and shares
    position_value = (risk_amount / risk_per_share) * spec.entry_price
    shares = int(risk_amount / risk_per_share)  # Round down to hit exact risk
    
    return PositionSizeResult(
        symbol=spec.symbol,
        kelly_fraction=effective_kelly,
        risk_amount=risk_amount,
        position_value=position_value,
        shares=shares,
        units_to_risk=risk_amount
    )


def portfolio_position_sizes(
    account_balance: float,
    positions: List[PositionSpec],
    kelly_fraction: float = 0.5,
    max_total_exposure: float = 1.0
) -> List[PositionSizeResult]:
    """
    Size multiple positions, ensuring total exposure does not exceed target.
    
    Parameters
    ----------
    account_balance : float
        Total account equity.
    positions : List[PositionSpec]
        List of position specifications.
    kelly_fraction : float, optional
        Fraction of full Kelly. Default 0.5.
    max_total_exposure : float, optional
        Maximum total portfolio exposure (0.0 to 1.0 for no leverage).
        Default 1.0.
    
    Returns
    -------
    List[PositionSizeResult]
        Sized positions, possibly scaled down to respect total exposure limit.
    """
    if not positions:
        return []
    
    # First pass: calculate raw Kelly sizes
    raw_sizes = [
        calculate_position_size(account_balance, p, kelly_fraction)
        for p in positions
    ]
    
    # Calculate total exposure
    total_exposure = sum(s.position_value for s in raw_sizes) / account_balance
    
    # Scale down if total exposure exceeds target
    if total_exposure > max_total_exposure:
        scale_factor = max_total_exposure / total_exposure
        for result in raw_sizes:
            result.position_value *= scale_factor
            result.shares = int(result.risk_amount / 
                               abs(positions[raw_sizes.index(result)].entry_price - 
                                   positions[raw_sizes.index(result)].stop_loss_price))
    
    return raw_sizes

7.3 Usage Example

if __name__ == "__main__":
    # Example: 60% win rate, 2:1 reward-to-risk strategy
    win_rate = 0.60
    reward_risk_ratio = 2.0
    
    # Calculate full Kelly
    full_kelly = single_kelly_fraction(win_rate, reward_risk_ratio)
    print(f"Full Kelly fraction: {full_kelly:.2%}")
    # Output: Full Kelly fraction: 40.00%
    
    # Calculate expected growth
    growth = expected_growth_rate(full_kelly, win_rate, reward_risk_ratio)
    print(f"Expected growth per bet: {growth:.2%}")
    # Output: Expected growth per bet: 16.00%
    
    # Compare fractional Kelly strategies
    for frac in [0.25, 0.50, 0.75, 1.0]:
        adj_kelly = full_kelly * frac
        growth = expected_growth_rate(adj_kelly, win_rate, reward_risk_ratio)
        print(f"  {frac:.0%} Kelly ({adj_kelly:.2%}): {growth:.2%} growth")
    
    # Size a specific position
    account = 100_000.0
    spec = PositionSpec(
        symbol="AAPL.US",
        entry_price=185.00,
        stop_loss_price=180.00,  # $5 risk per share
        win_rate=0.60,
        reward_risk_ratio=2.0
    )
    
    result = calculate_position_size(account, spec, kelly_fraction=0.5)
    print(f"\nPosition: {result.symbol}")
    print(f"  Kelly fraction: {result.kelly_fraction:.2%}")
    print(f"  Risk amount: ${result.risk_amount:,.2f}")
    print(f"  Position value: ${result.position_value:,.2f}")
    print(f"  Shares: {result.shares}")

8. Practical Risk Controls Beyond Kelly

8.1 Dynamic Kelly: Updating Estimates Over Time

Kelly fractions should be recalculated as new data arrives. A Bayesian updating approach treats $p$ as a random variable with a Beta distribution prior:

$$p \sim \text{Beta}(\alpha, \beta)$$

After $W$ wins and $L$ losses, the posterior is:

$$p | (W, L) \sim \text{Beta}(\alpha + W, \beta + L)$$

The posterior mean is:

$$\hat{p} = \frac{\alpha + W}{\alpha + \beta + W + L}$$

This "shrinks" the estimated win rate toward a prior, preventing overfitting to recent streaks. The degree of shrinkage depends on the choice of $\alpha$ and $\beta$ — conservative priors (e.g., $\alpha = 2$, $\beta = 3$, equivalent to one win and 1.5 losses as prior) produce stable estimates; aggressive priors (e.g., $\alpha = 1$, $\beta = 1$, uniform prior) adapt quickly.

8.2 Kelly with Variable Reward-to-Risk

In practice, reward-to-risk is not fixed. A mean-reversion strategy might have $b = 1.5$ on small timeframes but $b = 4.0$ on intraday reversals. Use the expected reward-to-risk, not the target:

$$\mathbb{E}[b] = \sum_i p_i \cdot b_i$$

Where $p_i$ is the probability of the $i$-th outcome scenario and $b_i$ is its reward-to-risk ratio.

8.3 Kelly as a Risk Cap, Not a Target

The most robust implementation treats Kelly as an upper bound, not a target allocation. Set a maximum Kelly fraction based on your drawdown tolerance, and use that as your hard cap regardless of what Kelly formula says:

if calculated_kelly > max_allowed_kelly:
    return max_allowed_kelly

Common maximums: 10% for conservative traders, 25% for moderate, 40% for aggressive (aligned with full Kelly for high-conviction setups).


9. Common Mistakes and How to Avoid Them

Mistake Why it matters Correct approach
Using target R/R instead of realized R/R Target R/R overstates the actual payout when wins are often less than target Use the average realized win / average realized loss from backtest
Ignoring correlation Two correlated positions double-count risk Apply correlation adjustment or reduce total exposure
Recalculating Kelly too frequently Short-term win/loss streaks cause Kelly whipsawing Use Bayesian updates or rolling windows with minimum sample size (n ≥ 30)
Betting full Kelly after small sample Estimation error is largest with few observations Use half-Kelly or quarter-Kelly until n ≥ 100
Ignoring transaction costs Kelly assumes zero friction; in reality, costs erode edge Adjust Kelly by subtracting expected costs from win rate
Confusing win rate with Sharpe Win rate alone is insufficient; magnitude matters Always specify both $p$ and $b$; use expected value $p \cdot b - q$

10. Summary and Implementation Checklist

The Kelly Criterion provides a mathematically optimal answer to the question of position sizing: for a strategy with $p = 60%$ and $b = 2:1$, the answer is 40% of bankroll per trade, yielding approximately 16% geometric growth per bet.

In practice, this answer must be modified by:

  1. Fractional Kelly (half or quarter) to reduce variance and protect against estimation error.
  2. Maximum position caps to prevent single-trade catastrophe.
  3. Correlation adjustments for multi-position portfolios.
  4. Dynamic updating via Bayesian inference rather than point estimates.
  5. Transaction cost modeling to subtract real-world friction.

Implementation checklist:

  • Calculate full Kelly fraction for each strategy using single_kelly_fraction().
  • Apply fractional Kelly (recommend 0.25–0.50) based on your drawdown tolerance.
  • Set maximum per-position cap (recommend 10–25% of bankroll).
  • Calculate total portfolio exposure; scale down if exceeding target leverage.
  • Track realized win rate and realized R/R; update Kelly monthly or after every 30 trades.
  • Monitor drawdown; if drawdown exceeds 2× expected Kelly drawdown, reduce fraction.
  • Backtest the strategy over ≥ 3 years and ≥ 200 trades before live deployment.

Next Steps

If you want to backtest Kelly-based position sizing against your strategy, TickDB provides 10+ years of US equity OHLCV data via the /v1/market/kline endpoint — ideal for cross-cycle validation of your sizing models.

If you want to run this calculation for your account, sign up at tickdb.ai (free tier available, no credit card required) and use the Python functions above with your live account balance.

If you use AI coding assistants, search for and install the tickdb-market-data SKILL in your AI tool's marketplace to access real-time data feeds directly from your agent.


This article does not constitute investment advice. Markets involve risk; past performance does not guarantee future results. The Kelly Criterion is a mathematical framework, not a guarantee of profitability. Always conduct your own due diligence and risk assessment before implementing any trading strategy.