Public market data via direct HTTP; authenticated CLOB trading via the official py-clob-client-v2 SDK. Includes README, endpoint reference, and trading/auth guide. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
4 KiB
Polymarket trading & authentication
Authenticated CLOB access is two-layered. TradingClient (in
scripts/polymarket.py) wraps the official v2 SDK (py_clob_client_v2),
which implements both layers correctly. Read this when an order behaves
unexpectedly or you need to choose a signature type.
pip install py_clob_client_v2
L1 — wallet / EIP-712
Your wallet private key signs an EIP-712 message under the ClobAuthDomain
(name ClobAuthDomain, version 1, chainId 137 Polygon). L1 is used to:
- create API credentials (
POST /auth/api-key) - derive existing credentials (
GET /auth/derive-api-key) - sign each order locally before it is posted
The L1 request headers are POLY_ADDRESS, POLY_SIGNATURE, POLY_TIMESTAMP,
POLY_NONCE. You never send the private key anywhere — only signatures.
L2 — API key / HMAC
Credential creation returns apiKey, secret, passphrase. Every subsequent
trading request (post/cancel/query orders, balances) is authenticated with an
HMAC-SHA256 signature over the request, sent as headers POLY_ADDRESS,
POLY_SIGNATURE, POLY_TIMESTAMP, POLY_API_KEY, POLY_PASSPHRASE.
TradingClient calls create_or_derive_api_key() on construction, so the
first run derives (or creates) and caches creds in memory. To reuse fixed creds
across runs, set CLOB_API_KEY, CLOB_SECRET, CLOB_PASSPHRASE.
Signature types (how your funds are held)
Pass signature_type to TradingClient(signature_type=...):
0— EOA: you trade directly from the signing wallet.1— Polymarket proxy (older email/magic login). Setfunder=/POLY_PROXY_ADDRESSto the proxy address that holds the USDC.2— Gnosis-safe proxy (browser-wallet signup). Also needsfunder=.3— newer Polymarket embedded-wallet accounts (current email/Google signups). The signer key (from "Export Private Key" in Settings → 账号 → 私钥) resolves to a Magic EOA, while the funded trading account is a separate address shown in Settings → 个人资料 → 地址 (even though it's labelled "for API use only"). Under type 3 the SDK derives that account from the signer automatically, soget_balance_allowance()shows the balance with nofunderneeded.
Undocumented gotcha that wastes hours: types 0/1/2 will all silently return
balance: 0 for these newer accounts because they derive the wrong proxy. If
auth succeeds (creds + correct signer address) but balance is 0 under 1/2, try
signature_type=3. Confirm you've got the right type when balance matches
your on-screen 现金 and the three exchange allowances are large (≈2^256-1).
If you signed up on polymarket.com with a browser wallet, you are almost always
type 2; older email/magic is 1, newer email/Google is often 3. Trading
from a raw key you funded directly
is type 0. Getting this wrong yields "not enough balance/allowance" errors
even when funds are visible in the UI.
Order types
GTC— good-till-cancelled limit order (rests on the book).GTD— good-till-date; supplyexpiration(unix seconds).FOK— fill-or-kill (used for market orders by default).FAK— fill-and-kill (immediate, partial allowed, remainder cancelled).
Prices are in USDC per share, 0–1. Size is in shares (for limit orders) or USDC
amount (for create_market_order). Tick size and min order size vary by market:
check clob.tick_size(token_id) first; orders off-tick are rejected.
Allowances
Before the first trade the exchange contracts need USDC (and CTF) allowances set
on-chain. The official client exposes update_balance_allowance() /
get_balance_allowance(); the Polymarket web UI sets these automatically on
first deposit. If posting fails with an allowance error and you funded via the
website, you likely have the wrong signature_type/funder (see above) rather
than a missing allowance.
Safety
These are real, hard-to-reverse financial actions. Always confirm token_id, side, price, and size with the user before posting, and never place an order the user did not explicitly authorize. Do not log the private key.