Polymarket Bot Tutorial · Chương 8 trên 32

Polymarket CLOB API cho bots: REST endpoints để lấy order book snapshots, WebSocket subscriptions cho real-time updates, phân tích bids/asks, tính mid-price và depth, code samples.

Chương này bao gồm những gì

CLOB API là nơi orders được ký, gửi, khớp, và cũng là nơi order book tồn tại. Polymarket có hai thế hệ SDK - v1 đã bị deprecate và v2 hiện tại. Chương này chỉ đề cập đến v2; v1 không nên xuất hiện trong bất kỳ bot nào bạn triển khai vào năm 2026. Chúng ta sẽ đi qua luồng REST snapshot, WebSocket update channel, các chi tiết parsing dễ khiến builder mới mắc lỗi, và logic reconnect mà nếu thiếu thì một bot chạy lâu sẽ lệch khỏi trạng thái thực tế chỉ sau vài giờ.

  • CLOB v1 so với v2 (dùng v2)
  • Order book REST snapshot
  • WebSocket subscriptions: market và user channels
  • Phân tích bids/asks/depth
  • Tính mid-price và best-bid/ask
  • Maker fees, taker fees, rebates
  • Code: kết nối WS và xử lý price-change events
  • Reconnect và xử lý gap

CLOB v1 so với v2 (dùng v2)

Polymarket duy trì hai thế hệ SDK. v1 (@polymarket/clob-client trên npm, py-clob-client <0.30) đã bị deprecate và thiếu một số order types được thêm vào năm 2024. v2 (@polymarket/clob-client-v2 v1.0.6 trong Node, py-clob-client 0.34.6+ trong Python) là standard hiện tại.

Có ba khác biệt cụ thể. v2 hỗ trợ cờ negRisk cho multi-outcome markets - yêu cầu bắt buộc kể từ khi NegRisk exchange ra mắt vào cuối năm 2024. v2 cung cấp TypeScript types cho cấu trúc WebSocket message; v1 trả về any. v2 xử lý native luồng ký Gnosis Safe từ tháng 8 năm 2025; v1 cần custom signing glue.

Phần còn lại của chương này được viết với giả định luôn dùng v2. Nếu bạn thấy code v1 trong một tutorial cũ, hãy xem nó là lỗi cho đến khi được chứng minh ngược lại - đặc biệt là việc đặt lệnh vào NegRisk markets dưới v1 có thể âm thầm route tới sai exchange contract.

Order book REST snapshot

REST snapshot endpoint trả về toàn bộ book cho một token duy nhất tại một thời điểm.

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

Cấu trúc 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"}, ...]
}

Prices là strings với 2-3 chữ số thập phân; sizes là strings biểu thị số lượng shares (không phải dollars). Bids được sắp xếp từ cao xuống thấp, asks từ thấp lên cao. hash là một marker để chống trùng lặp - các lần poll lặp lại trên một book không thay đổi sẽ trả về cùng hash và bot của bạn có thể bỏ qua việc xử lý.

REST snapshot là lựa chọn đúng cho các truy vấn một lần (kiểm tra giá khi ra quyết định vào lệnh). Với giám sát liên tục, hãy dùng WebSocket channel bên dưới.

WebSocket subscriptions: market và user channels

Có hai WebSocket channels quan trọng.

Market channel: wss://ws-subscriptions-clob.polymarket.com/ws/market. Subscribe một hoặc nhiều tokens; nhận các order-book updates khi chúng xảy ra.

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

Messages đến mỗi khi có thay đổi. Các loại bao gồm book (full snapshot), price_change (delta), tick_size_change (hiếm), và last_trade_price (lần khớp gần nhất).

User channel: wss://ws-subscriptions-clob.polymarket.com/ws/user. Đã xác thực; nhận các sự kiện order của chính bạn - fills, partial fills, cancellations.

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

User channel là cách sạch nhất để phát hiện một fill. Poll REST endpoint của orders tốn nhiều chi phí hơn và có thể bỏ lỡ thay đổi trạng thái giữa các lần poll; WebSocket đẩy sự kiện ngay khi matcher xác nhận nó.

Phân tích bids/asks/depth

Order book là danh sách các price levels với size được cộng gộp. Có hai quy ước parsing cần làm đúng.

Order direction: bids là buy orders (ai đó muốn MUA ở mức giá này). Khi bot của BẠN bán, bạn khớp vào một bid. Khi bot của bạn mua, bạn lift một ask. Polymarket UI hiển thị cùng chiều; một số exchange khác thì đảo ngược.

Sorting: bids đi theo thứ tự giảm dần (best bid trước). asks đi theo thứ tự tăng dần (best ask trước). Best bid là bids[0]; best ask là asks[0]. Lưu ý: public WebSocket đôi khi gửi partial book updates chưa được pre-sort - hãy luôn re-sort một cách phòng thủ sau mỗi lần merge.

Depth tại một level là giá trị dollar có thể giao dịch: price * size. Top-5-level depth là một chỉ số thanh khoản phổ biến: sum(b.price * b.size for b in bids[:5]). Nếu top-5 depth dưới $100, book này kém thanh khoản và hầu hết giả định chiến lược sẽ không còn đúng.

Tính mid-price và best-bid/ask

Có ba price points dẫn xuất mà bot của bạn cần.

  • Best bid / best ask: bids[0].priceasks[0].price. Đây là mức giá bạn thực sự có thể giao dịch, cho một share.
  • Mid-price: (best_bid + best_ask) / 2. Tâm toán học của spread. Hữu ích cho định giá; bạn không bao giờ giao dịch tại mid.
  • VWAP price cho size N: đi qua book cho đến khi cumulative size đạt N, rồi trả về giá trung bình gia quyền theo size. Đây là chi phí thực tế để MUA N shares ngay lúc này, có tính đến việc sweep sang các level sâu hơn.

Edge case: một bên bid hoặc ask trống (không ai bán, hoặc không ai mua) nghĩa là book chỉ có một phía. Trong cấu trúc market của Polymarket, điều này xảy ra ở các markets đã được resolve hoặc gần resolve, nơi một phía ở mức 0.999 và không ai cung cấp thanh khoản ở phía thua. Hãy xem best-bid = 0 hoặc best-ask = 1 là tín hiệu "không giao dịch".

Maker fees, taker fees, rebates

Trong phần lớn lịch sử của mình, Polymarket hoàn toàn không thu phí giao dịch. Điều đó đã thay đổi vào năm 2026: phí được áp dụng đầu năm trên các market crypto 15 phút, mở rộng sang Sports vào ngày 30 tháng 3 năm 2026, và kể từ đó được triển khai cho hầu hết các danh mục. Bất kỳ hướng dẫn nào vẫn khẳng định Polymarket miễn phí đều đã lỗi thời - và ai bỏ qua điều này trong một chiến lược tần suất cao sẽ bị ăn mòn âm thầm. Đây là cách mô hình thực sự vận hành, tính đến giữa năm 2026.

Trước hết là hai phía của mỗi giao dịch. Maker là người đặt một limit order nằm chờ trong book; taker là người gửi một order được khớp ngay lập tức với thanh khoản sẵn có. Maker vẫn trả không phí và còn nhận thêm rebate; chỉ taker mới trả phí.

Taker fee không phải một tỷ lệ phần trăm cố định. Nó đi theo một đường cong phụ thuộc cả vào khối lượng order lẫn giá:

fee = shares × feeRate × price × (1 - price)

Số hạng price × (1 - price) đạt cực đại ở mức giá 0,50 (một market kiểu tung đồng xu thực sự) và co lại về phía 0 hoặc 1. Nói cách khác, ở những market bất định nhất bạn trả phí cao nhất, còn ở những market gần như đã ngã ngũ thì gần như không đáng kể. feeRate được ấn định theo từng danh mục:

  • Crypto: feeRate 0,07 (cao nhất, đỉnh hiệu dụng khoảng 1,8%), maker rebate 20%.
  • Sports: feeRate 0,03 (đỉnh khoảng 0,75%), maker rebate 25%.
  • Finance, Politics, Tech, Mentions: feeRate 0,04, maker rebate 25%.
  • Economics, Culture, Weather, chung: feeRate 0,05, maker rebate 25%.
  • Geopolitics và các sự kiện thế giới lớn: 0, vẫn miễn phí.

Một ví dụ tính toán. Giả sử bot của bạn lấy 100 shares của một market crypto ở giá 0,50. Phí là 100 × 0,07 × 0,50 × (1 - 0,50) = 100 × 0,07 × 0,25 = $1,75. Nếu thay vào đó bạn lấy cùng 100 shares ở 0,90, phí giảm còn 100 × 0,07 × 0,90 × 0,10 = $0,63, vì giá nằm xa vùng giữa bất định. Với một bot, bài học rất rõ: lấy thanh khoản trên các market crypto và sports biến động, gần như cân bằng tốn phí nhiều nhất - vậy nên chính ở đó việc quote như maker và thu rebate có lợi hơn nhiều so với trả phí.

Ngoài phí tường minh, mỗi lần vượt qua bid-ask spread bạn đều phải trả spread đó. Spread là khoảng cách giữa giá mua tốt nhất và giá bán tốt nhất, và với một chiến lược vào ra theo kiểu taker, khoảng cách đó là một chi phí thực cộng thêm vào phí. Hãy giả định 1-3 cents cho một round-trip trên các book điển hình, và cao hơn ở các book kém thanh khoản. Các market NegRisk (multi-outcome exchange) dùng cùng mô hình phí nhưng settle trên một contract riêng, nên rewards của chúng tích lũy riêng. Chương 19 đề cập liquidity-rewards farming, nơi việc thu maker rebate chính là chiến lược, chứ không chỉ là một tác dụng phụ.

Code: kết nối WS và xử lý price-change events

Ví dụ Node tối giản: kết nối, subscribe, log mọi price-change event cho một 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));

Hãy subscribe khoảng tối đa ~30 tokens cho mỗi WebSocket connection một cách thoải mái. Vượt quá mức đó, hãy tách ra nhiều connections - server đôi khi sẽ làm rơi các subscriptions lớn mà không báo lỗi, dẫn đến việc đọc book bị stale một cách âm thầm.

Reconnect và xử lý gap

Một WebSocket connection chạy lâu sẽ bị rớt. Cloudflare luân chuyển connections mỗi vài giờ; network chập chờn; Polymarket đôi khi deploy. Hãy lên kế hoạch cho điều đó.

Chiến lược reconnect: khi close hoặc error, chờ min(2^attempt, 30) giây có thêm jitter, rồi subscribe lại. Reset attempt counter sau message thành công đầu tiên sau khi reconnect.

Xử lý gap quan trọng hơn tốc độ reconnect. Trong lúc WebSocket bị ngắt, book đã di chuyển. Mỗi khi reconnect, hãy fetch lại REST snapshot của mọi token đã subscribe và đối soát: bất kỳ open positions nào có book thay đổi đáng kể đều cần re-check state, các exits có thể cần kích hoạt, alarms có thể đã stale. Trường hợp "tôi đã bỏ lỡ 30 giây cập nhật book" là kẻ giết thầm lặng của các bot chạy dài - chúng tiếp tục hoạt động trên state cũ và đặt orders ở những mức giá không còn tồn tại.

Mẫu phòng thủ: snapshot mọi subscribed book một lần mỗi phút bất kể trạng thái WebSocket, và coi WS là một optimization fast-path nằm trên lớp poll snapshot.

Câu hỏi thường gặp

Polymarket CLOB API endpoint là gì?
Base CLOB endpoint là https://clob.polymarket.com (REST) và wss://ws-subscriptions-clob.polymarket.com/ws/market (WebSocket). Đây là các V2 endpoints được dùng bởi @polymarket/clob-client-v2 và py-clob-client.
Tôi có cần API key để đọc order book không?
Không. Việc đọc order book (snapshots và WebSocket subscriptions) là public và không cần authentication. Bạn chỉ cần API key để đặt/hủy orders và đọc dữ liệu riêng của tài khoản (positions, fills).
CLOB WebSocket đẩy price updates nhanh đến mức nào?
Nhanh như tốc độ orders được khớp. Các markets sôi động thấy updates mỗi vài trăm mili-giây; các markets mỏng chỉ cập nhật khi có orders thực sự. Cả depth changes và trade events đều đi qua cùng một WS channel - hãy parse event type để xử lý đúng từng loại.
Làm sao tính mid-price của một Polymarket order book?
mid = (best_bid + best_ask) / 2 nếu cả hai cùng tồn tại; nếu không, dùng last_trade_price làm phương án dự phòng. Hãy cẩn thận với book mỏng khi best_bid thấp hơn best_ask rất xa - mid có thể không còn ý nghĩa. Luôn xem xét spread trước khi coi mid là fair price.
Maker fee trên Polymarket năm 2026 là bao nhiêu?
Maker trả 0% và nhận rebate (20% với crypto, 25% với hầu hết các danh mục khác). Chỉ taker mới trả phí, và phí không cố định: nó đi theo fee = shares × feeRate × price × (1 - price), nên đạt đỉnh ở các market kiểu tung đồng xu quanh 0,50 và co lại về phía hai cực. feeRate theo từng danh mục dao động từ 0,03 (Sports, đỉnh hiệu dụng khoảng 0,75%) đến 0,07 (Crypto, đỉnh hiệu dụng khoảng 1,8%), trong khi Geopolitics vẫn miễn phí. Chính sự bất đối xứng maker-taker này là lý do các bot hoạt động hầu như luôn quote bằng limit order nằm chờ thay vì vượt spread bằng market order.
Làm sao xử lý WebSocket disconnects?
Reconnect với exponential backoff (1s, 2s, 4s, tối đa 30s), subscribe lại cùng các markets, và fetch lại một REST snapshot để lấp mọi khoảng trống. Đừng bao giờ tin vào một order book đã stale - nếu bạn đã bị ngắt kết nối hơn 5 giây, hãy yêu cầu snapshot mới trước khi đặt orders.