ينبغي أن يتكوّن سجل أشرطة مدة كل منها 1 دقيقة لعام تقويمي من 525,600 صف. لكن سجلنا لعام 2025 لعقود BTCUSDT الدائمة عاد بـ525,557 صفًا — أي أقل بـ43 دقيقة، بمعدل اكتمال 99.992%. أما عقد عملة بديلة متوسطة القيمة السوقية على المنصة نفسها، وبالسحب نفسه، ومسار الشيفرة نفسه، فعاد ناقصًا 1,247 دقيقة: 99.76%. وكان في سلسلة الدقائق لأسهم أمريكية في العام نفسه نحو 427,000 صف أقل من سلسلة العملات الرقمية، وهذا ليس فجوة أصلًا، بل سوق يغلق أبوابه.
ثلاثة من هذه الأرقام لا تستحق الالتفات. أما الرقم الذي يستحق ألف كلمة فهو 43.
أربعة أمور مختلفة تبدو كلها كأنها فجوة في إطار بياناتك
قبل الحديث عن الـ43 دقيقة، إليك التصنيف، لأن معظم شيفرات معالجة الفجوات تخطئ من هذه المرحلة أصلًا. عندما يغيب صف عن ملف parquet المحلي لديك، لا تعرف أيّ من هذه الأسباب أنتجته، والاستجابة الصحيحة تختلف باختلاف السبب.
| النوع | ما حدث فعلًا | كيف يظهر | التصرف الصحيح |
|---|---|---|---|
| لا توجد صفقات | السوق مفتوح، لكن لم يعبر أحد الفارق السعري خلال تلك الدقيقة | شمعة بحجم تداول صفري (قيم OHLC متساوية، trades=0) في بعض نقاط النهاية، وصف غائب في نقاط أخرى | أبقِه. إنه معلومة حقيقية: لم يرغب أحد في التداول. |
| تعطّل جهة التداول | محرك المطابقة متوقف عن العمل، سواء كان ذلك مجدولًا أم لا | صف غائب، وأحيانًا سلسلة من الصفوف الغائبة | علّمه على أنه قديم. لا تتداول عبره. |
| إيقاف الأداة المالية | تجاوز نطاق LULD، أو انتظار أخبار، أو إشعار بالشطب | صف غائب تتبعه صفقة مزاد إعادة الافتتاح | علّمه على أنه قديم، وتعامل مع إعادة الافتتاح بوصفها انقطاعًا. |
| خطأ من جانبك | ترقيم صفحات مقيّد بمعدل الطلبات، أو إعادة محاولة أسقطت صفحة، أو خطأ في حدود المنطقة الزمنية ضمن الحلقة | صف غائب لا يمكن تمييزه عن الحالات السابقة | اكتشفه وأعد جلب البيانات. هذا هو السبب الوحيد الذي يمكنك إصلاحه. |
تختلف جهات التداول بشأن الصف الأول في ذلك الجدول، وهو موضع المشكلة. فواجهة الشموع البرمجية لدى Coinbase تتجاوز الفترات الخالية تمامًا، لذا يمتلئ السجل التاريخي لزوج قليل السيولة بفجوات فعلية. أما klines لدى Binance فعادةً ما تعيد شمعة اصطناعية بحجم 0، تكون فيها قيم open=high=low=close مثبتة عند آخر صفقة. الحقيقة واحدة، لكن شكلها يختلف، وأداة تحميل تعيد الفهرسة على شبكة كاملة من الدقائق تحوّل أحد الشكلين إلى الآخر دون أن تخبرك. تحقّق مما تفعله جهة التداول قبل كتابة أداة ملء الفجوات، لا بعدها.
كانت الدقائق الـ1,247 المفقودة في العملة البديلة في معظمها من الفئة الأولى: دفتر أوامر ضعيف عند 04:00 UTC يوم الأحد، ولم يتداول أحد. أمر مزعج يسهل فهمه، وغير مؤذٍ إلى حد كبير لأن الاستراتيجية لم تكن لتتداول حينها على أي حال. وهذا بالضبط ما جعلني أتوقف عن النظر إليه وأعود إلى الـ43 دقيقة المفقودة.
الدقائق الـ43 لم تكن متناثرة
لو كان الفقدان موزعًا بالتساوي، لظهرت 43 دقيقة مفقودة على امتداد العام في صورة 43 حالة منفردة، بمعدل دقيقة كل ثمانية أيام ونصف، وكل منها خطأ تقريب بسيط. لكن هذا ليس ما وجدناه. جاءت على شكل ست فترات متصلة: واحدة من 19 دقيقة متتالية، وأخرى من 11، واثنتان من 4 دقائق، وزوجان من الدقائق. ستة أحداث، لا 43 حادثة منفصلة.
كما أن هذه الأحداث ترتبط بالشيء الذي يهمك. تتعطل المنصات عندما تكون تحت ضغط، وتكون تحت الضغط عندما تتحرك الأسعار. صنّفت كل ساعة من العام بحسب التقلب المحقق، ثم تحققت من مواضع الدقائق المفقودة: وقعت 61% منها ضمن أعلى 10% من الساعات تقلبًا. احتمال فقدان دقيقة معينة دون أي شروط هو 0.008%. أما إذا وقعت ضمن ساعة من أعلى 10% في التقلب، فيبلغ نحو 0.05% — أي أعلى بست مرات، وفوق ذلك تتجمع الدقائق المفقودة في فترات متقاربة.
لذلك، فإن مقياس الاكتمال في لوحة جودة بياناتك يقيس الشيء الخطأ. توحي نسبة 99.992% بأن مجموعة البيانات لا تستدعي مزيدًا من التفكير. لكنها في الواقع تصف سلسلة مكتملة خلال الساعات التي لا تفعل فيها استراتيجيتك شيئًا، ومثقوبة خلال الساعات التي تفعل فيها كل شيء. ترتفع احتمالية أن تصطدم استراتيجية زخم تطلق إشارة عند اتساع التقلب بفجوةٍ كثيرًا عمّا يوحي به الرقم العام، وتصطدم بها في منتصف الصفقة.
ما يفعله الملء بالقيمة السابقة بعد ثلاثة أسطر
إليك الخلل الذي دفعني إلى كتابة هذا المقال. لنأخذ الفترة المتصلة ذات الـ19 دقيقة. النظافة المعتادة للبيانات: أعد الفهرسة على شبكة الدقائق كاملة، واملأ قيم OHLC بآخر سعر إغلاق، واضبط الحجم على صفر. أصبحت السلسلة متصلة الآن، وتعمل مؤشراتك من دون ظهور أي NaN.
تتساوى قيم high وlow وclose في تلك الأشرطة الـ19. ويبلغ النطاق الحقيقي صفرًا
في كل واحد منها. ينخفض ATR(14) المحسوب على تلك النافذة، بعد قراءة سابقة
للانقطاع تقارب 240 USDT، إلى نحو 34 عند عودة المنصة — إذ تستند القيمة المتوسطة
بأكملها إلى الأشرطة الحقيقية الخمسة الباقية في النافذة. أدخل هذه القيمة الآن
في محدد حجم مراكز يضبط الحجم بحسب التقلب، من النوع المعتاد
size = risk_budget / ATR. يصبح حجم المركز سبعة أمثال حجمه السابق.
أول تداول عند إعادة الافتتاح هو الشمعة الحقيقية التالية، وهي ليست شمعة هادئة. في حالتنا، افتتحت على بُعد 1.8% من سعر الإغلاق الأخير قبل الانقطاع. اتخذ الاختبار التاريخي بكل سرور مركزًا بحجم 7x وسط فجوة قدرها 1.8%، بتنفيذ لم يكن ممكنًا وبسعر لم يعرضه أحد. وكانت قيمة تلك الصفقة الاصطناعية وحدها أكبر من عائد شهر كامل من التداول المشروع في منحنى رأس المال، وباتجاه خاطئ — وقد نشأت بالكامل من سطر لتنظيف البيانات كُتب لترتيب إطار البيانات.
وحذف الصفوف بدلًا من ملئها ليس حلًا أيضًا؛ إنه الخلل نفسه متخفيًا بشكل آخر. عند حذفها، تصبح نوافذ الاسترجاع المفهرسة بأعداد صحيحة مضللة: يمتد «EMA من 20 شريطًا» الآن على 39 دقيقة فعلية عبر فترة الانقطاع، ويُعامل عائد الانتقال بين الشريطين على جانبي الحد الفاصل قفزة الـ1.8% كاملةً كأنها حركة في دقيقة واحدة، كما يقرأ أي تقدير للتقلب لكل شريط تلك الحركة على أنها حدث بقوة 60 سيغما. لا شيء ينبهك. وما زال الفهرس تصاعديًا.
إعادة أخذ العينات هي المرحلة التي تختفي فيها المشكلة
لا تجري معظم الأبحاث على شموع مدتها 1 دقيقة، بل على شموع مجمّعة، وتُخفي عملية التجميع المشكلة. عند إعادة أخذ العينات بفواصل 5 دقائق، تتحول الفجوة ذات الـ19 دقيقة إلى أربع شموع، أولها وآخرها جزئيان. وسيحسب Pandas قيم OHLC تبدو معقولة تمامًا من دقيقتين سليمتين، ويضع عليها التسمية نفسها التي يضعها على شمعة بُنيت من خمس دقائق. لا شيء في المخرجات يميز بينهما.
أقل الحلول كلفةً مما أعرفه: مرّر عمود bars_in_window عبر كل عملية
لإعادة أخذ العينات، ولا تتخلص منه أبدًا. يكفي عدد صحيح واحد لكل صف كي يصبح
بالإمكان الإجابة عن أي سؤال لاحق حول موثوقية الشريط. ونمرّر أيضًا
seconds_since_last_real_print، وهي المعلومة نفسها بصيغة تستطيع
طبقة التنفيذ استخدامها.
السياسة، على ما هي عليه
ما يطبقه وكلاء الذكاء الاصطناعي لدينا الآن، بالترتيب:
- لا تُعِد الفهرسة بصمت أبدًا. تُصدر أداة التحميل سجلًا بالفجوات — البداية والنهاية والمدة والفئة التي ترجّحها من الفئات الأربع. إذا كانت الفترة المفقودة أقصر من 3 أشرطة وكان حجم التداول في الأشرطة المحيطة ضعيفًا، فهي دقيقة بلا تداول. أما أي فترة أطول خلال ساعات النشاط فتعامل معها على أنها تعطل حتى يثبت العكس.
- أعد جلب البيانات قبل تفسيرها. كان نصف فجواتنا الأولى ناتجًا عن أخطاء في ترقيم الصفحات. ويساعد جلب ثانٍ من واجهة برمجية مختلفة أو مزود بيانات مختلف على حسم ما إذا كانت الفجوة من الفئة الرابعة، ويقلّص المشكلة قبل الحاجة إلى أي حكم.
-
بوابة للتحقق من حداثة البيانات، لا ملء للفجوات. تحصل
الاستراتيجية على مُدخل
data_ageإدخال وقاعدة صارمة: لا دخول جديدًا عندما يكون آخر سعر حقيقي أقدم من N شموع، وتُغلق المراكز المفتوحة عند إعادة الافتتاح فقط بأمر سوق يُسعّر مع خصم صريح لمخاطر الفجوة. التنفيذات التي لم يكن من الممكن أن تحدث أسوأ من الصفقات التي لم تحدث. - المؤشرات ترى NaN، لا بيانات مختلقة. لا تصل الأسعار المملوءة بالقيمة السابقة إلى طبقة السمات. إذا تعذر حساب ATR، فتبقى قيمته غير معرّفة، وغير المعرّف يعني عدم فتح مراكز. الفشل الواضح أفضل من زيادة هادئة للحجم 7 مرات.
- أبلغ عن الأداء المشروط بالفجوات. يعرض كل اختبار تاريخي ننشره الأرباح والخسائر مع استبعاد الصفقات القريبة من الانقطاعات، إلى جانب النتيجة الرئيسية. إذا كانت تلك الصفقات هي ما يحمل النتيجة، فالنتيجة أثر ناتج عن خلل في البيانات.
تدقيق سريع يمكنك إجراؤه اليوم: جمّع دقائقك المفقودة في فترات متصلة، ثم تحقق من نسبة الصفقات في اختبارك التاريخي التي افتُتحت أو أُغلقت خلال 30 دقيقة من حدود تلك الفترات. إذا كانت النسبة أقل من 1%، فالأرجح أن الفجوات لا تؤثر في النتائج. وإذا بلغت 5% أو أكثر، فإن منحنى رأس المال يحكي جزئيًا قصة عن تعطل المنصة.
ما صرت أعتمد عليه هو شكل الفقدان، لا حجمه. عادةً لا بأس بمجموعة بيانات تضم آلاف الفجوات المتناثرة في ساعات الركود. أما المجموعة التي تضم بضع فجوات متقاربة ومتكتلة فتشير إلى أن شيئًا ما يتعطل تحت الضغط، وأن هذا الشيء هو المكان الذي تنشط فيه استراتيجيتك.
→ جميع المقالات


