الوثائق1.0 (latest)
الصفحاتدورة حياة الاستراتيجية · 8 / 29

دورة حياة الاستراتيجية

استراتيجية QuantCraft ملف Python عادي يعرّف مجموعة صغيرة من دوال الاستدعاء (callbacks). يستدعي محرك الاختبار الرجعي هذه الدوال بترتيب ثابت أثناء مروره على البيانات التاريخية. أنت لا تستدعيها بنفسك — المحرك هو من يفعل. استخدم Test لتشغيلها (تشغيل الشيفرة).

دورة الحياة من البداية إلى النهاية:

on_init → on_bar → on_tick (×4 per bar) → account tick(close) → on_finish └─────────── repeats for every bar ───────────┘

في الاختبار الرجعي يُطلَق on_tick أربع مرات لكل عمود على OHLC اصطناعي من كل عمود (دون سجل تيكات حقيقي). وبعد هذه التيكات الأربعة يجري المحرك تقييمًا نهائيًا للحساب بالسوق عند الإغلاق — وليس on_tick خامسًا. و*on_timer** متاح فقط في عمليات التشغيل الأمامية (أمامي على الرسم البياني، أمامي جماعي / QuantCloud) عند ضبط timerIntervalMs — ولا يملك مربع Run backtest في بيئة التطوير عنصر تحكم بالمؤقّت. وفي عمليات التشغيل الأمامية يعمل on_tick عند كل تحديث سعر من الوسيط المتصل لديك؛ وعند حدود اليوم غالبًا ما يُطلَق on_tick ثم on_bar — فلا تفترض ترتيب الاختبار الرجعي.*

تغطي هذه الصفحة كل دالة استدعاء، وكيف ترتبط بها استراتيجيات الرموز المتعددة، والأساسيات اللازمة لكتابة أول استراتيجية لك.


ملف الاستراتيجية

تبدو الاستراتيجية الدنيا هكذا:

import quantcraft.process.runtime as bt # account, chart_indicators, qc_* handles from quantcraft import Timeframe import quantcraft.runtime as rt def on_init(symbols=None): pass def on_bar(bar_index, bar, fundamentals=None, calendar=None, symbol=None): close_px = float(bar["close"]) daily = rt.get_bar(Timeframe.DAILY, shift=1) def on_tick(bar_index, tick_in_bar, price, bar, fundamentals=None, calendar=None, symbol=None): if tick_in_bar == 3: close_px = price def on_finish(bars, symbol=None, bars_by_symbol=None): pass

تنطبق بضع قواعد على كل دوال الاستدعاء:

  • يجب أن تكون دوالّ على المستوى الأعلى في ملفك (لا متداخلة ولا داخل صنف).
  • يتطلب محرك الاختبار الرجعي وجود on_init وon_bar وon_tick وon_finish قابلة للاستدعاء (وإلا فشل التشغيل برسالة User script must define callable: …). وتظهر أزرار Test وCompile وDebug Test في بيئة التطوير عندما تعرّف علامة تبويب .py النشطة on_init / on_bar / on_finish؛ وغياب on_tick يظل يُفشل الاختبار الرجعي عند بدئه. وon_timer اختياري ولا يُستخدم إلا في عمليات التشغيل الأمامية ذات فاصل المؤقّت.
  • أضف فقط الوسائط الاختيارية التي تستخدمها. تُطابَق calendar وsymbols (في on_init) ووسائط on_finish بالاسم؛ أما fundamentals وsymbol فتُطابَقان بتجربة الأشكال الشائعة تباعًا، لذا أبقِها بالترتيب الموثّق. أأمن توقيع كامل هو def on_bar(bar_index, bar, fundamentals=None, calendar=None, symbol=None). وأي calendar مُصرَّح عنه يتلقى دائمًا مقبض التقويم أو None — لا كائن البيانات الأساسية أبدًا.
  • داخل دوال الاستدعاء تضع الأوامر عبر account وتسجّل قيم المؤشرات عبر chart_indicators (سلاسل المؤشرات) — وكلاهما يُقرأ من quantcraft.process.runtime.

المتغيرات العامة لوقت التشغيل

يعرض المحرك هذه من quantcraft.process.runtime قبل تشغيل دوال الاستدعاء:

الاسمالغرض
accountكائن PaperAccount مضبوط من علامة تبويب Simulation (الرصيد + العمولة / الانزلاق). وفي عمليات التشغيل الأمامية هو حساب وسيط حقيقي بالواجهة نفسها يضع أوامر حقيقية — راجع نموذج الحساب
chart_indicatorsمجمِّع ChartIndicatorSeries يُدمج في النتيجة — اجمع القيم أثناء مرور التشغيل على الأعمدة وأصدر السلاسل في on_finish
qc_fundamentalsمقبض QcFundamentals اختياري عند تحميل البيانات الأساسية
qc_fama_frenchQcFamaFrench اختياري عند تحميل عوامل فاما-فرينش العالمية؛ فضّل fama_french.qc في دوال الاستدعاء — راجع عوامل فاما-فرينش
qc_calendarBacktestCalendar | None — بيانات التقويم عند تفعيل Include calendar data؛ تغطي كل رمز متداوَل. للاختبارات الرجعية فقط — دائمًا None في عمليات التشغيل الأمامية. ويمكن لدوال الاستدعاء تلقي المقبض نفسه بتسمية وسيط calendar — راجع بيانات التقويم
qc_ohlcv_by_tfمخازن اختيارية للأطر الزمنية الثانوية مفهرسة بسلسلة الإطار (متقدم؛ فضّل get_bar)
get_bar(tf, shift=1)الواجهة الموصى بها للإطار الأساسي والأطر الإضافية — تُرجع BarSnapshot أو None؛ تُستورد عبر import quantcraft.runtime as rt

فضّل وسيط bars في on_finish(bars, ...) لحسابات السلسلة الكاملة — ولا تعتمد على qc_ohlcv على مستوى الوحدة في استراتيجيات بيئة التطوير (فهو غالبًا None وقت الاستيراد، وNone في تشغيل بهدف ماسح، وفيما عدا ذلك يمتد على النطاق المحمَّل كله بما فيه التهيئة). اقرأ الأسعار من الكائن bar في دوال الاستدعاء. isinstance(bar, dict) هو False — فـOhlcvBarView هو Mapping (والوصول بأسلوب القاموس ما زال يعمل).

اقرأها كسمات وحدة. كل مقبض مدعوم بقيمة لكل جلسة، لذا تشير bt.account / bt.chart_indicators دائمًا إلى هذا التشغيل. أما from quantcraft.process.runtime import account فيربط لقطة — وهذا مقبول في ملف الخوارزمية الجذري في الاختبار الرجعي لأن المحرك يعيد ربط هذه الأسماء بعد تحميله (وعمليات التشغيل الأمامية تعيد ربط account وqc_fundamentals وqc_fama_french فقط، فاستخدم هناك bt.chart_indicators وrt.qc_ohlcv*)، لكنه خاطئ في وحدة مساعدة مقسّمة تبقى مخزّنة مؤقتًا في sys.modules فتحتفظ بمقبض الجلسة الأولى. راجع مقابض الوحدات مقابل الأسماء المستوردة.

الأطر الزمنية الثانوية

الإطار الزمني الأساسي للتشغيل متاح دائمًا عبر rt.get_bar. حدّد أحجام أعمدة إضافية في القائمة Additional timeframes في نافذة Run backtest ضمن Symbol & data (الاختبارات الرجعية)، ثم اقرأها من أي دالة استدعاء:

from quantcraft import Timeframe import quantcraft.runtime as rt def on_bar(bar_index, bar, fundamentals=None, calendar=None, symbol=None): daily = rt.get_bar(Timeframe.DAILY, shift=1) if daily and bar.close[0] > daily.close: account.open_trade(...)

تجد دلالات shift الكاملة وتعداد Timeframe وتحفظات التشغيل الأمامي في بيانات OHLCV والأعمدة.

توقيت التنفيذ

  • bar["close"] في on_bar هو إغلاق عمود التنفيذ الحالي.
  • يأخذ account.open_trade / close_trade سعرًا مطلوبًا ثم يطبّقان نموذجي الانزلاق والعمولة الخاصين بالتشغيل. و**entry_price / exit_price** المخزَّنان هما أسعار التنفيذ؛ وتُحفظ الأسعار المطلوبة باسم raw_entry_price / raw_exit_price. ومع الانزلاق الافتراضي بحصة الحجم عادةً ما تختلف عمليات التنفيذ عن السعر الذي تمرّره.
  • لاستهداف إغلاق العمود من on_bar مرّر float(bar["close"]) (مع بقاء الانزلاق/العمولة مطبّقين).
  • للتنفيذ أثناء المحاكاة داخل العمود استدعِ من on_tick عندما يكون tick_in_bar == 3 — إذ يكون price إغلاق ذلك الرمز للصف.

on_init — التهيئة

تعمل مباشرة بعد أن يكون المحرك قد جهّز الحساب وحمّل بيانات السوق وبنى وقت التشغيل — لكن قبل معالجة أي عمود.

استخدمها من أجل:

  • تهيئة المتغيرات التي تحملها استراتيجيتك بين الأعمدة (عدّادات وآلات حالة وقيم معاملات).
  • ضبط المؤشرات أو مخازن التهيئة.
  • قراءة معاملات الإدخال لتقود بقية التشغيل.
def on_init(symbols=None): global lookback, position_size lookback = 20 position_size = 100

لا تملك وصولًا إلى عمود حالي في on_init — فالمحاكاة لم تبدأ بعد في هذه النقطة.

وسيط symbols (عمليات تشغيل الماسح فقط): عندما يستخدم الاختبار الرجعي مصدر رموز ماسح، يُعاد إطلاق on_init عند كل إعادة توازن مع symbols=<قائمة الرموز> للمجموعة الجديدة. يتيح هذا لاستراتيجيتك التفاعل مع مجموعة رموز جديدة دون إعادة تشغيل المحاكاة.

  • عند بدء التشغيل يُطلَق on_init مرتين متعاقبتين — مرة مع symbols=None (استدعاء الإعداد القياسي) ومرة مع symbols=<الرموز الأولية>.
  • لا تعيد عمليات الإطلاق اللاحقة ضبط الحالة على مستوى الوحدة؛ وأي متغيرات ضبطتها في الاستدعاء الأول ما زالت موجودة.
  • الاستراتيجيات التي تعرّف def on_init(): (بلا معامل) تعمل تمامًا كما كانت — إذ يطابق المحرك الوسائط بالاسم، فيُتجاهل المعامل الغائب ببساطة.

on_bar — مرة لكل عمود

تعمل مرة لكل عمود تنفيذ، قبل التيكات الأربعة داخل العمود لذلك العمود. هنا تتخذ معظم الاستراتيجيات قراراتها.

def on_bar(bar_index, bar, fundamentals=None, calendar=None, symbol=None): if bar.bars_back < 1: return if bar.close[0] > bar.close[1]: account.open_trade(...)

المعاملات:

  • bar_index — فهرس عمود التنفيذ الحالي المبدوء من الصفر.
  • bar — عرض العمود الحالي (OhlcvBarView). يتصرّف كخريطة للقراءة فقط (bar["open"] وbar["high"] وbar["low"] وbar["close"] وbar["volume"] وbar["t"]) ويعرض أيضًا السجل عبر الإزاحات: فـbar.close[0] إغلاق العمود الحالي وbar.close[1] إغلاق العمود السابق وهكذا. ويخبرك len(bar.close) وbar.bars_back بحجم السجل المتاح. وهو ليس dict عاديًا (isinstance(bar, dict) هو False).
  • fundamentals — لقطة البيانات الأساسية لهذا العمود، أو None إن لم تُضبط.
  • calendar — مقبض BacktestCalendar عند تفعيل Include calendar data، وإلا None (دائمًا None في عمليات التشغيل الأمامية). راجع بيانات التقويم للواجهة الكاملة. ولأن الوسائط تُطابَق بالاسم، فإن حذف هذا المعامل يترك دالة الاستدعاء كما هي.
  • symbol — سلسلة الرمز بأحرف كبيرة. مفيدة في استراتيجيات الرموز المتعددة؛ ويمكنك حذفها إن حمّلت رمزًا واحدًا فقط.

أنماط شائعة:

  • اتخاذ قرارات الدخول/الخروج عند إغلاق العمود: مرّر bar.close[0] (أو float(bar["close"])) إلى account.open_trade / account.close_trade.
  • حساب مؤشرات بسيطة بقراءة إزاحات مثل bar.close[0] وbar.close[1] …
  • تخطّي الأعمدة الأولى التي ليس لها سجل كافٍ (if bar.bars_back < N: return).

نصيحة: يعمل on_bar دائمًا قبل أي دوال استدعاء للتيك للعمود نفسه.


on_tick — تحديثات السعر داخل العمود والحية

لـon_tick التوقيع نفسه في الاختبار الرجعي والتشغيل الأمامي، لكن متى يُطلَق وماذا يعني price يعتمدان على وضع التشغيل.

الاختبار الرجعي (Test)

يعمل حتى أربع مرات لكل عمود، بعد on_bar، لمحاكاة الحركة داخل العمود. يمرّ المحرك على OHLC كل عمود بهذا الترتيب:

tick_in_barالمعنى
0افتتاح العمود
1أعلى العمود
2أدنى العمود
3إغلاق العمود

لا بيانات تيك حقيقية في الاختبار الرجعي. لا تحمّل عمليات التشغيل التاريخية سجل تيكات الوسيط. تستخدم الاستدعاءات الأربعة لكل عمود أسعارًا اصطناعية مشتقة من OHLC كل عمود فقط. يمكنك تقريب عمليات التنفيذ داخل العمود في المحاكاة، لكن سلوك on_tick في الاختبار الرجعي لن يطابق التيكات الأمامية الحية. ولقرارات إغلاق العمود يكفي on_bar — فـon_tick مع tick_in_bar == 3 يعادل التصرّف على إغلاق العمود في المحاكاة.

def on_tick(bar_index, tick_in_bar, price, bar, fundamentals=None, calendar=None, symbol=None): if tick_in_bar == 3: # Backtest simulation: closing tick fill account.close_trade(position_id, price)

استخدم on_tick الاختبار الرجعي عندما يهمّ التوقيت داخل العمود في المحاكاة — مثل التنفيذ عند تيك الإغلاق أو محاكاة إيقاف داخل العمود أو تقييم ملامسة أعلى العمود أو أدناه.

عمليات التشغيل الأمامية (أمامي على الرسم البياني، أمامي جماعي / QuantCloud)

في عمليات التشغيل الأمامية يعمل on_tick في كل مرة تتلقى فيها المنصة سعرًا من وسيطك المتصل ما دامت خوارزميتك مرتبطة. لا يوجد مسار OHLC ثابت من أربعة تيكات — إذ يعكس كل استدعاء تسعيرة حية.

def on_tick(bar_index, tick_in_bar, price, bar, fundamentals=None, calendar=None, symbol=None): # Forward run: react to each broker price update if price <= stop_level: account.close_trade(position_id, price)
  • price — أحدث تسعيرة وسيط لهذا الرمز.
  • bar — عرض العمود الحالي للسجل (الشكل نفسه كما في الاختبار الرجعي).
  • tick_in_bar — قد يبقى موجودًا لتوافق التوقيع؛ وفي عمليات التشغيل الأمامية فرّع بحسب price لا بحسب مراحل OHLC الاصطناعية.

استخدم on_tick الأمامي لـمنطق حيّ داخل العمود — إيقافات أو خروج متتبّع أو أي تفاعل مع العلامات بين إغلاقات الأعمدة.

المعاملات (في الوضعين)

  • bar_index — كما في on_bar.
  • tick_in_bar — في الاختبار الرجعي 0 أو 1 أو 2 أو 3 (خطوة OHLC اصطناعية). وفي عمليات التشغيل الأمامية لا تعتمد عليه لمنطق مرحلة العمود.
  • price — خطوة OHLC اصطناعية في الاختبار الرجعي؛ وتسعيرة وسيط حية في عمليات التشغيل الأمامية.
  • bar — عرض العمود نفسه كما في on_bar.
  • fundamentals و**calendar** و**symbol** — المعنى نفسه كما في on_bar.

إن كنت تحتاج في الاختبار الرجعي إلى قرارات إغلاق العمود فقط، فيمكنك تجاهل on_tick تمامًا ووضع منطقك في on_bar.


on_timer — دالة استدعاء دورية اختيارية (عمليات التشغيل الأمامية فقط)

الاختبار الرجعي في بيئة التطوير: لا تضبط نافذة Run backtest فاصل مؤقّت. وحتى لو عرّفت on_timer في ملف استراتيجيتك فإنها لا تُستدعى أثناء الاختبارات الرجعية في بيئة التطوير. ضع المنطق الدوري أو المبني على الوقت في on_bar أو on_tick للاختبارات الرجعية.

يمكن لـعمليات التشغيل الأمامية (اختبار أمامي على الرسم البياني، أمامي جماعي / QuantCloud) ضبط timerIntervalMs في نافذة تشغيلها. وعند ضبطه تعمل on_timer على فاصل زمني ثابت بين التيكات، فقط عند تحقق شرطين:

  1. ضبطتَ timer_interval_ms / timerIntervalMs للتشغيل (عدد صحيح موجب بالميلي ثانية).
  2. يعرّف ملفك دالة on_timer.
def on_timer(bar_index, tick_in_bar, price, bar, fundamentals=None, calendar=None, symbol=None): pass

للتوقيع الشكل نفسه كما في on_tick. استخدم on_timer للسلوكيات المبنية على الوقت (مثل: تحديث إشارة بطيئة كل دقيقة، أو جدولة فحص مستقل عن عدد الأعمدة). وإذا لم يُضبط timer_interval_ms فلن تُستدعى on_timer أبدًا حتى لو كانت معرَّفة.


بيانات التقويم في دوال الاستدعاء

عند تفعيل Include calendar data في علامة تبويب Symbol & data يمكن لأي دالة استدعاء تلقي مقبض BacktestCalendar بإضافة معامل calendar:

def on_bar(bar_index, bar, calendar=None, symbol=None): if calendar is None: # always guard — not every run enables calendar data return days = calendar.days_to_earnings(bar["t"], symbol) if days is not None and days <= 2: return # avoid trading into an earnings print divs = calendar.dividends(bar["t"], symbol) if divs and (divs[-1].amount or 0) > 0.5: # amount can be None ...

المقبض نفسه متاح في on_tick وon_timer — لكن بيانات التقويم للاختبار الرجعي فقط، لذا يكون calendar دائمًا None في عمليات التشغيل الأمامية. وكل عمليات البحث لحظية (point-in-time) — إذ يُرجع dividends(bar["t"], symbol) فقط التوزيعات التي كانت معلنة عند ذلك العمود، ولا يُرجع المستقبلية أبدًا.

الدوال الرئيسية:

الدالةتُرجع
dividends(bar_time, symbol=None)التوزيعات المعلنة عند ذلك العمود (الأقدم أولًا)
splits(bar_time, symbol=None)التجزئات المعلنة حتى ذلك العمود (الأقدم أولًا)
next_earnings(bar_time, symbol=None){date, basis, estimated, …} أو None
days_to_earnings(bar_time, symbol=None)int أو None
has(symbol=None)هل لهذا الرمز بيانات تقويم أصلًا

القوائم مرتبة الأقدم أولًا — فـ[-1] هو أحدث حدث. وهذا عكس البيانات الأساسية حيث الفهرس 0 هو أحدث فترة.

يحمل المتغير العام لوقت التشغيل qc_calendar المقبض نفسه إن فضّلت قراءته من quantcraft.process.runtime بدل وسيط دالة الاستدعاء.

راجع بيانات التقويم لمخططات حقول الأحداث وتفاصيل محاكاة الإجراءات المؤسسية واستكشاف الأخطاء.


on_finish — الإنهاء

تعمل مرة واحدة، بعد آخر عمود. استخدمها لحساب المخرجات النهائية أو بناء مؤشرات الرسم البياني أو طباعة ملخّص.

def on_finish(bars, symbol=None, bars_by_symbol=None): closes = [b["close"] for b in bars] bt.chart_indicators.add(...)

المعاملات:

  • bars — قائمة زمنية بقواميس OHLC لـرمز الساعة، الأقدم أولًا — النافذة المنفَّذة، وهي الصفوف نفسها التي يرسمها مخطط Test Results. لكل إدخال t وopen وhigh وlow وclose وvolume واختياريًا fundamentals. وهذه هي السلسلة المرجعية لكامل السجل في on_finish.
  • symbol — الرمز بأحرف كبيرة لرمز الساعة.
  • في تشغيل Screener لا يوجد رمز ساعة: تكون bars تساوي [] وsymbol تساوي ""، لذا استخدم bars_by_symbol.
  • bars_by_symbol — لعمليات التشغيل متعددة الرموز، قاموس يربط كل رمز بقائمة أعمدته الزمنية (محاذاة لساعة التنفيذ). وفي التشغيل برمز واحد يمكنك تجاهله.

استخدامات شائعة:

  • تسليم سلاسل المؤشرات إلى chart_indicators.add(...) لتظهر على رسوم النتائج. فضّل القيم التي راكمتها لكل رمز أثناء مرور التشغيل على الأعمدة؛ ولا تعِد الحساب من bars إلا للمؤشرات التي لم تتتبّعها لكل عمود — راجع سلاسل المؤشرات.
  • طباعة أو تسجيل ملخّص نهائي في لوحة المخرجات.
  • تحديث مقاييس المحفظة لحمولة النتيجة.

كل return في on_finish صامت. يظل التشغيل ناجحًا وتظل Test Results تُعرض — فالإرجاع المبكر يعني فقط أن سلاسلك أو مقاييسك لم تُرفق قط، دون أي خطأ. اطبع إلى sys.stderr عند كل حارس أثناء تصحيح الأخطاء؛ وتظهر الرسالة في لوحة المخرجات.


أساسيات الرموز المتعددة

يمكن لاستراتيجيات QuantCraft العمل على رمز واحد أو على عدة رموز معًا. تبقى دورة الحياة نفسها — ولا يتغير إلا قليلًا توقيعات دوال الاستدعاء والبيانات التي تتلقاها.

ضبط رموز متعددة

في علامة تبويب Symbol & data في Run backtest حدّد رمزًا واحدًا أو أكثر بأحرف كبيرة. تُحمَّل كل الرموز المدرجة وتُحاكى معًا.

رمز الساعة

عند تشغيل رموز متعددة يقود أحدها الساعة — إذ تحدد الطوابع الزمنية لأعمدته متى تعمل دوال الاستدعاء. وليس في نافذة Run backtest أي عنصر تحكم بالرمز الأساسي. ترتيب الحسم:

  1. SYMBOL = "AAPL" على المستوى الأعلى في ملف استراتيجيتك، إن كان ذلك الرمز في القائمة المحمَّلة.
  2. وإلا فأول رمز محمَّل.

مع مصدر رموز Screener لا يوجد رمز ساعة إطلاقًا — فمجموعة الرموز تتغير أثناء التشغيل. ويقرأ rt.get_bar دائمًا أعمدة رمز الساعة (ويُرجع None في تشغيل Screener)، لذا فلسجل رمز آخر استخدم إزاحات bar.close[i] الخاصة بذلك الرمز.

ورمز الساعة هو أيضًا ما يستخدمه on_finish(bars, symbol=...) لوسيطيه bars وsymbol.

دوال الاستدعاء لكل رمز

لكل عمود تنفيذ يمرّ المحرك على الرموز بترتيب القائمة:

  1. تعمل on_bar مرة لكل رمز محمَّل عند وقت هذا العمود (قبل أي تيك لذلك العمود).
  2. الاختبار الرجعي فقط: لكل tick_in_bar (0 = افتتاح، 1 = أعلى، 2 = أدنى، 3 = إغلاق) تعمل on_tick مرة لكل رمز على OHLC اصطناعي (دون بيانات تيك حقيقية).
  3. الاختبار الرجعي فقط: بعد جولات التيك الأربع، يقيّم tick(close_map) نهائي للحساب حقوق الملكية عند الإغلاق — وليس on_tick خامسًا.
  4. عمليات التشغيل الأمامية: تعمل on_tick عند كل تحديث سعر من الوسيط لكل رمز مع وصول التسعيرات من وسيطك المتصل (غير محصورة في أربعة استدعاءات لكل عمود). وعند حدود اليوم غالبًا ما يُطلَق on_tick ثم on_bar — فلا تفترض ترتيب الاختبار الرجعي.
  5. تتبع on_timer (في عمليات التشغيل الأمامية مع ضبط timerIntervalMs فقط — وليس في الاختبار الرجعي ببيئة التطوير) النمط نفسه لكل رمز بين التيكات.

وهذا يعني أن on_bar متعدد الرموز يُستدعى مثلًا ثلاث مرات لكل عمود إذا حمّلت ثلاثة رموز. استخدم المعامل symbol لمعرفة أي رمز يخصّه الاستدعاء:

def on_bar(bar_index, bar, fundamentals=None, calendar=None, symbol=None): if symbol == "AAPL": ... elif symbol == "MSFT": ...

يخصّ عرض bar دائمًا الرمز الذي استُدعيت له دالة الاستدعاء. وينطبق الأمر نفسه على price في on_tick.

المحاذاة "as-of". لكل وقت عمود تنفيذ يتلقى كل رمز أحدث عمود له عند ذلك الوقت أو قبله. والرمز الذي لا عمود له عند ذلك الوقت بالضبط (إيقاف تداول أو دقيقة مفقودة أو تقويم تداول مختلف) يتلقى عموده السابق مجددًا. وإن كنت تعدّ الأعمدة أو الإشارات لكل رمز فتخطَّ التكرارات بتذكّر آخر bar["t"] رأيته لذلك الرمز:

_last_t = {} def on_bar(bar_index, bar, fundamentals=None, calendar=None, symbol=None): if _last_t.get(symbol) == bar["t"]: return # same bar as last step for this ticker _last_t[symbol] = bar["t"] ...

on_finish للرموز المتعددة

تظل on_finish تعمل مرة واحدة في النهاية. وللعمل مع سجل كل الرموز استخدم bars_by_symbol:

def on_finish(bars, symbol=None, bars_by_symbol=None): if bars_by_symbol: for ticker, ticker_bars in bars_by_symbol.items(): ...

جمع كل شيء معًا

استراتيجية نموذجية برمز واحد:

  1. تضبط معاملات الإدخال أو أي حالة أخرى في on_init.
  2. تقرأ سجل الأسعار (OHLCV) عبر bar.close[0] و**bar.close[1]** … في on_bar لاتخاذ قرارات التداول، وتستدعي account.open_trade / account.close_trade.
  3. تستخدم اختياريًا on_tick — في الاختبار الرجعي لعمليات تنفيذ اصطناعية داخل العمود (مثل tick_in_bar == 3 لتيك الإغلاق)؛ وفي عمليات التشغيل الأمامية للتفاعل مع أسعار الوسيط الحية بين إغلاقات الأعمدة.
  4. تستخدم اختياريًا on_timer في عمليات التشغيل الأمامية عند ضبط timerIntervalMs (غير متاحة في Run backtest ببيئة التطوير).
  5. تبني مؤشرات الرسم وتنهي النتائج في on_finish باستخدام bars.

تستخدم استراتيجية الرموز المتعددة دوال الاستدعاء نفسها، لكنها تتفرع بحسب وسيط symbol داخلها وتقرأ بيانات كل رمز عبر bar الذي تتلقاه — وعبر bars_by_symbol في on_finish.

تحتاج إلى مزيد من التفاصيل؟ راجع نموذج الحساب والبيانات الأساسية وعوامل فاما-فرينش وبيانات OHLCV والأعمدة وسلاسل المؤشرات، أو علامة التبويب Documentation المدمجة في الشريط الجانبي الأيمن (تخطيط مساحة العمل).

15 دقائق للقراءةاقترح تعديلًا ↗
دورة حياة الاستراتيجية — الوثائق (1.0 (latest)) | QuantCraft