أتمتة قائمة مراقبة يومية: سكربت مجدول يجلب البيانات ويحسب الإشارات ويكتب تقريرًا، مع مزالق مفاتيح API وحدود معدّل الطلبات
حوّل كود الدفتر إلى سكربت متين لسطر الأوامر يتضمن الإعدادات والتسجيل وإعادة المحاولة مع التراجع التدريجي والتعامل الآمن مع مفاتيح API وأداة جدولة، واكتب ملف تقرير يوميًا.
ما الذي ستتعلمه
- كيف تعيد هيكلة خلايا الدفتر في سكربت يتضمن دوالًا ونقطة دخول
main()وملف إعدادات. - كيف تُبقي مفاتيح API خارج الكود، وتتعامل مع حدود معدّل الطلبات بالانتظار والتراجع الأسي.
- كيف تكتب تقريرًا مفيدًا في الساعة 07:30 صباحًا: جدول مرتّب، وبضع علامات تنبيه، وطابع زمني.
- كيف تجدول السكربت باستخدام cron أو Windows Task Scheduler، وما الذي تسجّله كي لا تمرّ حالات الفشل الصامتة دون أن تُلاحَظ.
الشرح
الدفتر للاستكشاف؛ أما السكربت فيكرّر المهمة نفسها كل يوم دون أن تراقبه. تبقى المؤشرات (الدرس 6) ومنطق الإشارات (الدرسان 7 و8) كما هي؛ ويتغيّر كل ما يحيط بها.
بنية السكربت
قسّم العمل إلى دوال لكل منها مهمة واحدة: load_config() وfetch(ticker) وcompute_signals(df) وbuild_report(rows) وmain(). يتيح لك الشرط الحارس if __name__ == '__main__': main() تشغيل الملف، وكذلك استيراد دواله في الاختبارات. احتفظ بقائمة المراقبة والمعاملات ومجلد المخرجات في config.yaml أو config.json كي تتغيّر دون تعديل الكود.
مفاتيح API والأسرار
لا تكتب مفتاحًا أبدًا في الكود المصدري أو في دفتر قد تشاركه أو تحفظه في Git. اقرأه من متغير بيئة أو من ملف .env باستخدام os.environ['DATA_API_KEY'] (تحمّل حزمة python-dotenv ملف .env)، وأدرج .env في .gitignore. تعامل مع المفتاح ككلمة مرور، واستبدله إذا تسرّب.
حدود معدّل الطلبات وإعادة المحاولة والتراجع
حد معدّل الطلبات هو الحد الأقصى لعدد الطلبات التي يسمح بها المزوّد في الدقيقة أو في اليوم؛ وتجاوزه يعيد خطأ HTTP 429، أو ما هو أسوأ: بيانات فارغة دون أي خطأ. نظّم وتيرة الحلقة باستخدام time.sleep(60 / max_per_minute). وفي حالات الفشل المؤقت (429 و500 وانتهاء المهلة) أعد المحاولة مع تراجع أسي: انتظر 1 ث، ثم 2 ث، ثم 4 ث، ثم 8 ث، ثم توقّف وسجّل الرمز على أنه مفقود. لا تعِد المحاولة أبدًا في حلقة متلاحقة بلا انتظار؛ فهكذا تُحظر المفاتيح.
def fetch_with_retry(ticker, tries=4, base=1.0):for n in range(tries):try:return fetch(ticker)except TransientError as e:wait = base * 2 ** nlog.warning('%s: %s، إعادة المحاولة بعد %.0f ثانية', ticker, e, wait)time.sleep(wait)log.error('%s: التوقف عن المحاولة', ticker)return None
خزّن التنزيلات الخام مؤقتًا (data/raw/TICKER_YYYY-MM-DD.parquet): فالتشغيل الثاني في اليوم نفسه يقرأ الملف بدلًا من استهلاك الحصة، وتحتفظ بسجل تدقيق لما رآه السكربت.
التحقق قبل الإشارات
تصل البيانات معطوبة أكثر مما تتوقع: شمعة أخيرة مفقودة، أو تاريخ قديم، أو إغلاق قيمته 0، أو تجزئة غير معدّلة. تحقّق من أن آخر تاريخ يساوي تاريخ التداول المتوقع، وأن آخر 20 صفًا لا تحتوي على NaN، وأن القيمة المطلقة لعائد اليوم أقل من عتبة معقولية مثل 50 %. وتذهب حالات الفشل إلى قسم «مشكلات البيانات» في التقرير بدلًا من أن تُنتج إشارة شراء من سعر خاطئ.
التقرير
اكتب ملف Markdown أو HTML يتضمن الطابع الزمني للتشغيل وتاريخ البيانات، وجدولًا مرتّبًا حسب معيار الترتيب لديك (مثل المسافة عن SMA لخمسين يومًا بوحدات ATR)، والإشارات الجديدة منذ الأمس (بالمقارنة مع ملف الإشارات المحفوظ لليوم السابق)، ومشكلات البيانات. احفظه باسم reports/watchlist_2026-10-30.md كي يُحفظ السجل التاريخي؛ والرسوم البيانية لكل رمز عليه علامة تنبيه (الدرس 10) اختيارية.
الجدولة والتسجيل
على Linux وmacOS، يشغّل cron الأوامر وفق جدول زمني: يعمل 30 6 * * 1-5 /path/venv/bin/python /path/watchlist.py >> /path/logs/cron.log 2>&1 في الساعة 06:30 من أيام العمل؛ وعلى Windows، يؤدي Task Scheduler الأمر نفسه عبر نافذة حوار. استخدم المسار الكامل لبايثون البيئة الافتراضية (الدرس 1)، لأن أدوات الجدولة لا تفعّل البيئات. سجّل باستخدام وحدة logging في ملف: البدء، والرموز التي جُلبت، والإشارات التي وُجدت، والانتهاء. وغياب أي إدخال لهذا اليوم يعني أن أداة الجدولة فشلت. فالأجهزة تدخل في وضع السكون، والشبكات تنقطع، ونقاط النهاية تتغير؛ والسكربت الذي لا تتفقّده ليس أتمتة.
مثال محلول
مثال افتراضي: قائمة مراقبة من 40 سهمًا أوروبيًا وأمريكيًا، وخطة بيانات مجانية بحد 5 طلبات في الدقيقة و500 في اليوم (أرقام مختلَقة؛ راجع الشروط الحالية لمزوّدك).
- تنظيم الوتيرة. 40 رمزًا بمعدل 5 في الدقيقة = 40 / 5 = 8 دقائق على الأقل. يتوقف السكربت 12 ثانية بين الاستدعاءات. والجدولة في الساعة 06:30 تعني أن البيانات تكون جاهزة بحلول نحو 06:40.
- الحصة. يستهلك التشغيل الواحد 40 من أصل 500 استدعاء يومي (880 شهريًا على مدى 22 يوم تداول). وخلل برمجي يعيد التشغيل كل 10 دقائق سيستنزف 240 استدعاءً في الساعة ويبلغ الحد الأقصى في نحو ساعتين؛ والتخزين المؤقت على القرص يزيل هذه المخاطرة.
- التراجع. يعيد رمزان الخطأ HTTP 429 في المحاولة الأولى. وتنجح إعادة المحاولة بعد 1 و2 و4 ثوانٍ في المحاولة الثانية؛ وأسوأ وقت مضاف هو 1 + 2 + 4 + 8 = 15 ثانية لكل رمز، لذا ينتهي التشغيل مع ذلك ضمن الميزانية البالغة 10 دقائق.
- التقرير. القاعدة: «الإغلاق يتقاطع صعودًا فوق SMA لخمسين يومًا مع RSI(14) دون 60». كان ملف الأمس يتضمن 3 إشارات نشطة؛ ويجد تشغيل اليوم 5، منها 2 جديدتان. يسرد التقرير الاسمين الجديدين أولًا، ثم الثلاثة المستمرة، ورمزًا واحدًا تحت «مشكلات البيانات» لأن شمعته الأخيرة عمرها يومان.
ما يُستبعد: هذا لا يقول شيئًا عمّا إذا كانت الإشارة مربحة؛ بل يجعل التحضير اليومي موثوقًا وقابلًا للتكرار فحسب.
خطأ شائع
نشاط تطبيقي
على الورق: يسمح مزوّدك بـ 30 طلبًا في الدقيقة و2,000 في اليوم. تريد تشغيل قائمة مراقبة من 150 رمزًا مرة واحدة في الساعة 06:00، وتحديث 20 رمزًا ذا أولوية كل 30 دقيقة بين 09:00 و17:30 (بتوقيت وسط أوروبا CET). (أ) ما الحد الأدنى للتوقف بين الاستدعاءات الذي يحترم حد الدقيقة؟ (ب) كم استدعاءً يستهلك اليوم الكامل؟ وهل يقع ضمن الحصة اليومية؟ (ج) يُبلغ تشغيل الساعة 06:00 عن جلب 150 رمزًا، لكن جميع الإشارات مطابقة للأمس. اذكر فحصين يخبرانك ما إذا كانت البيانات حديثة.
عرض الحل
(أ) 60 / 30 = ثانيتان بين الاستدعاءات (استخدم 2.1 ث من باب الحيطة).
(ب) التشغيل الصباحي: 150 استدعاءً. خلال اليوم: من 09:00 إلى 17:30 تساوي 8.5 ساعات = 17 فترة نصف ساعية، إضافةً إلى فترة 09:00 نفسها = 18 تحديثًا × 20 رمزًا = 360 استدعاءً. الإجمالي 510 استدعاءات، أي ضمن 2,000 بفارق كبير. وحتى مع إعادة محاولة كاملة لكل استدعاء (1,020) تبقى الحصة كافية.
(ج) تحقّق من أن آخر تاريخ في فهرس كل إطار يساوي يوم التداول السابق المتوقع (مع مراعاة عطلات البورصة)، وقارن قيمة تجزئة (hash) أو آخر إغلاق في تنزيل اليوم بملف الأمس المخزّن مؤقتًا؛ فإذا كانت أسعار الإغلاق الأخيرة الـ 150 كلها مطابقة لأسعار الأمس، فقد قدّم المزوّد بيانات قديمة.
القيود: الحصص ونقاط النهاية وقواعد الفئات المجانية تتغير؛ والأرقام هنا توضيحية، ويجب أن تقرأ الوثائق الحالية لمزوّدك.
أهم النقاط
- تحتاج السكربتات إلى دوال وملف إعدادات وشرط حارس
main()وتسجيل؛ أما الدفاتر فلا. - احتفظ بالمفاتيح في متغيرات البيئة أو في
.env؛ ونظّم وتيرة الطلبات وفق الحد، وأعد المحاولة مع تراجع أسي، ثم توقّف وسجّل. - تحقّق من التواريخ وأعداد الصفوف قبل حساب الإشارات؛ وخزّن التنزيلات الخام مؤقتًا.
- جدول باستخدام cron أو Task Scheduler مع المسار الكامل لبايثون البيئة الافتراضية، وتفقّد السجل يوميًا.
الخطوة التالية
يجمع الدرس 13 كل شيء في مشروع دفتر بحث كامل، من البيانات إلى التقرير، ويراجعه بقائمة تحقق ضد انحياز الاستباق والإفراط في الملاءمة.
تقييم ذاتي
أجب عن الأسئلة، ثم تحقّق من إجاباتك. يمكنك إعادة المحاولة بقدر ما تشاء.
تقييم ذاتي تلقائي لمراجعتك الشخصية. تُفحَص إجاباتك في متصفحك ولا نطّلع عليها ولا نقيّمها. هذا ليس امتحانًا ولا مؤهّلًا.
تقدّمك
«مكتمل» يعني فقط أنك علّمت الدرس كمنتهٍ. وهو ليس اختبارًا لفهمك. يُحفظ التقدّم والملاحظات فقط في هذا المتصفح على هذا الجهاز — وليس في حساب.