المكتب الذي يخفّف المخاطر، ومهندس المناوبة الذي يوقف المهام، ومسؤول الوردية الذي يطلع الموظفين، كلهم يحتاجون إلى الرسالة نفسها قبل الصدور: الوقت بالتوقيت العالمي المنسق وبالتوقيت المحلي، والفترة التي يغطيها الإصدار، والقيمة السابقة. يعيد تقويم Narwhal الاقتصادي هذه الأربعة، ويحوّلها سكربت مجدول قصير إلى سطر واحد لكل إصدار.
ما الذي يجب أن يحمله التنبيه قبل الصدور
قبل صدور رقم مهم، يخفّف المكتب المخاطر، ويوقف مهندس المناوبة المهام الدفعية، ويطلع مسؤول الوردية الموظفين. ويعتمد الثلاثة على الحقائق نفسها: متى يصدر الرقم، وأي فترة يغطي، وما كانت آخر قيمة. ويحتاج الموظفون في مدينة أخرى إلى الوقت بتوقيتهم أيضًا، لأن رسالة تقول 13:30 بالتوقيت العالمي المنسق تجبرهم على حساب الفارق تحت الضغط. يعيد GET /v1/economics/calendar كل هذه المعلومات. يطلب هذا الطلب الولايات المتحدة في 10 نوفمبر.
curl -s -H "Authorization: Bearer $NARWHAL_API_KEY" \
"https://api.narwhalapi.com/v1/economics/calendar?countries=USA&start_date=2026-11-10&end_date=2026-11-10&limit=100"{
"releases": [
{
"release_id": "66f7f9f6-0318-4f25-8896-541c428ee07e",
"revision": 2,
"country": "USA",
"series_id": "usa-wages-and-earnings",
"name": "Wages and earnings",
"topic": "wages",
"family": "labour",
"period": "2026-10",
"status": "scheduled",
"at": "2026-11-10T13:30:00Z",
"timezone": "America/New_York",
"values": [
{
"measure": "real_average_hourly_earnings_mom",
"concept": "real_average_hourly_earnings",
"unit": "percent",
"transformation": "month_over_month",
"previous": "-0.5"
},
{
"measure": "real_average_hourly_earnings_yoy",
"concept": "real_average_hourly_earnings",
"unit": "percent",
"transformation": "year_over_year",
"previous": "-0.7"
}
]
},
{
"release_id": "f01e2289-2e17-49b3-9d64-d29118742dee",
"revision": 3,
"country": "USA",
"series_id": "usa-consumer-prices",
"name": "Consumer prices",
"topic": "consumer_prices",
"family": "prices",
"period": "2026-10",
"status": "scheduled",
"at": "2026-11-10T13:30:00Z",
"timezone": "America/New_York",
"values": [
{
"measure": "core_cpi_yoy",
"concept": "core_cpi",
"unit": "percent",
"transformation": "year_over_year",
"previous": "2.6",
"not_seasonally_adjusted": true
},
{
"measure": "cpi_mom",
"concept": "cpi",
"unit": "percent",
"transformation": "month_over_month",
"previous": "0.6"
},
{
"measure": "cpi_yoy",
"concept": "cpi",
"unit": "percent",
"transformation": "year_over_year",
"previous": "3.7",
"not_seasonally_adjusted": true
}
]
}
],
"next_cursor": null
}at هو وقت الصدور بالتوقيت العالمي المنسق. تسمّي period الشهر الذي تغطيه الأرقام، وتحمل values[].previous آخر رقم منشور لكل مقياس مع unit. تعرض الاستجابة القيمة السابقة ولا تتضمن توقعات، لذا يضيف المكتب الراغب في رقم التوافق من مصدره الخاص. وتبقى status هي scheduled إلى أن تصدر الأرقام.
كتابة سطر تنبيه واحد لكل إصدار
صُمّم السكربت أدناه ليعمل وفق جدول، مثلًا كل صباح، ويطبع سطرًا واحدًا لكل إصدار مستحق خلال الـ 24 ساعة القادمة.
- تحديد المنطقة الزمنية للمكتب والدول
DESK_TZهي المنطقة الزمنية التي يقرأ بها الموظفون الرسالة، وCOUNTRIESتسرد الاقتصادات التي يتداول فيها المكتب أو يعتمد عليها. - طلب نافذة تواريخ موسّعة يتبع مرشح التاريخ التاريخ المحلي لكل جهة نشر، لذا يطلب السكربت من يوم قبل اليوم إلى يومين بعده ثم يصفّي بحسب
atنفسها. - الإبقاء على ما لم يصدر بعد يُحتفظ بالإصدار عندما تكون حالته
scheduledويكون له وقتatويقع هذا الوقت بين الآن ومهلة التنبيه. وNOWمتغير اختياري يتيح الاختبار بساعة ثابتة. - تحويل الوقت وإضافة القيمة السابقة تحوّل
astimezoneالوقت من التوقيت العالمي المنسق إلى منطقة المكتب، فلا حاجة إلى فارق يدوي عند تغيّر الساعة في أي من المكانين. تأتي القيم السابقة منvalues.import os from datetime import datetime, timedelta, timezone from zoneinfo import ZoneInfo import requests DESK_TZ = ZoneInfo("Europe/Zurich") COUNTRIES = ["USA", "EMU"] LEAD = timedelta(hours=24) now = datetime.fromisoformat(os.environ["NOW"]) if "NOW" in os.environ else datetime.now(timezone.utc) r = requests.get( "https://api.narwhalapi.com/v1/economics/calendar", params={ "countries": COUNTRIES, "start_date": (now - timedelta(days=1)).date().isoformat(), "end_date": (now + timedelta(days=2)).date().isoformat(), "limit": 100, }, headers={"Authorization": f"Bearer {os.environ['NARWHAL_API_KEY']}"}, timeout=10, ) r.raise_for_status() due = [] for x in r.json()["releases"]: if x["status"] != "scheduled" or "at" not in x: continue at = datetime.fromisoformat(x["at"].replace("Z", "+00:00")) if now <= at < now + LEAD: due.append((at, x)) for at, x in sorted(due, key=lambda t: t[0]): prev = ", ".join(f"{v['measure']} {v['previous']}" for v in x["values"] if "previous" in v) print(f"{at:%H:%M} UTC / {at.astimezone(DESK_TZ):%H:%M} {DESK_TZ.key} | " f"{x['country']} {x['name']} {x.get('period', '-')} | previous: {prev or 'none listed'}")
عند ضبط NOW على 09:00 بالتوقيت العالمي المنسق في 10 نوفمبر، طبع السكربت سطرين. زيورخ تسبق التوقيت العالمي المنسق بساعة في ذلك التاريخ، ولهذا يظهر 13:30 بالتوقيت العالمي المنسق على أنه 14:30. يشترك إصداران أمريكيان في وقت واحد، فيمكن للمكتب الذي يريد رسالة واحدة تجميع الأسطر بحسب قيمة at.
13:30 UTC / 14:30 Europe/Zurich | USA Wages and earnings 2026-10 | previous: real_average_hourly_earnings_mom -0.5, real_average_hourly_earnings_yoy -0.7
13:30 UTC / 14:30 Europe/Zurich | USA Consumer prices 2026-10 | previous: core_cpi_yoy 2.6, cpi_mom 0.6, cpi_yoy 3.7مواءمة التنبيه مع من يقرأه
| القارئ | الإجراء قبل الصدور | ما يحتاجه التنبيه |
|---|---|---|
| المتداول | تقليص مركز أو التحوّط له | التوقيت العالمي المنسق والوقت المحلي والقيمة السابقة |
| مهندس المناوبة | إيقاف عملية نشر أو مهمة دفعية حول تلك الدقيقة | وقت at الدقيق، وstatus للتأكد من أن الإصدار لا يزال مجدولًا |
| مسؤول الوردية | إطلاع الموظفين على ما هو قادم | اسم الإصدار وperiod والقيمة السابقة |
أرسل الأسطر عبر القناة التي يتابعها الفريق أصلًا. توفّر الواجهة الحقائق، وتتولى أداة الدردشة أو البريد لديك إيصالها. شغّل السكربت من جدولة كما في جدولة سحب يومي للبيانات، وبوتيرة لا تقل عن مهلة التنبيه التي تريدها.
إبقاء التنبيه صحيحًا عند تغيّر موعد الإصدار
قد يتغير موعد الإصدار بعد أن ترسل قائمة الصباح. لكل عنصر في التقويم revision يرتفع عند تغيّر تفاصيله، فيمكن لسكربت يعيد قراءة التقويم قبيل الإصدار أن يقارن الـ revision بالذي أرسله. وللدفع الفوري تبلّغ webhooks عن release.scheduled وrelease.rescheduled وrelease.cancelled؛ راجع استقبال webhooks. يصل الـ webhook عند تغيّر الجدول ولا يحمل عدًّا تنازليًا، فتأتي مهلة التنبيه من مؤقتك أنت.
يمكن للموظفين الذين يريدون تذكيرًا على الهاتف فقط الاشتراك بتطبيق التقويم في خلاصة تُنشأ عبر POST /v1/calendars/subscriptions. يقبل الطلب countries وstart_date وend_date، وفي الاستجابة url يُعاد مرة واحدة، لذا احفظه كسر. هذا الاستدعاء ينشئ شيئًا، ولذلك تكتفي هذه الصفحة بوصفه ولا تنفّذه. الطلب الكامل في وثائق اشتراكات التقويم.
ماذا لو لم يكن للإصدار وقت محدد بعد؟
تحمل بعض الإصدارات date أو between أو by بدلًا من at. يتخطاها السكربت لأنه لا يستطيع وضعها على الساعة. اذكرها في ملاحظة صباحية منفصلة ليعرف المكتب أن إصدارًا قد يأتي دون دقيقة ثابتة.
هل تستطيع الواجهة إرسال التذكير بنفسها؟
لا توجد نقطة نهاية ترسل تذكيرًا في وقت محدد. يأتي التذكير من تطبيق تقويم، أو من سكربت مجدول لديك، أو من مستقبِل webhook يبدأ مؤقتًا خاصًا به.
لماذا يطلب السكربت تواريخ حول اليوم الحالي؟
تتبع نافذة التاريخ التاريخ المحلي لجهة النشر. قد يقع إصدار في طوكيو أو سيدني في تاريخ تقويمي مختلف عن وقته بالتوقيت العالمي المنسق، ولذلك يُوسَّع الطلب وتقرر at ما هو مستحق.
نُشر في .