Polymarket Bot Tutorial · บทที่ 7 จาก 32

เจาะลึก Polymarket Gamma API: endpoint /events และ /markets, pagination, tag IDs (864 Tennis, 745 NBA เป็นต้น), การกรองตาม volume 24 ชม., rate limits, และตัวอย่างโค้ด Python กับ Node

บทนี้ครอบคลุมอะไรบ้าง

Gamma คือ catalog API ของ Polymarket-มันแสดงทุก event, ทุก market, tag, image และ resolved outcome ที่ฝั่ง front-end แสดงอยู่ ส่วน CLOB API ใช้สำหรับเทรด; Gamma ใช้บอกรายการที่เทรดได้ บั๊กของบอตส่วนใหญ่ในชั้น discovery มักเกิดจากการสับสนสองอย่างนี้ หรือจากการไม่เข้าใจ pagination contract บทนี้คือ field reference ของ endpoint หลักใน Gamma พร้อมพฤติกรรมพารามิเตอร์ที่แม่นยำซึ่งตัว fetcher ใน production ของเราใช้งานอยู่

  • Gamma vs CLOB: ควรใช้เมื่อไร
  • โครงสร้าง /events endpoint
  • โครงสร้าง /markets endpoint
  • Tags และ tag IDs (รายการที่ยืนยันแล้ว)
  • การกรอง: active, closed, การเรียงตาม volume24hr
  • Pagination และ limits
  • Rate limits และ caching
  • Code: ดึงตลาดที่มี volume 24 ชม. สูงสุด

Gamma vs CLOB: ควรใช้เมื่อไร

มีสองบริการที่ต่างกันสำหรับงานสองแบบที่ต่างกัน

Gamma (gamma-api.polymarket.com): catalog ใช้แสดงรายการ event, market, tags, descriptions, images, resolved outcomes, volume 24 ชั่วโมง, volume รวม, end dates เป็น HTTP แบบ read-only ไม่จำเป็นต้องยืนยันตัวตนสำหรับการอ่านส่วนใหญ่ อัปเดตต่อเนื่องแต่เป็น eventually consistent-market ที่เพิ่งปิดอาจยังแสดง closed: false อยู่สักสองสามวินาที

CLOB (clob.polymarket.com): trading + order book แสดง best bid/ask ปัจจุบัน, book depth top-N, recent trades ต้องยืนยันตัวตนสำหรับ write endpoints (วาง order, ยกเลิก order) มี WebSocket แบบเรียลไทม์สำหรับอัปเดต book

กฎง่าย ๆ: ใช้ Gamma เพื่อหาอะไรที่จะเทรด; ใช้ CLOB เพื่อเทรดมัน บอตที่อ่านราคาจาก Gamma กำลังใช้ข้อมูลที่ล้าสมัย-ฟิลด์ราคาของ Gamma อัปเดตไม่ถี่เท่า order book ของ CLOB บอตที่อ่าน metadata ของ market จาก CLOB กำลังยิง request มากเกินจำเป็น

โครงสร้าง /events endpoint

GET /events ส่งคืนข้อมูลระดับ event “event” คือหน้า Polymarket หนึ่งหน้า; event เดียวอาจมีหลาย market (เช่น event การเลือกตั้งประธานาธิบดีปี 2024 มีหนึ่ง market ต่อผู้สมัครหนึ่งคน)

ฟิลด์สำคัญ:

  • slug: ตัวระบุที่ใช้ใน URL แบบปลอดภัย ตลอดอายุของ event จะคงที่
  • title, description: ใช้แสดงผลสำหรับมนุษย์
  • endDate (ISO 8601): เวลาที่ event ปิด
  • active, closed: boolean; ใช้ร่วมกันใน query เช่น ?active=true&closed=false สำหรับ live events
  • volume, volume24hr: ยอดรวมเป็น USD
  • tags: array ของ tag objects (ดูหัวข้อ tags ด้านล่าง)
  • markets: array ของ child market objects (ดูโครงสร้าง /markets)

รูปแบบ discovery ที่พบบ่อยที่สุด: GET /events?active=true&closed=false&order=volume24hr&ascending=false&limit=100. จะคืน 100 event ที่ยัง live อยู่และมี volume สูงที่สุด

โครงสร้าง /markets endpoint

GET /markets ส่งคืนข้อมูลระดับ market market คือสัญญาแบบ Yes/No หรือหลาย outcome หนึ่งรายการ; มันอยู่ภายใน event

ฟิลด์สำคัญ:

  • slug: ตัวระบุที่ใช้ใน URL แบบปลอดภัย
  • question: title ที่แสดงบนหน้าเทรด (เช่น "Will Trump be president on January 1, 2027?")
  • outcomes: JSON string ของชื่อ outcome เช่น '["Yes","No"]'. สำหรับ binary จะมี 2 ค่าเสมอ; ถ้าเป็น NegRisk จะมีมากกว่า
  • outcomePrices: JSON string ของราคาปัจจุบันในรูป decimals เช่น '["0.62","0.38"]'. ทั้งสองฝั่งรวมกันได้ประมาณ 1.0 ลบด้วย spread
  • clobTokenIds: JSON string ของ ERC-1155 token IDs ที่จับคู่กับ outcomes นี่คือ token ที่คุณซื้อ/ขายจริง
  • negRisk: boolean; เป็น true สำหรับตลาดหลาย outcome ที่รวมกันได้ 1.0 มีผลต่อการวาง order (บทที่ 11)

ฟิลด์ outcomes / outcomePrices / clobTokenIds จะมารูปแบบเป็น JSON strings ไม่ใช่ parsed arrays-ต้อง JSON-decode ก่อนใช้งาน

Tags และ tag IDs (รายการที่ยืนยันแล้ว)

Tags คือป้ายกำกับเชิงหมวดหมู่ (Sports, Crypto, Tennis, NBA เป็นต้น) tag IDs ที่ยืนยันแล้วใน production สำหรับหมวดที่ใช้บ่อย:

TagIDTagID
Sports1NBA745
Crypto21NFL450
Politics2Tennis864
Bitcoin100196Esports702
Ethereum100383Soccer1059
Election3EPL739
Middle East1432UCL2186

กรองตาม tag ด้วย ?tag_id=745 สำหรับ tag เฉพาะ หรือใช้ ?tag_slug=nba โดยอ้างอิง slug การกรองด้วย slug อ่านง่ายกว่าในโค้ดแต่ช้ากว่านิดหน่อย; การกรองด้วย ID คือค่าเริ่มต้นใน production

การกรอง: active, closed, การเรียงตาม volume24hr

มิติการกรอง 4 แบบที่คุณจะใช้ 95% ของเวลา

  • active=true|false: true จะตัด market ที่ทีม Polymarket ซ่อนไว้จาก UI ออก
  • closed=true|false: false จะตัด market ที่ resolved แล้วออก การจับคู่ active=true&closed=false คือ live filter ที่ใช้บ่อยที่สุด
  • order=volume24hr, order=volume, order=endDate: คีย์สำหรับ sort สิ่งที่มีประโยชน์ที่สุดคือ volume24hr สำหรับหา market ที่ยัง active อยู่
  • ascending=true|false: ค่าเริ่มต้นใน endpoint ส่วนใหญ่คือ true; โดยปกติคุณแทบจะต้องการ false สำหรับการเรียงตาม volume

ข้อควรระวัง: การกรองด้วย tag_id ร่วมกับ order=volume24hr และ ascending=false บางครั้งอาจคืนหน้าว่างเมื่อ tag นั้นมี live market น้อยมาก ควรดึงมาเกินก่อนเสมอ (request มากกว่าที่จะแสดง) แล้วค่อย post-filter เพื่อรับมือกับกรณีนี้

Pagination และ limits

พารามิเตอร์ limit รับค่า 1-500 ต่อครั้ง ค่าเริ่มต้นคือ 100 ถ้าไม่ระบุ เกิน 500 เซิร์ฟเวอร์จะ cap ให้แบบเงียบ ๆ-คุณจะได้ 500 แต่ response จะไม่มีตัวบอกว่ามีข้อมูลเพิ่ม

Pagination เป็นแบบ offset: ?limit=500&offset=500 สำหรับหน้าที่สอง ไม่มี cursor-based pagination ดังนั้นการ insert พร้อมกันอาจทำให้ขอบเขตของหน้าขยับระหว่างการเรียก สำหรับการ discovery ของบอตส่วนใหญ่สิ่งนี้ยอมรับได้; สำหรับการ scrape archive ให้ sort ด้วยฟิลด์ที่เสถียร (endDate หรือ createdAt) และตรวจหา overlap ด้วย slug

รูปแบบใช้งานจริงสำหรับ "all live markets": ดึง limit=500&order=volume24hr&ascending=false นั่นครอบคลุม top 500 ตาม volume ซึ่งแทบจะเป็นทุก market ที่มี activity จริงจัง การข้ามไป page 1 มักไม่ค่อยมีประโยชน์-market ที่อยู่หางของการกระจาย volume ตามนิยามแล้วไม่ใช่จุดที่มีกิจกรรมหลัก

Rate limits และ caching

Gamma ถูกวางหน้าไว้ด้วย Cloudflare และมี soft rate limits ต่อ IP ค่า threshold ที่สังเกตได้จากการใช้งานใน production:

  • สูงสุดราว ~30 req/sec จาก IP เดียวแบบต่อเนื่อง: ปกติ
  • burst 100+ req/sec: บางครั้งเจอ 429 แต่ retry แล้วสำเร็จ
  • ~500 req/sec แบบต่อเนื่อง: เจอหน้า rate-limit หรือถูกบล็อกชั่วคราว (10-60 วินาที)

response headers ที่เผยแพร่จะมีค่า Cache-Control ประมาณ 30-60 วินาทีสำหรับ endpoint ส่วนใหญ่ ให้เคารพมัน-ไม่มีประโยชน์ที่จะดึง event เดิม 10 ครั้งในหนึ่งนาที รูปแบบ caching ใน production: in-process LRU + TTL โดย key เป็น full URL, TTL 30 วินาที ช่วยลดจำนวน request และลด latency

สำหรับกลยุทธ์ที่ถี่มาก ให้ mirror ข้อมูล Gamma ลง local store ที่อัปเดตโดย process fetcher เดียว; ให้ consumer หลายตัวอ่านจาก store นั้น fetcher หนึ่งตัว × consumer หลายตัว ดีกว่า fetcher หลายตัว × Gamma

Code: ดึงตลาดที่มี volume 24 ชม. สูงสุด

ตัวอย่าง reference fetcher ใน 3 ภาษา โดยคืน top 50 live markets ตาม volume 24 ชั่วโมง

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 ของ Polymarket gamma ไม่รองรับพารามิเตอร์ค้นหาแบบ free-text-ถ้าเพิ่ม ?q=foo หรือ ?search=foo ระบบจะคืนลำดับเริ่มต้นแบบเงียบ ๆ ให้ กรองด้วย slug หรือ tag แทน

คำถามที่พบบ่อย

Polymarket Gamma API คืออะไร?
Gamma คือ metadata และ discovery API ของ Polymarket มันให้รายการ event/market, titles, descriptions, end dates, tags และ volume รวม มัน ไม่ให้ข้อมูล order book แบบเรียลไทม์-ข้อมูลนั้นอยู่ที่ CLOB API สำหรับ use case ด้าน discovery และ analytics ส่วนใหญ่ คุณจะเริ่มต้นที่ Gamma
ความแตกต่างระหว่าง event กับ market บน Polymarket คืออะไร?
event คือกลุ่มของ market หนึ่งรายการหรือมากกว่าที่แชร์ธีมคำถามเดียวกัน market คือ outcome แบบ Yes/No เฉพาะเจาะจงที่มี order book และ token IDs ของตัวเอง event "2026 NBA Champion" มี 30 markets (หนึ่งตลาดต่อหนึ่งทีม) สำหรับ binary Yes/No events ตัว event จะมี underlying market 1 รายการ
ฉันจะหา Polymarket tag IDs ได้อย่างไร?
Tags ถูกเปิดเผยผ่าน gamma /tags endpoint ID ที่ยืนยันแล้วที่เราใช้ใน production: 864 Tennis, 745 NBA tag slug ใน URL (?tag_slug=tennis) และ query แบบ free-text (?q=tennis) ไม่น่าเชื่อถือ-ให้ใช้ numerical tag_id เท่านั้น ตรวจ /tags ก่อนจะพึ่ง slug ใด ๆ
ฉันจะเรียง Polymarket events ตาม volume 24h ได้อย่างไร?
/events?order=volume24hr&ascending=false - นี่คือสิ่งที่ขับเคลื่อน widget "trending markets" ส่วนใหญ่ ใช้ร่วมกับ active=true&closed=false เพื่อกรอง market ที่หมดอายุหรือหยุดพักออก ค่า limit เริ่มต้นคือ 25; ค่าสูงสุดคือ 500 ต่อครั้ง
Gamma มีข้อจำกัด pagination ไหม?
มี /events และ /markets endpoint รองรับ limit (สูงสุด 500 ต่อครั้ง) และ offset สำหรับ pagination ไลบรารีส่วนใหญ่ไม่ได้ paginate ให้อัตโนมัติ - ถ้าคุณต้องการ universe ทั้งหมด ให้ loop ด้วย offset จนกว่าจะได้หน้าที่มีผลลัพธ์น้อยกว่า `limit`
Gamma รองรับ WebSocket ไหม?
ไม่ Gamma เป็นแบบ REST เท่านั้น สำหรับการอัปเดตแบบเรียลไทม์ (การเปลี่ยนแปลงราคา, market ใหม่, order book) ให้ใช้ CLOB WebSocket - ซึ่งจะอธิบายในบทที่ 8 ของซีรีส์นี้