Order book
Subscribe to live order books for one or more markets, both sides, over a single connection.
Self-hosted. Opened from your own process straight to the venue. Nothing here runs on Synpath's servers.
A snapshot arrives on subscribe, then a delta for every change. The stream keeps a local copy of each book too, readable at any time with stream.book(market_id, side).
On Kalshi and Polymarket US one book serves both sides and the NO view is the mirror. On Polymarket each side is its own token and its own book, so a subscription to a market watches both tokens.
Gaps are detected where the venue makes it possible and repaired with a fresh snapshot; until it arrives the local book is marked not ready. Subscriptions are re-sent after every reconnect.
Venues
| Venue | Support | Notes |
|---|---|---|
| Polymarket | Supported | PolymarketMarketStream, no credentials. A book per side. |
| Kalshi | Supported | KalshiStream, needs a Kalshi key: the venue signs the handshake even for market data. |
| Polymarket US | Supported | PolymarketUSMarketStream, needs the retail API key. The venue sends the whole visible book every time. |
| Opinion | Supported | OpinionMarketStream, needs an Opinion API key. Single-level changes with no snapshot or sequence: the book is read over REST once subscribed, and re-read every minute to catch a missed change. |
Parameters
| Name | Type | Description |
|---|---|---|
market_ids | list[str] | Synpath ids to watch. Call again to add more; unwatch (Polymarket) to drop some. |
BookEvent
The book changed.
| Name | Type | Description |
|---|---|---|
venue | string | Which venue the event came from. |
received_at | integer | When this process received it, ms since epoch. |
market_id | string | Synpath id. |
side | yes | no | Which side's book, and the terms its prices are in. |
kind | snapshot | delta | snapshot replaces the book; delta lists only changed levels, each with its size after the change (0 means removed). |
bids, asks | list | Levels, {price, size} in the terms of side. Best first. |
best_bid, best_ask | decimal | null | The local book's top after applying this event. |
sequence | integer | null | The venue's sequence number, where it has one (Kalshi). |
timestamp | integer | null | The venue's time, ms. |
StreamStatusEvent: gap when a message was missed, resynced once a fresh snapshot repaired the book.
import asyncio
from synpath import PolymarketMarketStream
stream = PolymarketMarketStream() # no credentials
from synpath import BookEvent
async def main():
async with stream:
await stream.watch_order_book(["polymarket:2252244"])
async for event in stream:
if isinstance(event, BookEvent):
print(event.side, event.kind, event.best_bid, event.best_ask)
asyncio.run(main()){
"venue": "polymarket",
"received_at": 1790077592174,
"market_id": "polymarket:2252244",
"side": "yes",
"kind": "delta",
"bids": [
{
"price": "0.41",
"size": "120"
}
],
"asks": [],
"best_bid": "0.41",
"best_ask": "0.43",
"sequence": null,
"timestamp": 1789655011496,
"info": {}
}
