Polyoxide
Python SDK for Polymarket APIs, powered by Rust via PyO3 and maturin.
Every client comes in async and sync variants. Async methods return Python awaitables; sync methods block via an internal Tokio runtime and release the GIL while waiting.
| Async | Sync | API | Description |
|---|---|---|---|
Gamma |
GammaSync |
Gamma | Market data, events, series, tags, comments, sports, search, users |
ClobClient |
ClobClientSync |
CLOB | Order book, prices, spreads, trade history, fee rates |
DataApi |
DataApiSync |
Data | User positions/trades/activity, leaderboard, holders, volume, open interest |
Installation
pip install polyoxide
Wheels are published for Linux (x86_64, aarch64), macOS (x86_64, aarch64), and Windows (x86_64).
Quick Start
Async (Gamma -- market data)
import asyncio
from polyoxide import Gamma
async def main():
gamma = Gamma()
markets = await gamma.markets().list(limit=5, open=True)
for m in markets:
print(f"{m.question} -- {m.slug}")
asyncio.run(main())
Sync (Gamma)
from polyoxide import GammaSync
gamma = GammaSync()
markets = gamma.markets().list(limit=5, open=True)
for m in markets:
print(f"{m.question} -- {m.slug}")
CLOB (order book data)
from polyoxide import ClobClientSync
clob = ClobClientSync()
book = clob.markets().order_book("TOKEN_ID")
print(book.bids, book.asks)
spread = clob.markets().spread("TOKEN_ID")
print(spread)
Data API (user positions and leaderboard)
import asyncio
from polyoxide import DataApi
async def main():
data = DataApi()
# Leaderboard
leaders = await data.leaderboard().get(limit=10, time_period="WEEK")
for t in leaders:
print(t.user_name, t.pnl)
# User positions
positions = await data.user("0xADDRESS").list_positions(limit=5)
for p in positions:
print(p.title, p.size)
asyncio.run(main())
Data API v2 (cursor pages)
DataApi().v2() and DataApiSync().v2() expose the /v2 routes: snake_case
fields, cursor-only paging, and errors with a stable code. Their result classes
live in polyoxide.v2, since several share a name with a v1 class.
from polyoxide import DataApiSync, v2
data = DataApiSync().v2()
# One page, and the cursor for the next one
page = data.trades(limit=50)
print(len(page), page.pagination.next_cursor)
# Every page, re-sending the same filters each time
for page in data.iter_activity("0xADDRESS", types=["TRADE"], limit=500):
for row in page.data:
print(row.activity_type, row.usdc_size)
# None, not an error, for a wallet the API does not know
stats = data.user_stats("0xADDRESS")
Async walks use async for page in DataApi().v2().iter_trades(...). Enum
arguments take the exact wire spelling (time_period="week",
sort_direction="DESC"), and a value the route does not accept raises
ValueError before any request is sent.
Client API Reference
Gamma / GammaSync
Constructed with optional base_url, timeout_ms, and pool_size keyword arguments.
| Namespace | Methods |
|---|---|
.markets() |
get(id), get_by_slug(slug), list(...), tags(id) |
.events() |
get(id), get_by_slug(slug), list(...), tags(id), tweet_count(id), comment_count(id) |
.series() |
get(id), list(...) |
.tags() |
get(id), get_by_slug(slug), list(...), get_related(id), get_related_by_slug(slug) |
.comments() |
get(id), list(...), by_user(address) |
.sports() |
list(), market_types(), list_teams(...) |
.search() |
public_search(query, ...) |
.user() |
get(address) |
.health() |
ping() |
ClobClient / ClobClientSync
No arguments required (uses public/unauthenticated endpoints).
| Namespace | Methods |
|---|---|
.markets() |
get(condition_id), get_by_token_ids(token_ids), list(), order_book(token_id), price(token_id, side), midpoint(token_id), prices_history(token_id), neg_risk(token_id), fee_rate(token_id), tick_size(token_id), spread(token_id), last_trade_price(token_id), live_activity(condition_id), simplified(), sampling(), sampling_simplified(), calculate_price(token_id, side, amount) |
.health() |
ping(), server_time() |
DataApi / DataApiSync
Constructed with optional base_url, timeout_ms, and pool_size keyword arguments.
| Namespace | Methods |
|---|---|
.user(address) |
list_positions(...), positions_value(...), closed_positions(...), trades(...), activity(...), traded() |
.trades() |
list(...) |
.holders() |
list(markets, ...) |
.open_interest() |
get(...) |
.live_volume() |
get(event_id) |
.leaderboard() |
get(...) |
.builders() |
leaderboard(...), volume(...) |
.health() |
ping() |
.v2() |
approvals, positions, combo_positions, user_pnl, user_stats, user_volume, value, activity, combo_activity, trades, holders, live_volume, open_interest, prices_history, resolutions, biggest_winners, builders_leaderboard, builder_volume, leaderboard, leaderboard_user, status; each paged route also has iter_<route>(...) |
Result Objects
All response objects expose named properties matching the upstream JSON fields, plus:
.to_dict()-- convert to a plain Pythondictstr(obj)-- JSON string representationrepr(obj)-- type-annotated representation
Error Handling
All exceptions inherit from PolyoxideError:
from polyoxide import PolyoxideError, ApiError, RateLimitError
try:
markets = gamma.markets().list()
except RateLimitError:
print("slow down")
except ApiError as e:
print(f"API error: {e}")
except PolyoxideError as e:
print(f"something else: {e}")
| Exception | When |
|---|---|
ApiError |
API returned an error response |
AuthenticationError |
Invalid or missing credentials |
ValidationError |
Request parameters failed validation |
RateLimitError |
Rate limit exceeded (HTTP 429) |
NetworkError |
Connection failure |
TimeoutError |
Request timed out |
A Data API v2 error maps by its code: invalid_request to ValidationError,
rate_limited to RateLimitError, request_timeout to TimeoutError, and
any other code to ApiError. Every exception also carries status, code,
retryable, trace_id, parameter and retry_after, which are None unless
the error came from a v2 route.
Async Support
Async clients (Gamma, ClobClient, DataApi) use pyo3-async-runtimes to bridge Rust futures into Python awaitables. They work with asyncio.run(), await, and any asyncio-compatible event loop.
Sync clients (GammaSync, ClobClientSync, DataApiSync) execute on a shared background Tokio runtime and release the GIL while blocking, so they are safe to use from threaded Python code.
Type Stubs
.pyi stub files are included at python/polyoxide/__init__.pyi and python/polyoxide/v2.pyi for editor autocomplete and type checking.
Building from Source
Requires Rust and Python 3.9+.
pip install maturin
maturin develop --release
License
Licensed under either of MIT or Apache-2.0 at your option.
Release files for polyoxide 0.32.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| polyoxide-0.32.2.tar.gz | 515.8 kB | Details |
Built distributions (wheels)
| File | Reset | |||
|---|---|---|---|---|
| polyoxide-0.32.2-cp39-abi3-win_amd64.whl | CPython 3.9 | abi3 | Windows x86-64 | Details |
| polyoxide-0.32.2-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl | CPython 3.9 | abi3 | Linux glibc 2.17+ x86-64 | Details |
| polyoxide-0.32.2-cp39-abi3-macosx_11_0_arm64.whl | CPython 3.9 | abi3 | macOS 11.0+ ARM64 | Details |
| polyoxide-0.32.2-cp39-abi3-macosx_10_12_x86_64.whl | CPython 3.9 | abi3 | macOS 10.12+ x86-64 | Details |
Total release size: 16.6 MB
Release files / polyoxide-0.32.2.tar.gz
| Download URL | polyoxide-0.32.2.tar.gz |
|---|---|
| Size | 515.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
7b3d963d0cde8a544c19f0a83cca76f952693fdbef6a2a4f999652c636a92601
|
|
BLAKE2b-256 checksum How to use checksums |
5bcbacfb2fc3d12acd6006cf54875db89526405954b721ed80502d962330801b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
maturin/1.15.0
|
Release files / polyoxide-0.32.2-cp39-abi3-win_amd64.whl
| Download URL | polyoxide-0.32.2-cp39-abi3-win_amd64.whl |
|---|---|
| Size | 4.4 MB |
| Tags | CPython 3.9 Windows x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
0021a09c2a3a9df650f9b4d10dcd25d9daa30abefa227fe721f9cd7433eef045
|
|
BLAKE2b-256 checksum How to use checksums |
44fc6fed6e68b6b46c1efd3ff11964af12a249bebbaca7975e2d36cfee4dad4b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
maturin/1.15.0
|
Release files / polyoxide-0.32.2-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
| Download URL | polyoxide-0.32.2-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl |
|---|---|
| Size | 4.0 MB |
| Tags | CPython 3.9 Linux glibc 2.17+ x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
3bea2991d1d4f38c4a8079629945ba7cb16e7654079510c07ca30ba9ccfc0a5d
|
|
BLAKE2b-256 checksum How to use checksums |
b261f4bb760ae19d3c69e23316777b2f0bd2373a96113c4a013d68a7dd378e98
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
maturin/1.15.0
|
Release files / polyoxide-0.32.2-cp39-abi3-macosx_11_0_arm64.whl
| Download URL | polyoxide-0.32.2-cp39-abi3-macosx_11_0_arm64.whl |
|---|---|
| Size | 3.7 MB |
| Tags | CPython 3.9 abi3 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
af736ce866b7ade28baedb4e3f4063594d7d79cb6873a188287b9e9088af69fa
|
|
BLAKE2b-256 checksum How to use checksums |
9afd6e24a6c6ef8d034dd7ae437c194880a5af9098e8342c7c5a757791fc1b7e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
maturin/1.15.0
|
Release files / polyoxide-0.32.2-cp39-abi3-macosx_10_12_x86_64.whl
| Download URL | polyoxide-0.32.2-cp39-abi3-macosx_10_12_x86_64.whl |
|---|---|
| Size | 3.9 MB |
| Tags | CPython 3.9 abi3 macOS 10.12+ x86-64 |
|
SHA-256 checksum How to use checksums |
7938ae037bb4a1e99ee328e8bdc7e624abc2fd1bca945c147baec32b90526c66
|
|
BLAKE2b-256 checksum How to use checksums |
b13ab691cb54c112f1c50a03acb34a524646e972a0832aa9539c98a735f97183
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
maturin/1.15.0
|