دليل بوت بوليماركت · الفصل 32 من 32

أخطاء حقيقية في بوت بوليماركت وتقارير ما بعد الحادث: التنفيذات الوهمية، وإزالة التكرار عند الفشل اللاصق، وحادثة whipsaw في lol-ctg-ccg، وخطأ NegRisk flag، والإطلاق المبكر - مع commits والتواريخ التي أصلحت كل مشكلة.

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

يومياتنا الإنتاجية الخاصة بالأخطاء التي كلّفتنا أموالًا حقيقية. النمط أهم من التفاصيل - فالفئات نفسها من الأخطاء تتكرر عبر البوتات، والعلاج غالبًا يكون مراقِبًا مفقودًا، لا استراتيجية أفضل. الهدف من هذا الفصل أن يوفر عليك الرسوم الدراسية.

  • التنفيذات الوهمية (commits e68a087، 8bb7761)
  • خطأ NegRisk flag (commit)
  • إزالة التكرار عند الفشل اللاصق (commit)
  • حادثة whipsaw: lol-ctg-ccg
  • الإطلاق المبكر: محو 2025
  • الاستغراق في النوم فوق خلل برمجي: مفتاح إيقاف عمل
  • دروس قابلة للتعميم

التنفيذات الوهمية (commits e68a087، 8bb7761)

أول حادثة كبيرة للتنفيذات الوهمية في المتداول الخاص بنا، في مايو 2025. وضع بوت عدد 22 من أوامر الشراء من نوع FOK، وتمت مطابقتها كلها على CLOB. بعد ذلك مباشرة حاول بوت إرسال 22 أمر بيع من نوع GTC. تم رفض 8 منها برسالة "balance: 0 / sum of active orders: 0 / order amount: 10000000."

السبب الجذري: تأخر التسوية (الفصل 12). تمّت مطابقة CLOB خلال 100ms، وأرسل بوت أمر البيع بعد 200ms، لكن نقل Polygon ERC-1155 استغرق نحو ثانيتين. رفض CLOB أمر البيع لأن السلسلة ما زالت تُظهر رصيدًا صفريًا.

الإصلاح: إدخال انتظار حاجز لمدة 5 ثوانٍ بين أي شراء ناجح وأي متابعة من نوع GTC على الرمز نفسه. commits e68a087 و8bb7761. لا توجد أي حوادث للتنفيذات الوهمية منذ ذلك الحين.

الدرس: وقت API ووقت السلسلة ليسا نفس الجدول الزمني. الكود الذي يفترض أنهما متزامنان سيصطدم بنمط الفشل هذا تحديدًا.

خطأ NegRisk flag (commit)

كان هناك حدث متعدد النتائج من نوع NegRisk يضم 8 مرشحين، وظهرت فيه فرصة مراجحة لحظية بمقدار 1.8c (مجموع أسعار الطلب على YES = 0.982). أطلق بوت المراجحة لدينا جميع أوامر الشراء الثمانية من نوع FOK. تم تنفيذ 6 منها؛ بينما استقرّ 2 في عقد منصة تداول خاطئ.

السبب الجذري: كان بوت يستدعي createAndPostOrder دون تعيين negRisk: true داخل كائن flags. كان لدى اثنين من الأسواق تاريخ إنشاء مختلف ويتطلبان هذه الراية؛ أما الأسواق الستة الأخرى فلم تكن بحاجة إليه لأن العقد الأساسي لديها كان يمر عبر NegRisk افتراضيًا أصلًا.

الإصلاح: قراءة market.negRisk من Gamma لكل سوق، وتمريره إلى كل استدعاء أوامر. commit. أعدنا تشغيل المراجحة مع تعيين الراية؛ وتمت تسوية السوقين المتبقيين بشكل صحيح.

الدرس: لا تجعل خاصية السوق افتراضية أبدًا. اقرأها صراحةً من مصدر الحقيقة في كل مرة.

إزالة التكرار عند الفشل اللاصق (commit)

أعاد بوت محاولة شراء فاشلة 5 مرات خلال 12 ثانية. المحاولة الأولى نجحت فعليًا (انقطاع الشبكة المؤقت جعل بوت لا يرى الاستجابة)؛ أما المحاولات الأربع التالية فقد أنشأت 4 مراكز إضافية. المحصلة: 5 مراكز في السوق نفسه بينما كنا نريد مركزًا واحدًا.

السبب الجذري: عدم وجود client-order-id قابل للتكرار. كان منطق إعادة المحاولة لدى بوت يقول: "إذا فشلت، جرّب مرة أخرى مع salt جديد." لم يكن لدى CLOB أي طريقة للتعرف على المحاولات المتكررة باعتبارها نسخًا مكررة.

الإصلاح: توليد UUID حتمي لكل أمر مقصود قبل المحاولة الأولى. جميع محاولات الإعادة تستخدم client-order-id نفسه، ما يسمح لـ CLOB بإجراء dedup. commit.

الدرس: إعادة المحاولة دون idempotence تعني أوامر مكررة. كل أمر يحتاج إلى معرّف ثابت على جانب العميل.

حادثة التذبذب: lol-ctg-ccg

مباراة رياضات إلكترونية (CTG vs CCG) دفعت بوت إلى الدخول في شراء عند 0.45 عندما أصبح الاختلال إيجابيًا. خلال 30 ثانية، انقلب الاختلال إلى سلبي، وتم ضرب أمر البيع GTC عند 0.50 بواسطة أمر من طرف آخر. الأرباح والخسائر: +5c × 10 أسهم = +$0.50.

بعد 10 دقائق، انقلب الاختلال في السوق نفسه إلى إيجابي مرة أخرى. دخل بوت مرة أخرى عند 0.42. هذه المرة لم يتعافَ الاختلال أبدًا؛ وانجرف السعر الأوسط إلى 0.18، ثم سارت الصفقة إلى التسوية النهائية عند 0.

السبب الجذري: كانت الاستراتيجية تتعامل مع الاختلال كإشارة اتجاهية لكنها لم تتابع أن الاختلال كان يتأرجح - كانت الإشارتان كلتاهما ضجيجًا، لا معلومات. تعرّض بوت للتذبذب عبر إشارتين فاشلتين في السوق نفسه خلال 20 دقيقة.

الإصلاح: فترة تهدئة لكل سوق - بعد أي تنفيذ، لا توجد أي دخولات جديدة في السوق نفسه لمدة 30 دقيقة. سُمح بعدة دخولات عبر أسواق مختلفة، لكن ليس بشكل متتالٍ في السوق نفسه.

الدرس: الإشارة التي تتأرجح ليست إشارة. صفِّها من أجل الاستمرارية قبل التصرف.

الإطلاق المبكر: محو 2025

استراتيجية صناعة السوق جديدة اجتازت 12 صفقة ورقية. لم ينتظر الباني حتى 30، وقرر أن "الوضع يبدو جيدًا"، ثم نشرها مباشرة برأس مال قدره $500. خلال 18 ساعة أصبحت المحفظة عند $200.

السبب الجذري: 12 صفقة ليست عينة كافية للتمييز بين معدل فوز 60% ومعدل فوز 35%. كانت الاستراتيجية في الواقع عند معدل فوز 35%؛ وكانت نافذة الصفقات الورقية الـ 12 مجرد سلسلة غير ممثلة للواقع.

بوابة الـ 30 صفقة موجودة لسبب. التباين في عينة من 12 صفقة يجعلها غير قابلة للتمييز عن "الاستراتيجية لا تعمل".

الدرس: الانضباط يتفوق على الاقتناع. بوابة الـ 30 صفقة ليست قابلة للتفاوض.

النوم أثناء الخطأ: مفتاح الإيقاف عمل

كان لدى بوت خطأ off-by-one في فلتر وقت اليوم - كان من المفترض أن يتوقف عند 02:00 UTC، لكنه كان يتوقف فعليًا عند 03:00 UTC. خلال الساعة غير المتوقفة 02:00-03:00، كان Polygon RPC يفرض تقييدًا صارمًا للمعدل على طلباتنا؛ وكانت مسار القراءة لدى بوت يعيد بيانات قديمة.

واصل بوت التداول بناءً على أسعار قديمة. الأرباح والخسائر خلال الساعة: -$3.20 عبر 22 صفقة. تم تشغيل مفتاح الإيقاف الخاص بالخسارة اليومية عند -5%، وأوقف البوت، وأرسل تنبيه Telegram عند 03:08 UTC. استيقظ الباني على بوت متوقف عند 09:00، وكان إجمالي الضرر محدودًا بحدّ الإيقاف.

الدرس: كان خللًا حقيقيًا لكن مفتاح الإيقاف عمل. -$3.20 بدلًا من -$50.00. ضوابط المخاطر لا تمنع الأخطاء؛ إنها تحدّ من تكلفة الأخطاء التي لم تتوقعها.

دروس قابلة للتعميم

عبر جميع تقارير ما بعد الحوادث، تتكرر أربعة أنماط.

  1. وقت API ≠ وقت السلسلة. تأخر التسوية، وتأخر RPC، وتأخر WebSocket - كلها تُدخل فجوات يجب على كود بوت التعامل معها صراحةً.
  2. الإعادة تحتاج إلى idempotence. أي إعادة محاولة بدون client-order-id هو خطر أوامر مكررة. دائمًا.
  3. اقرأ كل خاصية للسوق بشكل صريح. راية NegRisk، وحجم tick، والانتهاء. لا تجعل شيئًا افتراضيًا أبدًا؛ اقرأ دائمًا من مصدر الحقيقة.
  4. مفتاح الإيقاف هو الحد الأدنى، وليس ميزة. ضوابط المخاطر تحدّ من الخسائر الناتجة عن الأخطاء. الاستراتيجيات لا تمنع الأخطاء؛ إنها تفترض أن بوت يعمل بشكل صحيح. ولن يعمل بوت بشكل صحيح دائمًا.

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

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

ما هو أغلى خطأ يمكن أن يرتكبه بوت بوليماركت؟
الإطلاق المبكر قبل أن يصل التداول الورقي إلى بوابة الـ 30 صفقة. لقد فعلنا ذلك. الخطأ ليس مجرد خسارة المال - بل خسارة فرصة التعلّم من الاستراتيجية في بيئة مضبوطة. البوتات التي تُطلق مبكرًا جدًا إما تتعرض للإبادة ويُتخلّى عنها، أو تهدر أشهرًا في التعافي قبل العودة إلى التداول الورقي.
ما هو خلل التنفيذ الوهمي (phantom fill)؟
عندما يعتقد البوت أن أمرًا تم تنفيذه بينما سجّلته المنصة على أنه لم يُنفذ بعد. الأعراض: يظهر المركز في حالة بوتك لكن ليس على السلسلة، ما يؤدي إلى أوامر مزدوجة عند إعادة المحاولة. تم إصلاحه في متداولنا الخاص عبر ثلاثة commits (e68a087، 8bb7761، 06deaef): استخدم FOK للشراء، واستعلم عن الحالة حتى تتم المطابقة، ولا تثق أبدًا في status=delayed باعتباره تنفيذًا.
ما هي حادثة التذبذب lol-ctg-ccg؟
سوق رياضات إلكترونية على دفتر أوامر رقيق حيث أطلق متداولنا وقف خسارة بقيمة -$2.55 عند 0.14، ثم شاهد السعر يتعافى إلى 0.325 خلال دقيقتين. كنا قد ضبطنا وقف الخسارة عند -4 نقاط مئوية، وهو ضيق جدًا لدفاتر الرياضات الإلكترونية الرقيقة. الإصلاح: توسيع وقف الخسارة إلى -8 نقاط مئوية للأسواق منخفضة السيولة، مع الإبقاء على وقف خسارة أضيق فقط للدفاتر السميكة (NBA، كرة القدم عالية السيولة). راجع memory/trader-sl-wider.md.
كيف ظهر خطأ NegRisk flag؟
وضع بوت أوامر دون تعيين neg_risk=true في الأسواق متعددة النتائج. تم رفض الأوامر برسائل خطأ مربكة، ما أدى إلى تأخيرات لعدة ثوانٍ قبل إعادة المحاولة، وبالتالي فوات تنفيذات. تم الإصلاح في commit: عيّن دائمًا neg_risk وفق البيانات الوصفية الخاصة بالسوق، ولا تفترض أبدًا.
ما هي حادثة sleep-through-bug؟
علق المحفظة بسبب أمر عالق عند الساعة 4 صباحًا. وجّه المالك بوت إلى التوقف؛ ولامس ملف data/halt_autobuy. اكتشف بوت الملف قبل محاولة التداول التالية ورفض تنفيذ أوامر جديدة. استيقظ المالك على حالة نظيفة بدلًا من حالة أسوأ. تم التحقق من نمط حارس الإيقاف (halt-sentinel)؛ ونحن نُضمّنه الآن افتراضيًا في كل بوت.
ما هو الدرس الأكثر قابلية للتعميم من هذه التقارير؟
لا تثق أبدًا بالمسار السلس. كل خلل شحنّاه جاء من افتراض أن الطلب نجح، أو أن التنفيذ حقيقي، أو أن السعر لن يتحرك. اكتب الكود دفاعيًا: افترض أن الأوامر تفشل، وافترض أن التسويات تتباعد، وافترض أن سوقًا واحدًا على وشك أن يفعل شيئًا غريبًا. ضريبة الشك صغيرة؛ أما تكلفة تجاهلها فهي تقرير ما بعد الحادث الذي ستكتبه لاحقًا.