ワンクリックで
trading-polymarket
// Execute trades on Polymarket using py_clob_client - full API access for market data, orders, positions
// Execute trades on Polymarket using py_clob_client - full API access for market data, orders, positions
Trade crypto binary markets on Polymarket with 4 automated strategies. Support: 5-min BTC, 15-min/1h/4h/daily all assets (BTC, ETH, SOL, XRP)
Dollar-cost averaging across all platforms
Hyperliquid L1 perps DEX (69% market share)
Local hybrid search for markdown notes and docs. Use when searching notes, finding related content, or retrieving documents from indexed collections.
Trade perpetual futures on Binance, Bybit, Hyperliquid, MEXC with up to 200x leverage
Pump.fun - Complete Solana memecoin launchpad. Discovery, trending, gainers, losers, token data all work without a key. Trading requires SOLANA_PRIVATE_KEY.
| name | trading-polymarket |
| description | Execute trades on Polymarket using py_clob_client - full API access for market data, orders, positions |
| emoji | 💰 |
| gates | {"envs":["POLY_API_KEY","POLY_API_SECRET","POLY_API_PASSPHRASE","PRIVATE_KEY"]} |
Full access to Polymarket's CLOB (Central Limit Order Book) via the official py_clob_client library.
60+ methods documented. This is the complete reference.
PRIVATE_KEY=0x... # Ethereum private key for signing
POLY_FUNDER_ADDRESS=0x... # Your wallet address on Polygon
POLY_API_KEY=... # From Polymarket API
POLY_API_SECRET=... # Base64 encoded secret
POLY_API_PASSPHRASE=... # API passphrase
pip install py-clob-client requests
| Level | Requirements | Capabilities |
|---|---|---|
| L0 | None | Read-only: orderbooks, prices, markets |
| L1 | Private key | Create & sign orders (not post) |
| L2 | Private key + API creds | Full trading: post orders, cancel, query |
| Type | Use Case |
|---|---|
0 | Standard EOA (MetaMask, hardware wallets) |
1 | Magic/email wallets (delegated signing) |
2 | Proxy wallets (Gnosis Safe, browser proxy) |
from py_clob_client.client import ClobClient
from py_clob_client.clob_types import (
OrderArgs, MarketOrderArgs, ApiCreds, OrderType,
BookParams, TradeParams, OpenOrderParams, BalanceAllowanceParams,
AssetType, OrderScoringParams, OrdersScoringParams, DropNotificationParams
)
from py_clob_client.order_builder.constants import BUY, SELL
from py_clob_client.constants import POLYGON # 137
# Level 2 Auth (full trading access)
client = ClobClient(
host="https://clob.polymarket.com",
key=os.getenv("PRIVATE_KEY"), # Private key for signing
chain_id=POLYGON, # 137 for mainnet, 80002 for Amoy testnet
funder=os.getenv("POLY_FUNDER_ADDRESS"), # Wallet address (for proxy wallets)
signature_type=2 # 0=EOA, 1=MagicLink, 2=Proxy
)
# Set API credentials for authenticated endpoints
client.set_api_creds(ApiCreds(
api_key=os.getenv("POLY_API_KEY"),
api_secret=os.getenv("POLY_API_SECRET"),
api_passphrase=os.getenv("POLY_API_PASSPHRASE")
))
client.get_ok() # Check if server is up
client.get_server_time() # Get server timestamp
client.get_address() # Your signer's public address
client.get_collateral_address() # USDC contract address
client.get_conditional_address() # CTF contract address
client.get_exchange_address() # Exchange contract (neg_risk=False default)
# Get prices and spreads
client.get_midpoint(token_id) # Mid market price
client.get_price(token_id, side="BUY") # Best price for side
client.get_spread(token_id) # Current spread
client.get_last_trade_price(token_id) # Last executed trade price
# Get full orderbook
orderbook = client.get_order_book(token_id)
# Returns: OrderBookSummary with bids, asks, tick_size, neg_risk, timestamp, hash
params = [
BookParams(token_id="TOKEN1", side="BUY"),
BookParams(token_id="TOKEN2", side="SELL")
]
client.get_midpoints(params) # Multiple midpoints
client.get_prices(params) # Multiple prices
client.get_spreads(params) # Multiple spreads
client.get_order_books(params) # Multiple orderbooks
client.get_last_trades_prices(params) # Multiple last prices
client.get_tick_size(token_id) # Returns: "0.1", "0.01", "0.001", or "0.0001"
client.get_neg_risk(token_id) # Returns: True/False (negative risk market)
client.get_fee_rate_bps(token_id) # Returns: fee rate in basis points (0 or 1000)
from py_clob_client.clob_types import OrderType
OrderType.GTC # Good Till Cancelled - stays open until filled/cancelled
OrderType.FOK # Fill Or Kill - fill entirely immediately or cancel
OrderType.GTD # Good Till Date - expires at timestamp (min 60 seconds)
OrderType.FAK # Fill And Kill - fill what's possible, cancel rest
| Type | Use Case | Example |
|---|---|---|
| GTC | Entries - wait for fill | Place buy at 0.45, wait for dip |
| FOK | Exits - need immediate fill | Market sell entire position NOW |
| GTD | Time-limited orders | Offer expires in 5 minutes |
| FAK | Partial fills OK | Get as much as possible now |
OrderArgs(
token_id: str, # Token ID (outcome to trade)
price: float, # Price 0.01-0.99
size: float, # Number of shares
side: str, # "BUY" or "SELL" (or use BUY/SELL constants)
fee_rate_bps: int = 0, # Optional: fee rate in bps (0 or check market)
nonce: int = 0, # Optional: unique nonce for cancellation
expiration: int = 0, # Optional: expiry timestamp (0 = GTC, use timestamp for GTD)
taker: str = ZERO_ADDRESS # Optional: specific taker (ZERO_ADDRESS = anyone)
)
MarketOrderArgs(
token_id: str, # Token ID
amount: float, # Total USDC amount to spend (BUY) or shares (SELL)
side: str, # "BUY" or "SELL"
price: float = 0, # Optional: worst acceptable price (slippage protection)
fee_rate_bps: int = 0, # Optional: fee rate
nonce: int = 0, # Optional: nonce
taker: str = ZERO_ADDRESS, # Optional: taker address
order_type: OrderType = FOK # Optional: FOK (default) or FAK
)
from py_clob_client.order_builder.constants import BUY, SELL
# 1. LIMIT BUY (GTC) - sits on book until filled
order = client.create_and_post_order(
OrderArgs(token_id=TOKEN_ID, price=0.45, size=100.0, side=BUY)
)
# 2. LIMIT SELL (GTC)
order = client.create_and_post_order(
OrderArgs(token_id=TOKEN_ID, price=0.55, size=50.0, side=SELL)
)
# 3. MARKET BUY - spend $100 USDC at current prices (FOK)
signed = client.create_market_order(
MarketOrderArgs(token_id=TOKEN_ID, amount=100.0, side=BUY)
)
result = client.post_order(signed, orderType=OrderType.FOK)
# 4. MARKET SELL - sell all shares immediately (FOK)
signed = client.create_market_order(
MarketOrderArgs(token_id=TOKEN_ID, amount=my_shares, side=SELL)
)
result = client.post_order(signed, orderType=OrderType.FOK)
# 5. POST-ONLY MAKER ORDER (avoid taker fees, earn rebates)
signed = client.create_order(
OrderArgs(token_id=TOKEN_ID, price=0.44, size=100.0, side=BUY)
)
result = client.post_order(signed, orderType=OrderType.GTC, post_only=True)
# If order would cross spread, it gets REJECTED instead of taking
# 6. GOOD TIL DATE (GTD) - expires after timestamp
import time
expiry = int(time.time()) + 300 # 5 minutes from now
signed = client.create_order(
OrderArgs(token_id=TOKEN_ID, price=0.50, size=100.0, side=BUY, expiration=expiry)
)
result = client.post_order(signed, orderType=OrderType.GTD)
# 7. FILL AND KILL (FAK) - fill what you can, cancel rest
signed = client.create_market_order(
MarketOrderArgs(token_id=TOKEN_ID, amount=1000.0, side=BUY)
)
result = client.post_order(signed, orderType=OrderType.FAK)
# SIMPLE: Create and post in one call (recommended)
result = client.create_and_post_order(
OrderArgs(
token_id="123456789012345678901234567890",
price=0.45,
size=10.0,
side="BUY"
)
)
# Returns: {"orderID": "...", "status": "...", ...}
# ADVANCED: Separate create and post
order = client.create_order(OrderArgs(...)) # Returns SignedOrder
result = client.post_order(order, orderType=OrderType.GTC, post_only=False)
# Market order (calculates price automatically)
result = client.create_market_order(
MarketOrderArgs(
token_id="...",
amount=100.0, # Spend $100 USDC
side="BUY"
)
)
# Calculate expected fill price before market order
price = client.calculate_market_price(
token_id="...",
side="BUY",
amount=100.0,
order_type=OrderType.FOK
)
client.cancel(order_id="ORDER_ID") # Cancel specific order
client.cancel_orders(["ID1", "ID2", "ID3"]) # Cancel multiple
client.cancel_all() # Cancel ALL open orders
client.cancel_market_orders( # Cancel by market/asset
market="CONDITION_ID",
asset_id="TOKEN_ID"
)
# Get all open orders
orders = client.get_orders(
params=OpenOrderParams(
id="ORDER_ID", # Optional: specific order
market="COND_ID", # Optional: filter by market
asset_id="TOKEN" # Optional: filter by token
),
next_cursor="MA==" # For pagination
)
# Get specific order
order = client.get_order(order_id="ORDER_ID")
trades = client.get_trades(
params=TradeParams(
id="TRADE_ID", # Optional: specific trade
maker_address="0x...", # Optional: filter by maker
market="CONDITION_ID", # Optional: filter by market
asset_id="TOKEN_ID", # Optional: filter by token
before="2024-01-01", # Optional: before date
after="2023-01-01" # Optional: after date
),
next_cursor="MA=="
)
# Check balance and allowances
balance = client.get_balance_allowance(
params=BalanceAllowanceParams(
asset_type=AssetType.COLLATERAL, # USDC balance
# or AssetType.CONDITIONAL # Token balance
token_id="TOKEN_ID" # For conditional tokens
)
)
# Update/refresh allowance cache
client.update_balance_allowance(params=...)
# All active markets
markets = client.get_markets(next_cursor="MA==")
simplified = client.get_simplified_markets()
# Specific market
market = client.get_market(condition_id="CONDITION_ID")
# Market trade events
events = client.get_market_trades_events(condition_id="CONDITION_ID")
# Sampling/featured markets
client.get_sampling_markets()
client.get_sampling_simplified_markets()
import requests
def search_markets(query: str, limit: int = 10):
"""Search Polymarket markets by keyword"""
url = "https://gamma-api.polymarket.com/markets"
params = {
"_q": query,
"active": "true",
"closed": "false",
"_limit": limit
}
r = requests.get(url, params=params)
return r.json()
# Get market details
markets = search_markets("bitcoin")
for m in markets:
print(f"Question: {m['question']}")
print(f"Condition ID: {m['condition_id']}")
print(f"Volume: ${m.get('volume', 0):,.2f}")
for token in m.get('tokens', []):
print(f" {token['outcome']}: {token['token_id']}")
print(f" Price: {float(token['price']):.2f}")
import requests
CTF_CONTRACT = "0x4D97DCd97eC945f40cF65F87097ACe5EA0476045"
RPC_URL = "https://polygon-rpc.com/"
def get_token_balance(wallet: str, token_id: str) -> float:
"""Get balance of a specific outcome token in shares"""
token_int = int(token_id)
# ERC-1155 balanceOf(address,uint256)
data = f"0x00fdd58e000000000000000000000000{wallet[2:].lower()}{token_int:064x}"
r = requests.post(RPC_URL, json={
"jsonrpc": "2.0",
"method": "eth_call",
"params": [{"to": CTF_CONTRACT, "data": data}, "latest"],
"id": 1
})
result = r.json().get("result", "0x0")
balance = int(result, 16) / 1e6 # Convert from raw to shares
return balance
# Usage
balance = get_token_balance(
wallet="0x7c2211103e7Fbb257Ac6fa59f972cfd8bc9D4795",
token_id="12345678901234567890"
)
print(f"Position: {balance} shares")
USDC_CONTRACT = "0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174"
def get_usdc_balance(wallet: str) -> float:
"""Get USDC balance on Polygon"""
# ERC-20 balanceOf(address)
data = f"0x70a08231000000000000000000000000{wallet[2:].lower()}"
r = requests.post(RPC_URL, json={
"jsonrpc": "2.0",
"method": "eth_call",
"params": [{"to": USDC_CONTRACT, "data": data}, "latest"],
"id": 1
})
result = r.json().get("result", "0x0")
return int(result, 16) / 1e6 # USDC has 6 decimals
# Create new API key
creds = client.create_api_key(nonce=0)
# Derive existing API key (if you lost creds but have private key)
creds = client.derive_api_key(nonce=0)
# Create or derive (tries both)
creds = client.create_or_derive_api_creds(nonce=0)
# Get all your API keys
keys = client.get_api_keys()
# Delete current API key
client.delete_api_key()
# Readonly API keys (for monitoring only)
readonly = client.create_readonly_api_key()
client.get_readonly_api_keys()
client.delete_readonly_api_key(key="...")
client.validate_readonly_api_key(address="0x...", key="...")
# Start heartbeat - if not sent within 10s, all orders cancelled
heartbeat_id = client.post_heartbeat(heartbeat_id=None)
# Continue sending heartbeats
while trading:
client.post_heartbeat(heartbeat_id=heartbeat_id)
time.sleep(5)
# Check if order is scoring (earning rewards)
is_scoring = client.is_order_scoring(
params=OrderScoringParams(order_id="...")
)
# Check multiple orders
scores = client.are_orders_scoring(
params=OrdersScoringParams(order_ids=["ID1", "ID2"])
)
notifications = client.get_notifications()
client.drop_notifications(params=DropNotificationParams(...))
IMPORTANT: Most Polymarket markets have ZERO fees (0% maker, 0% taker).
Only 15-minute BTC/ETH/SOL/XRP price prediction markets have fees:
fee = shares × 0.25 × (price × (1 - price))²
| Entry Price | Fee % (per side) |
|---|---|
| 0.50 | ~1.56% |
| 0.60 or 0.40 | ~1.44% |
| 0.70 or 0.30 | ~1.10% |
| 0.80 or 0.20 | ~0.64% |
| 0.90 or 0.10 | ~0.20% |
TAKER = crosses spread = PAYS fee MAKER = adds liquidity = NO fee + earns rebates
To be a maker: Post orders that don't immediately fill (inside the spread).
| Order Side | Price Decimals | Size Decimals |
|---|---|---|
| BUY | 2 | 4 |
| SELL | 2 | 2 |
Min order size: $1 per side
#!/usr/bin/env python3
"""
Production-ready Polymarket trading script
"""
import os
import time
import requests
from py_clob_client.client import ClobClient
from py_clob_client.clob_types import OrderArgs, ApiCreds, OrderType
# Initialize
client = ClobClient(
"https://clob.polymarket.com",
key=os.getenv("PRIVATE_KEY"),
chain_id=137,
funder=os.getenv("POLY_FUNDER_ADDRESS"),
signature_type=2
)
client.set_api_creds(ApiCreds(
api_key=os.getenv("POLY_API_KEY"),
api_secret=os.getenv("POLY_API_SECRET"),
api_passphrase=os.getenv("POLY_API_PASSPHRASE")
))
TOKEN_ID = "YOUR_TOKEN_ID"
WALLET = os.getenv("POLY_FUNDER_ADDRESS")
CTF = "0x4D97DCd97eC945f40cF65F87097ACe5EA0476045"
def get_balance(token_id):
"""Get position size"""
token_int = int(token_id)
data = f"0x00fdd58e000000000000000000000000{WALLET[2:].lower()}{token_int:064x}"
r = requests.post("https://polygon-rpc.com/", json={
"jsonrpc": "2.0", "method": "eth_call",
"params": [{"to": CTF, "data": data}, "latest"], "id": 1
})
return int(r.json().get("result", "0x0"), 16) / 1e6
def get_orderbook(token_id):
"""Get current bid/ask"""
book = client.get_order_book(token_id)
return {
"best_bid": float(book.bids[0].price) if book.bids else 0,
"best_ask": float(book.asks[0].price) if book.asks else 1
}
# Check position
position = get_balance(TOKEN_ID)
print(f"Current position: {position} shares")
# Get market
book = get_orderbook(TOKEN_ID)
print(f"Bid: {book['best_bid']:.2f}, Ask: {book['best_ask']:.2f}")
# Place a buy order (maker - inside spread)
buy_price = book['best_bid'] + 0.01 # 1 cent above bid
if buy_price < book['best_ask']: # Ensure we're maker
result = client.create_and_post_order(OrderArgs(
token_id=TOKEN_ID,
price=buy_price,
size=10.0,
side="BUY"
))
print(f"Buy order placed: {result}")
# Place a sell order (market sell via FOK)
if position > 0:
result = client.create_and_post_order(OrderArgs(
token_id=TOKEN_ID,
price=0.01, # Lowest price = immediate fill
size=position,
side="SELL"
))
print(f"Sold position: {result}")
from py_clob_client.exceptions import PolyApiException
try:
result = client.create_and_post_order(OrderArgs(...))
except PolyApiException as e:
print(f"API Error: {e}")
except Exception as e:
print(f"Error: {e}")
Common errors:
"insufficient balance" - Not enough USDC/tokens"invalid price" - Price outside 0.01-0.99 or wrong decimals"order too small" - Below minimum order size"market closed" - Market not accepting orders/poly)Access Polymarket trading directly from Claude Code:
/poly search <query> # Search markets
/poly market <condition-id> # Market details
/poly book <token-id> # View orderbook
/poly buy <token-id> <size> <price> # Buy shares (limit)
/poly sell <token-id> <size> <price> # Sell shares (limit)
/poly orders # Open orders
/poly cancel <order-id> # Cancel order
/poly cancel all # Cancel all orders
/poly trades [limit] # Recent trade history
/poly balance # USDC + positions
/poly twap <buy|sell> <token> <total> <price> [slices] [interval-sec]
/poly bracket <token> <size> <tp> <sl> # TP + SL bracket
/poly trigger buy <token> <size> <price> # Buy when price drops
Note: TWAP and bracket orders are persisted to the database and will automatically resume after restarts.
/poly redeem # One-time redeem all resolved positions
/poly redeem start # Start auto-polling (default: every 60s)
/poly redeem stop # Stop auto-polling
/poly redeem status # Check auto-redeemer status
/poly redeem pending # List positions pending redemption
/poly redeem <conditionId> <tokenId> # Redeem specific position
Env vars:
POLY_REDEEM_INTERVAL_MS - Polling interval in ms (default: 60000 = 1 minute)/poly fills # Connect fills WebSocket
/poly fills status # Show connection + recent fills
/poly fills stop # Disconnect fills WebSocket
/poly fills clear # Clear tracked fills
/poly heartbeat # Start heartbeat (keeps orders alive)
/poly heartbeat status # Check heartbeat status
/poly heartbeat stop # Stop heartbeat (orders cancelled in 10s)
/poly settlements # View pending settlements from resolved markets
/poly allowance # Check USDC approval status
/poly orderbooks <token1> [token2] ... # Batch fetch orderbooks
| Method | Parameters | Returns | Description |
|---|---|---|---|
get_ok() | - | dict | Health check |
get_server_time() | - | dict | Server timestamp |
get_address() | - | str | Your signer address |
get_collateral_address() | - | str | USDC contract |
get_conditional_address() | - | str | CTF contract |
get_exchange_address(neg_risk) | bool | str | Exchange contract |
| Method | Parameters | Returns | Description |
|---|---|---|---|
get_midpoint(token_id) | str | dict | Mid price |
get_midpoints(params) | list[BookParams] | dict | Multiple mid prices |
get_price(token_id, side) | str, str | dict | Best price for side |
get_prices(params) | list[BookParams] | dict | Multiple prices |
get_spread(token_id) | str | dict | Bid-ask spread |
get_spreads(params) | list[BookParams] | dict | Multiple spreads |
get_order_book(token_id) | str | OrderBookSummary | Full orderbook |
get_order_books(params) | list[BookParams] | list | Multiple orderbooks |
get_last_trade_price(token_id) | str | dict | Last trade |
get_last_trades_prices(params) | list[BookParams] | dict | Multiple last trades |
get_tick_size(token_id) | str | TickSize | "0.1"/"0.01"/"0.001"/"0.0001" |
get_neg_risk(token_id) | str | bool | Is neg_risk market |
get_fee_rate_bps(token_id) | str | int | Fee in basis points |
| Method | Parameters | Returns | Description |
|---|---|---|---|
get_markets(next_cursor) | str | dict | Paginated markets |
get_simplified_markets(next_cursor) | str | dict | Simplified markets |
get_sampling_markets(next_cursor) | str | dict | Featured markets |
get_market(condition_id) | str | dict | Single market |
get_market_trades_events(condition_id) | str | dict | Trade events |
| Method | Parameters | Returns | Description |
|---|---|---|---|
create_order(order_args, options) | OrderArgs, CreateOrderOptions | dict | Sign limit order |
create_market_order(order_args, options) | MarketOrderArgs, CreateOrderOptions | dict | Sign market order |
calculate_market_price(token_id, side, amount, order_type) | str, str, float, OrderType | float | Expected fill price |
| Method | Parameters | Returns | Description |
|---|---|---|---|
post_order(order, orderType, post_only) | SignedOrder, OrderType, bool | dict | Post single order |
post_orders(args) | list[PostOrdersArgs] | dict | Post batch orders |
create_and_post_order(order_args, options) | OrderArgs, PartialCreateOrderOptions | dict | Create + post (recommended) |
| Method | Parameters | Returns | Description |
|---|---|---|---|
cancel(order_id) | str | dict | Cancel one order |
cancel_orders(order_ids) | list[str] | dict | Cancel multiple |
cancel_all() | - | dict | Cancel ALL orders |
cancel_market_orders(market, asset_id) | str, str | dict | Cancel by market |
| Method | Parameters | Returns | Description |
|---|---|---|---|
get_orders(params, next_cursor) | OpenOrderParams, str | list | Get open orders |
get_order(order_id) | str | dict | Get specific order |
get_trades(params, next_cursor) | TradeParams, str | list | Trade history |
| Method | Parameters | Returns | Description |
|---|---|---|---|
create_api_key(nonce) | int | ApiCreds | Create new key |
derive_api_key(nonce) | int | ApiCreds | Derive existing key |
create_or_derive_api_creds(nonce) | int | ApiCreds | Create or derive |
set_api_creds(creds) | ApiCreds | - | Set credentials |
get_api_keys() | - | dict | List your keys |
delete_api_key() | - | dict | Delete current key |
create_readonly_api_key() | - | ReadonlyApiKeyResponse | Readonly key |
get_readonly_api_keys() | - | list[str] | List readonly keys |
delete_readonly_api_key(key) | str | bool | Delete readonly key |
| Method | Parameters | Returns | Description |
|---|---|---|---|
get_balance_allowance(params) | BalanceAllowanceParams | dict | Check balance |
update_balance_allowance(params) | BalanceAllowanceParams | dict | Refresh allowance |
| Method | Parameters | Returns | Description |
|---|---|---|---|
post_heartbeat(heartbeat_id) | str | dict | Keep orders alive (10s timeout) |
is_order_scoring(params) | OrderScoringParams | dict | Check if earning rewards |
are_orders_scoring(params) | OrdersScoringParams | dict | Check multiple orders |
get_notifications() | - | dict | Get notifications |
drop_notifications(params) | DropNotificationParams | dict | Delete notifications |
get_closed_only_mode() | - | dict | Check closed-only status |
USDC = "0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174" # Collateral token
CTF = "0x4D97DCd97eC945f40cF65F87097ACe5EA0476045" # Conditional tokens (ERC-1155)
EXCHANGE = "0x4bFb41d5B3570DeFd03C39a9A4D8dE6Bd8B8982E" # Regular exchange
NEG_RISK = "0xC5d563A36AE78145C45a50134d48A1215220f80a" # Neg risk exchange (crypto)
balance = get_token_balance(wallet, token_id)
if balance > 0:
client.create_and_post_order(OrderArgs(
token_id=token_id, price=0.01, size=balance, side="SELL"
))
book = client.get_order_book(token_id)
best_bid = float(book.bids[0].price) if book.bids else 0
maker_price = best_bid + 0.01 # 1 cent above bid
signed = client.create_order(OrderArgs(token_id=token_id, price=maker_price, size=100, side="BUY"))
client.post_order(signed, orderType=OrderType.GTC, post_only=True)
signed = client.create_market_order(MarketOrderArgs(token_id=token_id, amount=50.0, side="BUY"))
client.post_order(signed, orderType=OrderType.FOK)
client.cancel_all()
Polymarket provides WebSocket channels for real-time updates. No RPC needed - everything goes through CLOB.
MARKET_WS = "wss://ws-subscriptions-clob.polymarket.com/ws/market"
USER_WS = "wss://ws-subscriptions-clob.polymarket.com/ws/user"
Subscribe to orderbook updates, price changes, trades for any market.
import websocket
import json
def on_message(ws, message):
data = json.loads(message)
event_type = data.get("event_type")
if event_type == "book":
# Full orderbook snapshot (on subscribe + after trades)
print(f"Book update: {data['bids']}, {data['asks']}")
elif event_type == "price_change":
# Order placed/cancelled affecting price level
print(f"Price change: {data}")
elif event_type == "last_trade_price":
# Trade executed
print(f"Trade: {data['price']} x {data['size']}")
elif event_type == "tick_size_change":
# Tick size changed (price went extreme)
print(f"Tick size: {data['old_tick_size']} -> {data['new_tick_size']}")
def on_open(ws):
# Subscribe to specific token
ws.send(json.dumps({
"type": "subscribe",
"channel": "market",
"assets_ids": [TOKEN_ID] # List of token IDs
}))
ws = websocket.WebSocketApp(
"wss://ws-subscriptions-clob.polymarket.com/ws/market",
on_message=on_message,
on_open=on_open
)
ws.run_forever()
Subscribe to YOUR order updates, fills, trades. This is how you get fill notifications.
import websocket
import json
import hmac
import hashlib
import time
import base64
API_KEY = os.getenv("POLY_API_KEY")
API_SECRET = os.getenv("POLY_API_SECRET")
API_PASSPHRASE = os.getenv("POLY_API_PASSPHRASE")
def get_auth_headers():
"""Generate HMAC auth for WebSocket"""
timestamp = str(int(time.time()))
message = f"GET\n{timestamp}\n/ws/user"
signature = hmac.new(
base64.b64decode(API_SECRET),
message.encode(),
hashlib.sha256
).digest()
return {
"POLY-ADDRESS": WALLET_ADDRESS,
"POLY-SIGNATURE": base64.b64encode(signature).decode(),
"POLY-TIMESTAMP": timestamp,
"POLY-API-KEY": API_KEY,
"POLY-PASSPHRASE": API_PASSPHRASE
}
def on_message(ws, message):
data = json.loads(message)
event_type = data.get("event_type")
if event_type == "trade":
# YOUR FILL - order matched!
status = data.get("status") # MATCHED, MINED, CONFIRMED, FAILED
print(f"FILL: {data['side']} {data['size']} @ {data['price']}")
print(f" Status: {status}")
print(f" Trade ID: {data['id']}")
print(f" Market: {data['market']}")
if status == "CONFIRMED":
print(" ✓ Trade confirmed on-chain!")
elif status == "FAILED":
print(" ✗ Trade failed - check logs")
elif event_type == "order":
order_type = data.get("type") # PLACEMENT, UPDATE, CANCELLATION
print(f"ORDER {order_type}: {data['side']} {data['original_size']} @ {data['price']}")
print(f" Filled: {data.get('size_matched', 0)}")
if order_type == "CANCELLATION":
print(" Order cancelled")
def on_open(ws):
# Subscribe with auth
ws.send(json.dumps({
"type": "subscribe",
"channel": "user",
"auth": get_auth_headers(),
# Optional: filter to specific market
# "markets": [CONDITION_ID]
}))
ws = websocket.WebSocketApp(
"wss://ws-subscriptions-clob.polymarket.com/ws/user",
on_message=on_message,
on_open=on_open
)
ws.run_forever()
Market Channel:
| Event | Trigger | Key Fields |
|---|---|---|
book | Subscribe, trades affect book | bids, asks, timestamp |
price_change | Order placed/cancelled | price, size, side |
last_trade_price | Trade executed | price, size, side |
tick_size_change | Price extreme (>0.96 or <0.04) | old_tick_size, new_tick_size |
User Channel:
| Event | Trigger | Key Fields |
|---|---|---|
trade | Your order filled | status, side, size, price, market |
order | Order placed/updated/cancelled | type (PLACEMENT/UPDATE/CANCELLATION), size_matched |
MATCHED → MINED → CONFIRMED (success)
→ RETRYING → CONFIRMED/FAILED
Send PING every 10 seconds to keep connection alive:
import threading
def send_ping():
while True:
ws.send(json.dumps({"type": "ping"}))
time.sleep(10)
threading.Thread(target=send_ping, daemon=True).start()
Polymarket also provides @polymarket/real-time-data-client for TypeScript:
import { RealTimeDataClient } from "@polymarket/real-time-data-client";
const client = new RealTimeDataClient({
onMessage: (msg) => console.log(msg),
onConnect: (c) => {
// Subscribe to user fills with auth
c.subscribe({
subscriptions: [{
topic: "clob_user",
type: "*",
clob_auth: {
key: API_KEY,
secret: API_SECRET,
passphrase: API_PASSPHRASE
}
}]
});
}
});
client.connect();
| Operation | Method |
|---|---|
| Get positions | GET /data/positions?user={address} via Gamma API |
| Get balance | client.get_balance_allowance() |
| Place orders | client.create_and_post_order() |
| Get fills | User WebSocket channel |
| Get prices | client.get_order_book() or Market WebSocket |
| Cancel orders | client.cancel() |
The only time you might use RPC is to check on-chain token balances independently, but even that's available via Gamma API positions endpoint.