Polymarket Bot Tutorial · الفصل 8 من 32

واجهة Polymarket CLOB API للـ bots: نقاط REST النهائية لقطات order book، واشتراكات WebSocket للتحديثات اللحظية، وتحليل bids/asks، وحساب mid-price وdepth، وأمثلة على code.

ما الذي يغطيه هذا الفصل

واجهة CLOB API هي المكان الذي تُوقَّع فيه الأوامر وتُرسل وتُطابَق، وهي أيضًا موطن order book. لدى Polymarket جيلان من SDK - الإصدار v1 المتروك، وv2 الحالي. يغطي هذا الفصل v2 فقط؛ فلا ينبغي أن يظهر v1 في أي bot تشغّله في 2026. سنستعرض مسار REST الخاص باللقطة snapshot، وقناة تحديثات WebSocket، وتفاصيل التحليل التي تُربك من يبنون للمرة الأولى، ومنطق إعادة الاتصال الذي بدونه ينحرف bot طويل التشغيل عن التزامن خلال ساعات.

  • 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. الإصدار v1 (@polymarket/clob-client على npm، وpy-clob-client <0.30) متروك ويفتقد عدة أنواع من الأوامر التي أُضيفت في 2024. أما v2 (@polymarket/clob-client-v2 v1.0.6 في Node، وpy-clob-client 0.34.6+ في Python) فهو المعيار الحالي.

هناك ثلاثة فروق عملية محددة. يدعم v2 وسم negRisk لأسواق متعددة النتائج - وهو مطلوب منذ إطلاق NegRisk exchange في أواخر 2024. كما يوفّر v2 أنواع TypeScript لأشكال رسائل WebSocket؛ بينما يعيد v1 قيمة any. ويعالج v2 تدفق توقيع Gnosis Safe في أغسطس 2025 بشكل أصيل؛ أما v1 فيتطلب طبقة ربط توقيع مخصصة.

بقية هذا الفصل مكتوبة بافتراض استخدام v2 في كل المواضع. إذا صادفت code قديمًا يستخدم v1 في tutorial أقدم، فاعتبره معطوبًا إلى أن يثبت العكس - خصوصًا أن تنفيذ الأوامر على أسواق NegRisk عبر v1 قد يُوجَّه بصمت إلى contract exchange الخاطئ.

Order book REST snapshot

يعيد REST snapshot endpoint الكتاب الكامل 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"}, ...]
}

تكون الأسعار سلاسل نصية بثلاث منازل عشرية أو منزلتين؛ وتكون الأحجام سلاسل نصية تمثل عدد الأسهم (وليس الدولارات). تُرتَّب bids من الأعلى إلى الأدنى، وasks من الأدنى إلى الأعلى. يُعد hash علامة لإزالة التكرار - فعمليات poll المتكررة لكتاب لم يتغير تعيد نفس hash، ويمكن لـ bot الخاص بك تخطي المعالجة.

لقطة REST هي الخيار الصحيح لعمليات lookup لمرة واحدة (مثل التحقق من السعر عند قرار الدخول). أما للمراقبة المستمرة، فاستعمل قناة WebSocket أدناه.

WebSocket subscriptions: market and user channels

هناك قناتان في WebSocket مهمتان.

قناة السوق: wss://ws-subscriptions-clob.polymarket.com/ws/market. اشترك في token واحد أو عدة tokens؛ وستتلقى تحديثات order book فور حدوثها.

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

تصل الرسائل عند كل تغيير. وتشمل الأنواع book (snapshot كامل)، وprice_change (delta)، وtick_size_change (نادر)، وlast_trade_price (آخر fill).

قناة المستخدم: wss://ws-subscriptions-clob.polymarket.com/ws/user. وهي مخصصة للمصادقة؛ وستتلقى أحداث أوامرك أنت - fills، وpartial fills، وcancellations.

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

قناة المستخدم هي أنظف طريقة لاكتشاف fill. أما polling لنقطة النهاية REST الخاصة بالأوامر فهو أعلى كلفة وقد يفوّت تغييرات الحالة بين عمليات poll؛ بينما يدفع WebSocket الحدث فور أن يؤكده matcher.

Parsing bids/asks/depth

order book هو قائمة بمستويات سعرية مع size مجمّع. وهناك اصطلاحان في التحليل يجب ضبطهما جيدًا.

اتجاه الأمر: تمثل bids أوامر شراء (أي أن هناك من يريد الشراء عند هذا السعر). عندما يبيع bot الخاص بك، فهو يضرب bid. وعندما يشتري، فهو يرفع ask. تعرض واجهة Polymarket نفس الاتجاه؛ بينما تعكسه بعض exchanges الأخرى.

الترتيب: تصل bids مرتبة تنازليًا (أفضل bid أولًا). وتصل asks مرتبة تصاعديًا (أفضل ask أولًا). أفضل bid هو bids[0]؛ وأفضل ask هو asks[0]. احذر: فقد يرسل WebSocket العام أحيانًا تحديثات جزئية للكتاب غير مرتبة مسبقًا - لذا أعد الترتيب دائمًا بشكل احترازي بعد أي دمج.

العمق depth عند مستوى معين هو القيمة الدولارية القابلة للتنفيذ: price * size. ويُعد عمق أعلى 5 مستويات metric شائعة للسيولة: sum(b.price * b.size for b in bids[:5]). إذا كان عمق أعلى 5 أقل من 100 دولار، فالكتاب غير سيّال ومعظم افتراضات الاستراتيجية تنهار.

Computing mid-price and best-bid/ask

هناك ثلاث نقاط سعرية مشتقة يحتاجها bot الخاص بك.

  • Best bid / best ask: bids[0].price وasks[0].price. وهي الأسعار التي يمكنك التداول عندها فعليًا، بسهم واحد.
  • Mid-price: (best_bid + best_ask) / 2. وهو المركز الرياضي للفارق spread. مفيد للتقييم؛ لكنك لا تتداول عند mid.
  • VWAP price for size N: امشِ في الكتاب حتى يصل الحجم التراكمي إلى N، ثم أعد متوسط السعر المرجّح بالحجم. هذه هي الكلفة الفعلية لشراء N سهم الآن، مع احتساب sweep إلى المستويات الأعمق.

حالة خاصة: إذا كان جانب bids أو asks فارغًا (لا أحد يبيع، أو لا أحد يشتري)، فهذا يعني أن الكتاب أحادي الجانب. في بنية سوق Polymarket يحدث هذا في الأسواق التي حُسمت أو تكاد تُحسم، حيث يكون أحد الجانبين عند 0.999 ولا يوفّر أحد سيولة على جانب الخاسر. تعامل مع best-bid = 0 أو best-ask = 1 كإشارات "لا تتداول".

Maker fees, taker fees, rebates

طوال معظم تاريخها لم تفرض Polymarket أي رسوم تداول إطلاقًا. تغيّر ذلك في 2026: أُدخلت الرسوم في بداية العام على أسواق العملات المشفرة ذات الـ 15 دقيقة، ثم وُسّعت إلى Sports في 30 مارس 2026، ومنذ ذلك الحين طُرحت على معظم الفئات. أي شرح لا يزال يزعم أن Polymarket بلا رسوم فهو قديم - ومن يغفل عن هذا في استراتيجية عالية التردد يُؤكَل بهدوء. إليك كيف يعمل النموذج فعليًا، اعتبارًا من منتصف 2026.

أولًا طرفا كل صفقة. الـ maker هو من يضع في الكتاب أمر limit ساكنًا ينتظر هناك؛ والـ taker هو من يرسل أمرًا يُنفَّذ فورًا مقابل السيولة الموجودة. لا يزال الـ makers يدفعون صفر رسوم ويحصلون فوق ذلك على rebate؛ ولا يدفع الرسوم سوى الـ takers.

الـ taker fee ليست نسبة ثابتة. إنها تتبع منحنى يعتمد على حجم الأمر وعلى السعر معًا:

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 واضح: أخذ السيولة في أسواق العملات المشفرة والرياضة المتقلبة وشبه المتوازنة يكلّف أعلى رسوم - ولذلك تحديدًا يكون الأجدى هناك أن تضع quote كـ maker وتجني الـ rebate بدلًا من دفع الرسوم.

وإضافةً إلى الرسوم الصريحة، تدفع spread الـ bid-ask في كل مرة تعبره. الـ spread هو الفجوة بين أفضل سعر شراء وأفضل سعر بيع، وبالنسبة لاستراتيجية تدخل وتخرج كـ taker تكون تلك الفجوة كلفة حقيقية فوق الرسوم. افترض 1-3 سنتات ذهابًا وإيابًا في الكتب المعتادة، وأكثر في غير السيّالة. أسواق NegRisk (الـ multi-outcome exchange) تستخدم نفس نموذج الرسوم لكنها تُسوَّى على contract منفصل، فتتراكم 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 token كحد مريح لكل اتصال WebSocket. وما بعد ذلك، قسّم الاشتراكات عبر عدة اتصالات - إذ إن الخادم يَسقط أحيانًا الاشتراكات الكبيرة بصمت دون إرجاع خطأ، ما يؤدي إلى قراءة stale book قديمة دون إنذار.

Reconnect and gap-handling

اتصال WebSocket طويل التشغيل سيفصل حتمًا. تقوم Cloudflare بتدوير الاتصالات كل بضع ساعات؛ والشبكات تتقطع؛ وPolymarket تنشر تحديثات أحيانًا. لذا خطّط لذلك.

استراتيجية إعادة الاتصال: عند close أو error، انتظر min(2^attempt, 30) ثانية مع jitter، ثم أعد الاشتراك. وأعد ضبط عداد المحاولات عند أول رسالة ناجحة بعد إعادة الاتصال.

أهمية معالجة الفجوات gap-handling أكبر من سرعة إعادة الاتصال. أثناء انقطاع WebSocket، يكون الكتاب قد تحرك. عند كل إعادة اتصال، أعد جلب REST snapshot لكل token مشترك واعمَل reconciliation: أي مراكز مفتوحة تحرك كتابها بشكل ملحوظ تحتاج إلى إعادة فحص للحالة، وقد تحتاج exits إلى التنفيذ، وقد تكون التنبيهات stale. إن حالة "فاتتني 30 ثانية من تحديثات الكتاب" هي القاتل الصامت للـ bots طويلة التشغيل - إذ تستمر في العمل على state قديم وتضع أوامر بأسعار لم تعد موجودة.

نمط دفاعي: خذ snapshot لكل book مشترك مرة كل دقيقة بغض النظر عن حالة WebSocket، وتعامل مع WS كتحسين سريع فوق polling للـ snapshot.

الأسئلة الشائعة

ما هو endpoint الخاص بـ Polymarket CLOB API؟
الـ CLOB endpoint الأساسي هو https://clob.polymarket.com (REST) وwss://ws-subscriptions-clob.polymarket.com/ws/market (WebSocket). وهذه هي نقاط النهاية V2 المستخدمة بواسطة @polymarket/clob-client-v2 وpy-clob-client.
هل أحتاج إلى API key لقراءة order book؟
لا. قراءات order book (الـ snapshots واشتراكات WebSocket) عامة ولا تتطلب أي مصادقة. تحتاج إلى API key فقط لوضع/إلغاء الأوامر وقراءة البيانات الخاصة بالحساب (المراكز، fills).
ما مدى سرعة WebSocket الخاص بـ CLOB في دفع تحديثات الأسعار؟
بسرعة تطابق الأوامر. الأسواق النشطة ترى تحديثات كل بضع مئات من الملي ثانية؛ أما الأسواق الخفيفة فتتحدث فقط عند ورود أوامر فعلية. كل من تغييرات depth وأحداث التداول تمر عبر نفس قناة WS - لذا حلّل نوع الحدث للتعامل مع كل منها بشكل صحيح.
كيف أحسب mid-price لكتاب أوامر Polymarket؟
mid = (best_bid + best_ask) / 2 إذا كان الاثنان موجودين؛ وإلا فاستخدم last_trade_price كخيار احتياطي. كن حذرًا مع الكتب الضعيفة حيث يكون best_bid بعيدًا جدًا عن best_ask - فقد يصبح mid بلا معنى. راعِ دائمًا spread أيضًا قبل اعتبار mid سعرًا عادلاً.
ما هي maker fee على Polymarket في 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 هو السبب في أن الـ bots النشطة تكاد دائمًا تضع quote بأوامر limit ساكنة بدلًا من عبور الـ spread بأوامر market.
كيف أتعامل مع انقطاعات WebSocket؟
أعد الاتصال باستخدام exponential backoff (1s، 2s، 4s، بحد أقصى 30s)، وأعد الاشتراك في الأسواق نفسها، ثم أعد جلب REST snapshot لملء أي فجوة. لا تثق أبدًا في order book قديم - إذا انقطع الاتصال لأكثر من 5 ثوانٍ، فاطلب snapshot جديدًا قبل وضع الأوامر.