Skip to main content

Pandas API client to Polymarket

Project description

polymarket-pandas

Pandas-native Python client for the full Polymarket API surface — REST, WebSocket, Relayer, and Bridge — with automatic type coercion and DataFrame output.


Installation

pip install polymarket-pandas
# or
uv add polymarket-pandas

Quick Start

from polymarket_pandas import PolymarketPandas

client = PolymarketPandas()

# Get active markets
markets = client.get_markets(closed=False, limit=100)
print(markets[["slug", "volume24hr", "endDate"]].head())

# Get the order book for a token
book = client.get_orderbook("15871154585880608648...")
print(book)

Configuration

All credentials are read from environment variables (or a .env file via python-dotenv). You can also pass them directly as constructor arguments.

Env var Constructor kwarg Purpose
POLYMARKET_ADDRESS address Your proxy wallet address
POLYMARKET_PRIVATE_KEY private_key Private key for EIP-712 (L1) signing
POLYMARKET_FUNDER private_funder_key Funder private key
POLYMARKET_API_KEY _api_key CLOB API key
POLYMARKET_API_SECRET _api_secret CLOB API secret (used for L2 HMAC)
POLYMARKET_API_PASSPHRASE _api_passphrase CLOB API passphrase
POLYMARKET_BUILDER_API_KEY _builder_api_key Builder API key
POLYMARKET_BUILDER_API_SECRET _builder_api_secret Builder API secret
POLYMARKET_BUILDER_API_PASSPHRASE _builder_api_passphrase Builder API passphrase
POLYMARKET_RELAYER_API_KEY _relayer_api_key Relayer API key
POLYMARKET_RELAYER_API_KEY_ADDRESS _relayer_api_key_address Address owning the relayer key
# Explicit credentials
client = PolymarketPandas(
    address="0xYourAddress",
    private_key="0xYourKey",
    _api_key="your-api-key",
    _api_secret="your-secret",
    _api_passphrase="your-passphrase",
)

API Key setup

# Step 1 — derive or create CLOB API credentials from your wallet key
creds = client.derive_api_key()   # uses private_key from env
# creds = client.create_api_key()  # creates a new key

# Step 2 — set credentials on the client
client._api_key = creds["apiKey"]
client._api_secret = creds["secret"]
client._api_passphrase = creds["passphrase"]

DataFrames and type coercion

Every method that returns a list of objects returns a preprocessed pd.DataFrame:

  • Numeric columns → float64
  • ISO-8601 string timestamps → datetime64[ns, UTC]
  • Unix-ms integer timestamps → datetime64[ns, UTC]
  • Boolean-ish string columns → bool
  • JSON-encoded string columns (clobTokenIds, outcomes, outcomePrices) → Python objects

Raw dict returns are used only where a single object is expected (e.g. get_market_by_id).


REST API Reference

Gamma API — Markets

get_markets(**kwargs) → pd.DataFrame

List markets with rich filtering.

df = client.get_markets(
    limit=500,                  # rows per page (default 500)
    offset=0,
    closed=False,               # exclude resolved markets
    tag_id=1337,
    liquidity_num_min=1000,
    end_date_min="2025-01-01",
    expand_clob_token_ids=True, # explode multi-outcome markets (default True)
    expand_events=True,         # inline event columns (default True)
    expand_series=True,         # inline series columns (default True)
)
Full parameter list
Parameter Type Description
limit int Rows per page (default 500)
offset int Pagination offset
order list[str] Fields to sort by
ascending bool Sort direction
id list[int] Filter by gamma market IDs
slug list[str] Filter by slugs
clob_token_ids list[str] Filter by CLOB token IDs
condition_ids list[str] Filter by condition IDs
market_maker_address list[str] Filter by market maker
liquidity_num_min/max float Liquidity range filter
volume_num_min/max float Volume range filter
start_date_min/max str|Timestamp Start date range
end_date_min/max str|Timestamp End date range
tag_id int Filter by tag
related_tags bool Include related tags
cyom bool CYOM markets only
uma_resolution_status str UMA resolution filter
game_id str Sports game ID
sports_market_types list[str] Sports market types
rewards_min_size float Minimum reward size
question_ids list[str] Filter by question IDs
closed bool Include/exclude closed markets
expand_clob_token_ids bool Explode multi-outcome rows (default True)
expand_events bool Inline event fields (default True)
expand_series bool Inline series fields (default True)

get_markets_all(**kwargs) → pd.DataFrame

Auto-paginate through all matching markets.

all_markets = client.get_markets_all(closed=False)

get_market_by_id(id, include_tag=None) → dict

market = client.get_market_by_id(12345)

get_market_by_slug(slug, include_tag=None) → dict

market = client.get_market_by_slug("will-trump-win-2024")

get_market_tags(id) → pd.DataFrame

tags = client.get_market_tags(12345)

Gamma API — Sampling / Simplified Markets (CLOB)

These three endpoints are served by the CLOB server and use cursor-based pagination. Each method returns a dict with keys data (DataFrame), next_cursor, count, limit. The corresponding _all() variants auto-paginate.

get_sampling_markets(next_cursor=None) → dict

Markets currently eligible for liquidity-provider rewards. Full market objects including tokens, rewards, minimum_tick_size, etc.

page = client.get_sampling_markets()
df   = page["data"]
# fetch next page
page2 = client.get_sampling_markets(next_cursor=page["next_cursor"])

get_simplified_markets(next_cursor=None) → dict

Lightweight snapshot of all CLOB markets: condition_id, tokens (price/outcome), rewards, active, closed, archived, accepting_orders.

page = client.get_simplified_markets()
# auto-page all
all_simplified = client.get_simplified_markets_all()

get_sampling_simplified_markets(next_cursor=None) → dict

Intersection of sampling and simplified — lightest payload for reward-eligible markets.

all_sampling = client.get_sampling_simplified_markets_all()

Gamma API — Events

get_events(**kwargs) → pd.DataFrame

events = client.get_events(
    closed=False,
    tag_id=1337,
    limit=500,
    expand_markets=True,            # inline market columns (default True)
    expand_clob_token_ids=True,     # explode token rows (default True)
)

get_events_all(**kwargs) → pd.DataFrame

Auto-paginate all matching events.

get_event_by_id(id, include_chat=None, include_template=None) → dict

get_event_by_slug(slug, ...) → dict

get_event_tags(id) → pd.DataFrame


Gamma API — Tags

get_tags(**kwargs) → pd.DataFrame

tags = client.get_tags(limit=300)

get_tags_all(**kwargs) → pd.DataFrame

get_tag_by_id(id, include_template=None) → dict

get_tag_by_slug(slug, include_template=None) → dict

get_related_tags_by_tag_id(id, omit_empty=None, status=None) → pd.DataFrame

get_related_tags_by_tag_slug(slug, omit_empty=None, status=None) → pd.DataFrame


Gamma API — Series

get_series(**kwargs) → pd.DataFrame

series = client.get_series(
    closed=False,
    expand_events=True,
    expand_event_tags=False,
)

get_series_by_id(id, include_chat=None) → dict


Gamma API — Sports

get_sports_metadata(**kwargs) → pd.DataFrame

meta = client.get_sports_metadata(sport="NFL")

get_sports_market_types() → dict

get_teams(**kwargs) → pd.DataFrame

teams = client.get_teams(league=["NFL", "NBA"])

Gamma API — Comments

get_comments(**kwargs) → pd.DataFrame

comments = client.get_comments(
    parent_entity_type="Event",
    parent_entity_id=12345,
    limit=100,
)

get_comments_by_user_address(user_address, **kwargs) → pd.DataFrame

get_comment_by_id(id, get_positions=None) → dict


Gamma API — Search

search_markets_events_profiles(q, **kwargs) → dict

results = client.search_markets_events_profiles("bitcoin", limit_per_type=10)
# results keys: "markets", "events", "profiles"

Gamma API — Profiles

get_profile(address) → dict

profile = client.get_profile("0xYourAddress")

Data API — Positions & Trades

get_positions(user, **kwargs) → pd.DataFrame

positions = client.get_positions(
    user="0xYourAddress",
    sizeThreshold=1,
    redeemable=False,
    limit=100,
    sortBy="TOKENS",
    sortDirection="DESC",
)

get_closed_positions(user, **kwargs) → pd.DataFrame

closed = client.get_closed_positions(
    user="0xYourAddress",
    sortBy="REALIZEDPNL",
    limit=50,
)

get_market_positions(market, **kwargs) → pd.DataFrame

All positions for a market, across traders.

pos = client.get_market_positions(
    market="0xConditionId...",
    status="OPEN",
    sortBy="TOTAL_PNL",
    limit=50,
)

get_top_holders(market, limit=100, minBalance=1) → pd.DataFrame

holders = client.get_top_holders(market=["0xConditionId..."])

get_positions_value(user, market=None) → pd.DataFrame

get_leaderboard(**kwargs) → pd.DataFrame

lb = client.get_leaderboard(
    category="CRYPTO",
    timePeriod="WEEK",
    orderBy="PNL",
    limit=25,
)

get_trades(**kwargs) → pd.DataFrame

trades = client.get_trades(
    user="0xYourAddress",
    market=["0xConditionId..."],
    limit=100,
)

get_user_activity(user, **kwargs) → pd.DataFrame

activity = client.get_user_activity(
    user="0xYourAddress",
    type=["TRADE", "REDEEM"],
    limit=100,
)

Data API — Misc

get_accounting_snapshot(user) → dict[str, pd.DataFrame]

Downloads and parses the ZIP accounting snapshot.

snapshot = client.get_accounting_snapshot("0xYourAddress")
positions_df = snapshot["positions"]
equity_df    = snapshot["equity"]

get_live_volume(id) → dict

vol = client.get_live_volume(id=12345)

get_open_interest(market=None) → dict

oi = client.get_open_interest(market=["0xConditionId..."])

get_traded_markets_count(user) → dict

count = client.get_traded_markets_count("0xYourAddress")

Data API — Builders

get_builder_leaderboard(timePeriod="DAY", limit=25, offset=0) → pd.DataFrame

lb = client.get_builder_leaderboard(timePeriod="WEEK")

get_builder_volume(timePeriod="DAY") → pd.DataFrame

vol = client.get_builder_volume(timePeriod="ALL")

CLOB API — Market Data (public)

get_server_time() → int

get_tick_size(token_id) → float

get_neg_risk(token_id) → bool

get_fee_rate(token_id=None) → int

Returns the base fee in basis points.

get_orderbook(token_id) → pd.DataFrame

book = client.get_orderbook("15871154585880...")
# columns: price, size, side (bids/asks), asset_id, hash, market, ...

get_orderbooks(data) → pd.DataFrame

POST endpoint — data is a DataFrame with token_id and side columns.

get_market_price(token_id, side) → float

price = client.get_market_price("15871...", side="BUY")

get_market_prices(token_sides) → pd.DataFrame

prices = client.get_market_prices([
    {"token_id": "15871...", "side": "BUY"},
    {"token_id": "15871...", "side": "SELL"},
])

get_midpoint_price(token_id) → float

get_midpoints(token_ids) → pd.DataFrame

mids = client.get_midpoints(["15871...", "99182..."])

get_spread(token_id) → float

get_last_trade_price(token_id) → dict

get_last_trade_prices(data) → pd.DataFrame

get_price_history(market, **kwargs) → pd.DataFrame

history = client.get_price_history(
    market="15871...",
    interval="1w",   # "1m", "1w", "1d", "6h", "1h", "max"
    fidelity=60,     # resolution in minutes
)

CLOB API — Private (L2 auth required)

All private endpoints use HMAC-SHA256 (_api_key, _api_secret, _api_passphrase).

get_balance_allowance(asset_type, token_id=None) → dict

# asset_type 0 = USDC collateral, 1 = conditional token
balance = client.get_balance_allowance(asset_type=0)

get_user_trades(**kwargs) → pd.DataFrame

trades = client.get_user_trades(market="0xConditionId...")

get_order(order_id) → dict

get_active_orders(id=None, market=None, asset_id=None) → pd.DataFrame

get_order_scoring(order_id) → bool

place_order(order, owner, orderType) → dict

result = client.place_order(
    order=signed_order_dict,
    owner="your-api-key",
    orderType="GTC",   # "GTC", "GTD", "FOK", "FAK"
)

place_orders(orders) → pd.DataFrame

Batch place up to 15 orders. orders is a DataFrame with order fields plus owner and orderType columns.

cancel_order(order_id) → dict

cancel_orders(order_ids) → dict

result = client.cancel_orders(["order-id-1", "order-id-2"])

cancel_all_orders() → dict

cancel_orders_from_market(market=None, asset_id=None) → dict

send_heartbeat() → dict

Must be called at least every 10 seconds while orders are open to prevent automatic cancellation.


CLOB API — Builder Trades (builder auth required)

Requires _builder_api_key, _builder_api_secret, _builder_api_passphrase.

get_builder_trades(**kwargs) → dict

Returns a cursor-paginated dict (data DataFrame + next_cursor).

page = client.get_builder_trades(
    builder="0199bfa0-f4c1-7a98-9c2b-b29cc6d39e10",
    market="0xConditionId...",
    after="1700000000",
)
df = page["data"]
# columns: id, tradeType, takerOrderHash, builder, market, assetId,
#          side, size, sizeUsdc, price, status, outcome, fee, matchTime, ...

CLOB API — Rebates (public)

get_rebates(date, maker_address) → pd.DataFrame

rebates = client.get_rebates(
    date="2026-02-27",
    maker_address="0xYourMakerAddress",
)
# columns: date, condition_id, asset_address, maker_address, rebated_fees_usdc

CLOB API — API Key Management (L1 auth)

Requires private_key (EIP-712 signing).

create_api_key(nonce=0) → dict

derive_api_key(nonce=0) → dict

get_api_keys() → pd.DataFrame

delete_api_key() → dict


Relayer API

Base URL: https://relayer-v2.polymarket.com

check_safe_deployed(address) → bool

deployed = client.check_safe_deployed("0xProxyAddress")

get_relayer_transaction(id) → list[dict]

txs = client.get_relayer_transaction("0190b317-a1d3-7bec-9b91-eeb6dcd3a620")

Each transaction has: transactionID, transactionHash, from, to, proxyAddress, data, nonce, value, signature, state (STATE_NEW | STATE_EXECUTED | STATE_MINED | STATE_CONFIRMED | STATE_INVALID | STATE_FAILED), type (SAFE | PROXY), owner, metadata, createdAt, updatedAt.

get_relayer_nonce(address, type) → str

nonce = client.get_relayer_nonce("0xSignerAddress", type="PROXY")

get_relayer_transactions() → pd.DataFrame

Requires relayer credentials. Returns recent transactions for the authenticated account.

get_relay_payload(address, type) → dict

Returns {"address": "<relayer_address>", "nonce": "<nonce>"} — needed to construct a transaction before signing.

payload = client.get_relay_payload("0xSignerAddress", type="PROXY")

submit_transaction(...) → dict

result = client.submit_transaction(
    from_="0xSignerAddress",
    to="0xContractAddress",
    proxy_wallet="0xProxyWallet",
    data="0xEncodedCalldata",
    nonce="31",
    signature="0xSignatureHex",
    type="PROXY",
    signature_params={
        "gasPrice": "100000000000",
        "operation": "0",
        "safeTxnGas": "0",
        "baseGas": "0",
        "gasToken": "0x0000000000000000000000000000000000000000",
        "refundReceiver": "0x0000000000000000000000000000000000000000",
    },
)
# result: {"transactionID": str, "transactionHash": str, "state": str}

Relayer API Keys

Requires _relayer_api_key and _relayer_api_key_address.

get_relayer_api_keys() → pd.DataFrame

keys = client.get_relayer_api_keys()
# columns: apiKey, address, createdAt, updatedAt

Bridge API

Base URL: https://bridge.polymarket.com

get_bridge_supported_assets() → list[dict]

assets = client.get_bridge_supported_assets()
# Each item: {chainId, chainName, token: {name, symbol, address, decimals}, minCheckoutUsd}

get_bridge_quote(...) → dict

Get a price estimate before bridging.

quote = client.get_bridge_quote(
    from_amount_base_unit="1000000",        # 1 USDC (6 decimals)
    from_chain_id="1",                      # Ethereum
    from_token_address="0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
    recipient_address="0xYourPolymarketWallet",
    to_chain_id="137",                      # Polygon
    to_token_address="0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174",
)
# quote keys: quoteId, estCheckoutTimeMs, estInputUsd, estOutputUsd,
#             estToTokenBaseUnit, estFeeBreakdown (appFeeUsd, gasUsd, ...)

create_deposit_address(address) → dict

Create multi-chain deposit addresses. Send funds to the returned address to have USDC.e credited to your Polymarket wallet.

result = client.create_deposit_address("0xYourPolymarketWallet")
# result: {"address": {"evm": "0x...", "svm": "...", "btc": "bc1q..."}, "note": "..."}

create_withdrawal_address(address, to_chain_id, to_token_address, recipient_addr) → dict

Bridge funds out of Polymarket to another chain.

result = client.create_withdrawal_address(
    address="0xYourPolymarketWallet",
    to_chain_id="1",                    # Ethereum mainnet
    to_token_address="0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
    recipient_addr="0xRecipientOnEthereum",
)

get_bridge_transaction_status(address) → pd.DataFrame

Poll for transaction status using an address returned by deposit/withdraw.

status = client.get_bridge_transaction_status("0xDepositAddress...")
# columns: fromChainId, fromTokenAddress, fromAmountBaseUnit,
#          toChainId, toTokenAddress, status, txHash, createdTimeMs
# status values: DEPOSIT_DETECTED | PROCESSING | ORIGIN_TX_CONFIRMED |
#                SUBMITTED | COMPLETED | FAILED

WebSocket API

from polymarket_pandas import PolymarketWebSocket, PolymarketPandas

ws = PolymarketWebSocket()
# Or share config with an existing HTTP client:
# ws = PolymarketWebSocket.from_client(client)

Market Channel

Real-time order book, price, and trade updates for one or more tokens.

def on_book(df):
    print("Book update:", df[["price", "size", "side"]])

def on_price_change(df):
    print("Price change:", df[["price", "size"]])

def on_best_bid_ask(df):
    print("BBA:", df[["best_bid", "best_ask"]])

session = ws.market_channel(
    asset_ids=["15871154585880..."],
    on_book=on_book,
    on_price_change=on_price_change,
    on_best_bid_ask=on_best_bid_ask,
    # on_last_trade_price=...,
    # on_tick_size_change=...,
    # on_new_market=...,
    # on_market_resolved=...,
    # on_message=lambda event_type, payload: ...,  # catch-all
    ping_interval=10,
)
session.run_forever()

Subscribe / unsubscribe additional tokens after connection:

session.subscribe(["99182..."])
session.unsubscribe(["15871..."])

User Channel

Private order and trade events. Requires API key credentials.

ws = PolymarketWebSocket(
    api_key="your-key",
    api_secret="your-secret",
    api_passphrase="your-passphrase",
)

def on_trade(df):
    print("Trade:", df)

def on_order(df):
    print("Order update:", df)

session = ws.user_channel(
    markets=["0xConditionId..."],
    on_trade=on_trade,
    on_order=on_order,
)
session.run_forever()

Sports Channel

Live sports resolution events.

def on_sport_result(df):
    print("Result:", df)

session = ws.sports_channel(on_sport_result=on_sport_result)
session.run_forever()

RTDS Channel (Real-Time Data Streams)

Crypto prices (Binance and Chainlink) and market comments.

def on_crypto_prices(df):
    print("Binance price:", df[["price"]])

def on_crypto_prices_chainlink(df):
    print("Chainlink price:", df[["price"]])

session = ws.rtds_channel(
    subscriptions=[{"type": "crypto_prices", "condition_id": "0x..."}],
    on_crypto_prices=on_crypto_prices,
    on_crypto_prices_chainlink=on_crypto_prices_chainlink,
    ping_interval=5,
)
session.run_forever()

Pagination Helpers

Offset-based (_autopage)

# Fetch ALL events matching a filter (auto-increments offset)
all_events = client.get_events_all(closed=False, tag_id=1337)

# Same for markets and tags
all_markets = client.get_markets_all(closed=False)
all_tags    = client.get_tags_all()

Cursor-based (_autopage_cursor)

# Fetch ALL sampling/simplified markets
all_sampling    = client.get_sampling_markets_all()
all_simplified  = client.get_simplified_markets_all()
all_samp_simple = client.get_sampling_simplified_markets_all()

# Limit pages
first_3 = client.get_simplified_markets_all(max_pages=3)

Utility Methods

preprocess_dataframe(data) → pd.DataFrame

Apply the full type-coercion pipeline to any raw DataFrame.

response_to_dataframe(data) → pd.DataFrame

pd.DataFrame(data) + preprocess_dataframe.

orderbook_to_dataframe(data) → pd.DataFrame

Parse a raw order book dict (with bids / asks arrays) into a flat DataFrame.


Environment Variables Reference

# Wallet / signing
POLYMARKET_ADDRESS=0xYourProxyWallet
POLYMARKET_PRIVATE_KEY=0xYourPrivateKey
POLYMARKET_FUNDER=0xFunderKey

# CLOB API (L2)
POLYMARKET_API_KEY=your-clob-api-key
POLYMARKET_API_SECRET=your-clob-api-secret
POLYMARKET_API_PASSPHRASE=your-clob-passphrase

# Builder API
POLYMARKET_BUILDER_API_KEY=your-builder-key
POLYMARKET_BUILDER_API_SECRET=your-builder-secret
POLYMARKET_BUILDER_API_PASSPHRASE=your-builder-passphrase

# Relayer API
POLYMARKET_RELAYER_API_KEY=your-relayer-key
POLYMARKET_RELAYER_API_KEY_ADDRESS=0xAddressThatOwnsRelayerKey

License

Apache-2.0

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

polymarket_pandas-0.2.0.tar.gz (54.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

polymarket_pandas-0.2.0-py3-none-any.whl (45.5 kB view details)

Uploaded Python 3

File details

Details for the file polymarket_pandas-0.2.0.tar.gz.

File metadata

  • Download URL: polymarket_pandas-0.2.0.tar.gz
  • Upload date:
  • Size: 54.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for polymarket_pandas-0.2.0.tar.gz
Algorithm Hash digest
SHA256 a5b98e449db6a277e504736c6ee32d08280ed22ec902025b5c7703a5d80db6be
MD5 6b19a88d848ff2df47620455ce332146
BLAKE2b-256 76efca186a2ab90e29791be40bf866cf7c329bae26ddd2fe6a4115af5154ede3

See more details on using hashes here.

Provenance

The following attestation bundles were made for polymarket_pandas-0.2.0.tar.gz:

Publisher: release.yml on sigma-quantiphi/polymarket-pandas

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file polymarket_pandas-0.2.0-py3-none-any.whl.

File metadata

File hashes

Hashes for polymarket_pandas-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 b42c3bca4b9274c4fd8a1a9109dac4ecdcf89e040061b00cc689587cb1a16c0a
MD5 eab44b3f7e5f3d4fa05985dac12ad5ee
BLAKE2b-256 19e63abb47e6bdb74bfc9d8e9463ce168ea33fdb644ad818857cb618da5ada29

See more details on using hashes here.

Provenance

The following attestation bundles were made for polymarket_pandas-0.2.0-py3-none-any.whl:

Publisher: release.yml on sigma-quantiphi/polymarket-pandas

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page