Polymarket Bot Tutorial · Chương 7 trên 32
Polymarket Gamma API deep dive: các endpoint /events và /markets, pagination, tag IDs (864 Tennis, 745 NBA, v.v.), lọc theo volume 24h, rate limits, và các code sample Python và Node.
Chương này bao gồm gì
Gamma là catalog API của Polymarket - nó liệt kê mọi event, mọi market, tag, image và resolved outcome mà front-end hiển thị. CLOB API dùng để trade; Gamma mô tả những gì có thể trade. Phần lớn bug của bot ở lớp discovery đến từ việc nhầm lẫn hai hệ thống này, hoặc do bỏ sót pagination contract. Chương này là tài liệu tham chiếu thực chiến cho các endpoint chính của Gamma, với hành vi tham số chính xác mà các fetcher production của chúng tôi phụ thuộc vào.
- Gamma vs CLOB: khi nào dùng cái nào
- Anatomy của endpoint /events
- Anatomy của endpoint /markets
- Tags và tag IDs (danh sách đã xác minh)
- Filtering: active, closed, sắp xếp volume24hr
- Pagination và limits
- Rate limits và caching
- Code: fetch top market theo 24h-volume
Gamma vs CLOB: khi nào dùng cái nào
Hai dịch vụ khác nhau cho hai công việc khác nhau.
Gamma (gamma-api.polymarket.com): catalog. Liệt kê events, markets, tags, descriptions, images, resolved outcomes, volume 24 giờ, tổng volume, ngày kết thúc. Chỉ đọc qua HTTP. Phần lớn lượt đọc không cần xác thực. Được cập nhật liên tục nhưng eventual consistency - một market vừa đóng có thể vẫn hiển thị closed: false trong vài giây.
CLOB (clob.polymarket.com): trading + order book. Liệt kê best bid/ask hiện tại, độ sâu order book top-N, các giao dịch gần đây. Yêu cầu xác thực cho các endpoint ghi (đặt lệnh, hủy lệnh). Có các WebSocket channel real-time cho cập nhật book.
Quy tắc thực tế: dùng Gamma để tìm cái gì nên trade; dùng CLOB để trade nó. Một bot đọc giá từ Gamma là đang dùng dữ liệu cũ - các field giá của Gamma cập nhật chậm hơn order book của CLOB. Một bot đọc metadata market từ CLOB là đang thực hiện nhiều request hơn mức cần thiết.
Anatomy của endpoint /events
GET /events trả về dữ liệu ở cấp event. Một "event" là một trang Polymarket; một event đơn lẻ có thể chứa nhiều market (ví dụ, event 2024 Presidential Election có một market cho mỗi ứng viên).
Các field chính:
slug: định danh an toàn cho URL, ổn định trong suốt vòng đời của event.title,description: hiển thị cho người dùng.endDate(ISO 8601): khi event đóng.active,closed: boolean; kết hợp trong query với?active=true&closed=falsecho các event đang chạy.volume,volume24hr: tổng USD.tags: mảng các tag object (xem phần tags bên dưới).markets: mảng các child market object (xem phần anatomy của/markets).
Pattern discovery phổ biến nhất: GET /events?active=true&closed=false&order=volume24hr&ascending=false&limit=100. Trả về 100 event đang live có volume cao nhất.
Anatomy của endpoint /markets
GET /markets trả về dữ liệu ở cấp market. Một market là một hợp đồng Y/N hoặc multi-outcome; nó nằm bên trong một event.
Các field chính:
slug: định danh an toàn cho URL.question: tiêu đề hiển thị trên trang giao dịch (ví dụ: "Will Trump be president on January 1, 2027?").outcomes: JSON string của tên outcome, ví dụ'["Yes","No"]'. Binary luôn có hai phần tử; NegRisk thì nhiều hơn.outcomePrices: JSON string của giá hiện tại dưới dạng decimal, ví dụ'["0.62","0.38"]'. Hai phía cộng lại xấp xỉ 1.0 trừ spread.clobTokenIds: JSON string của ERC-1155 token IDs khớp với outcomes. Đây là các token bạn thực sự mua/bán.negRisk: boolean; true với các market multi-outcome sum-to-1. Quan trọng cho việc đặt lệnh (chương 11).
Các field outcomes / outcomePrices / clobTokenIds được trả về dưới dạng JSON strings, không phải mảng đã parse - hãy JSON-decode trước khi dùng.
Tags và tag IDs (danh sách đã xác minh)
Tags là các nhãn phân loại (Sports, Crypto, Tennis, NBA, v.v.). Tag IDs production đã xác minh cho các category được dùng nhiều nhất:
| 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 |
Lọc theo tag bằng ?tag_id=745 cho một tag cụ thể, hoặc ?tag_slug=nba dùng slug. Lọc theo slug dễ đọc hơn trong code nhưng hơi chậm hơn; lọc theo ID là mặc định trong production.
Filtering: active, closed, sắp xếp volume24hr
Bốn chiều lọc bạn sẽ dùng 95% thời gian.
active=true|false:trueloại trừ các market mà team Polymarket đã ẩn khỏi UI.closed=true|false:falseloại trừ các market đã resolved. Kết hợpactive=true&closed=falselà bộ lọc live phổ biến nhất.order=volume24hr,order=volume,order=endDate: khóa sắp xếp. Hữu ích nhất làvolume24hrđể tìm các market đang hoạt động.ascending=true|false: mặc định là true trên hầu hết endpoint; gần như lúc nào bạn cũng muốnfalsecho các kiểu sắp xếp theo volume.
Lưu ý: lọc theo tag_id kết hợp với order=volume24hr và ascending=false đôi khi trả về một trang trống khi tag đó có rất ít live market. Luôn over-fetch (request nhiều hơn số bạn hiển thị) và post-filter để xử lý trường hợp này.
Pagination và limits
Tham số limit nhận 1-500 cho mỗi lần gọi. Mặc định là 100 nếu không chỉ định. Trên 500, server sẽ tự giới hạn ngầm - bạn nhận 500 nhưng response không báo rằng còn nhiều hơn.
Pagination dựa trên offset: ?limit=500&offset=500 cho trang thứ hai. Không có pagination dựa trên cursor, nên các insert đồng thời có thể làm ranh giới trang dịch chuyển giữa các lần gọi. Với đa số mục đích discovery của bot, điều này chấp nhận được; với các lần scrape archive, hãy sắp xếp theo một field ổn định (endDate hoặc createdAt) và phát hiện overlap bằng slug.
Pattern thực tế cho "tất cả market đang live": fetch limit=500&order=volume24hr&ascending=false. Cách này bao phủ top 500 theo volume, về cơ bản là mọi market có hoạt động đáng kể. Đi xa hơn page 1 hiếm khi hữu ích - các market ở phần đuôi phân phối volume theo định nghĩa là nơi không có nhiều action.
Rate limits và caching
Gamma được Cloudflare bảo vệ ở phía trước và có soft rate limits theo IP. Các ngưỡng thực nghiệm quan sát được dưới tải production:
- Khoảng đến ~30 req/sec từ một IP duy trì liên tục: ổn.
- Burst 100+ req/sec: thỉnh thoảng có 429, retry thì thành công.
- ~500 req/sec duy trì: rate-limit page hoặc block tạm thời (10-60 giây).
Response headers được công bố bao gồm giá trị Cache-Control từ 30-60 giây cho hầu hết endpoint. Hãy tuân thủ chúng - không có lợi ích gì khi fetch lại cùng một event 10 lần trong một phút. Pattern caching production: in-process LRU + TTL key theo toàn bộ URL, TTL 30 giây. Tiết kiệm số request và giảm latency.
Với các chiến lược tần suất cao, hãy mirror dữ liệu Gamma vào một local store được cập nhật bởi một fetcher process duy nhất; cho nhiều consumer đọc từ store đó. Một fetcher × nhiều consumer > nhiều fetcher × Gamma.
Code: fetch top market theo 24h-volume
Reference fetcher bằng ba ngôn ngữ, trả về top 50 live market theo volume 24 giờ.
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'
Endpoint /events của Polymarket gamma KHÔNG hỗ trợ tham số tìm kiếm free-text - thêm ?q=foo hoặc ?search=foo sẽ âm thầm trả về thứ tự mặc định. Hãy lọc theo slug hoặc tag thay thế.












