Polymarket Bot Tutorial · פרק 8 מתוך 32
Polymarket CLOB API לבוטים: נקודות קצה של REST לצילומי מצב של order book, מנויי WebSocket לעדכונים בזמן אמת, ניתוח bids/asks, חישוב mid-price ו-depth, ודוגמאות קוד.
מה מכוסה בפרק זה
ה־CLOB API הוא המקום שבו orders נחתמים, נשלחים, מותאמים, ושבו ה־order book חי. ל־Polymarket יש שני דורות של SDK - ה־v1 המיושן וה־v2 הנוכחי. הפרק הזה עוסק רק ב־v2; v1 לא אמור להופיע באף בוט שאתם משחררים ב־2026. נעבור על נתיב ה־REST לצילום מצב, על ערוץ העדכונים ב־WebSocket, על פרטי הניתוח שמכשילים בונים חדשים, ועל לוגיקת ה־reconnect שללא ביצועה בוט שרץ לאורך זמן יסטה מסנכרון בתוך שעות.
- CLOB v1 לעומת v2 (השתמשו ב־v2)
- צילום מצב REST של ה־order book
- מנויי WebSocket: ערוצי market ו-user
- ניתוח bids/asks/depth
- חישוב mid-price ו-best-bid/ask
- maker fees, taker fees, rebates
- קוד: חיבור WS ועיבוד אירועי price-change
- Reconnect וטיפול בפערים
CLOB v1 לעומת v2 (השתמשו ב־v2)
ל־Polymarket יש שני דורות של SDK. v1 (@polymarket/clob-client ב־npm, py-clob-client <0.30) מיושן וחסרים בו כמה סוגי orders שנוספו ב־2024. v2 (@polymarket/clob-client-v2 v1.0.6 ב־Node, py-clob-client 0.34.6+ ב־Python) הוא התקן הנוכחי.
יש שלושה הבדלים קונקרטיים. v2 תומך ב־negRisk flag עבור שווקים מרובי תוצאות - נדרש מאז השקת ה־NegRisk exchange בסוף 2024. v2 מספק טיפוסי TypeScript לצורות ההודעות של ה־WebSocket; v1 מחזיר any. v2 מטפל באופן מובנה בזרימת החתימה של Gnosis Safe מאוגוסט 2025; v1 דורש glue מותאם אישית לחתימה.
המשך הפרק נכתב בהנחה שמדובר תמיד ב־v2. אם אתם רואים קוד v1 במדריך ישן, התייחסו אליו כאל שבור עד שיוכח אחרת - במיוחד שליחת orders לשווקי NegRisk תנותב בשקט לחוזה ה־exchange הלא נכון תחת v1.
Order book REST snapshot
נקודת הקצה של ה־REST snapshot מחזירה את כל ה־book עבור token יחיד בנקודת זמן מסוימת.
GET https://clob.polymarket.com/book?token_id=<ERC1155_TOKEN_ID>
מבנה התגובה:
{
"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"}, ...]
}
המחירים הם מחרוזות עם 2-3 ספרות אחרי הנקודה; הגדלים הם מחרוזות שמייצגות מספר shares (לא דולרים). ה־bids ממוינים מהגבוה לנמוך, וה־asks מהנמוך לגבוה. hash הוא סימון deduplication - קריאות חוזרות ל־book שלא השתנה יחזירו את אותו hash, והבוט שלכם יכול לדלג על העיבוד.
צילום מצב REST הוא הבחירה הנכונה לחיפושים חד-פעמיים (בדיקת מחיר לפני החלטת כניסה). לניטור רציף, השתמשו בערוץ ה־WebSocket למטה.
WebSocket subscriptions: market and user channels
יש שני ערוצי WebSocket חשובים.
Market channel: wss://ws-subscriptions-clob.polymarket.com/ws/market. נרשמים ל־token אחד או רבים; מקבלים עדכוני order book כשהם קורים.
{"type":"Market","markets":["0xCondId1","0xCondId2"]}
הודעות מגיעות בכל שינוי. הסוגים כוללים book (צילום מצב מלא), price_change (delta), tick_size_change (נדיר), ו־last_trade_price (ה־fill האחרון).
User channel: wss://ws-subscriptions-clob.polymarket.com/ws/user. מאומת; מקבלים את אירועי ה־order שלכם - fills, partial fills, cancellations.
{"type":"User","auth":{"apiKey":"...","secret":"...","passphrase":"..."}}
ערוץ המשתמש הוא הדרך הנקייה ביותר לזהות fill. Polling של נקודת הקצה orders REST עולה יותר ועלול להחמיץ שינויי מצב בין pollingים; ה־WebSocket דוחף את האירוע ברגע שה־matcher מאשר אותו.
Parsing bids/asks/depth
ה־order book הוא רשימה של רמות מחיר עם גודל מצטבר. יש שתי מוסכמות ניתוח שחשוב לעשות נכון.
כיוון ה־order: bids הם orders לקנייה (מישהו רוצה BUY במחיר הזה). כשהבוט שלכם מוכר, אתם פוגעים ב־bid. כשהבוט שלכם קונה, אתם מרימים ask. ממשק Polymarket מציג את אותו כיוון; חלק מהבורסות האחרות הופכות אותו.
מיון: bids מגיעים ממוינים בסדר יורד (best bid ראשון). asks מגיעים ממוינים בסדר עולה (best ask ראשון). best bid הוא bids[0]; best ask הוא asks[0]. שימו לב: ה־WebSocket הציבורי לפעמים שולח עדכוני book חלקיים שאינם ממוינים מראש - תמיד בצעו מיון מחדש באופן הגנתי אחרי כל merge.
Depth ברמה מסוימת הוא הערך בדולרים שניתן לבצע בו טרנזקציה: price * size. Depth ברמת 5 הרמות העליונות הוא מדד נזילות נפוץ: sum(b.price * b.size for b in bids[:5]). אם depth של חמש הרמות העליונות נמוך מ־$100, ה־book לא נזיל ורוב הנחות האסטרטגיה נשברות.
Computing mid-price and best-bid/ask
שלוש נקודות מחיר נגזרות שהבוט שלכם צריך.
- Best bid / best ask:
bids[0].priceו־asks[0].price. המחירים שבהם אפשר באמת לסחור, share אחד. - Mid-price:
(best_bid + best_ask) / 2. המרכז המתמטי של ה־spread. שימושי להערכה; אף פעם לא סוחרים ב־mid. - VWAP price for size N: עוברים על ה־book עד שהכמות המצטברת מגיעה ל־N, ומחזירים את המחיר הממוצע המשוקלל לפי גודל. העלות בפועל לקנות עכשיו N shares, תוך התחשבות בסריקה לרמות עמוקות יותר.
מקרה קצה: צד bid או ask ריק (אף אחד לא מוכר, או אף אחד לא קונה) אומר שה־book הוא חד-צדדי. במבנה השוק של Polymarket זה קורה בשווקים שהוכרעו או כמעט הוכרעו, שבהם צד אחד על 0.999 ואף אחד לא מציע נזילות בצד המפסיד. התייחסו ל־best-bid = 0 או ל־best-ask = 1 כאותות "אל תסחרו".
Maker fees, taker fees, rebates
במשך רוב ההיסטוריה שלו Polymarket לא גבה עמלות מסחר כלל. זה השתנה ב־2026: עמלות הוכנסו בתחילת השנה בשווקי הקריפטו של 15 דקות, הורחבו ל־Sports ב־30 במרץ 2026, ומאז הוטמעו ברוב הקטגוריות. כל מדריך שעדיין טוען ש־Polymarket חינמי מעמלות מיושן - ומי שמפספס זאת באסטרטגיה בתדירות גבוהה נאכל בשקט. כך המודל באמת עובד, נכון לאמצע 2026.
תחילה שני הצדדים של כל trade. maker הוא מי שמניח ב־book limit order נח שממתין שם; taker הוא מי ששולח order שמבוצע מיד מול נזילות קיימת. ה־makers עדיין משלמים אפס עמלה ומקבלים מעבר לכך rebate; רק ה־takers משלמים עמלה.
ה־taker fee אינה אחוז קבוע. היא הולכת לפי עקומה התלויה גם בגודל ה־order וגם במחיר:
fee = shares × feeRate × price × (1 - price)
האיבר price × (1 - price) מקסימלי במחיר 0.50 (שוק "הטלת מטבע" אמיתי) ומתכווץ לכיוון 0 או 1. במילים אחרות, בשווקים הכי לא ודאיים אתם משלמים את העמלה הגבוהה ביותר, ובשווקים שכמעט הוכרעו כמעט כלום. ה־feeRate נקבע לפי קטגוריה:
- Crypto: feeRate 0.07 (הגבוה ביותר, שיא אפקטיבי כ־1.8%), maker rebate 20%.
- Sports: feeRate 0.03 (שיא כ־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, עדיין ללא עמלה.
דוגמה לחישוב. נניח שה־bot שלכם לוקח 100 shares בשוק קריפטו במחיר 0.50. העמלה היא 100 × 0.07 × 0.50 × (1 - 0.50) = 100 × 0.07 × 0.25 = $1.75. אם תיקחו את אותם 100 shares ב־0.90, העמלה יורדת ל־100 × 0.07 × 0.90 × 0.10 = $0.63, כי המחיר רחוק מהאמצע הלא־ודאי. עבור bot הלקח ברור: לקיחת נזילות בשווקי קריפטו וספורט תנודתיים וכמעט מאוזנים עולה הכי הרבה עמלה - ולכן דווקא שם הכי משתלם לצטט כ־maker ולגרוף את ה־rebate במקום לשלם את העמלה.
מעבר לעמלה המפורשת, בכל פעם שאתם חוצים את ה־bid-ask spread אתם משלמים אותו. ה־spread הוא הפער בין מחיר הקנייה הטוב ביותר למחיר המכירה הטוב ביותר, ועבור אסטרטגיה שנכנסת ויוצאת כ־taker הפער הזה הוא עלות אמיתית מעל העמלה. הניחו 1-3 סנט הלוך-חזור ב־books טיפוסיים, ויותר בלא־נזילים. שווקי NegRisk (ה־multi-outcome exchange) משתמשים באותו מודל עמלות אך מסולקים על חוזה נפרד, ולכן ה־rewards שלהם נצברים בנפרד. פרק 19 מכסה farming של liquidity rewards, שבו גריפת maker rebates היא האסטרטגיה עצמה ולא רק תופעת לוואי.
Code: connect WS and process price-change events
דוגמת Node מינימלית: מתחברים, נרשמים, ומדפיסים כל אירוע price-change עבור 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));
אפשר להירשם בנוחות לעד כ־30 tokens לכל חיבור WebSocket. מעבר לכך, פצלו למספר חיבורים - השרת לפעמים מפיל subscriptions גדולים בלי להחזיר שגיאה, מה שיוצר קריאות שקטות ל־book מיושן.
Reconnect and gap-handling
חיבור WebSocket שרץ לאורך זמן ייפול. Cloudflare מחליף connections כל כמה שעות; רשתות מהבהבות; Polymarket לפעמים מבצעת deploy. תכננו לזה.
אסטרטגיית reconnect: על close או error, המתינו min(2^attempt, 30) שניות עם jitter, ואז בצעו re-subscribe. אפסו את מונה הניסיונות על ההודעה הראשונה שהצליחה לאחר reconnect.
טיפול בפערים חשוב יותר ממהירות reconnect. בזמן שה־WebSocket היה מנותק, ה־book השתנה. בכל reconnect, שלפו מחדש את ה־REST snapshot של כל token שנרשמתם אליו ובצעו reconciliation: כל פוזיציה פתוחה שה־book שלה השתנה באופן משמעותי צריכה בדיקת מצב מחדש, ייתכן שצריך להפעיל exits, והתרעות עלולות להיות מיושנות. המקרה של "פספסתי 30 שניות של עדכוני book" הוא הרוצח השקט של בוטים שרצים לאורך זמן - הם ממשיכים לרוץ על מצב מיושן ומניחים orders במחירים שכבר לא קיימים.
דפוס הגנתי: לצלם snapshot של כל book מנוי פעם בדקה בלי קשר למצב ה־WebSocket, ולהתייחס ל־WS כאופטימיזציית fast-path מעל polling ה־snapshot.












