如何构建 Polymarket 交易机器人
大多数 Polymarket 机器人教程都基于已经不存在的 SDK。这是一条最新的端到端路径:2026 年该安装什么、认证实际如何运作、数据缺口在哪里,以及在第一周就让机器人挂掉的失效模式。
大多数 Polymarket 机器人教程已经过时
Polymarket 已经转向统一 SDK:Python 版是 polymarket-client,TypeScript 版是 @polymarket/client。它们取代了 py-clob-client、@polymarket/clob-client-v2、@polymarket/builder-relayer-client 和 @polymarket/builder-signing-sdk。如果某个指南让你 pip install py-clob-client,或者你的 AI 助手生成了那个导入,说明它用的是过时的材料。下面的所有内容都使用当前的包。
一个 Polymarket 机器人由六部分组成:发现市场、读取价格、做出决策、下单、管理持仓,以及保持运行。前两步很简单,第四步很繁琐,而第六步才是大多数机器人真正挂掉的地方。本指南用经过验证的代码走完全程,并如实说明哪些部分是真正困难的。
第 0 步:决定你的机器人交易什么
这一步值得在写第一行代码之前完成,因为它决定了后面的一切。Polymarket 的市场分为两大类,两者几乎没有共同点:
| 事件市场 | 加密货币 Up/Down 市场 | |
|---|---|---|
| 示例 | 选举、体育、颁奖 | btc-updown-5m、eth-updown-15m |
| 存续时间 | 数周到数月 | 5 分钟到 24 小时 |
| 推动价格的因素 | 新闻、信息、情绪 | 微观结构和订单流 |
| 优势来源 | 信息更灵通 | 速度更快或定价更好 |
| 每日交易次数 | 寥寥几笔 | 数百笔 |
| 延迟敏感度 | 低 | 高 |
如果你要做自动化,你几乎肯定对第二类感兴趣:高频、连续,而且足够机械化,可以写成代码。它们在 Up/Down 市场详解中有深入介绍。
第 1 步:安装当前的 SDK
两个 SDK 都为你提供一个覆盖 Polymarket 所有 API 的客户端接口、类型化模型、一致的分页和内置签名,这些是大量你不想重新实现的繁琐工作。
pip install polymarket-client
# or: uv add polymarket-client / poetry add polymarket-clientPython 有四个客户端,选对哪一个比看起来更重要:
| 客户端 | 公开数据 | 交易 | 实时数据 |
|---|---|---|---|
AsyncPublicClient | 是 | 否 | 是 |
AsyncSecureClient | 是 | 是 | 是 |
PublicClient | 是 | 否 | 否 |
SecureClient | 是 | 是 | 否 |
subscribe()。机器人应使用异步版本;同步版本适用于脚本和 notebook。从公开客户端开始
你可以用 AsyncPublicClient 构建并测试市场发现、价格读取、信号生成以及整个数据管道:不需要密钥,不需要钱包,没有风险。只有在准备下单时才换成 AsyncSecureClient。大多数 bug 早在那之前就会暴露出来。
第 2 步:查找市场
公开的市场发现完全不需要凭证。SDK 的分页器在所有列表方法上都是一致的,所以这个模式可以通用。
import asyncio
from polymarket import AsyncPublicClient
async def main() -> None:
async with AsyncPublicClient() as client:
pages = client.list_markets(closed=False, page_size=50)
# Iterate items directly when page boundaries do not matter.
async for market in pages.iter_items():
if "updown" in (market.slug or ""):
print(market.slug, market.condition_id)
asyncio.run(main())这里有两点要牢记。第一,page.next_cursor 是一个不透明的游标:如果你想稍后恢复扫描,就原样保存它,不要尝试解析或自行构造。第二,/markets 的速率限制是整个平台最严格的,每 10 秒 300 次请求,所以要缓存市场元数据,而不是在热循环中反复列出。完整数字见速率限制参考。
第 3 步:认证
交易需要钱包。Python SDK 用本地私钥构建签名者:
import os
from polymarket import AsyncSecureClient
client = await AsyncSecureClient.create(
private_key=os.environ["POLYMARKET_PRIVATE_KEY"],
wallet=os.environ["POLYMARKET_WALLET_ADDRESS"],
)在底层,Polymarket 使用两层认证:L1 是 EIP-712 钱包签名,证明你控制该地址,并允许你创建或派生 API 凭证;L2 使用这些凭证以 HMAC-SHA256 对每个私有请求签名。SDK 会处理这两层,这也是使用它的主要原因。
你会遇到的两种认证失败
凭证不完整:L2 需要 key、secret 以及 passphrase。只有其中两样,会产生一个格式正确但签名无法验证的请求。时钟漂移:签名中嵌入了时间戳,所以时钟偏差几秒的容器会被拒绝。两者都表现为同一个毫无帮助的 Unauthorized/Invalid api key。完整解读见错误参考。
密钥管理
这个私钥可以转移资金。把它放在环境变量或密钥管理服务中:永远不要放进源代码,永远不要放进容器镜像,永远不要放进你即将推送的仓库。使用一个专用钱包,只存入机器人允许亏掉的金额,这样 bug 造成的损失以余额为上限,而不是取决于你凌晨 3 点时的判断。
第 4 步:获取实时价格
第一个机器人最常见的架构错误,就是用定时器轮询 /book。它会耗尽你的速率限制额度、增加延迟,而且扩展性很差。改用订阅:SDK 会把多个数据流合并成一个事件流。
from polymarket.streams import MarketSpec
async with await client.subscribe([MarketSpec(token_ids=[token_id])]) as stream:
async for event in stream:
# MarketBookEvent | MarketPriceChangeEvent | MarketLastTradePriceEvent
# | MarketTickSizeChangeEvent | MarketBestBidAskEvent
# | NewMarketEvent | MarketResolvedEvent
handle(event)如果你不用 SDK 而是直接连接原始 WebSocket,就必须每 10 秒发送一次 PING,否则连接会被断开;而且你需要设置 custom_feature_enabled: true 才能收到 best_bid_ask、new_market 和 market_resolved 事件。这些以及重连模式在 WebSocket 指南中有介绍。另外,参考价格已于 2026 年 9 月 15 日迁移到 PolyBolt:如果你的机器人使用流式现货价格,请参阅迁移指南。
第 5 步:下单
市价单是最简单可行的方式,amount 的单位是你愿意花费的 pUSD,而不是份数:
market = await client.get_market(slug="<market-slug>")
token_id = market.outcomes.yes.token_id
assert token_id is not None
response = await client.place_market_order(
token_id=token_id,
side="BUY",
amount="10", # spend up to 10 pUSD
)
if not response.ok:
raise RuntimeError(response.message)
# Settlement is on-chain and asynchronous — this waits for it.
hashes = await client.wait_for_order_fill_settlement(response)对于挂出的限价单,有两条规则会最先让你吃亏。价格必须落在市场的价格网格(tick grid)上:按市场调用 GET /tick-size,而不是假设为 0.01,因为 tick size 各不相同,并且可能随市场成熟而收紧。另外,低于市场最小下单量的订单会被直接拒绝。两者都会返回带有具体消息的 400,列在错误参考中。
批量请求返回 200 不代表成功
当你提交多笔订单时,单笔订单的失败会以单独的 errorMsg 字段返回在 200 响应数组内部。遍历数组并检查每一项。只检查 HTTP 状态的机器人会悄悄地以为自己持有实际上并不存在的仓位,这是一类真正危险的 bug。
第 6 步:弄清楚策略是否有效
上面的一切都是管道工程,而管道工程是容易的那一半。困难的问题是你的策略能否赚钱,而这正是构建 Polymarket 机器人与构建加密货币现货机器人截然不同的地方。
没有测试网。没有沙盒,没有演示 API,没有模拟交易端点。这些词在 Polymarket 的文档中一处都没有出现。你的第一笔真实订单就是用真钱与真实对手方交易。四种变通方法见 Polymarket 有测试网吗。
也没有历史订单簿。市场一旦结算,它的订单簿就返回 404。它保留一条大约每分钟一个点的价格序列,而且只有在你显式传入开始和结束时间时才会返回:
TOK=<token_id_of_a_resolved_market>
START=<epoch seconds the window opened>
END=$((START + 300))
curl -s "https://clob.polymarket.com/book?token_id=$TOK"
# {"error":"No orderbook exists for the requested token id"} HTTP 404
curl -s "https://clob.polymarket.com/prices-history?market=$TOK&startTs=$START&endTs=$END&fidelity=1"
# about 6 points for a 5-minute market; interval=max returns [] for older ones所以你无法基于 Polymarket 做回测。你需要有人在市场运行期间记录下来的时点快照。这正是 PolyTest 为加密货币 Up/Down 市场提供的:240M+ 条快照,每边 8 档订单簿深度,亚秒级时间戳,已结算的市场也会保留:
import os, requests
BASE = "https://api.polytest.io/api/v1"
H = {"X-API-Key": os.environ["POLYTEST_KEY"]}
markets = requests.get(f"{BASE}/markets",
params={"coin": "btc", "market_type": "5m", "limit": 50},
headers=H).json()["markets"]
snaps = requests.get(f"{BASE}/markets/{markets[0]['id']}/snapshots",
params={"include_orderbook": "true"},
headers=H).json()["snapshots"]
def simulate_fill(levels, qty):
"""Walk the ladder. Mid-price is not a price you can trade at."""
filled = cost = 0.0
for lvl in levels:
take = min(lvl["size"], qty - filled)
cost += take * lvl["price"]
filled += take
if filled >= qty:
break
return cost / filled if filled >= qty else None
print(simulate_fill(snaps[0]["orderbook"]["asks"], 500))让回测变得毫无价值的错误
如果你对着中间价回测,你测试的是一个算术恒等式,而不是策略。在按 $1 结算的合约上,Up/Down 的价差通常有 2–5 美分,经常比宣称的优势还大。逐档吃单,按你真正能拿到的成交来计算。仅这一个改变就会淘汰大多数策略,而这正是你希望它做的:在投入资金之前,低成本地淘汰。
第 7 步:在生产环境中活下来
一个正确交易了一个小时然后卡死的机器人,比没有机器人更糟。下面是实际会发生的失效模式,大致按出现频率排序:
| 失效 | 你看到的现象 | 处理方式 |
|---|---|---|
| 被限流 | 延迟上升,而不是报错 | Cloudflare 通过延迟而不是拒绝来限流:关注 p99,而不是错误率 |
| 撮合引擎重启 | 425 Too Early | 带退避重试;不要对单次出现发出告警 |
| 交易所暂停 | 503 | 停止开仓。如允许则撤单 |
| 仅取消模式 | 新订单返回 503 | 撤单路径必须独立于入场路径正常工作 |
| 仅挂单模式 | 503 + retry_after_seconds | 精确休眠该时长,然后重试 |
| 签名者不匹配 | 400 订单签名者错误 | 来自另一个钱包的过时凭证:重新派生 |
| WebSocket 掉线 | 一片沉默 | 没有数据不等于没有变化:跟踪最后一条消息的时间 |
| 时钟漂移 | 昨天还正常的机器人返回 401 | 运行 NTP;这个问题最浪费时间 |
沉默才是危险的状态
掉线的 WebSocket 不会抛出异常,它只是不再推送消息。一个持有仓位却收不到任何更新的机器人,会心安理得地认为市场冻结在它最后看到的价格上。跟踪最后一条消息的时间,把数据过时当作错误状态,而不是平静。
- 先测试撤单路径,再测试入场路径。无法退出远比无法入场更糟。
- 在代码里限制敞口,而不是在脑子里。硬性仓位上限能把一个逻辑 bug 变成一笔小亏损,而不是无上限的亏损。
- 构建一个紧急停止开关,并真正测试它。未经测试的紧急停止开关只是一行注释。
- 给定时任务加入随机抖动。在整秒准时唤醒的 worker 会产生一个远高于平均速率的同步尖峰。
- 第一周记录每一个请求和响应。你会用得上,而且事后无法重建。
- 按类别告警,而不是按消息内容。Polymarket 会在错误字符串中嵌入订单 ID 和价格,所以按原始字符串告警纯粹是噪音。
一个切实可行的构建顺序
最不浪费时间和金钱的顺序:
- 只读集成,使用公开客户端,无需密钥。验证市场发现、解析、分页和退避。一天,免费。
- 回测策略,基于历史订单簿并进行如实的成交模拟。大多数想法会死在这里。这正是目的所在。
- 实盘模拟交易至少一周:把预期订单记录到日志而不是发送。验证持续运行、重连和时机。
- 以最小规模上线实盘,设置硬性敞口上限和经过测试的紧急停止开关。
- 只有在实盘数据与模拟数据吻合时才扩大规模。如果两者有差距,说明你的成交模型错了,回到第 2 步。
第 1、3、4 步你几天内就能搭好。第 2 步需要 Polymarket 不保留的数据,也是最能稳定帮你省钱的一步。在 PolyTest 开始免费试用:足够弄清楚你的想法能否扛住价差。
常见问题
- 如何构建 Polymarket 交易机器人?
- 安装当前的统一 SDK:Python 用 polymarket-client,TypeScript 用 @polymarket/client。用 AsyncPublicClient 在无需凭证的情况下发现市场和读取价格,然后用带私钥的 AsyncSecureClient 进行交易。订阅 WebSocket market 频道获取价格,而不是轮询;用 place_market_order 下单,并用退避处理 425、429 和 503 响应。上线实盘之前,基于历史订单簿快照进行带真实成交模拟的回测,因为 Polymarket 没有测试网,也不保留订单簿历史。
- 2026 年 Polymarket 机器人应该用什么 SDK?
- 用统一 SDK:Python 用 polymarket-client,TypeScript 用 @polymarket/client。它们取代了旧的 py-clob-client、@polymarket/clob-client-v2、@polymarket/builder-relayer-client 和 @polymarket/builder-signing-sdk 包。统一的 Rust SDK 正在开发中。大多数教程和 AI 生成的代码仍然引用已弃用的包,所以在相信一段代码之前先检查导入。
- 在冒真金白银的风险之前,可以在 Polymarket 上模拟交易吗?
- Polymarket 本身不提供:没有测试网、沙盒或演示 API。你可以自己搭建一个模拟交易层:让你的实盘策略循环对着生产市场数据运行,把预期订单连同那一刻的订单簿状态记录到日志,而不是提交。这能证明你的机器人在运维上可靠,但它假设订单都能成交,所以学不到排队位置或市场冲击。
- 如何回测 Polymarket 交易机器人?
- 你需要来自第三方的历史订单簿快照,因为 Polymarket 的 API 对已结算市场的订单簿返回 404,价格历史只保留大约每分钟一个点。拉取带完整深度的时点快照,按时间顺序回放且不偷看未来,并通过逐档吃单而不是假设中间价来模拟成交。在 $1 合约上 2-5 美分的 Up/Down 价差通常比宣称的优势还大,所以中间价回测具有误导性。
- 为什么我的 Polymarket 机器人返回 Unauthorized/Invalid api key?
- 最常见的是两种情况之一。要么你的凭证不完整:L2 认证需要 API key、secret 和 passphrase 三者一起;要么你的系统时钟发生了漂移,因为请求签名中嵌入了时间戳,几秒的漂移就会让它失效。较少见的情况是,你派生凭证所用的钱包与你交易所用的钱包不同。
- Polymarket 机器人需要 WebSocket,还是可以轮询?
- 用 WebSocket。用定时器轮询 /book 会耗尽速率限制额度、增加延迟,而且扩展性差。订阅 CLOB market 频道获取公开的订单簿和价格更新,订阅 user 频道获取你自己的订单和成交更新。如果你直接连接原始 WebSocket 而不是通过 SDK,需要每 10 秒发送一次 PING 来保持连接。
获取 Polymarket 不保留的历史数据
PolyTest 在 Polymarket 加密货币 Up/Down 市场运行期间实时记录:240M+ 条快照,包含 8 档订单簿深度、亚秒级时间戳,并保留已结算的市场。从 3 天免费试用开始。
继续阅读
Polymarket 现货滞后优势是真的,但它只有大约 $100 深
在 Polymarket 重新定价之前,买入现货已经确认的那一方。与人们声称的大多数策略不同,这个策略经得起数据检验,z 值高达 15。它之所以没能让所有人发财,原因就摆在订单簿里。
Polymarket WebSocket:不掉线的实时数据
轮询订单簿是白白耗尽速率限制额度最常见的方式。下面介绍四个数据流、没人写进文档的订阅选项,以及那种让你的机器人收到一片沉默、却以为市场很平静的失效模式。
2026 年的 Polymarket Python SDK(以及如何迁移出 py-clob-client)
如果你的代码还在从 py_clob_client 导入 ClobClient,那它就建立在一个已被取代的包之上,AI 助手为你写的大部分 Polymarket 代码也是如此。下面介绍当前的 SDK 以及如何迁移。