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

How Fast Does an Odds Feed Need to Be for +EV?

How fast does an odds feed need to be for +EV betting? Seconds, not milliseconds — and your poll interval, not the wire, is almost always the bottleneck.

The short answer

Seconds, not milliseconds — but with no polling interval anywhere in the chain. That is the whole answer, and the second half is where almost everyone loses money.

For +EV betting against soft books, the feed has to hand your code the sharp price change before the soft book reprices. That window is usually measured in seconds. So a sub-second push delivery and an end-to-end budget of roughly two seconds from the sharp move to your stake being submitted is plenty. What breaks that budget is never the wire. It's a setInterval(fetchOdds, 10000) somewhere in the codebase, quietly adding an average of five seconds of staleness and a worst case of ten.

You cannot optimise your way out of a scheduler you wrote yourself. If you remember one line from this post, make it that one.

Update frequency, feed latency, decision latency — three different things

These get collapsed into "speed" constantly, and the conflation is expensive.

Update frequency is how often the source publishes. Pinnacle reprices when its risk model or the market moves it — event-driven, not clocked. You don't control it and you can't tune it. During a red card it fires repeatedly in a few seconds; at 4am on a Tuesday, nothing.

Feed latency is the gap between that publication and your process holding the new number. This is the part you buy.

Decision latency is everything after: model evaluation, staking logic, risk checks, and the actual bet submission. For most operations this is the largest chunk by an order of magnitude, and it's also the cheapest to improve — no vendor required.

If you're polling REST every five seconds, arguing about whether a response takes 40ms or 90ms is a rounding error on a rounding error. Architecture first. Wire later.

What you're actually racing

Not Pinnacle. Pinnacle is the reference, not the opponent.

+EV against recreational books works because those books lag a sharp reference, and the edge is the gap between the two prices while it stays open. Three things close it: the soft book's own feed catching the move, a trader adjusting by hand, or somebody else hammering the stale line and triggering a reprice or a limit cut.

That third one is the real race. You're competing with every other person watching the same reference price — which is why "fast enough" is relative and why the distribution of your latency matters far more than the mean. A feed that's usually instant but stalls for eight seconds twice an hour doesn't cost you a proportional slice of your edge. It costs you disproportionately, because the stalls cluster around the busy moments when the moves are worth having, and it hands you exactly the trades where the soft book already knew.

A realistic latency budget

Here's how I'd allocate two seconds end to end for an automated workflow. These are budget targets to design against, not measurements of any particular system.

StageBudgetWho controls it
Source publishes change0Nobody
Feed → your processsub-second, pushYour data provider
Deserialise + map to your event IDtens of msYou
Compare against the soft price you already holdtens of msYou
Staking + risk checkstens of msYou
Bet submission200ms – several secondsThe soft book

Look at where the fat is. Bet submission runs on someone else's web stack and you cannot engineer it away. Which leaves exactly three stages worth real effort: the feed, the parse, and the lookup.

And notice what isn't in the table. There's no polling row. If you have one, add its full interval to every line above and re-read the total.

Push vs poll, concretely

Polling asks "anything new?" on a timer. Push tells you the instant there is. For odds this isn't a close call.

pinnodds pushes. There's a raw WebSocket passthrough at /ws/feed for the full market stream, and Server-Sent Events at /odds-drop and /odds-drop-prematch for the narrower case where you only care about a price falling against its own recent history. Auth is one API key: x-api-key: YOUR_KEY on REST, ?key= on the streams.

import EventSource from "eventsource";

const es = new EventSource("https://pinnodds.com/odds-drop?key=YOUR_KEY");

es.onmessage = (e) => {
  const d = JSON.parse(e.data);
  // sect    = market
  // outcome = the selection that moved
  // from_price / to_price = the move itself
  // limit   = Pinnacle's max stake, nvp = no-vig fair price
  queue.push(d);          // hand off immediately, do nothing else here
};

One detail worth internalising: the SSE payload carries no drop percentage. You get from_price and to_price and you derive the delta yourself. That's usually what you want, because your threshold is your own and a vendor's rounding shouldn't decide your trade. The REST form at /api/drops is the enriched version — market, designation, from/to, event_id, plus a precomputed drop_pct — and it's the right tool for backfilling after a reconnect, not for the hot path. Field-level detail is in the docs.

A worked example: where the two seconds actually go

Take a live soccer match. Pinnacle moves the total from 2.75 over -105 to 2.75 over -118 after a shot on target. Your chain:

  1. SSE alert lands. sect is the totals market, outcome is the over, from_price and to_price carry the move, limit tells you Pinnacle would actually take size at that number. Sub-second.
  2. Your handler pushes the raw dict onto a queue and returns. ~0ms.
  3. A worker maps id to your soft book's event. If that's a Postgres round trip per message, you just spent 5–20ms for no reason. In-memory dict: microseconds.
  4. You compare against the soft price you already hold in memory. If you have to go fetch the soft price now, you've added a network hop to the hot path and probably lost.
  5. Stake sizing, exposure check, submit.

Step 4 is the one people get wrong. Your soft book prices should already be resident and maintained by a separate loop. The sharp move is the trigger, not the start of a data-gathering exercise. If a single alert kicks off three sequential HTTP calls, your budget is gone before the arithmetic starts — and limit and nvp arriving in the same payload exist precisely so you can size and sanity-check without another round trip.

The honest caveats

Speed is oversold to bettors, and I'd rather you spent the money on the right thing.

Your constraint is usually the soft book, not the feed. Placing bets by hand in a browser tab? Shaving 300ms off the data path changes nothing — your budget is dominated by human reaction time and page loads. Fix the workflow before you buy a faster pipe.

Sub-second delivery doesn't make you first. Other people hold the same reference. Being fast gets you into the race. If your edge depends on beating everyone by 200ms, it's fragile and you should assume it gets competed away.

There is no historical odds archive. pinnodds is a real-time feed. Backtesting a closing-line-value model over last season isn't something this product does — you need an archive vendor, or you start recording the stream today and wait a few months.

It's Pinnacle only. That's deliberate: Pinnacle is the reference price, and it closed its public API in July 2025, which is why this service exists. But if your strategy needs forty books quoted side by side, use an aggregator. A single sharp reference and a broad aggregator solve different problems and plenty of people run both.

Reconnects happen. Every long-lived stream drops eventually. On reconnect, resync from /kit/v1/markets or /api/drops before trusting your in-memory book — otherwise your first few post-reconnect decisions run against a stale snapshot, which is the exact failure mode you bought a fast feed to avoid.

Specials multiply the payload. include_specials=1 takes soccer prematch from roughly 1,500 events to roughly 12,400, each special row carrying special, special_category, special_markets and a parent_id pointing back to the parent fixture. Excellent coverage, real parsing cost. If you're chasing latency, don't request bytes you won't read.

Measure your own latency, not ours

Don't trust anyone's marketing number, mine included. Instrument the thing you care about: message arrival to decision made.

import time
from pinnodds import Client   # pip install pinnodds

c = Client(api_key="YOUR_KEY")

for evt in c.odds_drops():                 # SSE stream
    t0 = time.perf_counter()
    delta = (evt["to_price"] - evt["from_price"]) / evt["from_price"]
    if delta < -0.03 and evt["limit"] > 1000:
        enqueue(evt)                       # placement happens elsewhere
    print(f"decision in {(time.perf_counter()-t0)*1000:.1f} ms")

Then log the wall-clock gap between consecutive messages during a busy live match. If your gaps are lumpy in a way the market isn't, the stall is yours — nine times out of ten it's a blocking call inside the handler. Never do I/O in the handler. Push to a queue, return, process on a worker.

And instrument the boring stage nobody instruments: mapping a Pinnacle event_id to your soft book's event. A database lookup per message is a very common, very invisible bottleneck. Cache it at startup and refresh on a slow loop.

What "fast enough" means per strategy

Live +EV and in-play arb is the only case with a genuinely tight budget. Push, a hot-path decision in the low tens of milliseconds, automated placement. Manual play here loses on average and you shouldn't kid yourself otherwise.

Prematch +EV against soft books: seconds are fine, sub-second is comfortable. Push still beats polling, because the moves cluster around team news and steam — precisely when a poll interval is most likely to hide the thing you're waiting for. /kit/v1/prematch/fixtures, /kit/v1/prematch/markets and /kit/v1/prematch/lines handle the snapshot side; pricing shows which plans include push.

CLV analysis: latency is irrelevant. Poll /kit/v1/markets on a schedule and store everything. Completeness and consistent sampling beat speed.

Human-facing dashboards: a few seconds is invisible to someone reading a screen. Spend the effort on alert quality instead.

Takeaway

Build the budget backwards from the bet. Time your slowest stage — almost always submission at the soft book — and every upstream stage only needs to be fast enough that it isn't the constraint. In practice that's four changes: replace every poll loop with a push subscription, keep the message handler non-blocking, cache the event ID mapping in memory, and resync from REST after every reconnect. Do those and the feed stops being your bottleneck, which leaves you staring at the one you should have been working on all along.

Frequently asked questions

How fast does an odds feed need to be for +EV betting?

Fast enough to deliver the sharp book's move before the soft book reprices — typically a window of seconds, not milliseconds. Sub-second push delivery with a total end-to-end budget of around two seconds covers nearly every workflow, provided there is no polling interval anywhere in the chain.

Is polling a REST odds API fast enough for +EV betting?

Usually not for live markets. A 10-second poll adds an average of 5 seconds of staleness and a 10-second worst case, which dwarfs any difference in API response time. Use a pushed stream like a WebSocket or SSE feed and keep REST for snapshots and post-reconnect resync.

Is there still a public Pinnacle API?

No. Pinnacle closed its public API in July 2025. pinnodds is an independent paid service that carries the same live and prematch market data, delivered by push over a WebSocket passthrough at /ws/feed and SSE odds-drop endpoints.

Does the pinnodds SSE alert include a drop percentage?

No. The SSE payload gives you sect, outcome, from_price, to_price, id, limit and nvp — you compute the delta yourself against your own threshold. The REST /api/drops row is the enriched form and includes a precomputed drop_pct.

Can I backtest odds history with pinnodds?

No. It is a real-time feed with no historical odds archive. For backtesting closing-line value over past seasons you need an archive vendor, or you start recording the stream now and build your own history.

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