الصفحاتدورة حياة الاستراتيجية · 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_french | QcFamaFrench اختياري عند تحميل عوامل فاما-فرينش العالمية؛ فضّل fama_french.qc في دوال الاستدعاء — راجع عوامل فاما-فرينش |
qc_calendar | BacktestCalendar | 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 على فاصل زمني ثابت بين التيكات، فقط عند تحقق شرطين:
- ضبطتَ
timer_interval_ms/timerIntervalMsللتشغيل (عدد صحيح موجب بالميلي ثانية). - يعرّف ملفك دالة
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 أي عنصر تحكم بالرمز الأساسي. ترتيب الحسم:
SYMBOL = "AAPL"على المستوى الأعلى في ملف استراتيجيتك، إن كان ذلك الرمز في القائمة المحمَّلة.- وإلا فأول رمز محمَّل.
مع مصدر رموز Screener لا يوجد رمز ساعة إطلاقًا — فمجموعة الرموز تتغير أثناء التشغيل. ويقرأ rt.get_bar دائمًا أعمدة رمز الساعة (ويُرجع None في تشغيل Screener)، لذا فلسجل رمز آخر استخدم إزاحات bar.close[i] الخاصة بذلك الرمز.
ورمز الساعة هو أيضًا ما يستخدمه on_finish(bars, symbol=...) لوسيطيه bars وsymbol.
دوال الاستدعاء لكل رمز
لكل عمود تنفيذ يمرّ المحرك على الرموز بترتيب القائمة:
- تعمل
on_barمرة لكل رمز محمَّل عند وقت هذا العمود (قبل أي تيك لذلك العمود). - الاختبار الرجعي فقط: لكل
tick_in_bar(0= افتتاح،1= أعلى،2= أدنى،3= إغلاق) تعملon_tickمرة لكل رمز على OHLC اصطناعي (دون بيانات تيك حقيقية). - الاختبار الرجعي فقط: بعد جولات التيك الأربع، يقيّم
tick(close_map)نهائي للحساب حقوق الملكية عند الإغلاق — وليسon_tickخامسًا. - عمليات التشغيل الأمامية: تعمل
on_tickعند كل تحديث سعر من الوسيط لكل رمز مع وصول التسعيرات من وسيطك المتصل (غير محصورة في أربعة استدعاءات لكل عمود). وعند حدود اليوم غالبًا ما يُطلَقon_tickثمon_bar— فلا تفترض ترتيب الاختبار الرجعي. - تتبع
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():
...جمع كل شيء معًا
استراتيجية نموذجية برمز واحد:
- تضبط معاملات الإدخال أو أي حالة أخرى في
on_init. - تقرأ سجل الأسعار (OHLCV) عبر
bar.close[0]و**bar.close[1]** … فيon_barلاتخاذ قرارات التداول، وتستدعيaccount.open_trade/account.close_trade. - تستخدم اختياريًا
on_tick— في الاختبار الرجعي لعمليات تنفيذ اصطناعية داخل العمود (مثلtick_in_bar == 3لتيك الإغلاق)؛ وفي عمليات التشغيل الأمامية للتفاعل مع أسعار الوسيط الحية بين إغلاقات الأعمدة. - تستخدم اختياريًا
on_timerفي عمليات التشغيل الأمامية عند ضبطtimerIntervalMs(غير متاحة في Run backtest ببيئة التطوير). - تبني مؤشرات الرسم وتنهي النتائج في
on_finishباستخدامbars.
تستخدم استراتيجية الرموز المتعددة دوال الاستدعاء نفسها، لكنها تتفرع بحسب وسيط symbol داخلها وتقرأ بيانات كل رمز عبر bar الذي تتلقاه — وعبر bars_by_symbol في on_finish.
تحتاج إلى مزيد من التفاصيل؟ راجع نموذج الحساب والبيانات الأساسية وعوامل فاما-فرينش وبيانات OHLCV والأعمدة وسلاسل المؤشرات، أو علامة التبويب Documentation المدمجة في الشريط الجانبي الأيمن (تخطيط مساحة العمل).

