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

Polymarket Gamma API 深度解析:/events 和 /markets 端点、分页、tag IDs(864 Tennis、745 NBA 等)、按 24h 成交量过滤、rate limits,以及 Python 和 Node 代码示例。

本章内容

Gamma 是 Polymarket 的 catalog API-它列出前端展示的每个 event、每个 market、tag、图片以及已结算结果。CLOB API 负责交易;Gamma 描述哪些内容可交易。大多数 bot 在发现层的 bug 都来自把这两者混淆,或者遗漏了 pagination contract。本章是 Gamma 主要端点的实战参考,包含我们的 production fetcher 所依赖的精确参数行为。

  • Gamma vs CLOB:何时使用哪个
  • /events 端点结构
  • /markets 端点结构
  • Tags 和 tag IDs(已验证列表)
  • 过滤:active、closed、volume24hr 排序
  • 分页和限制
  • rate limits 和缓存
  • 代码:获取按 24h 成交量排名前列的 markets

Gamma vs CLOB:何时使用哪个

两个不同的服务,承担两个不同的任务。

Gammagamma-api.polymarket.com):catalog。列出 events、markets、tags、描述、图片、已结算结果、24 小时成交量、总成交量、结束日期。只读 HTTP。大多数读取不需要认证。持续更新,但最终一致-一个刚关闭的 market 可能仍会在几秒内显示 closed: false

CLOBclob.polymarket.com):交易 + order book。列出当前最佳 bid/ask、Top-N book depth、最近成交。写入端点需要认证(下单、撤单)。提供实时 WebSocket channel 用于 book 更新。

经验法则:用 Gamma 找到可交易标的;用 CLOB 完成交易。如果 bot 从 Gamma 读取价格,就是在用陈旧数据-Gamma 的价格字段更新频率低于 CLOB 的 order book。如果 bot 从 CLOB 读取 market 元数据,则是在发出不必要的请求。

/events 端点结构

GET /events 返回 event 级别数据。一个 “event” 是 Polymarket 上的一个页面;单个 event 可能包含多个 markets(例如 2024 总统大选 event 每个候选人对应一个 market)。

关键字段:

  • slug:URL 安全的标识符,在 event 生命周期内保持稳定。
  • titledescription:面向人类展示。
  • endDate(ISO 8601):event 何时结束。
  • activeclosed:布尔值;在查询中组合使用 ?active=true&closed=false 可获取 live events。
  • volumevolume24hr:美元总额。
  • tags:tag 对象数组(见下方 tags 部分)。
  • markets:子 market 对象数组(见 /markets 结构)。

最常见的发现模式:GET /events?active=true&closed=false&order=volume24hr&ascending=false&limit=100。返回当前成交量最高的 100 个 live events。

/markets 端点结构

GET /markets 返回 market 级别数据。一个 market 是一个 Yes/No 或多结果合约;它存在于某个 event 内部。

关键字段:

  • slug:URL 安全的标识符。
  • question:交易页面显示的标题(例如 “Will Trump be president on January 1, 2027?”)。
  • outcomes:outcome 名称的 JSON 字符串,例如 '["Yes","No"]'。二元市场始终有两个元素;NegRisk 会更多。
  • outcomePrices:当前价格的 JSON 字符串,按 decimal 表示,例如 '["0.62","0.38"]'。两边之和约等于 1.0 减去 spread。
  • clobTokenIds:与 outcomes 对齐的 ERC-1155 token IDs 的 JSON 字符串。这些才是你实际买卖的 tokens。
  • negRisk:布尔值;对于多结果且总和为 1 的 markets 为 true。会影响下单(第 11 章)。

outcomes / outcomePrices / clobTokenIds 字段返回的是 JSON 字符串,而不是已解析数组-使用前先做 JSON decode。

Tags 和 tag IDs(已验证列表)

Tags 是分类标签(Sports、Crypto、Tennis、NBA 等)。以下是最常用分类在 production 中已验证的 tag IDs:

TagIDTagID
Sports1NBA745
Crypto21NFL450
Politics2Tennis864
Bitcoin100196Esports702
Ethereum100383Soccer1059
Election3EPL739
Middle East1432UCL2186

使用 ?tag_id=745 按 tag 过滤,或使用 slug 形式 ?tag_slug=nba。基于 slug 的过滤在代码里更易读,但速度略慢;基于 ID 的方式是 production 默认。

过滤:active、closed、volume24hr 排序

以下四种过滤维度在 95% 的场景中都会用到。

  • active=true|falsetrue 会排除被 Polymarket 团队从 UI 中隐藏的 markets。
  • closed=true|falsefalse 会排除已结算 markets。组合 active=true&closed=false 是最常见的 live 过滤条件。
  • order=volume24hrorder=volumeorder=endDate:排序键。最常用的是 volume24hr,用于查找当前活跃 markets。
  • ascending=true|false:大多数端点默认是 true;按成交量排序时,你几乎总是希望设为 false

注意:当 tag 下 live markets 很少时,tag_idorder=volume24hrascending=false 组合有时会返回空页。务必多取一些(请求数量大于展示数量),再在本地 post-filter 处理。

分页和限制

limit 参数每次调用可接受 1-500。未指定时默认只有 20 条,所以请务必显式设置,否则会悄无声息地漏掉目录的大部分内容。超过 500 时服务器会静默封顶-你会收到 500 条,但响应不会提示还有更多。

分页采用 offset 模式:第二页使用 ?limit=500&offset=500。这里没有 cursor-based pagination,所以并发插入会导致分页边界在不同调用之间发生偏移。对于大多数 bot discovery 场景这可以接受;对于 archive 抓取,建议按稳定字段(endDatecreatedAt)排序,并通过 slug 检测重叠。

“获取所有 live markets”的实用模式:请求 limit=500&order=volume24hr&ascending=false。这会覆盖成交量前 500 的市场,基本上包含所有有实际活动的 markets。通常没有必要翻到第 2 页-成交量分布尾部的 markets,按定义就不是最活跃的部分。

rate limits 和缓存

Gamma 前面有 Cloudflare,且对单个 IP 有软 rate limits。在 production 负载下观察到的经验阈值:

  • 单 IP 持续约 30 req/sec:正常。
  • 100+ req/sec 的突发:偶尔会出现 429,但重试可成功。
  • 持续约 500 req/sec:触发 rate-limit 页面或临时封禁(10-60 秒)。

公开的响应 headers 中,大多数端点的 Cache-Control 值为 30-60 秒。请遵守-一分钟内重复拉取同一个 event 10 次没有任何收益。production 缓存模式:以内存 LRU + TTL 为主,使用完整 URL 作为 key,TTL 设为 30 秒。这样既能节省请求数,也能降低延迟。

对于高频策略,将 Gamma 数据镜像到本地存储,并由单个 fetcher 进程更新;让多个 consumer 读取该存储。一个 fetcher × 多个 consumer > 多个 fetcher × Gamma。

代码:获取按 24h 成交量排序的 markets

以下是三种语言的参考 fetcher,返回按 24 小时成交量排名前 50 的 live markets。

Python:

import requests
r = requests.get("https://gamma-api.polymarket.com/events",
                 params={"active":"true","closed":"false",
                         "order":"volume24hr","ascending":"false","limit":50},
                 timeout=10)
for ev in r.json()[:50]:
    print(ev["slug"], ev.get("volume24hr"))

Node:

const url = "https://gamma-api.polymarket.com/events?active=true&closed=false" +
            "&order=volume24hr&ascending=false&limit=50";
const events = await fetch(url).then(r => r.json());
for (const ev of events) console.log(ev.slug, ev.volume24hr);

Curl:

curl -s "https://gamma-api.polymarket.com/events?active=true&closed=false&order=volume24hr&ascending=false&limit=50" \
  | jq '.[].slug'

Polymarket gamma 的 /events 端点不支持自由文本搜索参数-添加 ?q=foo?search=foo 只会静默返回默认排序。请改为按 slug 或 tag 过滤。

常见问题

什么是 Polymarket Gamma API?
Gamma 是 Polymarket 的 metadata 和 discovery API。它提供 event/market 列表、标题、描述、结束日期、tags 和汇总成交量。它提供实时 order book 数据-那部分属于 CLOB API。对于大多数 discovery 和 analytics 场景,你都应从 Gamma 开始。
Polymarket 上的 event 和 market 有什么区别?
event 会把一个或多个共享同一问题主题的 markets 组织在一起。market 是一个具体的 Yes/No 结果,拥有自己的 order book 和 token IDs。一个 “2026 NBA Champion” event 包含 30 个 markets(每支球队一个)。对于二元 Yes/No events,event 只有 1 个底层 market。
如何查找 Polymarket 的 tag IDs?
Tags 可通过 gamma /tags 端点获取。我们在 production 中使用的已验证 ID 包括:864 Tennis、745 NBA。URL 中的 tag slug(?tag_slug=tennis)和自由文本查询(?q=tennis)都不可靠-请只使用数值型 tag_id。依赖 slug 之前先检查 /tags。
如何按 24h volume 对 Polymarket events 排序?
/events?order=volume24hr&ascending=false - 这就是大多数 “trending markets” 组件的底层逻辑。结合 active=true&closed=false 可过滤掉已过期或暂停的 markets。Limit 默认是 20(请显式设置);每次调用最大是 500。
Gamma 有分页限制吗?
有。/events 和 /markets 端点都接受 limit(每次调用最大 500)和 offset 用于分页。大多数库不会自动分页-如果你需要完整数据集,就用 offset 循环,直到某一页返回少于 `limit` 条结果。
Gamma 支持 WebSocket 吗?
不支持。Gamma 仅支持 REST。要获取实时更新(价格变化、新 markets、order book),请使用 CLOB WebSocket-本系列第 8 章会讲到。