บทเรียนบอท โพลีมาร์เก็ต · บทที่ 8 จาก 32

โพลีมาร์เก็ต CLOB API สำหรับ bots: REST endpoints สำหรับ order book snapshots, WebSocket subscriptions สำหรับการอัปเดตแบบเรียลไทม์, การแยก bids/asks, การคำนวณ mid-price และ depth, ตัวอย่างโค้ด

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

CLOB API คือจุดที่ orders ถูก sign, ส่ง, match และเป็นที่อยู่ของ order book ด้วย โพลีมาร์เก็ต มี SDK สองเจเนอเรชัน - v1 ที่เลิกใช้แล้ว และ v2 ที่ใช้อยู่ในปัจจุบัน บทนี้ครอบคลุมเฉพาะ v2; v1 ไม่ควรปรากฏใน bot ใด ๆ ที่คุณส่งมอบในปี 2026 เราจะพาไล่ดูเส้นทาง REST snapshot, ช่องทางอัปเดต WebSocket, รายละเอียดการ parsing ที่มักทำให้ builder มือใหม่สะดุด และ logic สำหรับ reconnect ที่หากไม่มีมัน bot ที่รันยาว ๆ จะค่อย ๆ หลุด sync ภายในไม่กี่ชั่วโมง

  • CLOB v1 vs v2 (use v2]
  • Order book REST snapshot
  • WebSocket subscriptions: market and user channels
  • Parsing bids/asks/depth
  • Computing mid-price and best-bid/ask
  • Maker fees, taker fees, rebates
  • Code: connect WS and process price-change events
  • Reconnect and gap-handling

CLOB v1 vs v2 (use v2]

โพลีมาร์เก็ต ดูแล SDK สองเจเนอเรชัน v1 (@polymarket/clob-client บน npm, py-clob-client <0.30) เลิกใช้แล้วและขาด order types หลายแบบที่เพิ่มเข้ามาในปี 2024 ส่วน v2 (@polymarket/clob-client-v2 v1.0.2 ใน Node, py-clob-client 0.34.6+ ใน Python) คือมาตรฐานปัจจุบัน

มีความแตกต่างสำคัญ 3 ข้อ v2 รองรับ flag negRisk สำหรับ multi-outcome markets - ซึ่งจำเป็นตั้งแต่เปิดตัว NegRisk exchange ในช่วงปลายปี 2024 v2 มาพร้อม TypeScript types สำหรับรูปแบบข้อความ WebSocket; ส่วน v1 จะคืนค่าเป็น any v2 จัดการ flow การ sign ของ Gnosis Safe ในเดือนสิงหาคม 2025 ได้แบบ native; ส่วน v1 ต้องใช้ custom signing glue

เนื้อหาที่เหลือของบทนี้จะเขียนโดยอิง v2 ตลอดทั้งบท หากคุณเห็นโค้ด v1 ใน tutorial เก่า ให้ถือว่ายังใช้ไม่ได้จนกว่าจะพิสูจน์ได้เป็นอย่างอื่น - โดยเฉพาะการวาง order ในตลาด NegRisk ภายใต้ v1 จะถูกส่งไปยัง exchange contract ที่ผิดแบบเงียบ ๆ

Order book REST snapshot

REST snapshot endpoint จะคืนค่า book ทั้งหมดของ token เดียว ณ จุดเวลาใดจุดเวลาหนึ่ง

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

รูปแบบ response:

{
  "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"}, ...]
}

ราคาเป็น string ที่มีทศนิยม 2-3 ตำแหน่ง; sizes เป็น string ที่แทนจำนวน shares (ไม่ใช่ดอลลาร์) bids เรียงจากสูงไปต่ำ, asks เรียงจากต่ำไปสูง hash คือ marker สำหรับ deduplication - การ poll book เดิมซ้ำ ๆ ที่ไม่มีการเปลี่ยนแปลงจะได้ hash เดิม และ bot ของคุณสามารถข้ามการประมวลผลได้

REST snapshot เหมาะกับการ lookup แบบครั้งเดียว (เช่นเช็กราคาตอนตัดสินใจเข้าเทรด) สำหรับการติดตามแบบต่อเนื่อง ให้ใช้ WebSocket channel ด้านล่าง

WebSocket subscriptions: market and user channels

มี WebSocket channels สองแบบที่สำคัญ

Market channel: wss://ws-subscriptions-clob.polymarket.com/ws/market Subscribe ได้หนึ่ง token หรือหลาย token; รับ order-book updates ทันทีที่เกิดขึ้น

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

ข้อความจะเข้ามาทุกครั้งที่มีการเปลี่ยนแปลง Types ได้แก่ book (full snapshot), price_change (delta), tick_size_change (พบไม่บ่อย), และ last_trade_price (ราคาที่ fill ล่าสุด)

User channel: wss://ws-subscriptions-clob.polymarket.com/ws/user ต้อง auth; ใช้รับ event ของ order คุณเอง - fills, partial fills, cancellations

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

User channel เป็นวิธีที่สะอาดที่สุดในการตรวจจับ fill การ poll orders REST endpoint มีต้นทุนสูงกว่าและอาจพลาด state changes ระหว่างการ poll; WebSocket จะ push event ออกมาทันทีที่ matcher ยืนยัน

Parsing bids/asks/depth

Order book คือรายการของ price levels ที่รวม size แล้ว มี conventions ในการ parsing สองข้อที่ต้องทำให้ถูก

ทิศทางของ order: bids คือ buy orders (มีคนต้องการ BUY ที่ราคานี้) เมื่อ bot ของคุณขาย คุณจะไป hit bid เมื่อ bot ของคุณซื้อ คุณจะ lift ask โพลีมาร์เก็ต UI แสดงทิศทางเดียวกัน; แต่อีกหลาย exchange จะกลับด้าน

การเรียงลำดับ: bids จะมาเรียงจากมากไปน้อย (best bid มาก่อน) asks จะมาเรียงจากน้อยไปมาก (best ask มาก่อน) best bid คือ bids[0]; best ask คือ asks[0] ระวัง: public WebSocket บางครั้งส่ง partial book updates ที่ยังไม่ถูก pre-sort - ให้ re-sort ทุกครั้งอย่างระมัดระวังหลัง merge

Depth ในแต่ละระดับคือมูลค่าเป็นดอลลาร์ที่สามารถเทรดได้: price * size Top-5-level depth เป็น metric ด้านสภาพคล่องที่ใช้บ่อย: sum(b.price * b.size for b in bids[:5]) หาก top-5 depth ต่ำกว่า $100 book นี้ถือว่า illiquid และสมมติฐานของกลยุทธ์ส่วนใหญ่จะเริ่มใช้ไม่ได้

Computing mid-price and best-bid/ask

มี price points ที่ bot ของคุณต้องคำนวณเพิ่มอีก 3 ค่า

  • Best bid / best ask: bids[0].price และ asks[0].price คือราคาที่คุณเทรดได้จริงสำหรับ 1 share
  • Mid-price: (best_bid + best_ask) / 2 จุดกึ่งกลางทางคณิตศาสตร์ของ spread ใช้สำหรับ valuation; คุณไม่ได้เทรดที่ mid จริง ๆ
  • VWAP price สำหรับ size N: เดินไปตาม book จน cumulative size ถึง N แล้วคืนค่า average price แบบถ่วงน้ำหนักด้วย size นี่คือ cost จริงในการ BUY N shares ตอนนี้ โดยคิดรวมการ sweep ไปยังระดับที่ลึกกว่า

กรณีขอบเขต: ถ้าฝั่ง bid หรือ ask ว่างเปล่า (ไม่มีคนขาย หรือไม่มีคนซื้อ) แปลว่า book เป็น one-sided ในโครงสร้างตลาดของ โพลีมาร์เก็ต สิ่งนี้เกิดกับตลาดที่ปิดแล้วหรือใกล้ปิด โดยฝั่งหนึ่งอยู่ที่ 0.999 และไม่มีใครเสนอ liquidity ฝั่งผู้แพ้ ให้ถือว่า best-bid = 0 หรือ best-ask = 1 เป็นสัญญาณ "do not trade"

Maker fees, taker fees, rebates

โพลีมาร์เก็ต ใช้โมเดล fee แบบ maker-taker ตัวเลข ณ เดือนพฤษภาคม 2026:

  • Taker fee: 0 (ศูนย์) - orders ที่ไป lift liquidity ที่มีอยู่ใน book จะไม่เสีย fee แต่ยังมี gas / network costs สำหรับ proxy operations
  • Maker rebate: เป็นบวกเล็กน้อย จ่ายแบบ programmatic ต่อ rested order ที่ถูก fill ในตลาดที่เข้าเกณฑ์โปรแกรมรางวัล ไม่ใช่ทุกตลาดจะมี rewards
  • NegRisk markets: โครงสร้าง fee เหมือนกัน แต่ใช้ exchange contract แยกต่างหาก; rewards จะสะสมแยกกัน

การที่ taker fee เป็นศูนย์ทำให้ โพลีมาร์เก็ต แตกต่างจาก CFD venues แบบดั้งเดิมอย่างมีนัยสำคัญ - ต้นทุน "จริง" ส่วนใหญ่คือ bid-ask spread เอง ไม่ใช่ fee ที่ระบุชัดเจน สำหรับกลยุทธ์ที่ข้าม spread ทุกครั้ง ต้นทุนจาก spread คือค่าใช้จ่ายจริง; ให้สมมติราว 1-3 เซนต์ต่อ round-trip สำหรับ book ทั่วไป และมากกว่านั้นในตลาดที่ illiquid

Maker rebates คุ้มค่าที่จะไล่ล่าก็ต่อเมื่อ markets ที่มีสิทธิ์รับ liquidity rewards ตรงกับไอเดียของกลยุทธ์ Chapter 19 จะครอบคลุม liquidity-rewards farming เป็นแนวทางเฉพาะทาง

Code: connect WS and process price-change events

ตัวอย่าง Node แบบขั้นต่ำ: connect, subscribe, log ทุก price-change event สำหรับ token เดียว

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));

Subscribe ได้สบาย ๆ ถึงประมาณ 30 token ต่อ WebSocket connection หากมากกว่านั้น ให้แยกไปหลาย connections - เซิร์ฟเวอร์บางครั้งจะหล่น subscriptions ขนาดใหญ่ออกไปโดยไม่แจ้ง error ซึ่งทำให้เกิด stale book reads แบบเงียบ ๆ

Reconnect and gap-handling

WebSocket connection ที่รันยาว ๆ จะหลุดได้ Cloudflare มีการ cycle connections ทุกไม่กี่ชั่วโมง; เครือข่ายอาจสะดุด; โพลีมาร์เก็ต ก็มีช่วง deploy ได้เช่นกัน ต้องเตรียมรับมือไว้

กลยุทธ์ reconnect: เมื่อเกิด close หรือ error ให้รอ min(2^attempt, 30) วินาทีพร้อม jitter แล้วค่อย re-subscribe รีเซ็ตตัวนับ attempt เมื่อได้รับข้อความสำเร็จครั้งแรกหลัง reconnect

การจัดการ gap สำคัญยิ่งกว่าความเร็วในการ reconnect ระหว่างที่ WebSocket หลุด book อาจเคลื่อนไหวไปแล้ว เมื่อ reconnect ทุกครั้ง ให้ดึง REST snapshot ของ token ที่ subscribe ไว้อีกครั้งและ reconcile: open positions ใด ๆ ที่ book เคลื่อนไหวอย่างมีนัยสำคัญต้องตรวจ state ใหม่, exits อาจต้อง fire, alarms อาจล้าสมัย เคส "ฉันพลาด book updates ไป 30 วินาที" คือฆาตกรเงียบของ bot ที่รันยาว - มันจะยังทำงานต่อไปบน state เก่า และวาง orders ที่ราคาไม่มีอยู่จริงแล้ว

แพตเทิร์นแบบ defensive: snapshot ของ book ที่ subscribe ไว้ทุกนาทีไม่ว่า WebSocket จะอยู่ในสถานะใด และถือว่า WS เป็นการ optimize แบบ fast-path ที่ทำงานอยู่บน snapshot poll อีกชั้นหนึ่ง

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

โพลีมาร์เก็ต CLOB API endpoint คืออะไร?
Base CLOB endpoint คือ https://clob.polymarket.com (REST) และ wss://ws-subscriptions-clob.polymarket.com/ws/market (WebSocket) นี่คือ V2 endpoints ที่ใช้โดย @polymarket/clob-client-v2 และ py-clob-client
ต้องใช้ API key เพื่ออ่าน order book ไหม?
ไม่ต้อง Order book reads (snapshots และ WebSocket subscriptions) เป็น public และไม่ต้อง authenticate คุณต้องใช้ API key เฉพาะตอนวาง/cancel orders และอ่านข้อมูลเฉพาะบัญชี (positions, fills)
CLOB WebSocket push price updates เร็วแค่ไหน?
เร็วเท่ากับความเร็วที่ orders match กันได้ ตลาดที่ active จะเห็น updates ทุกไม่กี่ร้อยมิลลิวินาที; ตลาดบางจะอัปเดตเฉพาะเมื่อมี orders จริงเท่านั้น ทั้ง depth changes และ trade events ไหลผ่าน WS channel เดียวกัน - ให้ parse event type เพื่อจัดการแต่ละแบบให้ถูกต้อง
จะคำนวณ mid-price ของ โพลีมาร์เก็ต order book ได้อย่างไร?
mid = (best_bid + best_ask) / 2 ถ้ามีทั้งสองฝั่ง; ถ้าไม่มีก็ใช้ last_trade_price เป็นตัวสำรอง ระวัง book บาง ๆ ที่ best_bid ต่ำกว่า best_ask มาก - mid อาจไม่มีความหมาย ควรพิจารณา spread เสมอก่อนจะมอง mid เป็น fair price
maker fee บน โพลีมาร์เก็ต ในปี 2026 คือเท่าไร?
0% ในหมวดส่วนใหญ่ Makers จะได้ rebates เท่ากับ 20-25% ของ taker fees Taker fees แตกต่างตามหมวด: 0.75% sports, 1.00% politics, 1.25% economics, 1.80% crypto ความไม่สมดุลระหว่าง rebate กับ fee นี่เองที่ทำให้ bots ที่ active มักจะ quote ด้วย limit orders มากกว่า market orders
จะจัดการ WebSocket disconnects อย่างไร?
Reconnect ด้วย exponential backoff (1s, 2s, 4s, สูงสุด 30s), re-subscribe ไปยัง markets เดิม และ re-fetch REST snapshot เพื่อเติมช่องว่าง ห้ามเชื่อ order book ที่ stale - หากหลุดการเชื่อมต่อเกิน 5 วินาที ให้ขอ fresh snapshot ก่อนวาง orders