Unified, open-source prediction market SDK.
One interface to trade across Polymarket and Kalshi. Rust engine with Python & TypeScript SDKs.
# Rust — add to Cargo.toml
openpx = "0.1"
# Python
pip install openpx
# TypeScript
npm install @openpx/sdkuse openpx::ExchangeInner;
use serde_json::json;
#[tokio::main]
async fn main() {
let exchange = ExchangeInner::new("kalshi", json!({})).unwrap();
let (markets, _) = exchange.fetch_markets(&Default::default()).await.unwrap();
for m in &markets[..5] {
println!("{}: {}", m.id, m.title);
}
}from openpx import Exchange
exchange = Exchange("kalshi")
markets = exchange.fetch_markets()
for m in markets:
print(f"{m.id}: {m.title}")import { Exchange } from "@openpx/sdk";
const exchange = new Exchange("kalshi", {});
const markets = await exchange.fetchMarkets();
markets.forEach(m => console.log(`${m.id}: ${m.title}`));# CLI
openpx kalshi fetch-markets --limit 5let order = exchange.create_order(
"KXBTC-25MAR14", "Yes", OrderSide::Buy, 0.65, 10.0, HashMap::new(),
).await?;order = exchange.create_order("KXBTC-25MAR14", outcome="Yes", side="buy", price=0.65, size=10.0)const order = await exchange.createOrder("KXBTC-25MAR14", "Yes", "buy", 0.65, 10.0);Every exchange exposes the same interface — switch exchanges by changing one string.
| Method | Description |
|---|---|
fetch_markets |
List markets with pagination |
fetch_market |
Get a single market by ID |
fetch_orderbook |
L2 orderbook (bids/asks) |
fetch_price_history |
OHLCV candlestick data |
fetch_trades |
Recent public trades |
create_order |
Place a limit order |
cancel_order |
Cancel an open order |
fetch_positions |
Current portfolio positions |
fetch_balance |
Account balance |
fetch_fills |
Trade execution history |
ws orderbook |
Real-time orderbook stream |
ws activity |
Real-time trade & fill stream |
| Feature | ||
|---|---|---|
| Markets | ✅ | ✅ |
| Trading | ✅ | ✅ |
| Orderbook | ✅ | ✅ |
| Price History | ✅ | ✅ |
| Trades | ✅ | ✅ |
| Positions | ✅ | ✅ |
| Balance | ✅ | ✅ |
| Fills | ✅ | ✅ |
| WebSocket | ✅ | ✅ |
Each exchange is optional — only configure what you need.
| Exchange | Required Keys | Docs |
|---|---|---|
POLYMARKET_PRIVATE_KEY |
docs | |
KALSHI_API_KEY_ID, KALSHI_PRIVATE_KEY_PEM |
docs |
Set them as environment variables or in a .env file (auto-loaded by the CLI).
cargo install --path engine/cli
# Market data (no auth needed)
openpx kalshi fetch-markets
openpx polymarket fetch-market "0x1234..."
openpx kalshi fetch-orderbook KXBTC-25MAR14
# WebSocket streams
openpx kalshi ws-orderbook KXBTC-25MAR14
openpx polymarket ws-activity "0x1234..."
# Sports & crypto (no auth needed)
openpx sports --league nba --live-only
openpx crypto --symbols btcusdt,ethusdt
# Pipe to jq
openpx kalshi fetch-markets --limit 1 | jq '.markets[0].title'engine/
core/ Core types, Exchange trait, error handling
exchanges/ Exchange implementations (kalshi, polymarket)
sdk/ Unified facade (enum dispatch)
cli/ CLI tool
sports/ Sports WebSocket (Polymarket live scores)
crypto/ Crypto price WebSocket (Binance + Chainlink)
sdks/
python/ PyO3 bindings + Pydantic models
typescript/ NAPI-RS bindings + TS types
docs/ Mintlify documentation site
cargo check --workspace # Type check
cargo test --workspace # Run tests
cargo clippy --workspace -- -D warnings # Lint
cargo fmt --all # Format
just sync-all # Regenerate Python/TS SDKs from Rust types- Documentation — Full API reference, guides, and tutorials
- LLM-ready docs — All docs in one copy-pasteable markdown file
- Issues — Bugs & feature requests
- Discussions — Questions & chat
MIT

