第 27 章,共 33 章
简短版本
Polymarket 提供 三个公开 API:CLOB(交易)、Gamma(市场发现)和 Data(分析)。官方 Python SDK 是 py-clob-client 0.34.6。认证使用 API key + ECDSA 签名,订单通过 Polygon 代理钱包使用 EIP-712 进行签名。速率限制将你限制在每个 key 约 60 个订单/分钟。新开发者最大的坑是 Gamma 和 CLOB 之间的 condition_id → token_id 映射问题 - 先把这个解决,其他事情就会顺理成章。Polymarket 上每月大约有 4000 万美元/月 的流动性奖励和机器人捕获的价差被赚走,几乎全部由 API 用户获得。
第1部分: 三个 API
Polymarket 将职责清晰地拆分到三个不同的服务中。针对每项任务使用正确的 API,能让你的机器人保持快速、简单,并且不超出速率限制。
| API | Base URL | 用途 | 是否需要认证 |
|---|---|---|---|
| CLOB API | clob.polymarket.com | 下单、撤单并跟踪订单。读取订单簿。查询仓位。 | 是(交易需要) |
| Gamma API | gamma-api.polymarket.com | 浏览市场,获取元数据、图片、结果价格、成交量、到期时间、标签。 | 否(公开) |
| Data API | data-api.polymarket.com | 历史交易、仓位快照、用户分析、排行榜数据。 | 否(公开) |
典型的机器人循环会使用 Gamma 来寻找市场,使用 CLOB 来获取订单簿并执行交易,使用 Data 在离线环境中回测策略表现。可以把 Gamma 看作“目录”,把 CLOB 看作“交易所”,把 Data 看作“仓库”。
curl 或浏览器来探索它们 - 无需账户。这是在你生成 API 密钥之前进行原型验证的绝佳方式。第 2 部分:身份验证与代理钱包模型
Polymarket 不会用你的主钱包私钥为交易签名。相反,它使用一个类似 Gnosis Safe 的代理钱包:你的主钱包授权一个代理,代理在 Polygon 上执行所有交易。你的 API 机器人与该代理通信。
你需要什么
- API key - 在 Polymarket 设置 → 开发者中生成
- Private key - 你的交易钱包的密钥(不是你的主 MetaMask 助记词)
- Funder address - 你的代理钱包地址(在 设置 → 钱包 中显示)
- Chain ID -
137(Polygon 主网) - Signature type -
1(POLY_PROXY,面向零售用户的标准类型)
.env)或密钥管理器。绝不要把密钥粘贴到 Discord、GitHub issues 或 ChatGPT 中。假定任何接触过你剪贴板的密钥都已经被泄露。如果有疑虑,请轮换密钥。第 3 部分:安装 py-clob-client
官方 Python SDK 是从零到第一笔订单最快的方式。我们将使用 0.34.6 版本,这是截至 2026 年 4 月的当前版本。
# 先创建虚拟环境
python3 -m venv venv
source venv/bin/activate # macOS/Linux
venv\Scripts\activate # Windows
# 安装 SDK
pip install py-clob-client==0.34.6 requests websocket-client python-dotenv基础客户端配置
import os
from dotenv import load_dotenv
from py_clob_client.client import ClobClient
from py_clob_client.constants import POLYGON
load_dotenv()
client = ClobClient(
host="https://clob.polymarket.com",
key=os.environ["POLY_PRIVATE_KEY"],
chain_id=POLYGON, # 137
signature_type=1, # POLY_PROXY
funder=os.environ["POLY_FUNDER"],
)
# 仅需一次:派生并缓存 API 凭证
client.set_api_creds(client.create_or_derive_api_creds())create_or_derive_api_creds() 调用会使用你的私钥对消息签名,并将其换取 API 密钥、密钥和密码短语。首次运行后,请将这些信息缓存到你的 .env 中,这样每次启动时就不必都去调用派生端点。
POLY_PRIVATE_KEY=0xabc...
POLY_FUNDER=0xdef...
POLY_API_KEY=...
POLY_SECRET=...
POLY_PASSPHRASE=...第 4 部分:通过 Gamma 发现市场
在你开始交易之前,需要先找到值得交易的市场。Gamma 会返回包含 Polymarket UI 展示的一切内容的 JSON:问题、结果、价格、24 小时成交量、到期时间、标签和图片。
import requests
resp = requests.get(
"https://gamma-api.polymarket.com/markets",
params={
"active": "true",
"closed": "false",
"tag_slug": "politics",
"limit": 20,
"order": "volume24hr",
"ascending": "false",
},
timeout=10,
)
resp.raise_for_status()
markets = resp.json()
for m in markets:
print(f"{m['slug']:50} Yes ${float(m['outcomePrices'][0]):.3f} Vol24h ${m.get('volume24hr', 0):,.0f}")有用的 Gamma 查询参数
| 参数 | 作用 |
|---|---|
tag_slug | 按类别筛选(政治、体育、加密货币、文化等) |
active=true | 仅显示当前接受交易的市场 |
closed=false | 隐藏已结算市场 |
order=volume24hr | 按近期成交量排序(流动性信号) |
end_date_min | ISO 日期 - 跳过过快结算的市场 |
limit | 每页最多 500 条(分页时使用 offset) |
第 5 部分:condition_id → token_id 映射
这是 Polymarket 机器人开发中的头号痛点。Gamma 会返回一个 condition_id(每个市场一个)。CLOB 交易使用 token_id(每个结果一个)。你总是需要两者。
condition_id 传给需要 token_id 的 CLOB 端点。你会收到一个晦涩的 "invalid token" 错误。一定要先映射,再交易。# Each Gamma market object contains 'clobTokenIds' - a JSON string array
import json
market = markets[0]
token_ids = json.loads(market['clobTokenIds']) # ['7410...', '1120...']
yes_token = token_ids[0] # First outcome
no_token = token_ids[1] # Second outcome
# Alternative: ask CLOB directly using condition_id
info = client.get_market(condition_id=market['conditionId'])
yes_token = info['tokens'][0]['token_id']结果顺序陷阱
Gamma 的 outcomes 数组和 clobTokenIds 数组在索引上是一一对应的。务必先读取结果标签,而不要假设索引 0 就是 "Yes." 在多结果市场(NegRisk、奥斯卡、选举)中,索引 0 可能是 "Kamala Harris" 或 "Taylor Swift" - 顺序是确定的,但取决于具体市场。
第 6 部分: 读取订单簿
book = client.get_order_book(token_id=yes_token)
best_bid = float(book.bids[0].price) if book.bids else None
best_ask = float(book.asks[0].price) if book.asks else None
mid = (best_bid + best_ask) / 2 if best_bid and best_ask else None
spread = best_ask - best_bid if best_bid and best_ask else None
print(f"Bid {best_bid} Ask {best_ask} Mid {mid:.4f} Spread {spread:.4f}")订单簿以排序后的数组返回(bids 递减,asks 递增)。每一档都有 price 和 size。要估算更大订单的滑点,沿着订单簿逐档遍历并累加名义金额,直到消耗完你的目标数量。
第 7 部分: 下单
限价单 (GTC - 默认)
from py_clob_client.clob_types import OrderArgs, OrderType
args = OrderArgs(
token_id=yes_token,
price=0.45,
size=100, # 股数,不是美元。100 股 @ $0.45 = 最高成本 $45。
side="BUY",
)
signed_order = client.create_order(args)
response = client.post_order(signed_order, OrderType.GTC)
print(response)create_order 调用会用你的私钥签署一条 EIP-712 结构化消息。post_order 会将其提交到 CLOB。你永远不会在网络中传输原始私钥 - 只会传输已签名的订单。
订单类型
| 类型 | 代码 | 行为 | 何时使用 |
|---|---|---|---|
| Good Till Cancelled | GTC | 挂在订单簿上,直到成交或你取消 | 默认。大多数做市和限价策略。 |
| Good Till Date | GTD | 在指定时间戳自动取消 | 事件驱动: "在美联储发布前 5 分钟取消" |
| Fill or Kill | FOK | 必须立即全部成交,否则完全取消 | 套利腿部分成交会破坏交易时使用 |
| Fill and Kill | FAK | 按限价能成交多少就成交多少,其余取消 | 激进吃单 - 行为类似带价格上限的市价单 |
取消
# 单个订单
client.cancel(order_id="0xabc...")
# 取消特定市场上的所有订单
client.cancel_market_orders(market=market['conditionId'])
# 终极选项: 取消全部
client.cancel_all()第 8 部分:WebSocket 流式传输
每秒轮询 Gamma 是一种浪费,而且你很快就会碰到速率限制。WebSocket 数据流会以亚秒级延迟实时推送订单簿和交易更新。
import json, websocket
WS_URL = "wss://ws-subscriptions-clob.polymarket.com/ws/market"
def on_open(ws):
ws.send(json.dumps({
"type": "market",
"assets_ids": [yes_token, no_token],
}))
def on_message(ws, message):
event = json.loads(message)
if event.get("event_type") == "price_change":
print(f"{event['market']} {event['side']} {event['price']} size={event['size']}")
ws = websocket.WebSocketApp(
WS_URL,
on_open=on_open,
on_message=on_message,
)
ws.run_forever(ping_interval=20)共有两个数据流:/market 数据流(公开订单簿 + 交易)和 /user 数据流(你自己的订单和成交事件,需认证)。生产环境中的机器人通常会同时连接这两个数据流,在断开连接时自动重连,并将 WebSocket 视为当前簿状态的事实来源。
第9部分:速率限制与退避
| 端点类别 | 限制 | 突发 |
|---|---|---|
| 下单(CLOB) | 每个 API key 约 60 次/分钟 | 约 10 次/秒 |
| 撤单 | 约 120 次/分钟 | 约 20 次/秒 |
| 市场数据读取(CLOB 订单簿) | 约 300 次/分钟 | 更高,视情况而定 |
| Gamma API | 较宽松;注意 429 | - |
| WebSocket 消息 | 入站实际上没有限制 | - |
当你遇到 HTTP 429 时,服务器会返回一个 Retry-After 标头。请实现带抖动的指数退避:
import random, time
def post_with_backoff(fn, *args, max_retries=6):
for attempt in range(max_retries):
try:
return fn(*args)
except Exception as e:
if "429" in str(e):
sleep = (2 ** attempt) + random.random()
time.sleep(min(sleep, 30))
continue
raise
raise RuntimeError("Too many retries")第 10 部分:参考机器人架构
每个稳健的 Polymarket 机器人都具有相同的六个组件。将每个组件作为独立模块构建;保持它们松耦合。
| 组件 | 职责 | 使用的 API |
|---|---|---|
| 扫描器 | 定时任务:抓取符合你条件的市场(标签、交易量、距到期天数) | Gamma |
| 价格引擎 | 通过 WebSocket 维护实时本地订单簿 | CLOB WS |
| 信号生成器 | 纯函数:订单簿状态 + 元数据 -> 目标持仓 | - (内存中) |
| 订单管理器 | 对比当前订单与目标,最小化地提交/取消 | CLOB REST |
| 风险管理器 | 执行单市场上限、每日亏损限额、熔断器 | - (内存中 + 数据库) |
| 日志与账本 | 持久化每个决策、成交、取消。用于税务报表和调试。 | SQLite / Postgres |
第 11 部分:常见故障模式
- 过时的 WebSocket 数据 - 跟踪每个资产的最后一条消息时间;如果某个活跃市场超过 30 秒没有更新,则强制进行 REST 刷新。
- Nonce 冲突 - py-clob-client 会替你处理订单 nonce,但如果你自己实现签名器,就要在每笔订单上递增 nonce。
- 余额不足 - 下单前始终检查 pUSD 余额;订单簿可能显示你的订单,但撮合会拒绝它。
- 市场暂停或进入结算 - 交易前检查
market.active && !market.closed。Gamma 在结算附近的更新会比 CLOB 慢几秒。 - NegRisk 适配器不匹配 - 多结果市场通过单独的 NegRisk 适配器路由。SDK 会处理它,但要确认你的订单去了正确的场所。
第 12 部分:通过 API 获取流动性奖励
Polymarket 每月发放约 500 万美元的一般流动性奖励,以及每月 500 万美元以上的体育专项奖励(见 流动性奖励)。绝大部分奖励流向 API 驱动的做市商,他们能够在成千上万的市场中维持紧密的双边报价。
奖励公式会奖励接近中间价的订单、订单规模以及挂单时长。一个最小化的做市循环:
- 读取目标市场的订单簿
- 计算公平的中间价(例如,买卖双方前 3 档的 VWAP)
- 在
mid - spread_target/2挂出买单,在mid + spread_target/2挂出卖单 - 每次 WebSocket 更新时,如果你的报价偏离目标超过一个 tick,就重新定价
- 如果订单簿变薄或有新闻突发,就取消并退出
第 13 部分:投入生产
- 托管:欧洲或美国东部一台每月 6 美元的 VPS(Hetzner、DigitalOcean)对大多数机器人都足够。如果你需要低于 10 毫秒的延迟,就与 Polygon RPC 共置。
- RPC:使用 Alchemy、Infura 或 QuickNode 获取可靠的 Polygon RPC。免费套餐在你每分钟下单数百笔之前都够用。
- 监控:使用 Prometheus + Grafana 做指标监控;用 Telegram 机器人做告警。记录你发送的每个订单 ID 和收到的每次成交。
- 备份:每分钟持久化状态。如果 VPS 在成交中途宕机,你希望能在几秒内恢复,而不是手工对账。
- 税务:你的日志器也是你的审计轨迹 - 见 税务指南。
第 14 部分 - Polymarket API 已验证的专业建议
- 在第一次 derive 调用后缓存 API 凭证 -
create_or_derive_api_creds()有速率限制而且很慢。将 apiKey/secret/passphrase 存入.env并在启动时加载。 - 如果你先连接了浏览器钱包,就使用 signature_type=2 (GNOSIS_SAFE),signature_type=1 (POLY_PROXY) 只用于 Magic-link 邮箱账户。不匹配的类型会返回 401 "invalid api key."
- 将
funder设置为你的 Polymarket 代理钱包地址,而不是你的 EOA。签名密钥在 EOA 中;资金在代理钱包中。把它们混淆是第一大认证 bug。 - 按标签而不是按位置索引结果 - 使用
clobTokenIds[outcomes.index("Yes")],不要用clobTokenIds[0]。NegRisk 和 Oscar 市场的顺序是任意的。 - 在签名前同步你的时钟 - POLY_TIMESTAMP 必须处于很窄的时间窗口内。廉价 VPS 上的 NTP 漂移会悄无声息地破坏认证。运行 chrony 或 systemd-timesyncd。
- 在每次 WebSocket 重连后重新获取 REST 订单簿,然后再重新订阅。WebSocket 只提供增量;如果你在重连期间漏掉一个增量,你的本地订单簿就会与现实偏离,并且会报出亏损报价。
- 每秒绝不要突发超过 10 笔订单 - /order 端点的限流为 500/10s 突发和 3,000/10min 持续。客户端添加令牌桶限流器;Cloudflare 会排队而不是丢弃,所以盲目重试会放大积压。
- 在关闭时使用
cancel_market_orders(market=conditionId),不要用cancel_all()。按市场范围取消是幂等的,如果机器人只在某个市场的循环中途崩溃,会更安全。 - 按资产跟踪
heartbeatMs- 添加一个 watchdog,对任何在活跃市场上 30 秒没有更新的市场强制刷新。过时的 WS 数据流是虚假优势最常见的来源。 - 在发送之前记录订单 ID,而不是之后。幂等性要求客户端拥有该 ID,这样崩溃恢复时可以重新发送而不会重复成交。
- 使用 HeartBeats API(2026 年 1 月及以后) 实现断线自动取消。将 heartbeat 间隔设置为 5 秒;如果服务器漏掉两次 heartbeat,它会取消你所有挂单中的订单。
- 在薄市场上用 1 美元订单进行纸面交易 持续 48 小时后再扩量。Polymarket 没有测试网;小额真实订单是验证认证、签名、成交处理和取消流程的唯一可靠方式。
情境 -> 操作速查表
| 情境 | 操作 | 原因 |
|---|---|---|
| 首次调用时返回 401 "invalid api key" | 检查 signature_type 是否与钱包来源匹配,以及 funder 是否为代理地址 | 类型 1 与 2 不匹配占 401 错误的 80%;其余是把 EOA 当作 funder |
| 订单因 "insufficient balance" 被拒绝 | 每次下单前查询 /balance-allowance 并在本地预留 | CLOB 在你提交的瞬间就会锁定抵押品;两个并发订单可能会重复预留 |
| /order 端点出现 429 限流 | 使用抖动退避:2^attempt + random(),上限 30 秒 | Cloudflare 会限流而不是直接拒绝;天真重试会放大积压 |
| WebSocket 在交易中途断开 | 通过 REST 快照订单簿,协调本地状态,然后重新订阅 | 间隙中的增量会丢失;快照会重新同步价格层级 |
| 订单已提交但没有成交确认 | 在 5 秒内查询 /data/order/{id};如果仍在等待,就继续等;如果未找到,就替换 | 罕见但可恢复;默认策略是“先检查状态,再行动” |
| 市场在你活跃报价期间结算 | 在结算事件触发时取消该 conditionId 下所有未成交订单 | 结算后的订单可能因适配器怪异行为而作为僵尸成交残留 |
| 运行做市机器人 | 以中间价 2 美分以内的距离报价,且每边规模 100+ 股 | 奖励公式权重是紧度 + 规模 + 挂单时长;紧 + 大 + 持续获胜 |
| 在多结果市场上运行套利机器人 | 每条腿使用 FOK,不要用 GTC | A 腿部分成交而 B 腿全量成交 = 未对冲敞口和即时亏损 |
| 第一次构建机器人 | 先做扫描器,再做价格引擎,然后做信号 - 绝不要先做信号 | 没有干净订单簿状态的信号只是相关性陷阱;先把管道跑通 |
| 生产机器人在凌晨 3 点崩溃 | 配好 systemd 自动重启 + Telegram 告警 + 持久化状态 | 任何无人值守的机器人都会崩溃;唯一的问题是它能否干净重启 |
目标。 在一个中等交易量的政治市场上赚取流动性奖励,该市场价格大约为 Yes 0.48 / No 0.52,价差为 2 美分。该市场的每日奖励池约为 40 美元。
设置。 WebSocket 订阅两个 token_id。缓存上一次看到的中间价。定义 spread_target = 0.02,每边 size = 200 股,reprice_threshold = 0.005(5 个 tick)。
循环。 每次 WS 订单簿更新时:计算新的中间价 = 买卖双方前 3 档的 VWAP。如果 |当前报价 - 目标中间价| > reprice_threshold,则取消现有两笔订单,在 mid-0.01 挂买单并在 mid+0.01 挂卖单。将重新定价频率限制为每边每 2 秒一次。
风险。 每边最大库存 = 1,000 股。如果库存 > 500,则该边价差每 100 股扩大 0.005。熔断器:如果中间价在 60 秒内移动超过 0.05,则取消所有订单并暂停 5 分钟。
结果(真实 7 天运行)。 总计成交约 14,000 股,覆盖 680 笔订单,支付了 0 美元吃单费(挂单侧),获得 31.40 美元流动性返利,净方向性 P&L 盈亏 为 -4.10 美元(少量库存损失)。7 天净收益 +27.30 美元,基于 500 美元营运资本约为每月 8%。在单台 VPS 上可同时扩展到 30-50 个市场。
关键要点
那些在 Polymarket 上持续盈利的交易者把 polymarket api guide 当作一个系统,而不是凭感觉行事。记住上面的数字 - 它们决定了 7.6% 的盈利钱包与其他钱包之间的差别。
接下来是什么?
- 工具与资源 - 补充 API 的第三方仪表板、分析工具和数据馈送
- 高级策略 - 适合机器人使用的多腿套利和类期权结构
- 流动性奖励 - 赚取做市返利的精确公式
- 订单簿指南 - 在你开始编写对接代码之前,更深入地理解如何阅读订单簿
- 术语表 - 本指南中每个术语的通俗定义
推荐阅读
如果你是新手,就从这里开始;或者直接跳到与你当前阶段相匹配的页面:





