المقالات

وقت MetaTrader يبدو بتوقيت UTC. لكنه ساعة الوسيط.

مدة القراءة: 6 دقيقة

إذا سحبت الشموع من MetaTrader 5 في Python، فسيبدو عمود time كطابع زمني من Unix. لكنه ليس كذلك. إنه ساعة خادم الوسيط، مكتوبةً كثوانٍ منذ عام 1970 على تلك الساعة. مرّره إلى pd.to_datetime(unit="s") وستقع شموعك على بُعد ساعتين أو ثلاث من موعدها الحقيقي.

يبدأ الالتباس من التوثيق. تقول الصفحة الرسمية لـ copy_rates_from إن البيانات التي تعيدها الطرفية بتوقيت UTC (توثيق MQL5 (موقع خارجي)). وفي نقاش على المنتدى عام 2021 بعنوان «python api does not return UTC times»، وافق أحد المشرفين على أن توثيق Python يتعارض مع توثيق MQL5، وقال إن الأوقات بتوقيت خادم الوسيط (منتدى MQL5، 2021 (موقع خارجي)). وعاد السؤال في أكتوبر 2026، مع أوقات تيكات خام قيست متقدمةً على UTC بنحو 10799 ثانية، وجاء الجواب نفسه من أحد المشرفين (منتدى MQL5، 2026 (موقع خارجي)).

نشرت مكتبة Python صغيرة لهذا الغرض، هي brokerclock (موقع خارجي). وقبل الواجهة البرمجية، إليك لماذا لا يصمد الإصلاح المعتاد ذو السطر الواحد.

الساعة التي لا تراها

يضبط كثير من وسطاء الفوركس خوادمهم بحيث يحل منتصف الليل عند الساعة 17:00 في نيويورك، وهو الموعد المتعارف عليه لنهاية يوم تداول الفوركس. وهذا يضعهم على GMT+2 في شتاء نيويورك وGMT+3 في صيفها، فينتقلون بين التوقيتين في مواعيد التوقيت الصيفي الأمريكية لا الأوروبية (شرح توقيت خادم الوسيط (موقع خارجي)).

لا تملك حزمة Python الخاصة بـ MetaTrader أي استدعاء يعيد إزاحة الوسيط أو القاعدة التي تقف خلفها. لذا يكتب الناس إزاحةً ثابتة في الكود.

إزاحة +3 الثابتة خاطئة طوال الشتاء. وإزاحة +2 الثابتة خاطئة طوال الصيف. أما قاعدة التوقيت الصيفي الأوروبية فتبدو صحيحة معظم العام، ثم تنكسر مرتين لأن الولايات المتحدة وأوروبا تغيّران ساعاتهما في يومَي أحد مختلفين: نحو ثلاثة أسابيع في مارس، بعد انتقال الولايات المتحدة وقبل انتقال أوروبا، وأسبوعًا واحدًا قرابة بداية نوفمبر. في عام 2025 انتقلت الولايات المتحدة في 9 مارس وأوروبا في 30 مارس. كل شمعة في تلك الفترة مزاحة بساعة، ولا يظهر أي خطأ.

وتمتد المشكلة إلى الاتجاه الآخر أيضًا. فوسائط التاريخ في copy_rates_range وcopy_ticks_range، وقيمة expiration للأمر، تُقرأ بتوقيت الخادم. وكائن datetime الذي لا يحمل منطقة زمنية يمر في طريقه عبر المنطقة الزمنية المحلية للحاسوب، فتدخل ساعة ثالثة على المشكلة.

الساعة قاعدة لا رقم

الحل هو التوقف عن تخزين إزاحة وتخزين القاعدة بدلًا منها. تمثّل brokerclock ساعة الخادم كمنطقة زمنية من IANA مع إزاحة. وساعة الوسيط المعتادة، أي GMT+2/+3 بالمواعيد الأمريكية، هي ساعة نيويورك مضافًا إليها سبع ساعات:

from brokerclock import ServerZone

zone = ServerZone.us()    # GMT+2/+3 (US daylight saving)
zone.to_utc(1751371200)   # 2025-07-01 12:00 on the server clock
# datetime(2025, 7, 1, 9, 0, tzinfo=timezone.utc)

يسأل كل تحويل قاعدة بيانات المناطق الزمنية عن الإزاحة السارية في تلك اللحظة، فتخرج فجوة مارس وأسبوع نوفمبر صحيحتين من دون حالات خاصة. وتغطي ServerZone.eu() وServerZone.au() وServerZone.fixed(0) الإعدادات الشائعة الأخرى. وأي ساعة أخرى هي مفتاح من IANA مع إزاحة بخطوات من 15 دقيقة.

الساعة التي تتكرر عند انتهاء التوقيت الصيفي غموض حقيقي، لذا تطلق to_utc الخطأ AmbiguousTimeError ما لم تمرر ambiguous="earlier" أو "later". والساعة التي تُحذف في الربيع تطلق NonexistentTimeError. أفضّل أن أحصل على استثناء بدلًا من شمعة تنتقل بصمت.

استنتاج القاعدة من تاريخ الأسعار

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

ينتهي أسبوع الفوركس يوم الجمعة الساعة 17:00 بتوقيت نيويورك. وفي تاريخ الشموع يكون ذلك الإغلاق آخر شمعة قبل فجوة من 40 ساعة أو أكثر. ووقت نهايتها على ساعة الخادم، مقارنةً بالساعة 17:00 الحقيقية من يوم الجمعة، يعطي إزاحة الخادم في ذلك الأسبوع. وعام من الإغلاقات الأسبوعية هو عام من الإزاحات. وكل ساعة مرشحة (ثابتة، أو بتوقيت صيفي أمريكي أو أوروبي أو أسترالي عند أي إزاحة أساسية) تتنبأ ببعضها، وتفوز الساعة الأدق تنبؤًا.

import MetaTrader5 as mt5
import brokerclock

mt5.initialize()
rates = mt5.copy_rates_from_pos("EURUSD", mt5.TIMEFRAME_H1, 0, 6500)
result = brokerclock.detect(rates["time"], timeframe=3600)
print(result.zone)  # GMT+2/+3 (US daylight saving)
print(f"{result.matched} of {result.total} weeks agree")

تعيد detect أدلتها مع الجواب. فالأسابيع التي لا تطابق الساعة الفائزة، وهي غالبًا إغلاقات مبكرة في العطل، تعود في outliers. وحين لا تستطيع البيانات التمييز بين ساعتين، مثل شموع الصيف وحده حيث تتفق القاعدتان الأمريكية والأوروبية، تكون zone بقيمة None وتسرد candidates الساعات المتعادلة. هذا هو الجواب الصادق، والحل مدى أطول من البيانات.

يغلق الوسطاء عند الساعة 17:00 أو قبلها، لا بعدها، لذا تُقرَّب كل إزاحة أسبوعية صعودًا إلى الدقائق الخمس عشرة التالية. وشموع H1 هي المدخل الأكثر أمانًا، لأن آخر شمعة H1 في الأسبوع ما زالت تنتهي عند 17:00.

التحقق منها مقابل التيكات الحية

التاريخ يخبرك بالقاعدة. والتيك الحي يخبرك هل ما زالت صحيحة اليوم:

tick = mt5.symbol_info_tick("EURUSD")
brokerclock.check(zone, [tick.time_msc / 1000])

تحوّل check التيك وفق المنطقة وتقارنه بساعة الحاسوب. التيك القادم من المستقبل يطلق ZoneMismatchError. والتيك الحديث الموافق يعيد True. والتيك القديم يعيد False، لأن السوق المغلق لا يستطيع تأكيد أي شيء. ومن دون منطقة تعيد measure_offset الإزاحة الحالية، وتطلق StaleTickError بدل التخمين حين يكون التيك قديمًا.

أعمدة كاملة، وطريق العودة

مع إضافة pandas تأخذ frame_to_utc المصفوفة المهيكلة من copy_rates_* وتعيد DataFrame يكون عمود time فيه بتوقيت UTC صريح. وللاستعلامات وأوقات الانتهاء تحوّل zone.server_timestamp(instant) قيمة datetime بتوقيت UTC إلى العدد الصحيح على ساعة الخادم الذي ينتظره MetaTrader، وهذا يُبقي المنطقة الزمنية للحاسوب خارج الطلب أيضًا.

pip install "brokerclock[pandas]"

لا تستورد المكتبة MetaTrader5 أبدًا. ولا تحتاج إلا المكتبة القياسية، مع tzdata على Windows، لذا تعمل وتُختبر على Linux وmacOS حيث لا تُثبَّت حزمة الطرفية. وتضم مجموعة الاختبارات 260 اختبارًا على Python من 3.10 حتى 3.14.

طرق أخرى

عولجت هذه المشكلة داخل MQL5 من قبل. فمكتبة TimeGMT التي كتبها عمرو علي تقدّر إزاحة الخادم من أول شمعة H1 بعد كل عطلة نهاية أسبوع، وغرضها الأساسي إصلاح TimeGMT() في مختبر الاستراتيجيات (TimeGMT (موقع خارجي)). ومقالة Kabelo Frans Mampa تستنتج جدول التوقيت الصيفي من تقلبات Non-Farm Payrolls في شموع M15، ولا يمكنها العمل في مختبر الاستراتيجيات لأن التقويم الاقتصادي لا يعيد بيانات هناك (Monochronic Trading، الجزء 1 (موقع خارجي)).

كلتاهما تعمل داخل الطرفية. أما brokerclock فتجيب عن السؤال نفسه في Python، وتعيد القاعدة نفسها كي تتحول الأوقات المستقبلية أيضًا، وتتعامل مع طريق العودة إلى MetaTrader.

ما لا تحلّه

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

إذا كنت تخزّن بيانات MT5 بالفعل، فأول ما أتحقق منه أسبوع واحد: أواخر مارس. طابق شموعك مع مصدر آخر. فإن كانت مزاحة بساعة، فقد حُفظت الإزاحة كرقم حين كان يلزم أن تكون قاعدة.

المصادر

مشاركة المقال