Quick Setup
Credentials
There are three ways to provide credentials:- Private key only
- Full credentials
- Environment variables
When only You can also call the derivation manually before
private_key is set, Horizon automatically derives API credentials from the CLOB /auth/derive-api-key endpoint on startup (requires eth-account package):hz.run():This requires
pip install eth-account. The automatic derivation only happens in live mode. Call derive_api_credentials() manually if you need the credentials earlier.Polymarket Configuration
| Field | Default | Description |
|---|---|---|
private_key | None | Ethereum private key for EIP-712 signing |
clob_url | https://clob.polymarket.com | CLOB API base URL |
gamma_url | https://gamma-api.polymarket.com | Gamma API for market metadata |
api_key | None | CLOB API key |
api_secret | None | CLOB API secret (base64-encoded, used as HMAC-SHA256 key) |
api_passphrase | None | CLOB API passphrase |
EIP-712 Signing
Polymarket orders require EIP-712 typed data signatures for the CTF Exchange contract on Polygon (chainId 137). Horizon handles this entirely in Rust usingk256 (secp256k1). No Python crypto dependencies needed.
The signing flow:
- Build
CtfOrderstruct (token_id, maker address, price, size, nonce, etc.) - Generate a cryptographically random salt (UUID v4)
- Compute EIP-712 struct hash and domain separator
- Sign the digest with the private key (ECDSA on secp256k1)
- Submit the signed order to the CLOB API
Order Types & Time-in-Force
Polymarket supports four time-in-force modes for limit orders, plus market orders:| Order Type | TimeInForce | Behavior |
|---|---|---|
| Limit | GTC | Good-til-Canceled. Rests on the book until filled or canceled. |
| Limit | GTD | Good-til-Date. Expires at a specified time. |
| Limit | FOK | Fill-or-Kill. Must fill entirely in one match or is rejected. |
| Limit | FAK | Fill-and-Kill (Immediate-or-Cancel). Fills what it can, cancels the rest. |
| Market | (auto) | Uses FOK semantics. Executes immediately at best available price or fails. |
Order Management
Submit Orders
Orders are submitted through the pipeline viahz.Quote objects, or directly via the engine:
Cancel Orders
In the pipeline loop,
hz.run() automatically calls cancel_market() before submitting new quotes each cycle (cancel-before-requote pattern). You typically don’t need to cancel manually.Amend Orders
Token ID Routing
Polymarket uses numeric token IDs (not market slugs) to identify outcomes. Each market has a Yes token and a No token:Market Resolution
Whenmode="live", Horizon queries the Gamma API to resolve market metadata:
yes_token_id/no_token_id(from thetokensarray orclobTokenIdsfield)condition_idneg_riskexchange = "polymarket"
RuntimeError is raised to prevent trading with an invalid market.
Position Reconciliation
Horizon can fetch your current Polymarket positions for reconciliation:Position objects with:
market_id(the asset/token ID)side(Yes or No, parsed from theoutcomefield)sizeandavg_entry_priceexchange = "polymarket"
Fill Polling
Polymarket fills arrive via polling the/trades endpoint. Each cycle, drain_fills() calls poll_fills_async() which:
- Queries recent trades for tracked order IDs
- Deduplicates against previously seen fill IDs (FIFO eviction, capped at 10k)
- Returns new fills with exchange-assigned timestamps
Order Scoring & Rewards
Polymarket pays USDC liquidity rewards to qualifying market makers. You can check if a live order qualifies:GET /order-scoring?order_id=... endpoint. Returns False for non-Polymarket exchanges.
For full rewards tracking (eligible markets, rebate estimation, pipeline integration), see the Rewards Tracker documentation.
HMAC-SHA256 Authentication
API requests are authenticated with HMAC-SHA256:- The
api_secretis base64-decoded and used as the HMAC-SHA256 key - Each request includes headers:
POLY_TIMESTAMP,POLY_API_KEY,POLY_SIGNATURE, andPOLY_PASSPHRASE - The signature covers the timestamp, HTTP method, request path, and body
POLY_SIGNATURE header.