يجب على المكتب الخلفي لشركة وساطة تُسوّي صفقة بين بلدين أن يختار يومًا يكون فيه البلدان مفتوحين، لذا تُزيح عطل كل عملة التاريخ. يعيد Narwhal العطل الرسمية لكل بلد مع نطاقها ومناطقها الفرعية، ويستطيع سكربت قصير تمرير سجل صفقات كامل على التقويمين وتمييز كل صفقة يختلف تاريخها عن العدّ بأيام الأسبوع فقط.
لماذا تحتاج الصفقة العابرة للحدود إلى تقويمين للعطل
يحتاج المكتب الخلفي لشركة وساطة تُسوّي صفقة USD/JPY إلى يوم يكون فيه البلدان اليابان والولايات المتحدة مفتوحين. يكون العدّ بأيام الأسبوع فقط خاطئًا كلما وقعت عطلة لأي من البلدين داخل المدة، وتعليمات التسوية المنحرفة بيوم واحد تفشل أو تصل متأخرة. تجيب نقاط نهاية العطل عن بلد واحد في كل مرة، لذا يسأل المكتب الخلفي عن كل طرف ثم يدمج النتائج. يسأل هذا الطلب هل لدى اليابان عطلة في 23 نوفمبر 2026.
curl -s -H "Authorization: Bearer $NARWHAL_API_KEY" \
"https://api.narwhalapi.com/v1/calendars/holidays/JPN/on/2026-11-23"{
"country": "JPN",
"coverage": [
{
"scope": "national_public",
"subdivision_codes": []
}
],
"holidays": [
{
"date": "2026-11-23",
"name": "Labor Thanksgiving Day",
"holiday_key": "labor_thanksgiving_day",
"local_name": "勤労感謝の日",
"scope": "national_public",
"subdivision_codes": []
}
]
}الإدخال هو Labor Thanksgiving Day وقيمة scope فيه national_public، وتعني قائمة subdivision_codes الفارغة أنه ينطبق على البلد كله. ويعيد الطلب نفسه للولايات المتحدة في 26 نوفمبر Thanksgiving Day بنطاق federal_government. لكل بلد قائمته ونطاقها الخاص، لذا يسجّل المكتب الخلفي أي قائمة يعتمد عليها. أما العدّ بأيام الأسبوع وحده فيظل يعدّ يوم الاثنين 23 نوفمبر يوم تسوية.
تمرير سجل الصفقات على التقويمين
يُسوّي السكربت كل صفقة في سجل الصفقات وفق بلدي عملتيها، ويعرض التاريخ الذي كان سيعطيه العدّ بأيام الأسبوع فقط بجانب التاريخ الفعلي. وتوسَم الصفقة التي يختلف فيها التاريخان بـ CHECK، وهذه هي القائمة التي يراجعها مسؤول العمليات.
- تحديد بلدي كل طرف تُدرج
JPYاليابان والولايات المتحدة، وتُدرجGBPالمملكة المتحدة مع المنطقة الفرعية لمكتب التداولGB-ENGوالولايات المتحدة. - تحميل كل سنة مرة واحدة تجلب
holidaysقائمة بلد ما لسنة معينة وتحتفظ بها، فيحتاج سجل من مئات الصفقات إلى عدد قليل من الطلبات. وتحمّل الصفقة القريبة من 31 ديسمبر السنة التالية عندما يصل العدّ إليها. - تجاوز عطلات نهاية الأسبوع وإغلاقات أي من البلدين تعيد
closuresالعطل التي تقع في اليوم في أي من البلدان المدرجة، ولا يُحسب اليوم ضمن N إلا حين تكون هذه القائمة فارغة. أما العطلة التي لها قائمة مناطق فرعية فلا تُغلق المكتب إلا إذا كانت منطقته الفرعية ضمن القائمة.import os from datetime import date, timedelta from functools import cache import requests HEADERS = {"Authorization": f"Bearer {os.environ['NARWHAL_API_KEY']}"} @cache def holidays(country, year): r = requests.get( f"https://api.narwhalapi.com/v1/calendars/holidays/{country}/{year}", headers=HEADERS, timeout=10, ) r.raise_for_status() return r.json()["holidays"] def closures(day, places): out = [] for country, region in places.items(): for h in holidays(country, day.year): # an empty subdivision list means the holiday applies nationwide if h["date"] == day.isoformat() and (not h["subdivision_codes"] or region in h["subdivision_codes"]): out.append(f"{country} {h['name']}") return out def settle(trade, n, places): day, held = trade, [] while n > 0: day += timedelta(1) if day.weekday() >= 5: continue shut = closures(day, places) if shut: held.append(f"{day:%d %b} {'; '.join(shut)}") else: n -= 1 return day, held JPY = {"USA": None, "JPN": None} GBP = {"GBR": "GB-ENG", "USA": None} # country -> subdivision of the desk blotter = [ ("USD/JPY", date(2026, 11, 20), 2, JPY), ("USD/JPY", date(2026, 11, 24), 2, JPY), ("GBP/USD", date(2026, 12, 23), 2, GBP), ] for pair, trade, n, places in blotter: day, held = settle(trade, n, places) plain, _ = settle(trade, n, {}) flag = "CHECK" if day != plain else "same" print(f"{pair} {trade} T+{n} settles {day}, weekdays only {plain} [{flag}]", "; ".join(held))
USD/JPY 2026-11-20 T+2 settles 2026-11-25, weekdays only 2026-11-24 [CHECK] 23 Nov JPN Labor Thanksgiving Day
USD/JPY 2026-11-24 T+2 settles 2026-11-27, weekdays only 2026-11-26 [CHECK] 26 Nov USA Thanksgiving Day
GBP/USD 2026-12-23 T+2 settles 2026-12-29, weekdays only 2026-12-25 [CHECK] 25 Dec GBR Christmas Day; USA Christmas Day; 28 Dec GBR Boxing Dayالصفقة الأولى يوم الجمعة 20 نوفمبر، وكانت ستُسوّى يوم الثلاثاء 24 نوفمبر بأيام الأسبوع وحدها. اليابان مغلقة يوم الاثنين 23 نوفمبر، فينتقل اليوم الثاني إلى الأربعاء 25 نوفمبر. وتتأخر الصفقة الثانية بسبب Thanksgiving Day الأمريكي، وتتأخر الثالثة بسبب Christmas Day في البلدين وBoxing Day في المملكة المتحدة إلى الاثنين 28 ديسمبر. كل سطر في هذا السجل يختلف عن العدّ بأيام الأسبوع.
ما يزال المكتب الخلفي يراجعه يدويًا
| تحقّق | المصدر |
|---|---|
| عطلة نهاية الأسبوع | الحلقة التي تتخطى السبت والأحد |
| العطل الرسمية لبلد كل عملة | نقاط نهاية العطل، بلد واحد لكل طرف |
| عطلة إقليمية في مكتب الحجز | مقارنة subdivision_codes بالمنطقة الفرعية للمكتب |
| إغلاقات البورصة أو نظام الدفع | قائمة المنصة نفسها، تُضاف إلى المجموعة التي تفحصها الحلقة |
| عدد الأيام، T+1 أو T+2 | قواعد المنتج والمنصة، وهي مما لا تحدده الـ API |
يبقى الصفان الأخيران على عاتق المكتب الخلفي، لأن قائمة العطل تخص بلدًا وليس منصة.
تنبيه المتداول عند وجود إغلاق قرب الصفقة
يعيد GET /v1/calendars/holidays/{country}/next?from_date=2026-11-20 أول عطلة في ذلك التاريخ أو بعده داخل كائن holiday. وأعاد لليابان 23 نوفمبر وللولايات المتحدة 26 نوفمبر، وكلاهما داخل نافذة T+2. شغّله لكل طرف عند حجز الصفقة وأخبر المتداول بأن إغلاقًا قادم. واستخدم قائمة السنة للتحقق من التاريخ نفسه.
هل تطابق القائمة تقويم البورصة أو نظام الدفع؟
تسرد القائمة العطل الرسمية لبلد ما مع نطاقها ومناطقها الفرعية، ولا يظهر فيها إغلاق لا يوجد إلا في بورصة أو نظام دفع. تضم قائمة الولايات المتحدة لعام 2026 ما مجموعه 11 إدخالًا ولا تشمل Good Friday في 3 أبريل، وهو يوم تغلق فيه بعض البورصات. أضف إغلاقات المنصة إلى المجموعة التي تفحصها الحلقة.
ماذا يحدث إذا لم يكن لبلد ما تقويم لتلك السنة؟
تعيد الـ API استجابة مشكلة 404 بالرمز calendar_not_published، وهذا ما حدث مع طلب المملكة المتحدة لعام 2028. يوقف raise_for_status() السكربت، وهذا سلوك آمن لتعليمات لا يجوز أن تخرج خاطئة. قرّر هل تعود إلى أيام الأسبوع مع وسم التاريخ، أم تنتظر.
ما الأيام التي يجب أن يتخطاها زوج العملات؟
يُتخطى اليوم إذا كان أي من البلدين مغلقًا. تنتظر صفقة USD/JPY يومًا يكون فيه كل من طوكيو والولايات المتحدة مفتوحًا. تحقق من عُرف المنتج، لأن T+1 أو T+2 وأي استثناء لليوم الوسيط يأتيان من قواعد السوق التي لا تذكرها الـ API.
نُشر في .