全部文章
指南交易机器人Polymarket APIPython

如何构建 Polymarket 交易机器人

大多数 Polymarket 机器人教程都基于已经不存在的 SDK。这是一条最新的端到端路径:2026 年该安装什么、认证实际如何运作、数据缺口在哪里,以及在第一周就让机器人挂掉的失效模式。

阅读约 14 分钟

大多数 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-client

Python 有四个客户端,选对哪一个比看起来更重要:

客户端公开数据交易实时数据
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 和价格,所以按原始字符串告警纯粹是噪音。

一个切实可行的构建顺序

最不浪费时间和金钱的顺序:

  1. 只读集成,使用公开客户端,无需密钥。验证市场发现、解析、分页和退避。一天,免费。
  2. 回测策略,基于历史订单簿并进行如实的成交模拟。大多数想法会死在这里。这正是目的所在。
  3. 实盘模拟交易至少一周:把预期订单记录到日志而不是发送。验证持续运行、重连和时机。
  4. 以最小规模上线实盘,设置硬性敞口上限和经过测试的紧急停止开关。
  5. 只有在实盘数据与模拟数据吻合时才扩大规模。如果两者有差距,说明你的成交模型错了,回到第 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 天免费试用开始。

继续阅读