جميع المقالات
مرجع APIWebSocketsPolymarket APIبوتات التداول

WebSockets في Polymarket: بيانات آنية لا تنقطع

استطلاع دفتر الأوامر هو الطريقة الأكثر شيوعًا لاستنزاف ميزانية حد المعدل بلا فائدة. إليك التدفقات الأربعة، وخيارات الاشتراك التي لا يوثقها أحد، ونمط الفشل الذي يتلقى فيه بوتك الصمت فيظنه هدوءًا.

10 دقيقة للقراءةآخر تحديث 24 سبتمبر 2026

إذا كان بوتك يستطلع GET /book على مؤقت، فستوفر عليك هذه الصفحة معظم ميزانية حد المعدل وجزءًا من زمن الاستجابة. تدفع Polymarket تحديثات الدفتر عبر WebSocket، والاشتراك يكلفك اتصالًا واحدًا بدلًا من آلاف الطلبات.

النسخة المختصرة

اتصل بـ wss://ws-subscriptions-clob.polymarket.com/ws/market، وأرسل اشتراكًا يحدد assets_ids الخاصة بك، ثم أرسل PING كل 10 ثوانٍ وإلا سيُقطع اتصالك. اضبط custom_feature_enabled: true إذا أردت أحداث best_bid_ask أو new_market أو market_resolved — فهي معطّلة افتراضيًا وغيابها يبدو تمامًا كسوق هادئ.

التدفقات الأربعة

التدفقURLما يحملهالمصادقة
Marketwss://ws-subscriptions-clob.polymarket.com/ws/marketتحديثات عامة للدفتر والأسعار ودورة الحياةلا شيء
Userwss://ws-subscriptions-clob.polymarket.com/ws/userتحديثات أوامرك وصفقاتكنعم
RTDS (قديمة)wss://ws-live-data.polymarket.comالتعليقات — انتقلت الأسعار المرجعية إلى PolyBoltلا شيء
PolyBoltwss://ws-live-v2.polymarket.com/wsالأسعار المرجعية للعملات المشفرة والأسهم وTWAPنعم
Sportswss://sports-api.polymarket.com/wsحالة المباريات المباشرة والنتائجلا شيء

قناة User هي التي يغفل عنها الناس

إذا كان بوتك يستطلع /data/orders ليعرف ما إذا نُفّذ أمره، فأنت تنفق ميزانية حد المعدل على معلومات تدفعها إليك قناة User لحظة حدوثها — وبزمن استجابة أقل. أي بوت يقدّم أوامر يجب أن يكون على هذا التدفق.

انتقلت الأسعار المرجعية في 15 سبتمبر 2026

أطلقت Polymarket خدمة PolyBolt وجعلت RTDS قديمة بالنسبة للأسعار المرجعية. أصبحت crypto_prices وcrypto_prices_chainlink وequity_prices الآن على wss://ws-live-v2.polymarket.com/ws، وتغيّر المصدر من Binance/Chainlink إلى Pyth، والرموز بأحرف صغيرة btcusd بدلًا من btcusdt أو btc/usd، والمصادقة أصبحت مطلوبة الآن. المقابلة الكاملة في دليل الانتقال إلى PolyBolt. كل ما عدا ذلك في هذه الصفحة — قناتا السوق والمستخدم في CLOB — لم يتأثر.

الاشتراك في قناة السوق

اتصل، ثم أرسل رسالة اشتراك JSON واحدة. يأخذ assets_ids معرّفات التوكنات — نفسها التي تحصل عليها من البيانات الوصفية للأسواق — ويجب أن يكون type هو "market".

{
  "assets_ids": ["65818619657568813474341868652308942079804919287380422192892211131408793125422"],
  "type": "market",
  "initial_dump": true,
  "level": 2,
  "custom_feature_enabled": true
}
الحقلمطلوبالافتراضيما يفعله
assets_idsنعم—معرّفات التوكنات المراد الاشتراك فيها
typeنعم—يجب أن يكون "market"
initial_dumpلاtrueإرسال لقطة كاملة للدفتر عند الاشتراك
levelلا2مستوى الاشتراك — 1 أو 2 أو 3
custom_feature_enabledلاfalseيفعّل أحداث best_bid_ask وnew_market وmarket_resolved

custom_feature_enabled قيمته الافتراضية false

هذه هي مفاجأة الاشتراك التي تكلف الناس ظهيرة كاملة. ثلاثة أنواع من الأحداث — best_bid_ask وnew_market وmarket_resolved — لا تُسلَّم ما لم تفعّلها. لا يوجد خطأ ولا تحذير؛ ببساطة لن تتلقاها أبدًا. إذا كنت تنتظر حدث market_resolved لا يصل أبدًا، فهذا هو السبب.

أبقِ على initial_dump: true ما لم يكن لديك سبب محدد لعدم ذلك. بدونه تبدأ بلا حالة للدفتر وعليك انتظار التحديثات التدريجية لإعادة بنائها، ما يعني أن بوتك يبدأ حياته بصورة ناقصة.

أنواع الرسائل

تحمل كل رسالة event_type. تفرّع عليه بشكل شامل — النوع غير المعروف يجب تسجيله لا إسقاطه بصمت، لأن هذه هي الطريقة التي تكتشف بها أن البروتوكول تغيّر.

event_typeالمعنىيتطلب تفعيلًا
bookلقطة كاملة لدفتر الأوامرلا
price_changeتحديث تدريجي للسعر/المستوىلا
last_trade_priceنُفّذت صفقةلا
tick_size_changeتغيّرت شبكة التيك في السوقلا
best_bid_askتحديث أعلى الدفترنعم
new_marketأُنشئ سوقنعم
market_resolvedسُوّي سوقنعم

لا تتجاهل tick_size_change

حجم التيك خاص بكل سوق وقد يضيق مع نضج السوق. إذا خزّنت حجم التيك عند بدء التشغيل وغيّره السوق، فسيُرفض كل أمر حد لاحق بمخالفة الحد الأدنى لحجم التيك — خطأ 400 يبدو كخطأ في منطق التسعير لديك. تعامل مع الحدث وحدّث ذاكرتك المؤقتة.

البقاء متصلًا: PING كل 10 ثوانٍ

هذا هو الاشتراط الذي يوقع الجميع. يجب على العميل إرسال PING كل 10 ثوانٍ؛ ويرد الخادم بـ PONG. فوّت النبضة وسيُقطع الاتصال.

لاحظ الاتجاه: هذه نبضة من العميل. أنت لا تنتظر أن يرسل لك الخادم ping. وآلية keepalive المدمجة في مكتبة WebSocket بفاصل زمني آخر ليست بديلًا — أرسل PING على مستوى التطبيق بنفسك.

import asyncio, json, time
import websockets

URL = "wss://ws-subscriptions-clob.polymarket.com/ws/market"
STALE_AFTER = 30          # seconds without any message = treat as dead


async def stream(token_ids, on_event):
    backoff = 1
    while True:
        try:
            async with websockets.connect(URL) as ws:
                await ws.send(json.dumps({
                    "assets_ids": token_ids,
                    "type": "market",
                    "initial_dump": True,
                    "custom_feature_enabled": True,   # or lose 3 event types
                }))
                backoff = 1                            # reconnected cleanly
                last_msg = time.monotonic()

                async def heartbeat():
                    while True:
                        await asyncio.sleep(10)        # required cadence
                        await ws.send("PING")

                hb = asyncio.create_task(heartbeat())
                try:
                    while True:
                        # Silence is a failure mode, not a quiet market.
                        raw = await asyncio.wait_for(ws.recv(), timeout=STALE_AFTER)
                        last_msg = time.monotonic()
                        if raw == "PONG":
                            continue
                        for msg in json.loads(raw) if raw.startswith("[") else [json.loads(raw)]:
                            on_event(msg)
                finally:
                    hb.cancel()

        except Exception as exc:
            # Reconnect with capped exponential backoff + jitter.
            wait = min(backoff, 30) * (0.5 + 0.5 * asyncio.get_event_loop().time() % 1)
            print(f"ws down ({exc}); reconnecting in {wait:.1f}s")
            await asyncio.sleep(wait)
            backoff = min(backoff * 2, 30)

استخدم SDK ما لم يكن لديك سبب لعدم ذلك

تنفّذ polymarket-client (Python) و@polymarket/client (TypeScript) النبضة وإعادة الاتصال وتأطير الرسائل، وتدمجان عدة تغذيات في تدفق أحداث واحد محدد الأنواع. الكتابة اليدوية تستحق العناء فقط إذا احتجت إلى تحكم لا تكشفه SDK. لاحظ أن الاشتراكات غير متزامنة فقط — العملاء المتزامنون لا ينفّذون subscribe().

تغيير الاشتراكات دون إعادة الاتصال

تنتهي أسواق الخمس دقائق باستمرار، لذا يحتاج بوت يتتبع "أسواق BTC 5m الحالية" إلى تغيير مجموعة اشتراكاته باستمرار. لا يتعين عليك هدم الاتصال لذلك — قناة السوق تدعم الاشتراك وإلغاء الاشتراك على اتصال حي.

هذا أهم مما يبدو. إعادة الاتصال عند كل تدوير للأسواق تعني دفع تكلفة إعداد الاتصال مرارًا، وإعادة طلب اللقطات الأولية، وخلق نافذة لا تتلقى فيها شيئًا في اللحظة نفسها التي يُفتتح فيها سوق جديد.

نمط الفشل الذي يكلّف المال

انقطاع WebSocket لا يطلق استثناءً. بل يتوقف عن توصيل الرسائل. بالنسبة لبوت ساذج، لا يمكن تمييز "لا تحديثات" عن "السوق لا يتحرك" — لذا سيبقى بوت يحمل مركزًا على سعر متقادم إلى أجل غير مسمى، واثقًا من أن شيئًا لم يتغير.

  • تتبّع عمر آخر رسالة. إذا لم يصل شيء خلال ~30 ثانية في سوق نشط، فأنت منقطع، لا في هدوء. مهلة asyncio.wait_for أعلاه تؤدي هذه المهمة بالضبط.
  • تعامل مع التقادم كحالة خطأ. توقف عن التسعير، وصفِّ مراكزك إن كانت قواعد المخاطر لديك تقتضي ذلك، وأعد الاتصال — لا تواصل التداول على دفتر متجمد.
  • تراجع عند إعادة الاتصال، مع تذبذب عشوائي. حلقة إعادة اتصال ضيقة أثناء انقطاع هي الطريقة التي تُقيَّد بها بحد المعدل فوق انقطاعك، وأسطول يعيد الاتصال بالتزامن يزيد الأمر سوءًا.
  • أعد مزامنة الحالة بعد إعادة الاتصال. فاتتك تحديثات أثناء غيابك. اعتبر initial_dump الجديد هو الحقيقة وتخلّص من دفترك السابق، بدلًا من دمج التحديثات التدريجية في لقطة متقادمة.
  • طابق المراكز بعد أي فجوة. إذا انقطعت عن قناة User، فربما فاتك تنفيذ. أعد قراءة المراكز قبل التصرف بناءً على حالة مفترضة.

WebSockets وحدود المعدل

سؤال متكرر، وإجابته هي الغاية من التمرين كله: الاشتراك لا يستهلك ميزانية حد المعدل لكل طلب كما يفعل الاستطلاع. حدود Polymarket الموثقة هي حدود HTTP لكل نقطة نهاية، والبث يتجاوزها بالكامل تقريبًا.

النهجتكلفة تتبع 20 سوقًا لمدة ساعة
استطلاع /book كل ثانية72,000 طلب من ميزانية 1,500 طلب/10ث
استطلاع /books (مجمّع) كل ثانية3,600 طلب من ميزانية 500 طلب/10ث
اشتراك WebSocketاتصال واحد، بالإضافة إلى 360 نبضة
يمنحك الاستطلاع أيضًا إجابة أسوأ: ترى الدفتر كما كان عند آخر استطلاع، لا كما كان عند آخر تغيير.

ستظل تجري استدعاءات HTTP — لاكتشاف الأسواق، وأحجام التيك، وتقديم الأوامر، ومطابقة المراكز — وتبقى خاضعة لـ حدود المعدل الموثقة. البث يزيل فقط أكبر مصادر حجم الطلبات وأقلها فائدة.

زمن الاستجابة هو الإبطاء متنكرًا

لأن طبقة Cloudflare تُبطئ بالتأخير بدلًا من الرفض، فإن بوت الاستطلاع المتجاوز للحد لا يرى 429 — بل يرى أزمنة استجابته ترتفع بهدوء. إذا انجرفت بيانات دفترك من 40ms إلى 3 ثوانٍ، فأنت لا تواجه انقطاعًا؛ بل تواجه معدل طلباتك أنت.

ما لن تمنحك إياه التدفقات

حد يستحق التصريح به بوضوح، لأنه الشيء الذي يحاوله الناس بعد ذلك. يمنحك WebSocket الدفتر من لحظة اشتراكك. ولا يمكنه أن يمنحك الدفتر يوم الثلاثاء الماضي.

لا تحتفظ Polymarket بأي دفتر أوامر تاريخي. بمجرد حسم السوق، يُرجع دفتره 404، ولا تحتفظ prices-history إلا بنقطة واحدة تقريبًا في الدقيقة. إذا أردت اختبار استراتيجية مقابل الطريقة التي تداولت بها الأسواق فعلًا، فأنت تحتاج إلى لقطات سجّلها أحدهم في حينها. تفعل PolyTest ذلك لأسواق Up/Down للعملات المشفرة، مع 8 مستويات من العمق لكل جانب والاحتفاظ بالأسواق المحسومة. أو ابدأ أداة الجمع الخاصة بك اليوم، وتقبّل أنك تبدأ بلا أي سجل، وانتظر.

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

ما عنوان URL لـ WebSocket في Polymarket؟
قناة السوق العامة هي wss://ws-subscriptions-clob.polymarket.com/ws/market وقناة المستخدم المصادَق عليها هي wss://ws-subscriptions-clob.polymarket.com/ws/user. وهناك أيضًا تدفقان آخران: RTDS على wss://ws-live-data.polymarket.com للأسعار المرجعية والتعليقات ونشاط التداول، وتغذية رياضية على wss://sports-api.polymarket.com/ws.
هل يوجد حد معدل على WebSocket في Polymarket؟
اشتراك WebSocket لا يستهلك ميزانية حد المعدل لكل طلب كما يفعل استطلاع HTTP — فحدود Polymarket الموثقة هي حدود HTTP لكل نقطة نهاية. والبث هو تحديدًا الطريقة الموصى بها لتجنبها. الاشتراط الملزم على الاتصال هو النبضة: أرسل PING كل 10 ثوانٍ وإلا يُقطع الاتصال. واستدعاءات HTTP التي لا تزال تجريها للاكتشاف وأحجام التيك وتقديم الأوامر تبقى خاضعة للحدود العادية.
كيف أبقي اتصال WebSocket مع Polymarket حيًا؟
أرسل رسالة PING كل 10 ثوانٍ؛ ويرد الخادم بـ PONG. هذه نبضة على مستوى التطبيق من جانب العميل، لذا فآلية keepalive المدمجة في مكتبة WebSocket بفاصل زمني مختلف ليست بديلًا. وتتبّع أيضًا عمر آخر رسالة مستلمة — فالاتصال المنقطع يتوقف عن توصيل البيانات دون إطلاق خطأ، لذا تعامل مع نحو 30 ثانية من الصمت في سوق نشط كانقطاع لا كسوق هادئ.
لماذا لا أتلقى أحداث best_bid_ask أو market_resolved؟
هذه الأحداث معطّلة افتراضيًا. اضبط custom_feature_enabled على true في رسالة اشتراكك لتفعيل best_bid_ask وnew_market وmarket_resolved. لا يوجد خطأ أو تحذير عند غياب العلَم — ببساطة لا تصل الأحداث أبدًا، ومن السهل الخلط بين ذلك وسوق غير نشط.
هل يجب أن يستخدم بوتي على Polymarket WebSockets أم يستطلع REST API؟
استخدم WebSockets لبيانات الدفتر والأسعار المباشرة. تتبع 20 سوقًا باستطلاع /book مرة كل ثانية يكلف 72,000 طلب في الساعة من ميزانية 1,500 طلب/10ث، بينما يكلف الاشتراك اتصالًا واحدًا بالإضافة إلى النبضات — كما أن الاستطلاع يُرجع إجابة أكثر تقادمًا، إذ ترى الدفتر كما كان عند آخر استطلاع لا عند آخر تغيير. احتفظ بـ REST لاكتشاف الأسواق وأحجام التيك وتقديم الأوامر ومطابقة المراكز.
هل يمكنني تغيير الأسواق التي أشترك فيها دون إعادة الاتصال؟
نعم. تدعم قناة السوق الاشتراك في الأصول وإلغاء الاشتراك فيها على اتصال حي، وهذا مهم للأسواق قصيرة العمر مثل عقود Up/Down لمدة 5 دقائق التي تتبدل باستمرار. إعادة الاتصال عند كل تدوير تدفع تكلفة إعداد الاتصال مرارًا وتترك فجوة في التغطية في اللحظة نفسها التي يُفتتح فيها سوق جديد.

احصل على البيانات التاريخية التي لا تحتفظ بها Polymarket

يسجّل PolyTest أسواق Up/Down للعملات المشفرة على Polymarket أثناء تشغيلها — 240M+ لقطة مع 8 مستويات من عمق دفتر الأوامر، وطوابع زمنية بدقة أقل من الثانية، مع الاحتفاظ بالأسواق المحسومة. ابدأ بفترة تجريبية مجانية لمدة 3 أيام.

تابع القراءة