Feed liveChannel BlogSports 12
Transport MQTT / SSE / RESTPush 100–500 msV1
Comparisons

Flat Staking vs Kelly Criterion for Betting Bots

Flat staking vs Kelly criterion for betting bots: when level stakes beat proportional sizing, why fractional Kelly wins in production, and how to clamp stakes in code.

Short version: run flat stakes until you have a few thousand settled bets and a calibration curve you'd defend in an argument, then move to quarter Kelly with hard clamps. Full Kelly is the mathematically correct answer to a question nobody betting real money is actually asking.

The flat staking vs Kelly criterion debate gets argued as a maths problem. It isn't. Kelly is provably optimal given your true edge, and your bot has no idea what its true edge is. It has a noisy estimate built on a model you trained yourself, on prices that may already have moved, over a sample smaller than you think it is. Every interesting question about staking is a question about how wrong that estimate is.

What flat staking is genuinely good at

Level stakes — the same unit on every bet, whether that's 1u or 0.5% of the starting bankroll — is the most underrated staking plan in automated betting. I say that as someone who ships tooling for people running Kelly.

Three things it does that nothing else does as cleanly:

  • It isolates your model. Every bet contributes equally to P&L, so yield is a clean read on selection quality. With proportional stakes, one fat-edge winner in month two can carry a losing model for a year and you won't see it in the equity curve.
  • It cannot compound an estimation error. If your model systematically overstates edge by three points, flat stakes bleed you slowly. Kelly bleeds you fast, because the overstatement inflates the stake at exactly the moment it should be shrinking it.
  • It's trivially debuggable. When stake size is a constant, every anomaly in your logs is a selection bug or an execution bug. Never a sizing bug. That narrowing is worth more in the first month of live trading than any growth-rate argument.

Flat staking also happens to match how liquidity actually behaves. Pinnacle publishes a max stake per line — the limit field on our odds-drop alerts — and on a quarter-line soccer total or a thin prematch prop that limit can sit below whatever your Kelly formula just asked for. A bot that always requests 1u rarely gets partially filled and never has to reconcile a half-executed position at 2am.

The flat-stakes crowd is right about the thing the Kelly crowd tends to wave away: growth is worthless if the variance ejects you first. Level stakes trades growth for a drawdown profile you can live with without opening a spreadsheet to reassure yourself.

Where the fit gets bad

Flat staking breaks the moment your edges stop being roughly equal in size. And in a bot that touches live markets, they never are.

Say your bot fires on both of these in the same afternoon:

  • A prematch soccer total. Your devigged fair price is 1.95, the book is 2.00. Edge: roughly 2.5%.
  • A live line thirty seconds after a goal, where the market hasn't finished repricing. Your fair price is 2.40 against an offered 3.10. Edge: roughly 29%.

Betting the same unit on both is not a rounding error, it's the whole business. You are underbetting the second by an order of magnitude, and those opportunities are rare and short-lived — there's no "catch it later." Over a season of in-play betting, level stakes leaves most of the available money on the table by construction.

Then there's the bankroll problem. Start at $5,000, grow to $12,000, and a fixed 1u stake is now a much smaller fraction of your capital: you are de-risking as you get richer, which is backwards. Drop to $2,000 and the same unit becomes a much bigger bite, which is worse than backwards.

Fixed-percentage staking — 1% of current bankroll — patches that second problem and leaves the first untouched. I'd still put it above flat staking for anyone past validation who doesn't want to model edge explicitly, because it self-scales in both directions and makes ruin impossible in the fractional sense: you can shrink forever without hitting zero. But a 2% edge and a 25% edge both get 1%. You've solved bankroll management and called it staking.

What Kelly actually says, and the part people skip

For a binary bet at decimal odds o with true win probability p:

b = o - 1                 # net odds
q = 1 - p
f = (p * b - q) / b       # fraction of bankroll

If f <= 0, don't bet. That's the entire thing. It maximises expected log wealth, which is equivalent to maximising long-run geometric growth.

The skipped part is that p is the true probability, not your estimate, and optimality collapses fast under overestimation. Bet double the correct Kelly fraction and your expected growth rate goes to zero — enormous swings, flat account. Go beyond that and you shrink with certainty, even holding a real positive edge. This is the single most important asymmetry in staking: overbetting costs you far more than underbetting.

Which is why full Kelly is a trap for bots specifically. Model error isn't a small perturbation here, it's the dominant term. Fractional Kelly — multiply f by 0.25 or 0.5 — is the practical answer, and half Kelly retains most of the growth for roughly half the volatility while buying you a wide margin on a wrong p.

One more input problem, and it's the one I see most often in code reviews: your edge estimate needs a vig-free reference or it's noise. Compare your model to a raw two-way price with 2–3% margin baked in and you'll congratulate yourself on an edge that's just the book's cut. This is exactly why our feed carries nvp, the no-vig fair price, on odds-drop alerts. Devigging isn't preparation for a staking plan. It is the staking plan's input.

Staking plan drawdown, ordered honestly

Rough shape, assuming a real edge and a long run of bets at even-ish odds:

PlanGrowthWorst drawdownFails whenBest for
Flat / level stakesLinear, slowShallow, predictableEdges vary a lotValidation, low-limit markets
% of bankroll (1%)Geometric, modestModerate, self-limitingEdge size ignoredDefault for a live bot with no edge estimate
Quarter KellyGeometric, goodUncomfortable but survivableModel badly miscalibratedProduction bots, most people
Half KellyGeometric, strongGenuinely painfulModel moderately miscalibratedWell-validated models, thick markets
Full KellyTheoretical maxDeep and routineAny overestimate at allNobody, in practice

The drawdown column is deliberately unquantified, because the numbers depend entirely on your odds distribution and the accuracy of your probabilities. The ordering is what's stable, and the ordering never changes.

There's a behavioural point hiding underneath the maths. At full Kelly, halving the account at some stage of a long career is closer to expected behaviour than to a tail event. Ask yourself honestly whether your bot will still be running after that — or rather, whether you will still let it run. Most operators won't. Full Kelly's optimality is unreachable for human reasons before model error even gets a say.

Where a Pinnacle feed changes the calculation

Staking plans are input-bound, and the two inputs that quietly break bots are stale prices and missing lines.

Stale prices first. If you poll every thirty seconds and size a Kelly stake against a price that moved twelve seconds ago, your f is computed against a number that no longer exists. No fraction is small enough to fix that; it's not a sizing error, it's a data error wearing a sizing error's clothes. pinnodds pushes odds over a raw WebSocket at /ws/feed instead of making you poll, so sizing happens against the price you can still get. There are also Server-Sent Events at /odds-drop and /odds-drop-prematch for markets whose price is falling against its own recent history — frequently the exact moments the fat edges live in.

Missing lines second. See only the whole-number totals and you never see the quarter lines, which is where a great deal of soccer value sits. Every line Pinnacle prices comes through: totals at 1.75 / 2.25 / 2.75 / 3.25, quarter-ball handicaps at -0.75 / -1.25 / -1.75 / -2.25. Depth is identical on every plan — plans differ in rate limit and push access, not in what you can see. Field-by-field detail lives in the docs.

The two payload shapes matter for staking code, and they genuinely differ. An SSE alert names the market in sect, the moving selection in outcome, prices in from_price / to_price, the event in id, and carries limit and nvp — but no drop percentage. A REST /kit/v1 companion, /api/drops (with mode=live or mode=prematch), is the enriched form: market, designation, from / to, event_id, plus a precomputed drop_pct. If your sizing logic keys off drop magnitude, read the REST rows. If it wants speed and the fair price, stay on the stream.

Sizing in code

Fractional Kelly, clamped by a hard ceiling and by Pinnacle's published stake limit:

from pinnodds import Client

client = Client(api_key="YOUR_KEY")

KELLY_FRACTION = 0.25   # quarter Kelly
MAX_PCT        = 0.02   # never risk >2% on one bet

def kelly_stake(model_p, price, bankroll, limit=None):
    b = price - 1.0
    f = (model_p * b - (1.0 - model_p)) / b
    if f <= 0:
        return 0.0
    f = min(f * KELLY_FRACTION, MAX_PCT)
    stake = bankroll * f
    return min(stake, limit) if limit else stake

for alert in client.odds_drop():                 # SSE stream
    fair_prob = 1.0 / alert["nvp"]               # nvp is already devigged
    model_p   = my_model(alert["id"], alert["sect"], alert["outcome"])

    # gate: only bet where we disagree with the devigged price
    if model_p <= fair_prob:
        continue

    bankroll = ledger.current_bankroll()         # re-read every time
    stake = kelly_stake(model_p, alert["to_price"], bankroll, alert.get("limit"))
    if stake > 0:
        place_bet(alert["id"], alert["outcome"], alert["to_price"], stake)

Three details in there matter more than the formula does.

MAX_PCT is doing the heavy lifting. It's what stops a mispriced model_p of 0.95 from requesting half your bankroll on a coin flip. Every production staking function needs a ceiling that has nothing to do with Kelly — a clamp that survives your model being catastrophically wrong, because one day it will be.

min(stake, limit) respects the market instead of the maths. Ask for more than Pinnacle will take and you get a partial fill plus a reconciliation problem.

And bankroll gets re-read from the ledger on every bet, not held in a module-level float across restarts. Proportional staking on a stale bankroll is flat staking with extra steps and a false sense of sophistication.

Where this comparison is the wrong frame

Some limits, on staking theory and on us.

Staking plans do not create edge. At -2% ROI no sizing scheme saves you; Kelly correctly tells you to bet nothing. The highest-value thing most bot operators could do this month is stop tuning stakes and start measuring calibration.

Kelly assumes independent, sequential, fully-resolved bets. Your bot almost certainly fires correlated positions — same match, overlapping totals, related props — and the Kelly fraction is simply wrong for correlated exposure. You need a joint treatment or, realistically, a per-event exposure cap. That cap is not in the formula. You have to write it.

We do not do backtesting. pinnodds is a real-time feed, live and prematch. There is no historical odds archive to replay, so validating a staking plan against five years of closing lines means recording the stream yourself from today, or sourcing history elsewhere. That's a real gap and you should know it before building on us.

It's Pinnacle only. If your strategy is arbing forty books against each other, use an aggregator. Our premise is narrower and deliberate: Pinnacle's price is the sharpest reference available, and you want it fast and complete rather than blended with soft books.

Specials are off by default, and turning them on is expensive. Pass include_specials=1 and player props, exact scores, futures and outrights arrive as their own event rows carrying special, special_category, special_markets and a parent_id back to the parent fixture. Soccer prematch is roughly 1,500 events without the flag and roughly 12,400 with it. If your Kelly loop runs per-event model inference, that flag multiplies your compute bill by about eight. Be deliberate.

Picking, or combining

The recommendation is staged, and it's the same one I'd give a friend over a beer.

Bets 1–500: flat stakes. Small unit, no compounding, no exceptions. You are gathering data, not making money. Log the model probability, the devigged price at bet time, and the closing price for every single bet — without that third column you can't diagnose anything later.

Bets 500–2,000: percentage of current bankroll. 0.5–1%. Still edge-blind, but scaling with capital. Meanwhile, do the calibration work: bucket predicted probabilities into deciles and compare to realised frequency. If your 60% bucket wins 52% of the time, you are not ready for Kelly, and Kelly will find out before you do.

Past 2,000 bets with decent calibration: quarter Kelly, capped. Multiply the raw fraction by 0.25, clamp at 1–2% per bet, clamp per event, clamp at Pinnacle's limit. Graduate to half Kelly only if calibration holds for another few thousand bets.

Combining tiers is legitimate and I'd defend it: Kelly on the high-confidence slice of your model, flat stakes on the marginal slice. Growth where you trust the number, safety where you don't. That's not a compromise, it's an honest map of where your uncertainty actually sits.

Takeaway

Treat flat staking vs Kelly criterion as a question about your model's calibration error, not about growth curves. The formula was settled in 1956; your inputs are not settled at all. Practically: devig every price before it reaches the sizing function (use nvp when it's on the payload), scale the Kelly fraction to 0.25, clamp again with a hard percentage ceiling, cap exposure per event because Kelly won't, and never request more than the market's published limit. Write those clamps as separate, individually testable lines — on the day your model drifts, they're the only thing between a bad estimate and a bad quarter. Rate limits and push access differ by plan at /#pricing; payload fields are documented at /docs.

Frequently asked questions

Is flat staking or Kelly criterion better for a betting bot?

Flat staking while you are still proving the edge exists, then quarter Kelly once you have a few thousand settled bets and a calibration curve that holds up. Flat stakes isolate model quality and can't compound an estimation error; Kelly only pays off if your probabilities are close to true.

Why shouldn't I use full Kelly staking?

Because your win probability is an estimate, not the truth, and Kelly punishes overestimation severely — betting roughly double the correct fraction drives expected growth to zero. Fractional Kelly at 0.25 or 0.5 keeps most of the growth with a wide margin for model error.

How do you calculate a Kelly stake from decimal odds?

With b = odds - 1 and q = 1 - p, the fraction is f = (p * b - q) / b, and you don't bet if f is zero or negative. Multiply f by your Kelly fraction (0.25 is a sane default) and clamp the result with a hard percentage ceiling before sizing.

Do I need no-vig odds to size bets correctly?

Yes. Comparing your model to a raw two-way price with margin baked in makes the bookmaker's cut look like your edge, so devig first. pinnodds odds-drop alerts carry an nvp field with the no-vig fair price so you can feed a clean number into the sizing function.

Can I backtest a staking plan with pinnodds?

No — pinnodds is a real-time live and prematch feed with no historical odds archive to replay. If you want to test a staking plan against past closing lines, record the stream yourself from now on or source history elsewhere.

Get real-time Pinnacle odds in your code

Live & prematch markets with instant odds-drop alerts over SSE and WebSocket. Free trial key in seconds — no card.

Start free trial