Polymarket Bot Tutorial · Chapter 15 of 32

Sports microstructure bots on Polymarket: in-game edge, scoreline-driven mispricing, the NBA tag (745) and Tennis tag (864), live data sources, and execution patterns for high-frequency sports markets.

What this chapter covers

Sports markets are the most consistently active non-political segment on Polymarket. The bots that work fall into two clean buckets: pre-game line-catchers that trade once the line is set, and in-game microstructure bots that react to order-book movement during play. This chapter covers both with the specific tag IDs, data sources, and latency budgets that apply to each.

Sports markets are the busiest non-political segment on Polymarket. The execution pattern that works combines a live-score feed (ESPN, PandaScore) with order-book microstructure signals. This chapter covers what works for NFL, NBA, soccer, and tennis specifically, and where esports differs.

  • Why sports markets are tradeable
  • Pre-game vs in-game (different bots)
  • Verified tag IDs (745 NBA, 864 Tennis)
  • Data sources: ESPN, official APIs, on-screen
  • Latency budget for in-game
  • The 0.99 / 0.01 trap
  • Code: subscribe to a games book and react

Why sports markets are tradeable

Sports markets clear in defined timeframes (hours to days), have public live data, and attract continuous order flow during games. All three are necessary for a tradeable market - political markets miss "defined timeframe," weather markets miss "continuous flow," obscure tournaments miss "public live data."

The trader population on sports markets is also more diverse than on, say, election markets. Casual sports bettors price emotionally; informed traders correct toward fair value over the course of a game. The gap between the two is the bot edge.

Volume distribution is uneven: an NFL Sunday will rotate hundreds of millions of dollars across Polymarket sports markets; a Tuesday-night Saudi Pro League fixture might do under $50k. Size your strategy to where the action actually is.

Pre-game vs in-game (different bots)

Two fundamentally different bot designs.

Pre-game line-catcher: scan markets that just opened, identify mis-priced lines against your model or against a sharper venue's number, place a FOK buy. Hold to in-play, sometimes to resolution. Speed: minutes-not-seconds. Edge: model + line-shopping.

In-game microstructure: subscribe to a live game's order book WebSocket, react to imbalance signals + score events within seconds. Speed: seconds-not-minutes. Edge: latency + reading order flow.

The two share almost no code. They have different risk profiles, different data sources, different exit strategies. A bot trying to do both ends up doing neither well; pick one.

Verified tag IDs (745 NBA, 864 Tennis)

Production tag IDs verified May 2026 for major sports categories. Use these to filter /events calls efficiently.

Sport / LeagueTag IDTag slugNotes
NBA745nbahighest volume Oct-Jun
NFL450nflpeak Sun/Mon Sep-Feb
Tennis (all)864tennisyear-round, tournament cadence
Soccer (general)1059soccercombine with sub-tags below
EPL739epl
UCL2186uefa-champions-league
Esports (all)702esportsLoL+CS2+Valorant+Dota
MLB1245mlbpeak Apr-Oct
NHL823nhlpeak Oct-Jun

Tag IDs are stable across years. New tags are added (Saudi Pro League, IPL) but old tags don't get renumbered.

Data sources: ESPN, official APIs, on-screen

For traditional sports the free ESPN scoreboard API covers everything you need: scores, period/clock, win-probability, sometimes shot location. No key required; rate-limited only at the IP level. Endpoint pattern: https://site.api.espn.com/apis/site/v2/sports/<sport>/<league>/scoreboard.

For esports, ESPN has no coverage. Options: PandaScore ($30-60/mo, the industry standard), HLTV (CS2-only, scrapeable, no API), Liquipedia (community-maintained, scrapeable, slower update cadence).

On-screen feeds (paying for a TV stream and OCR-reading the scorebug) work but are operationally heavy. Recommended only if you have a strategy that requires sub-3-second updates on a sport that no API covers in real time.

Latency budget for in-game

The end-to-end latency budget for an in-game reactive bot.

  • Score event happens: t=0
  • Source feed reflects: t+3-15s (ESPN: ~10s; PandaScore: ~3s)
  • Your bot reads the feed: t+10-16s
  • Bot decides action: +50ms
  • FOK order placed: +200-500ms
  • Matched at CLOB: +300-1000ms (network + matching)

Total: 11-17 seconds. The fastest professional firms achieve 3-5 seconds end-to-end with paid premium feeds and co-located VPS. Retail bots running on standard hosts and free ESPN are at the slower end.

Strategies that need sub-5s are not viable for retail. Strategies that work in 10-17s window are: line-catching after a score, fading overreactions, late-game certainty plays.

The 0.99 / 0.01 trap

The most common in-play sports bot failure: buying the heavy favorite at 0.99 with one minute left, expecting easy +1¢. Three reasons it fails.

First, the 1% implied probability of the underdog isn't zero - late comebacks happen with non-trivial frequency. A 99.5% certain win, played 200 times, produces one loss for full position size.

Second, the spread at 0.99/0.01 means you pay 99c per share, win 1c on success, lose 99c on the rare reversal. Risk-reward is brutal.

Third, the bot using GTC sell at 0.999 will rarely fill - there are no buyers at that price. The position rides to resolution. If it wins, you got 1c. If the reversal happens, you lose 99c.

The trap is real money lost by builders who didn't run the math. Stay out of 0.95+ priced markets unless your strategy is specifically built for the redemption-arbitrage profile.

Code: subscribe to a games book and react

Reference: subscribe to a specific NBA game's WebSocket, log book updates, fire FOK on imbalance signal.

import websocket, json
THRESHOLD = 0.5  # imbalance level to trigger

def on_message(ws, message):
    msg = json.loads(message)
    if msg.get("event_type") != "book": return
    bids = msg.get("bids", [])
    asks = msg.get("asks", [])
    bid_depth = sum(float(b["price"]) * float(b["size"]) for b in bids[:5])
    ask_depth = sum(float(a["price"]) * float(a["size"]) for a in asks[:5])
    total = bid_depth + ask_depth
    if total < 100: return  # too illiquid
    imb = (bid_depth - ask_depth) / total
    if abs(imb) > THRESHOLD:
        print(f"signal imb={imb:.2f} bid={bid_depth:.0f} ask={ask_depth:.0f}")
        # fire FOK here

ws = websocket.WebSocketApp(
    "wss://ws-subscriptions-clob.polymarket.com/ws/market",
    on_open=lambda ws: ws.send(json.dumps({"type":"Market","markets":["<CONDITION_ID>"]})),
    on_message=on_message
)
ws.run_forever()

Production additions: cooldown between fires, per-token inventory cap, kill on stale book (no message in 30s).

Frequently asked questions

What sports tags are most active on Polymarket?
NBA (tag_id 745), Tennis (tag_id 864), and soccer (varies by competition) lead 24h volume during their seasons. NFL spikes weekly during the regular season and playoffs. We have verified the NBA and Tennis tag IDs in production - others should be checked via the gamma /tags endpoint before relying on them.
Can I bot in-game sports markets profitably?
Possibly - but it is hard. The edge is real (live scoreline often mispriced for 30-90 seconds) but other bots are watching too. Best results we have seen come from combining a fast live-score data source with simple rules ("opponent scored, market hasnt moved yet, buy"). Pure stat-arb without the data source loses to faster competitors.
Where do I get live sports data?
ESPN.com has unofficial JSON endpoints that return live scores - good enough for many strategies. Official APIs (NBA Stats API, NFL public endpoints) are more reliable but slower. Twitter accounts of beat reporters give text but require LLM parsing. None are HFT-grade; all are "fast enough" for retail.
What is the 0.99 / 0.01 trap?
When a sports market is at 99 cents YES (very likely won), there is almost no upside left and a 1-cent move can wipe a months expected gain. Many bots get caught buying at 0.99 chasing the last cent and getting smacked when an unexpected event drops the price to 0.85. Hard rule: do not buy above ~0.95 unless your expected value math is bulletproof.
How does Polymarket sports compare to traditional sportsbooks?
No house edge on the spread (vs ~5-10% vig at FanDuel/DraftKings), but liquidity is thinner and spreads can be wider. Polymarket excels for events that traditional books underprice - international tournaments, esports, niche markets. For mainstream NFL/NBA, traditional books are more liquid but cost more in vig.
Can my bot trade across multiple sports markets concurrently?
Yes - and you should. Sports microstructure works best as a portfolio of 5-20 simultaneous games. Per-game position cap (e.g. 50 USD), portfolio cap (e.g. 500 USD), and uncorrelated exposure across games. Concentrating on one game maxes out variance.