تحميل بيانات الأسعار: ملفات CSV وواجهات API المجانية والأسعار المعدّلة مقابل غير المعدّلة والقيم المفقودة والمناطق الزمنية
اقرأ ملفات الأسعار وتنزيلات واجهات API في إطار DataFrame نظيف، وافهم كيف تعمل تعديلات تجزئة الأسهم والتوزيعات، وتعامل مع الفجوات والمناطق الزمنية بشكل صحيح.
ما الذي ستتعلمه
- كيف تقرأ ملف CSV في إطار DataFrame بتواريخ سليمة، والوسائط التي تصلح مشكلات الاستيراد المعتادة.
- ما الذي تقدّمه لك واجهات API المجانية للبيانات، وما معنى تراخيصها وإعداداتها الافتراضية، وكيف تخزّن التنزيلات مؤقتًا.
- كيف تُحسب عوامل التعديل الخاصة بتجزئة الأسهم والتوزيعات، ولماذا يحتاج الاختبار الرجعي إلى أسعار معدّلة بينما يحتاج الأمر الحي إلى أسعار غير معدّلة.
- كيف تعثر على القيم المفقودة وتعالجها، وكيف تضبط المناطق الزمنية وتحوّلها دون إزاحة شموعك.
الشرح
ملفات CSV. ملف CSV (قيم مفصولة بفواصل) نص عادي يحتوي على صف واحد لكل شمعة. والاستدعاء الأساسي هو:
df = pd.read_csv("data/raw/xyz.csv", parse_dates=["Date"], index_col="Date")
يحوّل parse_dates عمود النص إلى طوابع زمنية، ويجعله index_col هو الفهرس. الإصلاحات الشائعة: sep=";" وdecimal="," للملفات المصدَّرة بالتنسيق الألماني، وdayfirst=True لتواريخ مثل 03.04.2025، وdate_format="%d.%m.%Y" عندما يكون التحليل خاطئًا. بعد التحميل، نفّذ df = df.sort_index() (بعض الملفات المصدَّرة تبدأ بالأحدث)، وتحقّق من df.index.is_unique، وحوّل أسماء الأعمدة إلى أحرف صغيرة باستخدام df.columns = df.columns.str.lower().
واجهات API المجانية. تتيح واجهة برمجة التطبيقات (API) للكود طلب البيانات من خادم. في المشروع الأول تكون مكتبة yfinance (بيانات Yahoo Finance) الخيار المعتاد: yf.download("SAP.DE", start="2015-01-01")؛ وهي مخصّصة للبحث الشخصي ودقّتها غير مضمونة. ثمة إعداد افتراضي مهم: اعتبارًا من عام 2026 تكون القيمة auto_adjust=True، أي أن الافتتاح والأعلى والأدنى والإغلاق معدّلة سلفًا لتجزئة الأسهم والتوزيعات، ولا يوجد عمود "Adj Close"؛ أما مع auto_adjust=False فتحصل على بيانات OHLC معدّلة للتجزئة فقط إضافةً إلى عمود "Adj Close" يشمل التوزيعات أيضًا. ومن البدائل ذات الفئات المجانية: Stooq (تنزيلات CSV) وAlpha Vantage وTiingo (يتطلبان التسجيل ومفتاح API، مع حدود صارمة لعدد الطلبات)؛ والشروط تتغير، لذا راجع الشروط الحالية، ويتناول الدرس 12 التعامل مع المفاتيح وحدود معدّل الطلبات. وأيًّا كان المصدر، احفظ التنزيل الخام مرة واحدة في data/raw/ (بصيغة CSV أو Parquet) واعمل انطلاقًا من الملف؛ فالمزوّدون يراجعون البيانات التاريخية، والحدود شحيحة.
المعدّلة مقابل غير المعدّلة. شرحت دورة «التداول المنهجي والاختبار الرجعي» لماذا تشوّه تجزئة الأسهم والتوزيعات الاختبارات الرجعية؛ وإليك هنا كيف يعمل التصحيح. في تجزئة بنسبة n مقابل 1، يُقسَم كل سعر سابق على n (ويُضرب الحجم في n). وفي توزيع نقدي D يكون تاريخ استحقاقه السابق (ex-date) في اليوم t، تضرب الطريقة المعيارية جميع الأسعار قبل اليوم t في العامل 1 − D ÷ C، حيث C هو سعر الإغلاق في آخر يوم قبل تاريخ الاستحقاق السابق. وتتراكم التعديلات رجوعًا إلى الخلف. النتائج: تتغير البيانات التاريخية المعدّلة مع كل توزيع جديد، وتكون العوائد النسبية المئوية صحيحة بينما لا تكون مستويات الأسعار باليورو كذلك. القاعدة: أجرِ الاختبار الرجعي على بيانات معدّلة، وضع الأوامر الحقيقية عند أسعار غير معدّلة، ولا تخلط بين الاثنين في حساب واحد أبدًا.
القيم المفقودة. يرمز pandas إلى الفجوات بـ NaN. اعثر عليها باستخدام df.isna().sum(). يُقبَل الملء الأمامي لعدد قليل من فجوات الأسعار باستخدام df["close"].ffill()، لكن لا تملأ الحجم ملئًا أماميًا أبدًا، ولا تستكمل الأسعار بالاستيفاء (interpolation) أبدًا، لأن الاستيفاء يستخدم القيمة المستقبلية ويزرع انحياز الاستباق (الدرس 7). وفي غير ذلك، احذف الصفوف باستخدام df.dropna(subset=["close"]) وسجّل عددها. لاحظ أن الصيغة القديمة fillna(method="ffill") مُوقَفة منذ pandas 2.1 ولا ينبغي استخدامها في الكود الجديد؛ اكتب .ffill().
المناطق الزمنية. نادرًا ما تحتاج إليها الشموع اليومية؛ أما بيانات التداول اللحظي فتحتاج إليها دائمًا. يُلحق tz_localize("Europe/Berlin") منطقة زمنية بفهرس لا يحمل منطقة دون تغيير أوقات الساعة؛ بينما يغيّر tz_convert("America/New_York") أوقات الساعة. وضبط بيانات UTC على توقيت برلين عن طريق الخطأ يزيح كل شمعة بصمت بساعة أو ساعتين، لذا راجع وثائق المزوّد. وتختلف مواعيد التوقيت الصيفي بين أوروبا والولايات المتحدة، وفي تلك الفترات تحديدًا تتسبّب الطوابع الزمنية المعالَجة بشكل خاطئ في عدم تطابق الأدوات.
مثال محلول
مثال افتراضي: يغلق سهم عند €50.00 يوم الاثنين. ويقع تاريخ الاستحقاق السابق لتوزيع قدره €1.00 يوم الثلاثاء، حين يغلق السهم عند €49.50. تُهمَل الرسوم والضرائب.
عامل التعديل = 1 − 1.00 ÷ 50.00 = 0.98. تُضرب جميع الأسعار قبل الثلاثاء في 0.98: فيصبح إغلاق الاثنين 50 × 0.98 = €49.00؛ ويصبح إغلاق قدره €48.00 من الأسبوع السابق 48 × 0.98 = €47.04.
العائد عبر تاريخ الاستحقاق السابق: غير المعدّل (49.50 − 50.00) ÷ 50.00 = −1.0%، وهو ما يبدو خطأً كأنه خسارة. والمعدّل (49.50 − 49.00) ÷ 49.00 = +1.02%، وهو ما يعكس بشكل صحيح استلام €1.00 نقدًا مقابل خسارة سعرية قدرها €0.50 (صافي +€0.50 على €50؛ وينشأ الفرق الصغير لأن الأساس المعدّل هو €49).
والآن تجزئة بنسبة 2 مقابل 1: أسعار الإغلاق الخام 100 و102 و104 قبلها، و52 و53 بعدها. قسمة الأسعار السابقة للتجزئة على 2 تعطي 50 و51 و52 و52 و53، وهي سلسلة متصلة. ومن دون ذلك، يُبلغ pct_change() عن عائد قدره −50% في يوم التجزئة، أي انهيار لم يحدث قط.
خطأ شائع
info() وhead() وtail() وisna().sum() ورسم بياني خطي لسعر الإغلاق.نشاط تطبيقي
على الورق: سهم له سعرا إغلاق €90.00 و€93.00 في يومين، ثم تجزئة بنسبة 3 مقابل 1، ثم سعرا إغلاق €31.00 و€30.38 (افتراضي). في يوم إغلاق €30.38 يحلّ تاريخ الاستحقاق السابق لتوزيع قدره €0.60، وكان الإغلاق السابق له €31.00. (أ) اكتب القيم المعدّلة للتجزئة لسعرَي الإغلاق السابقين للتجزئة. (ب) احسب عامل تعديل التوزيع وطبّقه على أسعار الإغلاق الثلاثة جميعها قبل تاريخ الاستحقاق السابق. (ج) اذكر العائد الخام والعائد المعدّل بالكامل من إغلاق €31.00 إلى إغلاق €30.38.
عرض الحل
(أ) القسمة على 3: €90.00 ← €30.00 و€93.00 ← €31.00.
(ب) العامل = 1 − 0.60 ÷ 31.00 = 0.98065 (مقرّبًا). بتطبيقه: 30.00 × 0.98065 = €29.42؛ و31.00 × 0.98065 = €30.40؛ ويصبح إغلاق €31.00 السابق لتاريخ الاستحقاق السابق هو الآخر €30.40. ويبقى إغلاق €30.38 دون تغيير.
(ج) الخام: (30.38 − 31.00) ÷ 31.00 = −2.00%. المعدّل: (30.38 − 30.40) ÷ 30.40 = −0.07%، وهو قريب من الثبات: فقد انخفض السعر بما يعادل مبلغ التوزيع تقريبًا، لذا لم يخسر حامل السهم شيئًا يُذكر من العائد الإجمالي.
القيود: يقرّب المزوّدون العوامل بطرق مختلفة، ويستخدم بعضهم سعرًا مرجعيًا مختلفًا؛ استخدم السلسلة المعدّلة من مزوّد واحد باتساق.
أهم النقاط
- حمّل البيانات باستخدام
parse_datesوindex_col، ثم رتّبها وتحقّق من التفرّد ووحّد أسماء الأعمدة. - نزّل البيانات مرة واحدة، واحفظ البيانات الخام محليًا، واقرأ ترخيص واجهة API وإعداداتها الافتراضية للتعديل (yfinance:
auto_adjust=Trueاعتبارًا من عام 2026). - عامل التجزئة 1 ÷ n، وعامل التوزيع 1 − D ÷ C، ويُطبَّقان رجوعًا إلى الخلف؛ أجرِ الاختبار الرجعي على الأسعار المعدّلة، وتداول على الأسعار غير المعدّلة.
- املأ ملئًا أماميًا بضع فجوات سعرية على الأكثر، ولا تستخدم الاستيفاء أبدًا، ولا تملأ الحجم ملئًا أماميًا أبدًا، واضبط المناطق الزمنية مرة واحدة على المنطقة الفعلية لدى المزوّد.
الخطوة التالية
يحوّل الدرس 5 الأسعار إلى عوائد: العوائد البسيطة مقابل اللوغاريتمية، والعوائد التراكمية، والعائد والتقلب السنويان، والنوافذ المتحركة.
تقييم ذاتي
أجب عن الأسئلة، ثم تحقّق من إجاباتك. يمكنك إعادة المحاولة بقدر ما تشاء.
تقييم ذاتي تلقائي لمراجعتك الشخصية. تُفحَص إجاباتك في متصفحك ولا نطّلع عليها ولا نقيّمها. هذا ليس امتحانًا ولا مؤهّلًا.
تقدّمك
«مكتمل» يعني فقط أنك علّمت الدرس كمنتهٍ. وهو ليس اختبارًا لفهمك. يُحفظ التقدّم والملاحظات فقط في هذا المتصفح على هذا الجهاز — وليس في حساب.