Bankrolls grow geometrically, not arithmetically. The expected growth rate is g = E[ln(1 + f×b)], where f is fraction wagered and b is net payoff. Kelly sizing maximizes this rate. A 50% loss requires a 100% gain to recover — which is why drawdown management dominates return chasing for any agent operating at scale.

Why This Matters for Agents

An autonomous betting agent’s bankroll is its oxygen supply. Growth rate determines how fast the agent compounds capital. Drawdown depth determines whether the agent survives long enough to compound at all.

This is Layer 2 — Wallet. The growth math lives in the wallet infrastructure layer of the Agent Betting Stack, where systems like Coinbase Agentic Wallets or Safe multisig contracts track balance state and enforce position limits. An agent’s wallet module needs three numbers at all times: current bankroll, expected geometric growth rate, and maximum tolerable drawdown. The first comes from on-chain balance queries. The second and third come from the math in this guide. Without them, the agent is flying blind — it cannot distinguish a profitable strategy experiencing normal variance from a broken strategy bleeding capital. The agent wallet comparison covers the infrastructure; this guide covers the math that infrastructure must implement.

The Math

Why Geometric Mean, Not Arithmetic Mean

The single most important insight in bankroll management: sequential bets multiply, they do not add.

Suppose you make two bets. The first returns +50%. The second returns -50%.

Arithmetic average return: (+50% + -50%) / 2 = 0%. Looks fine.

Actual bankroll trajectory: $1,000 → $1,500 → $750. You lost 25%.

The arithmetic mean lies. The geometric mean tells the truth:

Geometric growth factor = (1.50 × 0.50)^(1/2) = 0.75^(1/2) = 0.866
Geometric mean return = 0.866 - 1 = -13.4% per bet

Over n sequential bets with returns r₁, r₂, …, rₙ, the final bankroll is:

W_n = W_0 × ∏(1 + rᵢ)

where W₀ is the starting bankroll and rᵢ is the fractional return on bet i. The geometric mean return per bet is:

G = [∏(1 + rᵢ)]^(1/n) - 1

If G > 0, the bankroll grows over time. If G < 0, the bankroll shrinks. The arithmetic mean is irrelevant for long-run outcomes.

The Geometric Growth Rate

For a repeated bet where you wager fraction f of your bankroll on each bet, the expected geometric growth rate per bet is:

g = E[ln(1 + f × X)]

where X is the random net return per unit staked. For a binary bet with probability p of winning payoff b and probability q = 1 - p of losing the stake:

g = p × ln(1 + f × b) + q × ln(1 - f)

where f is the fraction of bankroll wagered, b is the net payoff (decimal odds minus 1), p is the true win probability, and q = 1 - p.

This is the quantity Kelly Criterion maximizes. Taking the derivative and setting it to zero:

dg/df = p × b / (1 + f × b) - q / (1 - f) = 0

Solving for f gives the Kelly fraction:

f* = (b × p - q) / b = p - q / b

At f = f*, the geometric growth rate is maximized. Bet more than Kelly, and the growth rate drops — eventually turning negative. Bet less than Kelly, and growth is slower but variance is lower. This tradeoff is the foundation of fractional Kelly strategies.

The Gain-Loss Asymmetry

Losses and gains are not symmetric in percentage terms. After a loss of fraction L, the required gain G to recover is:

G = L / (1 - L)
LossRequired Gain to Recover
10%11.1%
20%25.0%
33%50.0%
50%100.0%
75%300.0%
90%900.0%

This asymmetry has a direct consequence for agent design: preventing large drawdowns is mathematically more valuable than capturing large gains. An agent that avoids a 50% drawdown avoids needing a 100% return to break even. This is why the drawdown math guide focuses on variance management — it is the defensive complement to this guide’s growth optimization.

Time to Double

Given a per-bet geometric growth rate g, the number of bets required to double the bankroll is:

T_double = ln(2) / g

For an agent betting at -110 odds (b = 0.909) with true win probability p = 0.54 using full Kelly sizing:

f* = (0.909 × 0.54 - 0.46) / 0.909 = (0.491 - 0.46) / 0.909 = 0.034

g = 0.54 × ln(1 + 0.034 × 0.909) + 0.46 × ln(1 - 0.034)
g = 0.54 × ln(1.0309) + 0.46 × ln(0.966)
g = 0.54 × 0.03042 + 0.46 × (-0.03459)
g = 0.01643 - 0.01591
g = 0.000518

T_double = ln(2) / 0.000518 = 1,338 bets

At 10 bets per day, that is ~134 days to double. At 100 bets per day (achievable for an agent scanning Polymarket and multiple sportsbooks via The Odds API), that is ~13.4 days.

With a larger edge — say p = 0.57 at -110 odds:

f* = (0.909 × 0.57 - 0.43) / 0.909 = 0.0888

g = 0.57 × ln(1.0807) + 0.43 × ln(0.9112)
g = 0.57 × 0.0776 + 0.43 × (-0.0930)
g = 0.0442 - 0.0400
g = 0.00424

T_double = ln(2) / 0.00424 = 164 bets

Edge matters exponentially. A 3% edge increase (54% to 57% win rate) cut doubling time by 8×.

Compounding: Proportional vs. Flat Betting

Two fundamental staking strategies exist:

Flat betting: Wager a fixed dollar amount on every bet regardless of bankroll size. Growth is linear. If you start with $10,000 and bet $100 per bet with a 3% edge, your expected profit per bet is $3. After 1,000 bets: $13,000. Linear.

Proportional betting: Wager a fixed fraction of current bankroll on every bet. Growth is exponential. The Kelly Criterion is a proportional betting strategy — it specifies the optimal fraction.

Flat:          W_n = W_0 + n × f × W_0 × edge
Proportional:  W_n = W_0 × (1 + f × edge)^n    (simplified for constant edge)

The proportional strategy dominates over long horizons because gains reinvest automatically. An agent that wins a bet immediately has a larger bankroll for the next bet. This is the power of compounding.

The tradeoff: proportional betting also compounds losses. After a losing streak, the agent bets smaller absolute amounts — which slows recovery. This is the variance cost of proportional betting, and it is why the drawdown math guide is essential companion reading.

The Certainty Equivalent

Not all agents (or their operators) have pure log-utility preferences. The certainty equivalent (CE) is the guaranteed return an agent would accept in lieu of a risky bet stream.

For a bet with expected return μ and variance σ², the certainty equivalent under mean-variance preferences is:

CE = μ - (λ / 2) × σ²

where λ is the risk aversion parameter. A log-utility agent (which Kelly assumes) has λ ≈ 1. A more risk-averse agent has λ > 1.

Full Kelly maximizes expected log growth (λ = 1). Half-Kelly approximates λ = 2. Quarter-Kelly approximates λ = 4.

The key insight: reducing from full Kelly to half-Kelly gives up ~25% of expected geometric growth rate but reduces variance by ~75%. The certainty equivalent actually increases for any agent with λ > 1. This is why production agents at sharp betting operations almost universally use fractional Kelly.

StrategyExpected Growth (% of Kelly)Variance (% of Kelly)Best For
Full Kelly100%100%Theoretical maximum growth
3/4 Kelly~94%~56%Aggressive agents with verified edge
Half Kelly~75%~25%Standard production agents
Quarter Kelly~44%~6%Conservative or uncertain-edge agents

Worked Examples

Example 1: Polymarket Binary Market

An agent identifies edge on a Polymarket binary contract: “Will the Fed raise rates at the June 2026 meeting?”

Market: YES at $0.35 on Polymarket. Agent’s model: 42% true probability.

b = (1.00 / 0.35) - 1 = 1.857  (net payoff per dollar risked)
p = 0.42
q = 0.58

f* = (1.857 × 0.42 - 0.58) / 1.857 = (0.780 - 0.58) / 1.857 = 0.1077

Half-Kelly: f = 0.0539

Geometric growth rate (half-Kelly):
g = 0.42 × ln(1 + 0.0539 × 1.857) + 0.58 × ln(1 - 0.0539)
g = 0.42 × ln(1.1001) + 0.58 × ln(0.9461)
g = 0.42 × 0.0954 + 0.58 × (-0.0554)
g = 0.04007 - 0.03213
g = 0.00794

T_double = ln(2) / 0.00794 = 87 bets

With a $50,000 bankroll, the agent bets $50,000 × 0.0539 = $2,695 on YES. At this growth rate, assuming one comparable opportunity per day, the agent doubles in ~87 days.

Example 2: Sportsbook Grind at BetOnline

An agent finds consistent 2.5% CLV (closing line value) on NFL sides at BetOnline at -110 lines. True win probability: 0.535 vs. the 0.524 implied by -110.

b = 100/110 = 0.909
p = 0.535
q = 0.465

f* = (0.909 × 0.535 - 0.465) / 0.909 = 0.0225

Quarter-Kelly (conservative, NFL-appropriate): f = 0.0056

g = 0.535 × ln(1 + 0.0056 × 0.909) + 0.465 × ln(1 - 0.0056)
g = 0.535 × ln(1.005091) + 0.465 × ln(0.9944)
g = 0.535 × 0.005078 + 0.465 × (-0.005616)
g = 0.002717 - 0.002612
g = 0.000105

T_double = ln(2) / 0.000105 = 6,601 bets

At ~5 bets per NFL Sunday (17-week season, ~85 bets per year), doubling takes ~78 years at quarter-Kelly. This is why NFL-only bettors need higher edge, more bets per game, or higher Kelly fractions. Alternatively, an agent can combine NFL with Polymarket and other sportsbooks via an arbitrage detection pipeline to increase bet frequency.

Example 3: Growth Comparison Over 1,000 Bets

Starting bankroll: $10,000. Edge: 3% on -110 lines (p = 0.545, b = 0.909).

Strategy          f       E[W_1000]     Median W_1000    P(Ruin < $2,500)
──────────────────────────────────────────────────────────────────────────
Flat $200         $200    $15,454       $15,200          ~0%
Full Kelly        0.061   $46,888       $22,103          ~2%
Half Kelly        0.031   $22,907       $19,306          ~0.01%
Quarter Kelly     0.015   $16,279       $15,612          ~0%

Full Kelly has the highest expected value but the median lags the mean — a classic sign of right-skewed distributions. Half-Kelly’s median is closer to its mean, indicating more predictable growth. Quarter-Kelly barely beats flat betting in expectation but has near-zero ruin probability.

Implementation

import numpy as np
from dataclasses import dataclass


@dataclass
class GrowthMetrics:
    """Bankroll growth analysis results."""
    geometric_growth_rate: float
    doubling_time_bets: float
    kelly_fraction: float
    half_kelly_fraction: float
    certainty_equivalent: float
    expected_log_growth: float


def compute_growth_metrics(
    p: float,
    b: float,
    risk_aversion: float = 2.0
) -> GrowthMetrics:
    """
    Compute bankroll growth metrics for a binary bet.

    Args:
        p: True win probability.
        b: Net payoff per unit staked (decimal odds - 1).
        risk_aversion: Lambda for certainty equivalent (1 = Kelly, 2 = half-Kelly).

    Returns:
        GrowthMetrics with all growth parameters.
    """
    q = 1 - p
    kelly = (b * p - q) / b
    kelly = max(kelly, 0.0)  # No bet if negative edge

    half_kelly = kelly / 2.0

    # Geometric growth rate at half-Kelly
    if half_kelly > 0:
        g = p * np.log(1 + half_kelly * b) + q * np.log(1 - half_kelly)
    else:
        g = 0.0

    doubling_time = np.log(2) / g if g > 0 else float('inf')

    # Certainty equivalent: CE = mu - (lambda/2) * sigma^2
    mu = half_kelly * (p * b - q)
    sigma_sq = (half_kelly ** 2) * (p * b**2 + q) - mu**2
    ce = mu - (risk_aversion / 2) * sigma_sq

    return GrowthMetrics(
        geometric_growth_rate=g,
        doubling_time_bets=doubling_time,
        kelly_fraction=kelly,
        half_kelly_fraction=half_kelly,
        certainty_equivalent=ce,
        expected_log_growth=g,
    )


def simulate_bankroll_paths(
    p: float,
    b: float,
    fractions: dict[str, float],
    n_bets: int = 1000,
    n_sims: int = 5000,
    initial_bankroll: float = 10000.0,
    seed: int = 42
) -> dict[str, dict]:
    """
    Monte Carlo simulation of bankroll paths under different staking strategies.

    Args:
        p: True win probability.
        b: Net payoff per unit staked.
        fractions: Dict of strategy_name -> fraction of bankroll to wager.
        n_bets: Number of bets per simulation.
        n_sims: Number of simulation paths.
        initial_bankroll: Starting bankroll.
        seed: Random seed for reproducibility.

    Returns:
        Dict of strategy_name -> {mean, median, std, p_ruin, paths_sample}.
    """
    rng = np.random.default_rng(seed)
    outcomes = rng.random((n_sims, n_bets)) < p  # True = win

    results = {}

    for name, f in fractions.items():
        bankrolls = np.full(n_sims, initial_bankroll)
        path_sample = np.zeros((min(10, n_sims), n_bets + 1))
        path_sample[:, 0] = initial_bankroll

        for bet_idx in range(n_bets):
            wins = outcomes[:, bet_idx]
            returns = np.where(wins, f * b, -f)
            bankrolls *= (1 + returns)
            bankrolls = np.maximum(bankrolls, 0.0)

            if bet_idx < n_bets:
                for s in range(min(10, n_sims)):
                    path_sample[s, bet_idx + 1] = bankrolls[s]

        ruin_threshold = initial_bankroll * 0.25
        p_ruin = np.mean(np.min(
            np.column_stack([np.full(n_sims, initial_bankroll), bankrolls]),
            axis=1
        ) < ruin_threshold)

        results[name] = {
            "mean": float(np.mean(bankrolls)),
            "median": float(np.median(bankrolls)),
            "std": float(np.std(bankrolls)),
            "p_ruin": float(p_ruin),
            "final_bankrolls": bankrolls,
        }

    return results


def betting_sharpe_ratio(
    returns: np.ndarray,
    risk_free_rate: float = 0.0,
    annualization_factor: float = 1.0
) -> float:
    """
    Compute Sharpe ratio for a sequence of bet returns.

    Args:
        returns: Array of per-bet fractional returns.
        risk_free_rate: Per-bet risk-free rate (default 0).
        annualization_factor: Multiply by sqrt(N) for annualized SR.

    Returns:
        Sharpe ratio.
    """
    excess = returns - risk_free_rate
    if np.std(excess) == 0:
        return 0.0
    return float(np.mean(excess) / np.std(excess) * np.sqrt(annualization_factor))


def gain_to_recover(loss_fraction: float) -> float:
    """
    Compute the gain required to recover from a given loss.

    Args:
        loss_fraction: Fraction of bankroll lost (0 to 1).

    Returns:
        Required fractional gain to return to original bankroll.
    """
    if loss_fraction >= 1.0:
        return float('inf')
    return loss_fraction / (1 - loss_fraction)


if __name__ == "__main__":
    # Example: NFL sides at -110 with 53.5% true win rate
    p = 0.535
    b = 100 / 110  # 0.909

    metrics = compute_growth_metrics(p, b, risk_aversion=2.0)
    print("=== Growth Metrics (NFL -110, p=0.535) ===")
    print(f"Kelly fraction:     {metrics.kelly_fraction:.4f}")
    print(f"Half-Kelly:         {metrics.half_kelly_fraction:.4f}")
    print(f"Geometric growth:   {metrics.geometric_growth_rate:.6f}")
    print(f"Doubling time:      {metrics.doubling_time_bets:.0f} bets")
    print(f"Certainty equiv:    {metrics.certainty_equivalent:.6f}")
    print()

    # Simulate 1,000 bets under different strategies
    strategies = {
        "Full Kelly": metrics.kelly_fraction,
        "Half Kelly": metrics.half_kelly_fraction,
        "Quarter Kelly": metrics.kelly_fraction / 4,
        "Flat 2%": 0.02,
    }

    sim = simulate_bankroll_paths(p, b, strategies, n_bets=1000, n_sims=5000)

    print("=== Simulation Results (1,000 bets, 5,000 paths) ===")
    print(f"{'Strategy':<16} {'Mean':>10} {'Median':>10} {'Std':>10} {'P(Ruin)':>8}")
    print("-" * 58)
    for name, res in sim.items():
        print(
            f"{name:<16} ${res['mean']:>9,.0f} ${res['median']:>9,.0f} "
            f"${res['std']:>9,.0f} {res['p_ruin']:>7.2%}"
        )
    print()

    # Gain-loss asymmetry table
    print("=== Gain-Loss Asymmetry ===")
    for loss in [0.10, 0.20, 0.33, 0.50, 0.75]:
        print(f"  {loss:.0%} loss → {gain_to_recover(loss):.1%} gain to recover")

Limitations and Edge Cases

1. Edge estimation error dominates everything. Every formula above assumes you know the true probability p. You don’t. If your model says p = 0.54 but reality is p = 0.52, your Kelly fraction is ~40% too large, and your expected geometric growth rate may be negative. This is the strongest argument for fractional Kelly — it provides a buffer against estimation error.

2. Non-stationarity. Markets change. An edge that existed last month may not exist today. The growth rate g assumes a stationary betting opportunity. In practice, an agent’s edge fluctuates as markets adapt to its activity, sportsbooks limit its accounts, and new information shifts true probabilities. Agents operating at BookMaker or other sharp-friendly books will find their limits reduced as their CLV signals get detected.

3. Correlated bets violate the multiplicative model. The bankroll path W_n = W₀ × ∏(1 + rᵢ) assumes bets are independent. Betting on Lakers -3.5 and Lakers Over 215.5 in the same game introduces correlation. Correlated losing bets compound drawdowns faster than the independent model predicts. The correlation and portfolio theory guide covers how to handle this.

4. Discrete ruin is real. The continuous model says Kelly never goes to zero (since ln(0) = -∞). In practice, platforms have minimum bet sizes. A bankroll that shrinks to $1.23 on a platform with a $5 minimum bet is functionally ruined even though it’s technically nonzero. Agents must define a practical ruin threshold — typically 10-25% of starting bankroll.

5. Withdrawal and deposit friction. Crypto gas fees on Polymarket, withdrawal minimums at offshore sportsbooks like BetUS, and sportsbook rollover requirements create friction that the pure model ignores. These costs reduce effective growth rate.

FAQ

Why is geometric mean better than arithmetic mean for measuring betting returns?

Sequential bets multiply — a +50% gain followed by a -50% loss gives 1.5 × 0.5 = 0.75, a net 25% loss, even though the arithmetic average return is 0%. The geometric mean captures this compounding reality. Any strategy evaluated by arithmetic mean will overstate long-run performance. This is not a modeling choice; it is a mathematical consequence of how sequential returns compose.

How long does it take to double a betting bankroll?

Doubling time is T = ln(2) / g, where g is the per-bet geometric growth rate. An agent with a 1% geometric edge per bet doubles in ~69 bets. At 100 bets per day, that is under one day. At 0.1% edge per bet, doubling takes ~693 bets. The formula assumes constant edge and bet size, so real doubling times vary with market conditions.

What is gain-loss asymmetry in bankroll management?

Losses are harder to recover from than gains are to accumulate. A 50% loss requires a 100% gain to break even. A 33% loss requires 50%. This asymmetry means drawdown prevention is mathematically more important than return maximization. The drawdown math guide covers the variance management strategies that follow from this asymmetry.

How does Kelly Criterion relate to geometric bankroll growth?

Kelly sizing maximizes the expected geometric growth rate g = E[ln(1 + f×b)]. It is the unique bet fraction f* that solves dg/df = 0. This is why Kelly is optimal for long-run bankroll growth — it directly maximizes the quantity that determines compounding speed. See the full Kelly Criterion derivation for the proof.

What is a certainty equivalent in betting?

The certainty equivalent is the guaranteed return a bettor would accept instead of a risky bet stream. For a log-utility bettor, CE approximates E[return] - Var[return]/2. Fractional Kelly (half-Kelly, quarter-Kelly) trades growth rate for a higher certainty equivalent by reducing variance faster than it reduces expected return. Production betting bots almost universally prefer fractional Kelly for this reason.

What’s Next

This guide covers how bankrolls grow. The companion piece on the defensive side — how to survive the inevitable losing streaks — is the Drawdown Math and Variance in Betting guide.

  • Optimal sizing: The Kelly Criterion guide derives the f* formula from first principles and covers multi-outcome extensions.
  • When bets aren’t independent: The Correlation and Portfolio Theory guide extends this to correlated bet portfolios, including the math for parlay risk.
  • Agent wallet infrastructure: The Agent Wallet Comparison reviews Coinbase Agentic Wallets, Safe, and other Layer 2 solutions where this growth math gets implemented.
  • Measuring your edge: Closing Line Value (CLV) is the most reliable way to verify you actually have the edge that feeds these growth calculations.