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.

שאלות נפוצות

What is the Polymarket CLOB API endpoint?
נקודת הקצה הבסיסית של ה־CLOB היא https://clob.polymarket.com (REST) ו־wss://ws-subscriptions-clob.polymarket.com/ws/market (WebSocket). אלה נקודות הקצה של V2 שמשמשות את @polymarket/clob-client-v2 ואת py-clob-client.
Do I need an API key to read the order book?
לא. קריאות ל־order book (צילומי מצב ומנויי WebSocket) הן ציבוריות ולא דורשות אימות. צריך API key רק כדי להניח/לבטל orders ולקרוא נתונים ספציפיים לחשבון (positions, fills).
How fast does the CLOB WebSocket push price updates?
כמה מהר ש־orders מתאימים. שווקים פעילים רואים עדכונים כל כמה מאות מילישניות; שווקים דלילים מתעדכנים רק על orders אמיתיים. גם שינויי depth וגם אירועי trade זורמים דרך אותו ערוץ WS - נתחו את סוג האירוע כדי לטפל בכל אחד נכון.
How do I compute the mid-price of a Polymarket order book?
mid = (best_bid + best_ask) / 2 אם שניהם קיימים; אחרת השתמשו ב־last_trade_price כ־fallback. היזהרו מ־books דלילים שבהם best_bid רחוק בהרבה מ־best_ask - ה־mid יכול להיות חסר משמעות. תמיד שקלו גם את ה־spread לפני שמתייחסים ל־mid כאל מחיר הוגן.
What is the maker fee on Polymarket in 2026?
ה־makers משלמים 0% ומקבלים rebate (20% בקריפטו, 25% ברוב הקטגוריות האחרות). רק ה־takers משלמים עמלה, והיא אינה קבועה: היא הולכת לפי fee = shares × feeRate × price × (1 - price), כך שהיא בשיא בשווקי "הטלת מטבע" סביב 0.50 ומתכווצת לכיוון הקצוות. ה־feeRates לפי קטגוריה נעים מ־0.03 (Sports, שיא אפקטיבי כ־0.75%) עד 0.07 (Crypto, שיא אפקטיבי כ־1.8%), כש־Geopolitics עדיין ללא עמלה. הא-סימטריה הזו בין maker ל־taker היא הסיבה לכך שבוטים פעילים כמעט תמיד מצטטים עם limit orders נחים במקום לחצות את ה־spread עם market orders.
How do I handle WebSocket disconnects?
בצעו reconnect עם exponential backoff (1s, 2s, 4s, מקסימום 30s), הירשמו מחדש לאותם markets, ושלפו מחדש snapshot של REST כדי למלא כל פער. לעולם אל תסמכו על order book מיושן - אם הייתם מנותקים ליותר מ־5 שניות, בקשו snapshot טרי לפני הנחת orders.