انتقل إلى المحتوى

الوحدة 01 · الدرس 2 من 5 (01.2)

أساسيات Python من خلال أمثلة التداول

مبتدئ18 دقيقةمسودة — قيد المراجعة

المتغيّرات والأرقام والنصوص والقوائم والحلقات والشروط والدوال، تتعلّمها ببناء حاسبة لحجم المركز وتشغيلها على قائمة من إعدادات الصفقات.

قبل هذا الدرس: تجهيز بيئة العمل

في هذا الدرس ستتعلّم أن

  • خزّن القيم في متغيّرات وتعرّف على الأنواع الأساسية في Python.
  • تعامل مع قوائم نتائج الصفقات باستخدام الفهرسة والحلقات والشروط.
  • اكتب دالة بمدخلات ونص توثيقي (docstring) وقيمة مُرجَعة.
  • ابنِ حاسبة لحجم المركز وطبّقها على عدة إعدادات دفعة واحدة.

يعلّمك هذا الدرس جوهر Python من خلال عمليات حسابية تجريها أصلاً بصفتك متداولاً. وفي نهايته ستكون قد كتبت حاسبة لحجم المركز واستخدمتها على عدة إعدادات دفعة واحدة. يُشرح كل مفهوم عند أول ظهور له، فلا حاجة إلى خبرة برمجية. اكتب الأمثلة بيدك بدلاً من لصقها إن استطعت؛ فهذا أسرع طريقة لتعلّم الصياغة.

المتغيّرات والأنواع

المتغيّر اسم يشير إلى قيمة. تنشئه بـ=، وتعني في Python «خزّن»، لا «يساوي».

variables.pyPython
account_size = 25_000        # an integer: a whole number
risk_percent = 0.01          # a float: a number with a decimal point
symbol = "DEMO"              # a string: text inside quotes
is_long = True               # a boolean: True or False
 
risk_dollars = account_size * risk_percent
print(symbol, is_long, risk_dollars)
print(type(account_size), type(risk_percent), type(symbol), type(is_long))
print(f"Risking ${risk_dollars:,.2f} per trade on {symbol}")
Output
DEMO True 250.0
<class 'int'> <class 'float'> <class 'str'> <class 'bool'>
Risking $250.00 per trade on DEMO

كل ما يأتي بعد # في سطر ما تعليق. تتجاهله Python؛ وهو موجود للقارئ.

الأنواع الأربعة هنا تغطي معظم سكربتات التداول. int عدد صحيح، مثل عدد الأسهم. وfloat عدد بفاصلة عشرية، مثل السعر أو النسبة المئوية. وstr (نص) كلام. وbool (قيمة منطقية) هي True أو False، جواب سؤال بنعم أو لا. وتخبرك الدالة المدمجة type() بنوع القيمة.

ضرب عدد صحيح في عدد عشري يعطي عدداً عشرياً، ولهذا تُطبع risk_dollars على صورة 250.0. والسطر الأخير f-string، وقد تعرّفت عليه في الدرس السابق. داخل الأقواس المعقوفة، :,.2f تنسيق: , تضيف فواصل الآلاف و.2f تعرض خانتين عشريتين. أما $ قبل القوس فهي مجرد علامة دولار في النص.

القوائم والحلقات

القائمة تحمل عدة قيم بالترتيب، داخل أقواس مربعة. وهنا تحمل نتائج ثماني صفقات، بوحدة R.

trade_list.pyPython
trades_r = [1.8, -1.0, -1.0, 2.4, -0.5, 3.1, -1.0, 0.9]   # each trade's result in R
 
print("Number of trades:", len(trades_r))
print("First trade:", trades_r[0], "| last trade:", trades_r[-1])
print("Total:", round(sum(trades_r), 2), "R")
 
wins = 0
for r in trades_r:
    if r > 0:
        wins = wins + 1
 
print(f"Win rate: {wins / len(trades_r):.0%}")
Output
Number of trades: 8
First trade: 1.8 | last trade: 0.9
Total: 4.7 R
Win rate: 50%

تعدّ len() العناصر. وتختار الأقواس المربعة بعد القائمة عنصراً واحداً بموضعه، ويسمّى فهرسه. تعدّ Python من الصفر، فـtrades_r[0] هي الصفقة الأولى. والفهارس السالبة تعدّ من النهاية: trades_r[-1] هي الأخيرة. وتجمع sum() العناصر، وتقرّب round(x, 2) إلى خانتين عشريتين.

الحلقة هي الجزء المهم. for r in trades_r: تعني «لكل عنصر في القائمة، سمِّه r وشغّل الأسطر المزاحة تحته». الإزاحة هي ما تعرف به Python أي الأسطر تنتمي إلى الحلقة: أربع مسافات هي العُرف. وداخلها، يشغّل if r > 0: سطره المزاح الخاص فقط حين يتحقق الشرط. فتزور الحلقة كل صفقة وتضيف واحداً إلى wins لكل صفقة رابحة.

بعد الحلقة، تساوي wins / len(trades_r) القيمة 0.5، ويعرضها التنسيق :.0% على هيئة نسبة مئوية بلا خانات عشرية.

الدوال: حاسبة حجم المركز

الدالة قطعة شيفرة مسمّاة قابلة لإعادة الاستخدام. تعطيها مدخلات، تسمّى وسائط، فتُعيد لك نتيجة. وهذه هي العملية الحسابية وراء تحديد حجم المركز بنسبة كسرية ثابتة: خاطر بنسبة مئوية محددة من الحساب، ودع المسافة إلى وقف الخسارة تقرّر كم سهماً تشتري.

position_size.pyPython
def position_size(account, risk_pct, entry, stop):
    """Shares to buy so that a stop-out loses risk_pct of the account."""
    risk_dollars = account * risk_pct
    risk_per_share = abs(entry - stop)
    if risk_per_share == 0:
        raise ValueError("entry and stop cannot be the same price")
    return int(risk_dollars // risk_per_share)
 
 
shares = position_size(account=25_000, risk_pct=0.01, entry=50.00, stop=48.50)
print("Shares:", shares)
print(f"Position value: ${shares * 50.00:,.2f}")
print(f"Loss if stopped: ${shares * 1.50:,.2f}")
Output
Shares: 166
Position value: $8,300.00
Loss if stopped: $249.00

يبدأ def تعريف دالة: اسمها، ثم وسائطها بين قوسين، ثم نقطتان رأسيتان. والأسطر المزاحة هي الجسم. والنص بين علامات الاقتباس الثلاثية نص توثيقي (docstring)، وصف قصير تعرضه المحرّرات حين تستخدم الدالة.

الأسطر المظلَّلة هي التي تؤدي العمل. يخاطر الحساب بنسبة 1% من 25,000، أي 250. ووقف الخسارة أقل من سعر الدخول بمقدار 1.50؛ وتأخذ abs() القيمة المطلقة، فتعمل الدالة نفسها مع المراكز القصيرة التي يكون فيها الوقف أعلى من الدخول. ثم يقسم // ويقرّب لأسفل: 250 / 1.50 تساوي 166.67، ولا يمكنك شراء ثلثي سهم، فالجواب 166. والتقريب لأسفل يعني أن المخاطرة الفعلية، 249، لا تتجاوز الخطة. وتحوّل int() الناتج إلى عدد صحيح، وreturn تسلّمه لمن استدعى الدالة.

يحمي فحص if من وقف عند سعر الدخول نفسه، وهذا يعني القسمة على صفر. ويوقف raise ValueError(...) البرنامج برسالة واضحة بدلاً من إنتاج رقم بلا معنى. الفشل بصوت عالٍ عادة جيدة في شيفرة التداول: فالإجابة الخاطئة الصامتة قد تتحول إلى أمر حقيقي.

عند استدعاء الدالة، كتابة account=25_000 بدلاً من 25_000 فقط اختيارية، لكنها توضّح معنى كل رقم.

جمع كل شيء: عدة إعدادات دفعة واحدة

قيمة الدالة أن القاعدة نفسها تعمل بالتطابق على كل مدخل. يحدّد هذا المثال حجم ثلاثة إعدادات افتراضية. كل إعداد قاموس (dictionary): مجموعة قيم مسمّاة داخل أقواس معقوفة، حيث يبحث setup["entry"] عن القيمة المخزّنة تحت المفتاح "entry".

size_setups.pyPython
def position_size(account, risk_pct, entry, stop):
    """Shares to buy so that a stop-out loses risk_pct of the account."""
    risk_dollars = account * risk_pct
    risk_per_share = abs(entry - stop)
    if risk_per_share == 0:
        raise ValueError("entry and stop cannot be the same price")
    return int(risk_dollars // risk_per_share)
 
 
account = 25_000
setups = [
    {"symbol": "AAA", "entry": 50.00, "stop": 48.50},
    {"symbol": "BBB", "entry": 120.00, "stop": 114.00},
    {"symbol": "CCC", "entry": 8.40, "stop": 8.10},
]
 
for setup in setups:
    shares = position_size(account, 0.01, setup["entry"], setup["stop"])
    exposure = shares * setup["entry"]
    print(f"{setup['symbol']}: {shares:>4} shares  ${exposure:>9,.2f} position  {exposure / account:.0%} of the account")
Output
AAA:  166 shares  $ 8,300.00 position  33% of the account
BBB:   41 shares  $ 4,920.00 position  20% of the account
CCC:  833 shares  $ 6,997.20 position  28% of the account

تتكرر الدالة في الأعلى ليعمل المثال بمفرده؛ وفي مشروع حقيقي تعرّفها مرة واحدة وتعيد استخدامها. وفي رموز التنسيق، يحاذي >4 و>9 القيمة إلى اليمين في مساحة بعرض أربعة أو تسعة أحرف، فتصطف الأعمدة.

انظر إلى النتيجة لا إلى الشيفرة للحظة. كل إعداد يخاطر بالمبلغ نفسه، 250، ومع ذلك تتراوح المراكز من 20% إلى 33% من الحساب، لأن مسافات وقف الخسارة تختلف. هذا هو تحديد الحجم بحسب المخاطرة وهو يؤدي عمله: تبقى المخاطرة لكل صفقة ثابتة بينما يتكيّف حجم المركز. وهو يبيّن أيضاً لماذا يستحق وجود حدّ لقيمة المركز، وهو موضوع تمرين هذا الدرس، حين يكون الوقف ضيقاً جداً.

ما تعلّمته

في بضع عشرات من الأسطر استخدمت معظم اللبنات التي تعتمد عليها الوحدات اللاحقة: المتغيّرات والأنواع والقوائم والحلقات والشروط والقواميس والدوال. لكن بيانات الأسعار الحقيقية لن تأتي في قوائم قصيرة تُكتب يدوياً. يقدّم الدرس التالي pandas، التي تعالج آلاف الصفوف من الأسعار المؤرَّخة بوصفها جدولاً واحداً.

أهم الخلاصات

  • المتغيّر اسم لقيمة. والأعداد الصحيحة والأعداد العشرية والنصوص والقيم المنطقية تغطي معظم ما يحتاجه سكربت التداول.
  • القوائم تحمل متتاليات مثل نتائج الصفقات، وحلقة for تعالج كل عنصر بدوره.
  • الدالة تغلّف عملية حسابية تحت اسم، فتُطبَّق القاعدة نفسها بالطريقة نفسها في كل مرة.
  • تحديد حجم المركز من حجم الحساب ونسبة المخاطرة ومسافة وقف الخسارة بضعة أسطر من الشيفرة، والشيفرة تطبّقه دون استثناءات.

تمرين الـ Lab

وسّع حاسبة حجم المركز

أضف وسيطاً باسم max_position_pct إلى position_size يحدّ قيمة المركز بنسبة من الحساب، مثل 25%، ويُرجع الأصغر من عددَي الأسهم. شغّلها على الإعدادات الثلاثة من هذا الدرس وتحقّق يدوياً من أيّها يُقيَّد بالحد. ثم اجعل الدالة تُطلق خطأً واضحاً إذا كانت risk_pct أعلى من 0.05.

اختبار ذاتي

أجب بكلماتك أولاً، ثم اكشف الإجابة.

  1. 01في القائمة trades_r = [1.8, -1.0, -1.0, 2.4]، ما قيمة trades_r[0] وtrades_r[-1]؟

    اعرض الإجابة

    trades_r[0] هي 1.8، أي العنصر الأول، لأن Python تعدّ من الصفر. وtrades_r[-1] هي 2.4: الفهارس السالبة تعدّ من النهاية، فـ-1 هو العنصر الأخير.

  2. 02لماذا تستخدم position_size العامل // والدالة int() بدلاً من القسمة العادية؟

    اعرض الإجابة

    لا يمكنك شراء جزء من سهم في معظم الأسواق. العامل // يقسم ويقرّب لأسفل إلى عدد صحيح، فلا تتجاوز المخاطرة الفعلية المخاطرة المخطّطة، وتحوّل int() الناتج إلى عدد صحيح.

  3. 03ماذا يحدث إذا استُدعيت position_size بسعر الدخول وسعر الوقف نفسيهما، ولماذا هذا أفضل من إرجاع رقم؟

    اعرض الإجابة

    تُطلق ValueError مع رسالة. فمسافة الوقف الصفرية تعني القسمة على صفر، أو مركزاً بلا حد. والتوقف بصوت عالٍ مع رسالة واضحة أكثر أماناً من إرجاع حجم بلا معنى أو ضخم بصمت.

هل أنهيت الدرس وتمرين الـ Lab والاختبار الذاتي؟

مصطلحات المسرد في هذا الدرس

مقالات ذات صلة من الأكاديمية

مادة تعليمية فقط. تستخدم الأمثلة بيانات اصطناعية، وليست نصيحة استثمارية ولا توقّعاً للنتائج.