Oracle3
Open-source trading engine and MCP server for prediction markets. Fee-aware no-arbitrage trading across related contracts, live on Kalshi, Polymarket and Solana or on paper.
Trade with algorithms, connect with apps, and build financial apps with one SDK across Kalshi and Polymarket: market data, matched markets, arbitrage, order entry and live streams.
FinancePython · RustGitHub @Synpath-aiOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
One open-source API for prediction markets. Trade Kalshi, Polymarket, Polymarket US and Opinion with one Python SDK: unified market data, smart order routing across venues, and advanced order types. Plus tick-level Kalshi order book history.
Taken from the repository README
Loading the full README. The saved excerpt is shown below.
Synpath – One API for prediction markets
Build on prediction markets without building against each one.
One open-source API across Kalshi, Polymarket, Polymarket US and Opinion: market data, order entry, live streams, and an execution engine that remembers what it sent. In-process from Python, over REST and WebSocket from anywhere.
🆕 New: Smart order routing across Kalshi and Polymarket.
One order, both order books combined, filled from the cheapest price after fees. See how it works →
⭐ If Synpath saves you time, star it on GitHub. It's how other traders find it.Read the full README ↗Build on prediction markets without building against each one. One open-source API across 16 venues (Kalshi, Polymarket, Polymarket US, Opinion, Hyperliquid, predict.fun, Limitless, SX Bet, Myriad and Gemini, and the sports betting venues Betfair, Smarkets, Novig, Matchbook, ProphetX and Azuro): market data, order entry, live streams, and an execution engine that remembers what it sent. In-process from Python, over REST and WebSocket from anywhere.
🆕 New: free tick-level Kalshi order book history. Every public Kalshi market, full depth, every change and every trade, straight from Kalshi's live feed. Sign up from your terminal and query it in one line of Python. Get it in 60 seconds ↓
⭐ Star Synpath on GitHub if the data saves you money. Stars are how we decide what to open up next.
1. Install
pip install synpath
2. Sign up: opens Google sign-in in your browser, then returns to the terminal. Free, no card.
synpath login
3. Create your API key: it's saved on your machine and Python picks it up automatically.
synpath keys create my-laptop
4. Query any moment
import synpath
t = 1792065600000 # 2026-10-15 12:00 UTC, in venue Unix milliseconds
# The full book exactly as it stood at that millisecond
snap = synpath.fetch_order_book_at("kalshi:KXQUANTUM-30", as_of_ms=t)
print(snap.book.bids[0].price, snap.book.asks[0].price, len(snap.book.bids), "bid levels")
# Every change over an hour: a starting book, then each update in venue-time order
changes = synpath.fetch_order_book_range("kalshi:KXQUANTUM-30", start_ms=t, end_ms=t + 3_600_000)
# Every trade: price, size and taker side
trades = synpath.fetch_trades_range("kalshi:KXQUANTUM-30", start_ms=t, end_ms=t + 3_600_000)
Request windows use Kalshi venue time (metadata.time_basis="venue"); observed_at_ms is the separate recorder receive time.
No silent gaps: if we weren't recording at a moment, you get the reason instead of an empty book. Up to an hour per request; plain HTTP works too (Authorization: Bearer <key>). More: synpath.dev/tick-data · API reference
⭐ Free data stays free as long as people use it. If this saves you a data bill, star the repo. It takes one click and it's how other traders find it.
Also new: smart order routing across Kalshi and Polymarket. One order, both order books combined, filled from the cheapest price after fees. See how it works →
| Exchange | id | Market data | Order entry | Streams | Order books | |
|---|---|---|---|---|---|---|
| Kalshi | kalshi | ✓ | ✓ | WebSocket | one book per market, both sides read it | |
| Polymarket | polymarket | ✓ | ✓ | WebSocket | one book per outcome token | |
| Polymarket US | polymarket_us | ✓ | ✓ retail and exchange APIs | WebSocket and gRPC | one book per market, both sides read it | |
| Opinion | opinion | ✓ | ✓ | WebSocket (API key) | one book per outcome token | |
| Hyperliquid | hyperliquid | ✓ outcome markets (HIP-4) | ✓ | WebSocket (no key) | one book per market, both sides read it | |
| predict.fun | predict_fun | ✓ (API key) | ✓ | WebSocket (API key) | one book per market, both sides read it | |
| Limitless |
Betfair is a betting exchange, not a prediction market, read here the same way: each runner (selection) is a yes/no market, betfair:1.234567890-47972, and the Betfair market holding the runners is the event. Every Betfair call needs your own Betfair account and application key (betting needs Betfair's live key; the free delayed one reads), and the API is refused from several countries (the US, Germany, France, the Netherlands, Singapore, India, Turkey, the UAE and others). Betfair's keys are for your own betting: showing its prices to anyone else needs a data licence from Betfair. See capabilities.
Gemini Predictions is Gemini Titan's CFTC-registered event-contract exchange. Each contract is a yes/no market named by its instrument symbol, gemini:GEMI-NBA-2610232000-CHI-MIL-M-MIL, and the Gemini event holding the contracts is the event. Sports events carry Gemini's taxonomy (moneyline, spread, total, prop; the sport, scope and statistic), which listings filter on. Market data needs no account; trading needs a Gemini account with Prediction Markets access (US) and an API key. See capabilities.
Smarkets, a UK betting exchange, is read the same way: each contract is a yes/no market, smarkets:164973231-456060183, and the Smarkets market holding the contracts is the event. Its market data needs no account (quotes are delayed without a login); betting logs in with your own Smarkets username and password, and placing orders needs Smarkets' approved API access (a one-off £150 fee). Smarkets' API terms allow viewing prices and betting on your own account, and prohibit odds scraping. See capabilities.
Novig, a US sports exchange, lists two-outcome markets (a moneyline, a spread, a total, a Yes/No prop), each one yes/no market, novig:01a1577c-d666-7e81-852e-68bed1446801, under its game as the event. Its catalog, books and trades are public and need no key. Trading signs each request with a subaccount's key; Production trades real money for verified US customers outside Arizona, Michigan and Nevada, and Paper (NOVIG_ENV=paper) is the same API with play money. Novig's parlay RFQ is supported from the liquidity provider's side: NovigPricer prices and last-looks parlays for a registered LP account (trading). See capabilities.
Matchbook, a betting exchange licensed in the UK and Alderney, is read the same way: each runner is a yes/no market, matchbook:<event id>-<market id>-<runner id>, and the Matchbook market holding the runners is the event. Its market data needs no account; betting logs in with your own Matchbook username and password. Every GET is chargeable on Matchbook's API plans (£100 per million a month), and its terms allow viewing prices and betting on your own account only. See capabilities.
ProphetX, a US peer-to-peer sports exchange, is read the way SX Bet is: each line (a moneyline, or a spread or total at one number) is a yes/no market whose first side is YES, prophetx:44285780-90de769f4f4977a04446ed203e957351 (the event, then the YES side's strike id), and the game is the event. Prices are American odds, converted exactly to probabilities. Every call needs a key: the Trading API key pair, which any KYC-approved ProphetX account generates under API Integration, or a Market Data API key issued by ProphetX on request. See capabilities.
Azuro is an onchain sports betting protocol: a shared liquidity pool takes every bet at the odds it quotes, so there is no order book and nothing rests. A two-outcome condition ("Total Goals Over/Under 2.5") is one yes/no market, azuro:<conditionId>, with the lower outcome id as YES; a condition with three or more outcomes (1X2, correct score) is one market per outcome, azuro:<conditionId>-<outcomeId>, where only YES can be bought. The game is the event. Prices are 1 / odds. Ids are the same on every chain; Azuro(chain=...) picks the pool read (Polygon USDT by default, Base WETH). Bets are EIP-712 messages signed by your wallet and placed on chain by Azuro's relayer. Azuro's bet API and streams are refused from some regions. See capabilities.
Myriad runs order-book markets on BNB Chain and AMM (pool) markets on BNB Chain, Abstract and Linea behind one API. A market id carries its network, and amm for a pool market, since the two kinds number their markets separately: myriad:56-2385 is an order-book market, myriad:56-amm-2385 an unrelated pool market. Order entry covers both: signed orders on the order book, and market orders against a pool, each sent as one on-chain transaction from the wallet. See capabilities.
Liquidity is fragmented. Your time shouldn't be. The same market trades on Kalshi, Polymarket, Polymarket US, Opinion, Hyperliquid, predict.fun, Limitless, SX Bet, Myriad and Gemini, and the sports betting venues Betfair, Smarkets, Novig, Matchbook, ProphetX and Azuro, each with its own API, units and quirks. Synpath gives you one interface for all of them, and smart order routing buys from whichever book is cheapest. Spend your time on alpha, not plumbing.
Traders deserve advanced order types. Stops, trailing stops, icebergs, OCO, brackets, TWAP and pegs, on every venue, even where the exchange has none. Orders are journaled before they're sent, so a crash never places one twice.
A home after Dome and pmxt. Dome's API shut down in April 2026, and pmxt hasn't shipped since July 2026. Synpath is MIT-licensed, actively maintained, and follows ccxt conventions.
pip install synpath # market data, order entry, streams, the engine and the server
pip install "synpath[grpc]" # + Polymarket US exchange gRPC streams
Python 3.10 or newer. The hot paths (order books, reading the venues' book streams, order signing and the order router) run on a Rust core that ships prebuilt inside the wheel for Linux, macOS and Windows; nothing else to install.
Hosted API. Run synpath login, then synpath keys create (step by step ↑). It serves tick-level Kalshi order book and trade history, and cross-venue market matching. Trading stays on your machine: Synpath never holds your keys or funds.
Markets and quotes
import synpath
kalshi = synpath.Kalshi()
market = kalshi.fetch_markets(limit=1)[0]
print(market.title) # Will Elon Musk visit Mars before Aug 1, 2099?
print(market.yes.quote.bid, market.yes.quote.ask) # 0.1 0.12
Order books and search
book = kalshi.fetch_order_book(market.id, depth=5)
book.best_bid, book.best_ask # best first on both sides
kalshi.fetch_order_book(market.id, side="no") # what NO costs
markets = kalshi.fetch_markets(query="trump", limit=10)
fee = kalshi.fetch_fee_schedule(markets[0].id)
fee.estimate(price=0.50, contracts=100) # 1.75
Same code, every venue
for venue_id in synpath.exchanges: # [..., 'betfair', 'smarkets', 'novig', 'matchbook', 'prophetx', 'azuro', 'myriad', 'gemini'] (Betfair, predict.fun and ProphetX need keys)
with synpath.exchange(venue_id) as venue:
page = venue.fetch_markets(limit=5)
client = synpath.Client() # or one client, routed by the id
client.fetch_market("polymarket:2252244") # every id starts with its venue
Order entry
from decimal import Decimal
from synpath import KalshiTrading, OrderRequest, Side, load_credentials, require
async with KalshiTrading(require("kalshi", load_credentials())) as kalshi:
order = await kalshi.create_order(OrderRequest(
market_id=market.id, side=Side.BUY, # buy takes YES, sell takes NO
quantity=Decimal("10"), price=Decimal("0.42"), # always the YES price
))
Live streams
from synpath import PolymarketMarketStream, BookEvent
async with PolymarketMarketStream() as stream:
await stream.watch_order_book(["polymarket:2252244"]) # both sides of the market
async for event in stream:
if isinstance(event, BookEvent):
print(event.market_id, event.side, event.best_bid, event.best_ask)
Cross-venue matching: the same market on other venues
synpath.match_market("kalshi:KXHIGHTATL-26SEP23-B80") # .matched: the same question on another venue, or None
synpath.match_market("kalshi:KXMLB-26-LAD", venue="polymarket_us") # on one venue in particular
synpath.match_event("kalshi:KXHIGHTATL-26SEP23") # each venue's events on the same event
Matching covers Kalshi, Polymarket, Polymarket US, Opinion, Hyperliquid, predict.fun, Limitless and SX Bet. It is hosted at api.synpath.dev and needs a Synpath API key (synpath login, then synpath keys create). A match is a deterministic parse both listings land on, not a similarity score, and side_map says when one venue asks the question the other way round. Crypto up-or-down markets are never matched, since each venue sets its own price to beat. Browse matched events at synpath.dev; API: match a market, match an event.
Smart order routing: one order across Kalshi and Polymarket
from synpath import Bucket, BucketMember, OrderType, PolymarketTrading
from synpath.engine import Engine, EngineConfig
creds = load_credentials()
async with KalshiTrading(require("kalshi", creds)) as kalshi, \
PolymarketTrading(require("polymarket", creds)) as poly, \
Engine({"kalshi": kalshi, "polymarket": poly}, EngineConfig(journal_path="trading.db")) as engine:
# The same market on both venues; flip=True where a venue asks the question the other way round
bucket = await engine.save_bucket(Bucket(book="alpha", name="Fed cut in December", members=[
BucketMember(market_id="kalshi:KXFEDDECISION-26DEC-C25"),
BucketMember(market_id="polymarket:2252244", flip=True),
]))
# Both order books combined, each level net of fees, filled from the cheapest price outward
await engine.submit(OrderRequest(
market_id=bucket.market_id, side=Side.BUY, quantity=Decimal("500"),
type=OrderType.MARKET, price=Decimal("0.45"), # the worst price you accept
book="alpha",
))
REST server
python -m synpath.server # http://127.0.0.1:8000/docs
curl "localhost:8000/venues/kalshi/markets?limit=1"
Trading has its own app, with per-account keys and an append-only audit log:
python -m synpath.server bootstrap --control control.db # the first key
python -m synpath.server schema --trading --out openapi.json
npx openapi-typescript openapi.json --default-non-nullable false -o src/synpath.d.ts
See the API Reference for detailed documentation and more examples.
git clone https://github.com/Synpath-ai/synpath
cd synpath
pip install -e ".[dev]" # builds the Rust core too: needs a Rust toolchain (rustup.rs)
pytest # offline, against recorded venue payloads
pytest -m live # market data against the real venues
pytest -m demo # order entry on a venue's demo environment
SYNPATH_PURE_PYTHON=1 pytest # the same tests on the pure-Python fallback
cargo test -p synpath-core # the Rust core on its own
The Rust core lives in crates/synpath-core (pure Rust) and
bindings/python (its PyO3 wrapper, built as synpath._core). Every class
it provides has a pure-Python twin with the same interface, and the library
uses the twin when the extension is not built. Venue adapters are plain
Python: adding a venue needs no Rust.
The demo tests place and cancel real orders on a demo exchange with the
credentials in your environment, and leave the account flat. python -m synpath.trading doctor says which venues are configured without printing a
secret.
ccxt set the conventions this library follows.
MIT
limitless |
| ✓ |
| ✓ |
| WebSocket |
| one book per market, both sides read it |
| SX Bet | sx_bet | ✓ sports | ✓ | WebSocket | one book per market, both sides read it |
| Gemini Predictions | gemini | ✓ no account, sports taxonomy | ✓ US accounts with Prediction Markets access | WebSocket (no key for books) | one book per contract, in YES space |
| Betfair Exchange | betfair | ✓ your own account and app key (delayed key: 1-180 s late, 3 levels) | ✓ your own account and a live app key | Exchange Stream API (TLS socket) | one book per runner, back and lay read as YES |
| Smarkets | smarkets | ✓ no account (quotes delayed without a login) | ✓ your own login, with Smarkets' approved API access | polled from REST quotes | one book per contract, bids are YES bids |
| Novig | novig | ✓ sports, no key | ✓ (US, identity and location checks; Paper for play money) | WebSocket (trading key), else polled from the public book | one book per market, both sides read it |
| Matchbook | matchbook | ✓ no account | ✓ your own login | polled from REST | one book per runner, back and lay read as YES |
| ProphetX | prophetx | ✓ sports (Trading API key pair, or a Market Data API key) | ✓ | WebSocket (Trading API key pair) | one book per line, both sides read it |
| Azuro | azuro | ✓ sports, no key | ✓ bets with a worst price | WebSocket (no key) | no book: the pool's quoted odds, one level a side sized by its limits |
| Myriad | myriad | ✓ order-book and AMM markets, sports | ✓ order book; AMM as market orders | WebSocket (no key) | one book per market, both sides read it; AMM books built from the pool |