Polymarket Bot Tutorial · অধ্যায় 8 of 32
বটের জন্য Polymarket CLOB API: order book snapshot-এর জন্য REST endpoints, real-time আপডেটের জন্য WebSocket subscriptions, bids/asks parsing, mid-price এবং depth computing, code samples.
এই অধ্যায়ে কী আছে
CLOB API-ই হলো সেই জায়গা যেখানে orders sign করা হয়, পাঠানো হয়, match করা হয়, এবং order book থাকে। Polymarket-এর দুইটি SDK generation আছে - deprecated v1 এবং বর্তমান v2। এই অধ্যায়ে শুধু v2 cover করা হয়েছে; 2026-এ আপনি যে bot ship করবেন তাতে v1 থাকা উচিত নয়। আমরা REST snapshot path, WebSocket update channel, নতুন builder-দের আটকে দেওয়া parsing details, এবং reconnect logic নিয়ে আলোচনা করব - এগুলো ছাড়া একটি long-running bot কয়েক ঘণ্টার মধ্যেই out of 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)
Polymarket দুইটি SDK generation maintain করে। v1 (@polymarket/clob-client on npm, py-clob-client <0.30) deprecated এবং 2024-এ যোগ হওয়া বেশ কিছু order type নেই। v2 (@polymarket/clob-client-v2 Node-এ v1.0.6, Python-এ py-clob-client 0.34.6+) হলো current standard।
তিনটি concrete difference। v2 multi-outcome market-এর জন্য negRisk flag support করে - NegRisk exchange late 2024-এ চালু হওয়ার পর থেকে এটি required। v2 WebSocket message shape-এর জন্য TypeScript types ship করে; v1 any return করে। v2 August 2025-এর Gnosis Safe signature flow natively handle করে; v1-এ custom signing glue লাগে।
এই অধ্যায়ের বাকি অংশ জুড়ে আমরা v2 ধরে লিখছি। আপনি যদি কোনো পুরনো tutorial-এ v1 code দেখেন, প্রমাণ না হওয়া পর্যন্ত সেটিকে broken ধরে নিন - বিশেষ করে NegRisk market-এ order placement v1-এ silently ভুল exchange contract-এ route হতে পারে।
Order book REST snapshot
REST snapshot endpoint নির্দিষ্ট একটি token-এর পূর্ণ book একটি নির্দিষ্ট সময়ে return করে।
GET https://clob.polymarket.com/book?token_id=<ERC1155_TOKEN_ID>
Response shape:
{
"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"}, ...]
}
Price string আকারে 2-3 decimal place-এ আসে; size হলো share count-এর string (dollar নয়)। Bids high-to-low sorted, asks low-to-high sorted। hash হলো deduplication marker - unchanged book-এর repeated poll একই hash return করে এবং আপনার bot processing skip করতে পারে।
একবারের lookup-এর জন্য REST snapshot-ই সঠিক পছন্দ (entry decision-এ price check)। Continuous monitoring-এর জন্য নিচের WebSocket channel ব্যবহার করুন।
WebSocket subscriptions: market and user channels
দুটি WebSocket channel গুরুত্বপূর্ণ।
Market channel: wss://ws-subscriptions-clob.polymarket.com/ws/market. এক বা একাধিক token subscribe করুন; order-book update যতক্ষণ ঘটছে ততক্ষণ তা receive করবেন।
{"type":"Market","markets":["0xCondId1","0xCondId2"]}
প্রতি change-এ message আসে। Type-এর মধ্যে আছে book (full snapshot), price_change (delta), tick_size_change (rare), এবং last_trade_price (সর্বশেষ fill)।
User channel: wss://ws-subscriptions-clob.polymarket.com/ws/user. Authenticated; আপনার own order event - fills, partial fills, cancellations - receive করবেন।
{"type":"User","auth":{"apiKey":"...","secret":"...","passphrase":"..."}}
Fill detect করার জন্য user channel সবচেয়ে clean way। orders REST endpoint poll করা বেশি expensive এবং poll-এর মধ্যে state change miss করতে পারে; WebSocket matcher সেটা acknowledge করার মুহূর্তেই event push করে।
Parsing bids/asks/depth
Order book হলো aggregated size-সহ price level-এর একটি list। ঠিকভাবে ধরার জন্য দুটি parsing convention গুরুত্বপূর্ণ।
Order direction: bids হলো buy order (এই price-এ কেউ BUY করতে চায়)। যখন আপনার bot sell করে, তখন আপনি একটি bid hit করেন। যখন আপনার bot buy করে, তখন আপনি ask lift করেন। Polymarket UI একই direction দেখায়; অন্য কিছু exchange উল্টোভাবে দেখায়।
Sorting: bids descending order-এ আসে (best bid প্রথমে)। asks ascending order-এ আসে (best ask প্রথমে)। Best bid হলো bids[0]; best ask হলো asks[0]। সতর্ক থাকুন: public WebSocket কখনও কখনও partial book update পাঠায় যা pre-sorted নয় - কোনো merge-এর পরে সবসময় defensively re-sort করুন।
কোনো level-এ depth মানে হলো transactable dollar value: price * size। Top-5-level depth একটি common liquidity metric: sum(b.price * b.size for b in bids[:5])। যদি top-5 depth $100-এর নিচে হয়, book illiquid এবং বেশিরভাগ strategy assumption ভেঙে যায়।
Computing mid-price and best-bid/ask
আপনার bot-এর দরকার তিনটি derived price point।
- Best bid / best ask:
bids[0].priceএবংasks[0].price. আপনি বাস্তবে যেটাতে trade করতে পারবেন, এক share-এর জন্য। - Mid-price:
(best_bid + best_ask) / 2. Spread-এর mathematical center। valuation-এর জন্য useful; আপনি mid-এ trade করেন না। - VWAP price for size N: cumulative size N-এ পৌঁছানো পর্যন্ত book walk করুন, তারপর size-weighted average price return করুন। এখনই N share BUY করার আসল cost, deeper level sweep ধরেই।
Edge case: bid বা ask side empty থাকা (কেউ sell করছে না, বা কেউ buy করছে না) মানে book one-sided। Polymarket-এর market structure-এ এটা resolved বা near-resolved market-এ ঘটে, যেখানে এক side 0.999-এ এবং loser side-এ কেউ liquidity offer করে না। best-bid = 0 বা best-ask = 1-কে "do not trade" signal হিসেবে নিন।
Maker fees, taker fees, rebates
নিজের ইতিহাসের বেশিরভাগ সময় Polymarket কোনো trading fee নেয়নি। 2026-এ এটি বদলে যায়: fee বছরের শুরুতে 15-মিনিটের crypto market-এ চালু হয়, 30 মার্চ 2026-এ Sports-এ সম্প্রসারিত হয়, এবং তারপর থেকে বেশিরভাগ category-তে প্রয়োগ হয়। যে কোনো tutorial যা এখনও দাবি করে Polymarket fee-মুক্ত, তা পুরনো - আর high-frequency strategy-তে কেউ এটি উপেক্ষা করলে নীরবে খেয়ে ফেলা হবে। 2026-এর মাঝামাঝি অনুযায়ী model আসলে যেভাবে কাজ করে তা এখানে।
প্রথমে প্রতিটি trade-এর দুটি দিক। maker হলো সেই যে book-এ একটি অপেক্ষমাণ limit order রাখে যা সেখানে অপেক্ষা করে; taker হলো সেই যে এমন order পাঠায় যা বিদ্যমান liquidity-র বিপরীতে সঙ্গে সঙ্গে execute হয়। maker এখনও শূন্য fee দেয় এবং উপরন্তু একটি rebate পায়; fee কেবল taker-রা দেয়।
taker fee কোনো স্থির শতাংশ নয়। এটি এমন একটি curve অনুসরণ করে যা order-এর আকার এবং price উভয়ের উপর নির্ভর করে:
fee = shares × feeRate × price × (1 - price)
price × (1 - price) পদটি price 0.50-তে (একটি সত্যিকারের "coin-flip" market) সর্বোচ্চ হয় এবং 0 বা 1-এর দিকে সংকুচিত হয়। অন্য কথায়, সবচেয়ে অনিশ্চিত market-এ আপনি সর্বোচ্চ fee দেন এবং প্রায়-নিষ্পন্ন market-এ প্রায় কিছুই নয়। feeRate প্রতিটি category-র জন্য নির্ধারিত:
- Crypto: feeRate 0.07 (সর্বোচ্চ, effective peak প্রায় 1.8%), maker rebate 20%।
- Sports: feeRate 0.03 (peak প্রায় 0.75%), maker rebate 25%।
- Finance, Politics, Tech, Mentions: feeRate 0.04, maker rebate 25%।
- Economics, Culture, Weather, সাধারণ: feeRate 0.05, maker rebate 25%।
- Geopolitics এবং বড় বিশ্ব-ঘটনা: 0, এখনও fee-মুক্ত।
একটি হিসাবের উদাহরণ। ধরুন আপনার bot 0.50 price-এ একটি crypto market-এর 100 shares নেয়। fee হবে 100 × 0.07 × 0.50 × (1 - 0.50) = 100 × 0.07 × 0.25 = $1.75। আপনি যদি একই 100 shares 0.90-তে নেন, fee কমে 100 × 0.07 × 0.90 × 0.10 = $0.63 হয়, কারণ price অনিশ্চিত মাঝখান থেকে দূরে। bot-এর জন্য শিক্ষা স্পষ্ট: অস্থির, প্রায়-ভারসাম্যপূর্ণ crypto ও sports market-এ liquidity নেওয়া সবচেয়ে বেশি fee নেয় - তাই ঠিক সেখানেই fee দেওয়ার বদলে maker হিসেবে quote করে rebate তুলে নেওয়া সবচেয়ে লাভজনক।
explicit fee ছাড়াও, প্রতিবার আপনি bid-ask spread cross করলে সেই spread-ও দেন। spread হলো সেরা buy price এবং সেরা sell price-এর মধ্যকার ফাঁক, এবং taker হিসেবে ঢোকা-বেরোনো strategy-র জন্য সেই ফাঁক fee-র উপরে একটি বাস্তব cost। সাধারণ book-এ round-trip 1-3 cents এবং illiquid-এ আরও বেশি ধরে নিন। NegRisk market (multi-outcome exchange) একই fee model ব্যবহার করে কিন্তু আলাদা contract-এ settle হয়, তাই তাদের rewards আলাদাভাবে accrue করে। Chapter 19-এ liquidity-rewards farming cover করা হয়েছে, যেখানে maker rebate তুলে নেওয়াই strategy, কেবল কোনো side-effect নয়।
Code: connect WS and process price-change events
Minimal Node example: connect করুন, subscribe করুন, একটি token-এর জন্য প্রতিটি price-change event log করুন।
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));
একটি WebSocket connection-এ প্রায় 30 token পর্যন্ত subscribe করা আরামদায়ক। এর বেশি হলে multiple connection-এ split করুন - server মাঝে মাঝে error না দিয়েই বড় subscription drop করে দেয়, ফলে silent stale book read তৈরি হয়।
Reconnect and gap-handling
একটি long-running WebSocket connection drop করবে। Cloudflare কয়েক ঘণ্টা পরপর connection cycle করে; network blink করে; Polymarket কখনও কখনও deploy করে। সে অনুযায়ী পরিকল্পনা করুন।
Reconnect strategy: close বা error-এ min(2^attempt, 30) seconds jitter-সহ wait করুন, তারপর re-subscribe করুন। Reconnect-এর পরে প্রথম successful message-এ attempt counter reset করুন।
Gap handling reconnect speed-এর চেয়ে বেশি গুরুত্বপূর্ণ। WebSocket disconnected থাকার সময় book নড়েছে। প্রতিটি reconnect-এ subscribed token-এর REST snapshot আবার fetch করুন এবং reconcile করুন: যেকোনো open position whose book meaningfully moved, state re-check দরকার; exits fire করতে হতে পারে; alarm stale হতে পারে। "আমি 30 seconds-এর book update miss করেছি" - এটা long-running bot-এর silent killer; bot stale state-এ চালতে থাকে এবং এমন price-এ order দেয় যা আর নেই।
Defensive pattern: WebSocket state যাই হোক না কেন, প্রতি মিনিটে সব subscribed book-এর snapshot নিন, এবং WS-কে snapshot poll-এর উপর built একটি fast-path optimization হিসেবে ধরুন।












