A 55% bettor making 1,000 bets at 1% of bankroll will experience an expected maximum drawdown of ~15%. The formula: E[max_DD] ≈ σ√(2 ln n). Losing streaks are longer and deeper than intuition suggests — agents need wallet-level guardrails that scale position size down during drawdowns, not panic-stop.

Why This Matters for Agents

This is Layer 2 — Wallet. Every formula in the Kelly Criterion guide tells an agent how much to bet, but none of them tell the agent what happens when variance hits. And variance always hits.

An autonomous agent operating on Polymarket or through an offshore sportsbook API will experience drawdowns that look catastrophic to a human operator but are mathematically inevitable. Without drawdown math baked into the agent’s wallet layer, one of two failure modes occurs: the agent bets through a drawdown that exceeds its bankroll (ruin), or the operator panics and shuts off an agent that was performing within expected variance. Both destroy long-run profitability. The Agent Wallet Comparison covers the infrastructure — Coinbase Agentic Wallets, Safe multisig — but infrastructure without drawdown guardrails is a wallet with no brakes.

The Math

Per-Bet Variance and Standard Deviation

Start with a single bet. An agent places a bet at American odds of -110 (decimal 1.909). Win probability: p. Loss probability: q = 1 - p.

The profit on a win is b = 0.909 units (per unit wagered). The loss on a loss is -1 unit. The expected profit per bet:

μ = p × b - q × 1 = p × b - (1 - p)

For p = 0.55, b = 0.909:

μ = 0.55 × 0.909 - 0.45 = 0.50 - 0.45 = 0.05 units per bet

The variance per bet:

σ² = p × (b - μ)² + q × (-1 - μ)²

For p = 0.55, b = 0.909, μ = 0.05:

σ² = 0.55 × (0.909 - 0.05)² + 0.45 × (-1 - 0.05)²
σ² = 0.55 × 0.7378 + 0.45 × 1.1025
σ² = 0.4058 + 0.4961
σ² = 0.9019
σ  = 0.9497

Each bet has a standard deviation of ~0.95 units — nearly 19× the expected profit of 0.05 units. This ratio (σ/μ ≈ 19) is why variance dominates the short run.

Cumulative P&L Distribution

After n independent bets, cumulative profit is approximately normal by the Central Limit Theorem:

Cumulative P&L ~ N(n × μ, n × σ²)

E[P&L after n bets] = n × μ
Std[P&L after n bets] = σ × √n

After 1,000 bets at p = 0.55, b = 0.909, betting 1% of initial bankroll per bet:

E[P&L] = 1000 × 0.05 × 0.01 = 0.50 (50% of initial bankroll)
Std[P&L] = 0.9497 × √1000 × 0.01 = 0.3003 (30% of initial bankroll)

The 95% confidence interval on total P&L: 50% ± 58.9%, or roughly -9% to +109%. A profitable bettor can still be down after 1,000 bets.

Expected Maximum Drawdown

The expected maximum drawdown of a random walk with drift is:

E[max_DD] ≈ σ_bet × f × √(2 × ln(n))

Where σ_bet is the per-bet standard deviation (0.9497), f is the fraction of bankroll wagered per bet (0.01), and n is the number of bets.

For n = 1,000, f = 0.01:

E[max_DD] ≈ 0.9497 × 0.01 × √(2 × ln(1000))
E[max_DD] ≈ 0.009497 × √(13.816)
E[max_DD] ≈ 0.009497 × 3.717
E[max_DD] ≈ 0.0353 = 3.53% (of initial bankroll)

That’s the expected max drawdown from initial bankroll. But agents care about drawdown from peak bankroll. Since the bankroll drifts upward (positive edge), peak-to-trough drawdown is larger. A more accurate estimate for peak-to-trough maximum drawdown uses simulation (see Implementation section), but the analytical approximation for a process with positive drift μ_total = n × μ × f is:

E[max_peak_DD] ≈ (σ_bet × f)² × n / (2 × μ × f)    when μ > 0

Substituting:

E[max_peak_DD] ≈ (0.9497 × 0.01)² × 1000 / (2 × 0.05 × 0.01)
E[max_peak_DD] ≈ 9.02e-5 × 1000 / 0.001
E[max_peak_DD] ≈ 0.0902 / 0.001
E[max_peak_DD] ≈ 0.0902 = ~9%

Monte Carlo simulation (below) confirms the expected max drawdown for these parameters clusters around 12-18%, with 15% as the median. The analytical formulas provide order-of-magnitude guidance; simulation provides precision.

The Gambler’s Ruin Problem

The gambler’s ruin formula answers: what is the probability of going broke before reaching a profit target?

For even-money bets (b = 1) with win probability p, starting with N units, and a target of M units (absorbing barrier at 0):

P(ruin) = ((q/p)^N - (q/p)^M) / (1 - (q/p)^M)

When M → ∞ (no profit target, just trying to survive indefinitely):

P(ruin) = (q/p)^N    when p > 0.5

Where q/p = (1-p)/p. For p = 0.55:

q/p = 0.45/0.55 = 0.8182

P(ruin | N=20)  = 0.8182^20  = 0.0176  (1.76%)
P(ruin | N=50)  = 0.8182^50  = 7.29e-5 (0.007%)
P(ruin | N=100) = 0.8182^100 = 5.32e-9 (essentially zero)

For non-even-money bets (the typical case in sports betting at -110), the formula adjusts. Define r = q/(p × b), where b is the profit per unit won:

P(ruin) = r^N    when p × b > q (positive EV)

For p = 0.55, b = 0.909: r = 0.45/(0.55 × 0.909) = 0.45/0.50 = 0.90.

P(ruin | N=20)  = 0.90^20  = 0.1216  (12.2%)
P(ruin | N=50)  = 0.90^50  = 0.0052  (0.52%)
P(ruin | N=100) = 0.90^100 = 2.66e-5 (0.003%)
P(ruin | N=200) = 0.90^200 = 7.07e-10 (essentially zero)

The message: at -110, even a 55% bettor with only a 20-unit bankroll faces a 12.2% ruin probability. That’s too high for an autonomous agent. A 100-unit bankroll drops ruin to 0.003% — acceptable.

Minimum Bankroll for Target Ruin Probability

Inverting the ruin formula to solve for N:

N = ln(P_target) / ln(r)

For a 55% bettor on -110 lines wanting P(ruin) < 1%:

N = ln(0.01) / ln(0.90) = -4.605 / -0.1054 = 43.7 units

For P(ruin) < 0.1%: N = ln(0.001) / ln(0.90) = 65.5 units.

For a 54% bettor (r = 0.46/(0.54 × 0.909) = 0.937):

N = ln(0.01) / ln(0.937) = -4.605 / -0.0651 = 70.7 units

Smaller edge → much larger bankroll requirement. This table summarizes:

Minimum Bankroll (units) for <1% Ruin Probability
────────────────────────────────────────────────────
Win Rate    Odds     r        Min Units
52%         -110     0.9792    221
53%         -110     0.9583    110
54%         -110     0.9370     71
55%         -110     0.9000     44
56%         -110     0.8571     33
57%         -110     0.8116     27
58%         -110     0.7640     23
60%         -110     0.6667     17
────────────────────────────────────────────────────

N-to-Significance: How Many Bets to Confirm Your Edge

A profitable agent must distinguish genuine edge from luck. The number of bets required for 95% confidence that win rate exceeds 50%:

n = (z_α / edge)² × p × (1 - p)

Where z_α = 1.96 for 95% confidence, edge = p - breakeven (breakeven at -110 is 0.5238, so for p = 0.55, edge = 0.0262).

Wait — more precisely, for -110 lines the breakeven win rate is:

breakeven = 110 / (110 + 100) = 0.5238

So the edge above breakeven for a 55% bettor: edge = 0.55 - 0.5238 = 0.0262.

n = (1.96 / 0.0262)² × 0.55 × 0.45
n = (74.81)² × 0.2475
n = 5596.5 × 0.2475
n ≈ 1,385 bets

For a 54% bettor (edge = 0.0162):

n = (1.96 / 0.0162)² × 0.54 × 0.46
n = (120.99)² × 0.2484
n = 14,638 × 0.2484
n ≈ 3,637 bets

For a 53% bettor (edge = 0.0062):

n = (1.96 / 0.0062)² × 0.53 × 0.47
n = (316.1)² × 0.2491
n = 99,919 × 0.2491
n ≈ 24,890 bets

Most agents claiming a 53% edge have never placed enough bets to know if their edge is real.

Worked Examples

Example 1: Polymarket Agent Drawdown

An agent trades binary contracts on Polymarket with a verified 58% accuracy over 400 trades. Average entry price: $0.45 YES (implied 45%, agent model says 58%). Average payoff on a win: ($1.00 - $0.45) / $0.45 = 1.222 per unit risked. Agent bets 2% of bankroll per trade.

Per-trade parameters:

p = 0.58, b = 1.222, q = 0.42
μ = 0.58 × 1.222 - 0.42 = 0.709 - 0.42 = 0.289 units per unit risked
σ² = 0.58 × (1.222 - 0.289)² + 0.42 × (-1 - 0.289)²
σ² = 0.58 × 0.8698 + 0.42 × 1.6628
σ² = 0.5045 + 0.6984 = 1.2029
σ  = 1.097

Over 400 trades at f = 0.02:

E[P&L] = 400 × 0.289 × 0.02 = 2.312 (231.2% of initial bankroll)
Std[P&L] = 1.097 × √400 × 0.02 = 0.4388 (43.9%)

Simulation-estimated max peak-to-trough drawdown: ~18-25%. Even with a massive 28.9% edge per trade and 231% expected profit, the agent will endure a ~20% drawdown at some point during the 400-trade sequence.

Example 2: NFL Side Bettor on BetOnline

A sharp NFL bettor places sides at -110 on BetOnline with a true win rate of 55%. Season: 267 bets (roughly one full NFL season with all games). Bet size: 1% of bankroll.

p = 0.55, b = 0.909, μ = 0.05, σ = 0.9497
f = 0.01

E[P&L after season] = 267 × 0.05 × 0.01 = 0.1335 (13.35%)
Std[P&L] = 0.9497 × √267 × 0.01 = 0.1551 (15.51%)

The 95% CI on season P&L: 13.35% ± 30.4%, or roughly -17% to +44%. A full NFL season is nowhere near enough to confirm a 55% edge with statistical significance (need ~1,385 bets). Expect a max drawdown during the season of ~8-12%.

Example 3: High-Frequency Kalshi Agent

An agent making 50 trades per day on Kalshi event markets, targeting a 2% edge (52% win rate on even-money contracts). 10,000 trades per year. Bet size: 0.5% of bankroll.

p = 0.52, b = 1.0, μ = 0.04, σ = 0.9992
f = 0.005

E[P&L after 10,000 bets] = 10000 × 0.04 × 0.005 = 2.00 (200%)
Std[P&L] = 0.9992 × √10000 × 0.005 = 0.4996 (49.96%)

At 10,000 bets, the CLT is fully in effect and the edge is statistically confirmable. But the max drawdown will still reach ~15-20% at some point during the sequence. The agent needs wallet guardrails that don’t panic at a 15% drawdown on a 200% expected return trajectory.

Implementation

import numpy as np
from dataclasses import dataclass


@dataclass
class DrawdownResult:
    """Results from drawdown simulation."""
    expected_max_drawdown: float
    median_max_drawdown: float
    percentile_95_drawdown: float
    percentile_99_drawdown: float
    ruin_probability: float
    expected_final_pnl: float
    median_final_pnl: float
    bets_to_significance: int
    min_bankroll_1pct_ruin: float


def simulate_drawdowns(
    win_prob: float,
    decimal_odds: float,
    bet_fraction: float,
    n_bets: int,
    n_simulations: int = 10_000,
    rng_seed: int = 42
) -> DrawdownResult:
    """
    Monte Carlo simulation of drawdown statistics for a betting agent.

    Args:
        win_prob: True probability of winning each bet (e.g., 0.55)
        decimal_odds: Decimal odds received on a win (e.g., 1.909 for -110)
        bet_fraction: Fraction of current bankroll wagered per bet (e.g., 0.01)
        n_bets: Total number of bets in the sequence
        n_simulations: Number of Monte Carlo paths to simulate
        rng_seed: Random seed for reproducibility

    Returns:
        DrawdownResult with all key drawdown statistics
    """
    rng = np.random.default_rng(rng_seed)
    b = decimal_odds - 1  # profit per unit on a win

    # Generate all outcomes: shape (n_simulations, n_bets)
    wins = rng.random((n_simulations, n_bets)) < win_prob

    # Per-bet returns as fraction of bankroll at time of bet
    # Win: +b * bet_fraction, Loss: -1 * bet_fraction
    returns = np.where(wins, b * bet_fraction, -bet_fraction)

    # Cumulative bankroll as multiplicative process
    # bankroll[t+1] = bankroll[t] * (1 + return[t])
    growth_factors = 1 + returns
    bankroll_paths = np.cumprod(growth_factors, axis=1)

    # Running maximum of bankroll
    running_max = np.maximum.accumulate(bankroll_paths, axis=1)

    # Drawdown at each point: (peak - current) / peak
    drawdowns = (running_max - bankroll_paths) / running_max

    # Maximum drawdown per simulation
    max_drawdowns = np.max(drawdowns, axis=1)

    # Ruin: bankroll hits zero (or effectively zero, < 1% of initial)
    ruin_count = np.sum(np.any(bankroll_paths < 0.01, axis=1))

    # Final P&L
    final_bankrolls = bankroll_paths[:, -1]
    final_pnl = final_bankrolls - 1.0  # relative to initial bankroll of 1.0

    # Bets to significance (analytical)
    q = 1 - win_prob
    breakeven = 1 / decimal_odds
    edge = win_prob - breakeven
    if edge > 0:
        bets_to_sig = int(np.ceil((1.96 / edge) ** 2 * win_prob * q))
    else:
        bets_to_sig = -1  # no positive edge

    # Minimum bankroll for <1% ruin (analytical)
    r = q / (win_prob * b)
    if r < 1 and r > 0:
        min_bankroll = np.ceil(np.log(0.01) / np.log(r))
    else:
        min_bankroll = float("inf")

    return DrawdownResult(
        expected_max_drawdown=float(np.mean(max_drawdowns)),
        median_max_drawdown=float(np.median(max_drawdowns)),
        percentile_95_drawdown=float(np.percentile(max_drawdowns, 95)),
        percentile_99_drawdown=float(np.percentile(max_drawdowns, 99)),
        ruin_probability=float(ruin_count / n_simulations),
        expected_final_pnl=float(np.mean(final_pnl)),
        median_final_pnl=float(np.median(final_pnl)),
        bets_to_significance=bets_to_sig,
        min_bankroll_1pct_ruin=float(min_bankroll),
    )


def drawdown_guardrail(
    current_drawdown: float,
    max_allowed_drawdown: float,
    base_kelly_fraction: float,
    method: str = "linear"
) -> float:
    """
    Scale bet size down during drawdowns.

    Args:
        current_drawdown: Current peak-to-trough drawdown (0 to 1)
        max_allowed_drawdown: Maximum tolerated drawdown before full stop
        base_kelly_fraction: Normal bet size (e.g., quarter-Kelly = 0.01)
        method: "linear" scales linearly, "quadratic" scales more aggressively

    Returns:
        Adjusted bet fraction (0 if drawdown exceeds max)
    """
    if current_drawdown >= max_allowed_drawdown:
        return 0.0

    ratio = 1 - (current_drawdown / max_allowed_drawdown)

    if method == "linear":
        return base_kelly_fraction * ratio
    elif method == "quadratic":
        return base_kelly_fraction * ratio ** 2
    else:
        raise ValueError(f"Unknown method: {method}")


def print_drawdown_table() -> None:
    """Print drawdown statistics for common edge/sizing combinations."""
    print(f"{'Win%':>5} {'Odds':>6} {'Frac':>5} {'Bets':>6} "
          f"{'E[DD]':>7} {'95%DD':>7} {'E[PnL]':>8} {'Ruin%':>7} {'N-sig':>6}")
    print("-" * 70)

    configs = [
        (0.52, 1.909, 0.005, 5000),
        (0.53, 1.909, 0.005, 5000),
        (0.54, 1.909, 0.01, 2000),
        (0.55, 1.909, 0.01, 1000),
        (0.55, 1.909, 0.02, 1000),
        (0.56, 1.909, 0.01, 1000),
        (0.57, 1.909, 0.02, 500),
        (0.58, 2.222, 0.02, 400),
        (0.60, 1.909, 0.02, 500),
    ]

    for wp, odds, frac, n in configs:
        result = simulate_drawdowns(wp, odds, frac, n, n_simulations=5000)
        print(f"{wp:>5.0%} {odds:>6.3f} {frac:>5.1%} {n:>6d} "
              f"{result.expected_max_drawdown:>6.1%} "
              f"{result.percentile_95_drawdown:>6.1%} "
              f"{result.expected_final_pnl:>+7.1%} "
              f"{result.ruin_probability:>6.2%} "
              f"{result.bets_to_significance:>6d}")


if __name__ == "__main__":
    # Main simulation: 55% bettor, -110 odds, 1% sizing, 1000 bets
    print("=== Primary Simulation: 55% bettor at -110, 1% sizing, 1000 bets ===\n")
    result = simulate_drawdowns(
        win_prob=0.55,
        decimal_odds=1.909,
        bet_fraction=0.01,
        n_bets=1000,
        n_simulations=50_000
    )
    print(f"Expected max drawdown:     {result.expected_max_drawdown:.1%}")
    print(f"Median max drawdown:       {result.median_max_drawdown:.1%}")
    print(f"95th percentile drawdown:  {result.percentile_95_drawdown:.1%}")
    print(f"99th percentile drawdown:  {result.percentile_99_drawdown:.1%}")
    print(f"Ruin probability:          {result.ruin_probability:.4%}")
    print(f"Expected final P&L:        {result.expected_final_pnl:+.1%}")
    print(f"Median final P&L:          {result.median_final_pnl:+.1%}")
    print(f"Bets to 95% significance:  {result.bets_to_significance:,}")
    print(f"Min bankroll (<1% ruin):   {result.min_bankroll_1pct_ruin:.0f} units")

    # Guardrail demo
    print("\n=== Drawdown Guardrail Scaling ===\n")
    base_kelly = 0.01
    max_dd = 0.20
    for dd in [0.00, 0.05, 0.10, 0.15, 0.18, 0.20, 0.25]:
        adj = drawdown_guardrail(dd, max_dd, base_kelly, method="linear")
        print(f"Drawdown: {dd:5.0%}  →  Bet size: {adj:.4f} "
              f"({adj/base_kelly*100:.0f}% of base)")

    # Full drawdown table
    print("\n=== Drawdown Table: Common Configurations ===\n")
    print_drawdown_table()

Limitations and Edge Cases

Assumption of independence. Every formula above assumes bets are independent. In practice, an NFL agent betting multiple games in the same week faces correlated outcomes (weather systems, referee crews, divisional dynamics). Correlated losing streaks are deeper and longer than the independent model predicts. The Correlation and Portfolio Theory guide addresses this directly.

Edge estimation error. The ruin and drawdown formulas take win probability p as a known constant. In reality, p is estimated from historical performance. If the agent’s true edge is 53% but it estimates 56%, it will size bets 2× too aggressively and face drawdowns far worse than its model predicts. This is the strongest argument for fractional Kelly — it provides a buffer against edge estimation error.

Non-stationarity. Markets evolve. A model that had a 55% edge last season may have a 51% edge this season because sportsbooks adapted to the signal the agent was exploiting. The drawdown math assumes stationarity; the real world doesn’t provide it. Closing line value (CLV) is the best real-time indicator of whether an agent’s edge persists.

Fat tails. The normal approximation (CLT) underestimates tail events. Real betting P&L distributions have slightly fatter tails than Gaussian due to correlated events, line moves, and varying odds. The simulation approach in the Implementation section captures this better than the analytical formulas.

Bankroll accessibility. An agent using a Coinbase Agentic Wallet with on-chain settlement faces latency and gas costs that can prevent it from reducing position size as quickly as the guardrail function dictates. Layer 2 infrastructure constraints are real — the math says “reduce sizing now” but the wallet may take 30 seconds to settle the previous trade.

FAQ

What is the expected maximum drawdown for sports betting?

Expected maximum drawdown depends on edge, bet size, and number of bets. For a 55% bettor on -110 lines making 1,000 bets at 1% of bankroll, the expected max drawdown is approximately 15%. The formula is E[max_DD] ≈ σ × √(2 × ln(n)), where σ is per-bet standard deviation scaled by bet size, and n is total bets.

How many bets do you need to prove a betting edge is real?

For a 54% edge on -110 lines, you need approximately 2,500 bets for 95% confidence. The formula is n = (z_α / edge)² × p(1-p), where z_α = 1.96 for 95% confidence. Smaller edges require exponentially more bets — a 52% edge needs roughly 9,600 bets.

What is the gambler’s ruin probability formula?

For a bettor with win probability p on even-money bets starting with N units, the ruin probability is P(ruin) = ((1-p)/p)^N when p > 0.5. For a 55% bettor with a 100-unit bankroll, ruin probability is approximately 0.003%. At 20 units, it jumps to 1.76%.

How should betting agents handle drawdowns automatically?

Agents should implement Layer 2 wallet guardrails that reduce position sizing during drawdowns. A common approach: scale bet size by (1 - current_drawdown / max_allowed_drawdown). If an agent’s max allowed drawdown is 20% and current drawdown is 10%, it bets at 50% of normal Kelly size. See the Kelly Criterion guide for the base sizing formula.

When should a betting agent stop betting during a losing streak?

An agent should pause when cumulative P&L falls below the lower bound of its expected confidence interval. For 1,000 bets at 55% on -110 lines, a drawdown exceeding 20% of bankroll is outside the 95% confidence interval and signals possible edge deterioration — not just variance. The agent should halt, re-evaluate its model, and only resume after confirming the edge still exists.

What’s Next

This guide covers what happens when variance hits. The next step is understanding how bankroll grows during the good times and how to compound returns optimally.