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>
84 lines
4 KiB
Markdown
84 lines
4 KiB
Markdown
# 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.
|
||
|
||
```bash
|
||
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). Set `funder=` /
|
||
`POLY_PROXY_ADDRESS` to the proxy address that holds the USDC.
|
||
- `2` — Gnosis-safe proxy (browser-wallet signup). Also needs `funder=`.
|
||
- `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, so
|
||
`get_balance_allowance()` shows the balance with no `funder` needed.
|
||
|
||
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; supply `expiration` (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.
|