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:何时使用哪个
两个不同的服务,承担两个不同的任务。
Gamma(gamma-api.polymarket.com):catalog。列出 events、markets、tags、描述、图片、已结算结果、24 小时成交量、总成交量、结束日期。只读 HTTP。大多数读取不需要认证。持续更新,但最终一致-一个刚关闭的 market 可能仍会在几秒内显示 closed: false。
CLOB(clob.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 生命周期内保持稳定。title、description:面向人类展示。endDate(ISO 8601):event 何时结束。active、closed:布尔值;在查询中组合使用?active=true&closed=false可获取 live events。volume、volume24hr:美元总额。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:
| Tag | ID | Tag | ID |
|---|---|---|---|
| Sports | 1 | NBA | 745 |
| Crypto | 21 | NFL | 450 |
| Politics | 2 | Tennis | 864 |
| Bitcoin | 100196 | Esports | 702 |
| Ethereum | 100383 | Soccer | 1059 |
| Election | 3 | EPL | 739 |
| Middle East | 1432 | UCL | 2186 |
使用 ?tag_id=745 按 tag 过滤,或使用 slug 形式 ?tag_slug=nba。基于 slug 的过滤在代码里更易读,但速度略慢;基于 ID 的方式是 production 默认。
过滤:active、closed、volume24hr 排序
以下四种过滤维度在 95% 的场景中都会用到。
active=true|false:true会排除被 Polymarket 团队从 UI 中隐藏的 markets。closed=true|false:false会排除已结算 markets。组合active=true&closed=false是最常见的 live 过滤条件。order=volume24hr、order=volume、order=endDate:排序键。最常用的是volume24hr,用于查找当前活跃 markets。ascending=true|false:大多数端点默认是 true;按成交量排序时,你几乎总是希望设为false。
注意:当 tag 下 live markets 很少时,tag_id 与 order=volume24hr 和 ascending=false 组合有时会返回空页。务必多取一些(请求数量大于展示数量),再在本地 post-filter 处理。
分页和限制
limit 参数每次调用可接受 1-500。未指定时默认只有 20 条,所以请务必显式设置,否则会悄无声息地漏掉目录的大部分内容。超过 500 时服务器会静默封顶-你会收到 500 条,但响应不会提示还有更多。
分页采用 offset 模式:第二页使用 ?limit=500&offset=500。这里没有 cursor-based pagination,所以并发插入会导致分页边界在不同调用之间发生偏移。对于大多数 bot discovery 场景这可以接受;对于 archive 抓取,建议按稳定字段(endDate 或 createdAt)排序,并通过 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 过滤。












