أساسيات بايثون للتمويل في جلسة واحدة: أنواع البيانات والقوائم والقواميس والحلقات والدوال ورسائل الخطأ
تعلّم الحد الأدنى من أساسيات بايثون الذي يحتاجه المتداول: الأرقام والنصوص والقوائم والقواميس والحلقات والدوال وكيفية قراءة تتبّع الخطأ (traceback).
ما الذي ستتعلمه
- أنواع البيانات التي ستصادفها في بيانات الأسعار:
intوfloatوstrوboolوNoneوdatetime. - كيف تخزّن القوائم والقواميس قائمة صفقات، وكيف تعالجها حلقة
for. - كيف تكتب دالة مع سلسلة توثيق (docstring) ومعامل افتراضي، ولماذا تجعل الدوال الاختبارات الرجعية قابلة للاختبار.
- كيف تقرأ تتبّع الخطأ في بايثون من الأسفل إلى الأعلى وتصلح الأخطاء الخمسة الأكثر شيوعًا.
الشرح
الأنواع. لكل قيمة في بايثون نوع. فالقيمة 42 من نوع int (عدد صحيح)، و42.5 من نوع float (عدد عشري مخزّن بالنظام الثنائي)، و"AAPL" من نوع str (نص)، وTrue من نوع bool، أما None فتعني «لا قيمة». الأعداد العشرية تقريبية (يطبع 0.1 + 0.2 القيمة 0.30000000000000004)، لذا لا تقارنها أبدًا باستخدام ==؛ بل استخدم round() أو هامش تسامح. وللتواريخ استخدم الطوابع الزمنية في pandas (الدرس 3).
القوائم مجموعات مرتّبة تُكتب بين قوسين مربعين: closes = [100.0, 102.0, 101.5]. تبدأ الفهرسة من الصفر (closes[0] هو 100.0)، والفهارس السالبة تعدّ من النهاية (closes[-1] هو آخر سعر إغلاق)، والتقطيع closes[1:3] يعيد العنصرين 1 و2 دون العنصر 3. وتنطبق قاعدة استبعاد النهاية نفسها على iloc في pandas.
القواميس تربط المفاتيح بالقيم: trade = {"symbol": "AAA", "entry": 50.0, "qty": 100}. يتم الوصول إليها بـ trade["entry"]؛ والمفتاح المفقود يثير الخطأ KeyError، بينما يعيد trade.get("fee", 0.0) قيمة افتراضية.
الحلقات والشروط. تمرّ حلقة for على كل عنصر: for t in trades: يليها كتلة مُزاحة. والإزاحة (أربع مسافات) هي التي تحدّد الكتلة. تتفرّع if وelif وelse حسب الشروط، وعوامل المقارنة هي == و!= و< و>=.
الدوال تغلّف المنطق بحيث يمكن إعادة استخدامه واختباره. تبدأ الكلمة المفتاحية def التعريف، وتوضع المعاملات بين قوسين، وتعيد return قيمةً:
def r_multiple(entry, exit_price, stop, side="long"):
'''أعِد الربح بوحدات المخاطرة الأولية (R).'''
risk = abs(entry - stop)
pnl = exit_price - entry if side == "long" else entry - exit_price
return pnl / risk
النص المحاط بثلاث علامات اقتباس هو سلسلة توثيق (docstring)، وside="long" معامل افتراضي. اجعل الدوال صغيرة وصريحة في مدخلاتها وخالية من الآثار الجانبية؛ فهذا ما يتيح للدرس 9 كتابة اختبارات وحدة لها.
قراءة الأخطاء. عندما يفشل شيء ما، تطبع بايثون تتبّع الخطأ (traceback). اقرأ السطر الأخير أولًا: فهو يذكر نوع الخطأ ورسالته. ثم انظر إلى السطر الذي فوقه مباشرة، فهو يبيّن أين حدث الخطأ في كودك. أكثر الأخطاء شيوعًا: NameError (استخدمت متغيرًا قبل تعريفه، وكثيرًا ما يكون السبب أن خلية في الدفتر لم تُشغَّل)؛ وTypeError (مثل جمع نص من ملف CSV مع رقم، ويُصلَح بـ float())؛ وKeyError (اسم عمود أو مفتاح قاموس مكتوب بشكل مختلف، تحقّق من المسافات والأحرف الكبيرة)؛ وIndexError (طلبت العنصر 10 من قائمة تضم 10 عناصر، تذكّر أن الفهرسة تبدأ من الصفر)؛ وZeroDivisionError (وقف مساوٍ لسعر الدخول يعطي مخاطرة صفرية).
مثال محلول
مثال افتراضي: ثلاث صفقات شراء مغلقة، جميعها باليورو، مع إهمال العمولات والضرائب.
trades = [
{"symbol": "AAA", "entry": 50.0, "exit": 53.0, "stop": 48.0, "qty": 100},
{"symbol": "BBB", "entry": 20.0, "exit": 19.0, "stop": 19.0, "qty": 250},
{"symbol": "CCC", "entry": 80.0, "exit": 78.0, "stop": 76.0, "qty": 60},
]
total = 0.0
for t in trades:
pnl = (t["exit"] - t["entry"]) * t["qty"]
r = r_multiple(t["entry"], t["exit"], t["stop"])
total += pnl
print(t["symbol"], pnl, round(r, 2))
print("Total:", total)
ربح AAA = (53 − 50) × 100 = €300؛ والمخاطرة لكل سهم €2، لذا R = 3 ÷ 2 = 1.5. وBBB = (19 − 20) × 250 = −€250؛ والمخاطرة €1 لكل سهم، R = −1.0 (خرجت عند الوقف تمامًا). وCCC = (78 − 80) × 60 = −€120؛ والمخاطرة €4، R = −0.5. الإجمالي = 300 − 250 − 120 = −€70. أسطر المخرجات: AAA 300.0 1.5 وBBB -250.0 -1.0 وCCC -120.0 -0.5 وTotal: -70.0.
total += pnl اختصار لـ total = total + pnl. ثلاث صفقات لا تقول شيئًا عن أي أسلوب؛ فالمقصود هنا هو الآلية.
خطأ شائع
trades وأعد تشغيل خلية الحلقة وحدها، فتغذّي قيمة قديمة النتيجة بصمت؛ وبعد إعادة تشغيل النواة (kernel) تحصل بدلًا من ذلك على NameError. قبل أن تثق بأي رقم، استخدم «إعادة تشغيل النواة وتشغيل جميع الخلايا» وتأكّد من أن الدفتر يعمل من الأعلى إلى الأسفل دون أخطاء.نشاط تطبيقي
اكتب على الورق دالة position_size(account, risk_pct, entry, stop) تعيد العدد الصحيح من الأسهم (مع التقريب إلى الأسفل) وتثير خطأ ValueError واضحًا إذا كان الوقف مساويًا لسعر الدخول. ثم اكتب النتيجة لحساب بقيمة €8,000، ومخاطرة 1.25%، وسعر دخول €32.50، ووقف €30.00. وأخيرًا، اذكر نوع الخطأ الذي ستثيره بايثون إذا استدعيت الدالة بـ entry="32.50" (نص) دون تحويله.
عرض الحل
def position_size(account, risk_pct, entry, stop):
per_share = abs(entry - stop)
if per_share == 0:
raise ValueError("يجب أن يختلف الوقف عن سعر الدخول")
return int(account * risk_pct // per_share)
الأرقام: ميزانية المخاطرة = 8,000 × 0.0125 = €100؛ والمخاطرة لكل سهم = 32.50 − 30.00 = €2.50؛ و100 ÷ 2.50 = 40 سهمًا بالضبط، لذا تعيد الدالة 40 (مخاطرة مخطّطة €100، وقيمة المركز €1,300).
مع entry="32.50"، يثير التعبير "32.50" - 30.0 الخطأ TypeError: unsupported operand type(s) for -: 'str' and 'float'. حوّل القيمة باستخدام float(entry).
القيود: تتجاهل الدالة الحد الأدنى لحجم اللوت والعمولات وحقيقة أن الفجوة السعرية قد تسبّب خسارة تفوق €100 المخطّطة.
أهم النقاط
- الأعداد العشرية تقريبية، والفهرسة تبدأ من الصفر، والشرائح تستبعد النهاية؛ هذه الحقائق الثلاث تمنع معظم أخطاء المبتدئين.
- قائمة من القواميس هي الشكل الطبيعي للصفقات قبل pandas؛ تعالجها الحلقات، وتمنحها الدوال منطقًا قابلًا لإعادة الاستخدام.
- اكتب دوال صغيرة ونقية مع سلاسل توثيق؛ فهي الوحدات التي ستختبرها في الدرس 9.
- اقرأ تتبّعات الأخطاء من الأسفل إلى الأعلى، وأعد التشغيل مع تشغيل جميع الخلايا قبل أن تثق بنتيجة دفتر.
الخطوة التالية
يقدّم الدرس 3 مكتبة pandas: السلاسل Series وإطارات DataFrames وفهرس DatetimeIndex وتحديد الصفوف وتصفيتها وتحويل الشموع اليومية إلى أسبوعية باستخدام resample.
تقييم ذاتي
أجب عن الأسئلة، ثم تحقّق من إجاباتك. يمكنك إعادة المحاولة بقدر ما تشاء.
تقييم ذاتي تلقائي لمراجعتك الشخصية. تُفحَص إجاباتك في متصفحك ولا نطّلع عليها ولا نقيّمها. هذا ليس امتحانًا ولا مؤهّلًا.
تقدّمك
«مكتمل» يعني فقط أنك علّمت الدرس كمنتهٍ. وهو ليس اختبارًا لفهمك. يُحفظ التقدّم والملاحظات فقط في هذا المتصفح على هذا الجهاز — وليس في حساب.