Polymarket Bot 教程 · 第 8 章,共 32 章

面向 bot 的 Polymarket CLOB API:用于订单簿快照的 REST endpoints、用于实时更新的 WebSocket subscriptions、bids/asks 解析、mid-price 和 depth 计算、代码示例。

本章内容

CLOB API 是订单被签名、发送、撮合,以及订单簿所在的地方。Polymarket 维护两代 SDK-已弃用的 v1 和当前的 v2。本章仅覆盖 v2;在你 2026 年交付的任何 bot 里都不应出现 v1。我们会讲解 REST snapshot 路径、WebSocket 更新通道、新手最容易出错的解析细节,以及没有它就会让长期运行的 bot 在数小时内与真实状态失去同步的 reconnect 逻辑。

  • CLOB v1 vs v2(使用 v2)
  • 订单簿 REST snapshot
  • WebSocket subscriptions:market 和 user channels
  • bids/asks/depth 解析
  • 计算 mid-price 和 best-bid/ask
  • maker fees、taker fees、rebates
  • 代码:连接 WS 并处理 price-change events
  • reconnect 和 gap-handling

CLOB v1 vs v2(使用 v2)

Polymarket 维护两代 SDK。v1(npm 上的 @polymarket/clob-clientpy-clob-client <0.30)已弃用,并且缺少 2024 年新增的若干订单类型。v2(Node 中的 @polymarket/clob-client-v2 v1.0.6,Python 中的 py-clob-client 0.34.6+)是当前标准。

有三个具体差异。v2 支持多结果市场的 negRisk 标志-这是 NegRisk exchange 在 2024 年底上线后所必需的。v2 为 WebSocket message shapes 提供 TypeScript types;v1 返回 any。v2 原生处理 2025 年 8 月的 Gnosis Safe signature flow;v1 需要自定义 signing glue。

本章其余部分都默认使用 v2。如果你在旧教程里看到 v1 代码,在被证明无误之前都应视为有问题-尤其是在 NegRisk markets 上提交订单时,v1 可能会静默地把订单路由到错误的 exchange contract。

订单簿 REST snapshot

REST snapshot endpoint 会返回某个单一 token 在某一时刻的完整订单簿。

GET https://clob.polymarket.com/book?token_id=<ERC1155_TOKEN_ID>

响应结构:

{
  "market": "0x...",
  "asset_id": "5413...",
  "timestamp": "1715600000000",
  "hash": "0x...",
  "bids": [{"price":"0.45","size":"120"}, {"price":"0.44","size":"380"}, ...],
  "asks": [{"price":"0.47","size":"85"}, {"price":"0.48","size":"210"}, ...]
}

价格是带有 2-3 位小数的字符串;size 是表示份额数量的字符串(不是美元)。bids 按从高到低排序,asks 按从低到高排序。hash 是一个去重标记-对未变化订单簿的重复轮询会返回相同的 hash,你的 bot 可以跳过处理。

REST snapshot 适合一次性查询(例如在入场决策时检查价格)。对于持续监控,请使用下面的 WebSocket channel。

WebSocket subscriptions:market 和 user channels

有两个 WebSocket channel 很重要。

Market channelwss://ws-subscriptions-clob.polymarket.com/ws/market。订阅一个或多个 token;按发生顺序接收 order-book updates。

{"type":"Market","markets":["0xCondId1","0xCondId2"]}

消息会在每次变化时到达。类型包括 book(完整 snapshot)、price_change(delta)、tick_size_change(较少见)和 last_trade_price(最近一次成交价)。

User channelwss://ws-subscriptions-clob.polymarket.com/ws/user。需要认证;接收你自己的订单事件-fills、partial fills、cancellations。

{"type":"User","auth":{"apiKey":"...","secret":"...","passphrase":"..."}}

User channel 是检测 fill 最干净的方式。轮询 orders REST endpoint 成本更高,而且可能错过两次轮询之间的状态变化;WebSocket 会在 matcher 确认的瞬间推送事件。

解析 bids/asks/depth

订单簿是按价格层级列出的聚合 size。这里有两个必须正确处理的解析约定。

订单方向bids 是买单(表示有人想以这个价格 BUY)。当你的 bot 卖出时,你是在吃掉 bid;当你的 bot 买入时,你是在抬升 ask。Polymarket UI 显示的是同样的方向;其他一些交易所则相反。

排序bids 以降序到达(最佳 bid 在前)。asks 以升序到达(最佳 ask 在前)。最佳 bid 是 bids[0];最佳 ask 是 asks[0]。注意:公共 WebSocket 有时会发送未预排序的部分订单簿更新-在任何 merge 之后都要防御性地重新排序。

某一层的 depth 是可成交的美元价值:price * size。前 5 层 depth 是常见的流动性指标:sum(b.price * b.size for b in bids[:5])。如果前 5 层 depth 低于 100 美元,订单簿就是 illiquid,大多数策略假设都会失效。

计算 mid-price 和 best-bid/ask

你的 bot 需要三个派生价格点。

  • Best bid / best askbids[0].priceasks[0].price。这是你实际可以交易到的价格,按 1 份额计算。
  • Mid-price(best_bid + best_ask) / 2。spread 的数学中心。它适合估值;你永远不会在 mid 上成交。
  • VWAP price for size N:沿着订单簿往下吃,直到累计 size 达到 N,返回按 size 加权的平均价格。这是现在立刻 BUY N 份额的真实成本,考虑了向更深层级扫单的影响。

边界情况:某一侧为空的 bid 或 ask(没有人卖,或者没有人买)意味着订单簿是单边的。在 Polymarket 的市场结构中,这通常发生在已结算或接近结算的市场,此时一侧接近 0.999,另一侧没有人提供流动性。把 best-bid = 0 或 best-ask = 1 视为“不要交易”的信号。

maker fees、taker fees、rebates

Polymarket 在很长一段时间里完全不收交易手续费,但这一点在 2026 年发生了改变:年初先在 15 分钟 crypto 市场引入手续费,2026 年 3 月 30 日扩展到 Sports,此后逐步覆盖了大多数类别。任何还在说“Polymarket 免手续费”的教程都已经过时,而对高频策略来说,搞错这一点会悄悄把你吃光。下面是截至 2026 年中的真实模型。

先理解每笔交易的两个角色。maker 是挂出一个停留在订单簿里、等待成交的限价单的人;taker 是发出一个立即与现有挂单成交的订单的人。maker 依然不收手续费,而且还能拿到返佣;只有 taker 付费。

taker 手续费不是固定百分比,而是一条随交易量和价格变化的曲线:

fee = shares × feeRate × price × (1 - price)

其中 price × (1 - price) 在价格为 0.50(价格真正 50/50 的市场)时达到最大,越接近 0 或 1 越小。换句话说:越不确定的市场你付的手续费越高,接近已定局的市场几乎不收费。feeRate 按类别设定:

  • Crypto:feeRate 0.07(最高,约 1.8% 峰值实际费率),maker 返佣 20%。
  • Sports:feeRate 0.03(约 0.75% 峰值),maker 返佣 25%。
  • Finance、Politics、Tech、Mentions:feeRate 0.04,maker 返佣 25%。
  • Economics、Culture、Weather、一般类别:feeRate 0.05,maker 返佣 25%。
  • Geopolitics 及重大世界事件:0,仍然免手续费。

举个例子。假设你的 bot 在一个 crypto 市场以 $0.50 的价格 take 100 股,手续费为 100 × 0.07 × 0.50 × (1 - 0.50) = 100 × 0.07 × 0.25 = $1.75。把同样的 100 股放到 $0.90 去 take,手续费降到 100 × 0.07 × 0.90 × 0.10 = $0.63,因为价格远离了不确定的中间区。对 bot 来说结论很直接:在波动大、接近五五开的 crypto 和 sports 市场里 take 流动性,手续费咬得最狠-所以恰恰是这些市场,作为 maker 挂单(收返佣而不是付手续费)最划算。

除了显式手续费,你每次跨越 spread 还要付出 bid-ask spread。spread 是最优买价和最优卖价之间的差距,对一个靠 take 流动性进出场的策略来说,这个差距是手续费之外的真实成本;在典型订单簿上可假设单次往返约 1-3 美分,流动性差的市场更高。NegRisk 市场(多结果交易所)使用相同的手续费模型,但在独立合约上结算,所以其 rewards 单独累计。第 19 章会专门讲 liquidity-rewards farming,那里收 maker 返佣本身就是策略,而不只是副产品。

代码:连接 WS 并处理 price-change events

最小化 Node 示例:连接、订阅、记录某个 token 的每个 price-change event。

import WebSocket from "ws";
const ws = new WebSocket("wss://ws-subscriptions-clob.polymarket.com/ws/market");
ws.on("open", () => {
  ws.send(JSON.stringify({ type: "Market", markets: ["<CONDITION_ID>"] }));
});
ws.on("message", (data) => {
  const msg = JSON.parse(data.toString());
  if (msg.event_type === "price_change") {
    console.log("price_change", msg.asset_id, msg.changes);
  } else if (msg.event_type === "book") {
    console.log("book snapshot", msg.bids?.[0], msg.asks?.[0]);
  }
});
ws.on("close", () => console.log("closed"));
ws.on("error", (e) => console.error("err", e.message));

在单个 WebSocket connection 下,舒适地订阅最多大约 30 个 token。超过这个数量后,请拆分到多个 connection-服务器有时会静默丢弃较大的 subscriptions 而不报错,从而导致你读到陈旧的订单簿。

reconnect 和 gap-handling

长期运行的 WebSocket connection 一定会断开。Cloudflare 每隔几小时会轮换 connection;网络会短暂中断;Polymarket 也会偶尔部署更新。要提前做好准备。

reconnect strategy:在 closeerror 后,等待带抖动的 min(2^attempt, 30) 秒,然后重新订阅。第一次 reconnect 后收到成功消息时,重置 attempt 计数器。

gap handling 比 reconnect 速度更重要。WebSocket 断开期间,订单簿已经发生变化。每次 reconnect 后,都要重新拉取所有已订阅 token 的 REST snapshot 并进行 reconcile:任何 book 发生明显变化的 open positions 都需要重新检查状态,exit 可能需要触发,alarms 也可能已经过时。“我错过了 30 秒的订单簿更新”是长期运行 bot 的无声杀手-它们会继续基于陈旧状态运行,并以已不存在的价格下单。

防御性模式:无论 WebSocket 状态如何,都每分钟对所有已订阅订单簿做一次 snapshot,并把 WS 视为建立在 snapshot 轮询之上的快速路径优化。

常见问题

Polymarket CLOB API endpoint 是什么?
基础 CLOB endpoint 是 https://clob.polymarket.com(REST)和 wss://ws-subscriptions-clob.polymarket.com/ws/market(WebSocket)。这些是 @polymarket/clob-client-v2 和 py-clob-client 使用的 V2 endpoints。
读取订单簿需要 API key 吗?
不需要。读取订单簿(snapshots 和 WebSocket subscriptions)是公开的,不需要认证。只有在下单/撤单以及读取账户专属数据(positions、fills)时才需要 API key。
CLOB WebSocket 推送价格更新有多快?
与订单撮合的速度一样快。活跃市场每隔几百毫秒就会有更新;流动性较薄的市场只会在实际有订单时更新。depth 变化和 trade events 都通过同一个 WS channel 流动-需要通过解析 event type 来正确处理每一种消息。
如何计算 Polymarket 订单簿的 mid-price?
如果两侧都存在,则 mid = (best_bid + best_ask) / 2;否则使用 last_trade_price 作为回退。要注意薄订单簿中 best_bid 远低于 best_ask 的情况-此时 mid 可能没有意义。在把 mid 当作公平价格之前,一定也要考虑 spread。
2026 年 Polymarket 的 maker fee 是多少?
Maker 付 0% 并能拿到返佣(crypto 20%,多数其他类别 25%)。只有 taker 付费,而且不是固定值:fee = shares × feeRate × price × (1 - price),在 $0.50 附近的五五开市场达到峰值,越接近两端越小。各类别 feeRate 从 0.03(Sports,峰值约 0.75%)到 0.07(Crypto,峰值约 1.8%)不等,Geopolitics 仍然免费。这种 maker-taker 不对称,正是为什么活跃 bot 几乎总是用挂单(limit orders)而不是用 market orders 跨越 spread。
如何处理 WebSocket disconnects?
使用指数退避重连(1s、2s、4s,最多 30s),重新订阅相同 markets,并重新拉取 REST snapshot 以补齐缺口。不要相信陈旧的订单簿-如果你已经断开超过 5 秒,在下单前先请求新的 snapshot。