الوثائق1.0 (latest)
الصفحاتبيانات OHLCV والأعمدة · 10 / 29

بيانات OHLCV والأعمدة

تحتاج الاختبارات الرجعية في QuantCraft إلى شموع OHLCV (الافتتاح والأعلى والأدنى والإغلاق والحجم) لكل رمز تتداوله. يحمّل المحرك هذه البيانات قبل تشغيل استراتيجيتك، ثم يشغّل دوال دورة حياة استراتيجيتك مع عرض للعمود الحالي (bar) في كل خطوة. وفي نهاية التشغيل يمكنك اختياريًا العمل مع السلسلة الكاملة الممرَّرة إلى on_finish(bars, …). اضبط التحميل من Test (تشغيل الشيفرة).

تغطي هذه الصفحة مصدر البيانات (المحمِّلات) وكيفية عمل نطاقات التواريخ والتهيئة وكيفية استخدام وسيط السلسلة الكاملة bars في on_finish. اقرنها مع البيانات الأساسية عند الجمع بين الأسعار وبيانات الإيداعات؛ وراجع نموذج الحساب لمعرفة كيف ترتبط الصفقات بالأسعار.


المحمِّلات (مصادر البيانات)

في علامة تبويب Symbol & data في Run backtest تختار مصدر الأسعار. يستخدم المحرك أحد محمِّلين خلف الكواليس:

مصدر الوسيط المتصل

  • يحمّل الشموع من حساب الوسيط المتصل باستخدام مفتاح API والسر الخاصين بك، أو عبر اتصال مرتبط بـ OAuth بمعرّف ربط صالح.
  • يدعم الأسهم الأمريكية والعملات المشفرة (تختار نوع الأصل في النافذة).
  • يدعم أطرًا زمنية كثيرة — اليومي والأسبوعي والساعي و4 ساعات وعدة أعمدة دقائق خلال اليوم (متوافقة مع تسميات الأطر الزمنية لرسم التطبيق).
  • يُجلب السجل على دفعات حتى يُستوفى النطاق المطلوب (أو حتى بلوغ حد أدنى من الأعمدة عند استخدام الوضع القديم "بلا تواريخ صريحة").

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

تخزين QuantCraft (مستضاف)

  • يحمّل الشموع من التخزين المستضاف لدى QuantCraft عندما تكون مسجّلًا للدخول (يرسل التطبيق رمز جلستك).
  • تُنظَّم الملفات بحسب الرمز والإطار الزمني. وفي الخطة المجانية تعرض نافذة الاختبار الرجعي اليومي والأسبوعي والشهري؛ ويفتح Premium الإطار خلال اليوم والأطر الموسّعة.
  • يُجلب الملف كاملًا ثم يُصفّى اختياريًا إلى نطاق التواريخ التقويمية الذي اخترته.
  • تحمل الأعمدة اليومية t بتاريخ فقط مثل "2024-01-02"، يُقرأ بتوقيت UTC.

رموز الأطر الزمنية في QuantCraft B2: 1s و1m و2m وm5 و15m و30m وh1 و2h و4h وd وw وm وq وy. انتبه: m تعني شهري لا دقائق — الدقيقة الواحدة 1m والخمس دقائق m5.

إذا لم يكن في نطاق التواريخ أي أعمدة يفشل التحميل برسالة مثل No AAPL bars (d) between 2010-01-01 and 2010-02-01. Available range is … to … — adjust the backtest dates.

استخدم تخزين QuantCraft عندما تكون مسجّلًا للدخول دون بيانات اعتماد وسيط، أو عندما تريد حزم OHLCV مستضافة من كتالوج رموز QuantCraft (5 دقائق أو ساعي أو يومي أو أسبوعي أو شهري).

الاختيار بينهما

الحاجةالاختيار المعتاد
المجموعة الكاملة خلال اليوم من الوسيط المتصل (1m و5m و15m و30m و1H و4H …)مصدر الوسيط المتصل
5 دقائق أو ساعي من كتالوج QuantCraftتخزين QuantCraft
يومي / أسبوعي / شهري من ملفات مستضافةتخزين QuantCraft
حساب وسيط متصل + مفاتيحمصدر الوسيط المتصل
وصول بتسجيل دخول دون بيانات اعتماد وسيطتخزين QuantCraft

في دوال استدعاء الاستراتيجية اقرأ الأسعار من الكائن bar الذي يمرّره المحرك إليك — لا من كائن OHLCV عام وحيد. في بيئة التطوير غالبًا ما يكون qc_ohlcv على مستوى الوحدة غير مضبوط عند تحميل ملفك؛ والاعتماد عليه قد يكسر الشيفرة. وهو أيضًا None في تشغيل بهدف ماسح، وحيث يكون مضبوطًا فإنه يمتد على النطاق المحمَّل بأكمله بما فيه التهيئة — لا على النافذة المنفَّذة التي يرسمها الرسم البياني — فهو المصدر الخطأ لسلاسل الرسم البياني. أما العرض bar فصحيح دائمًا لخطوة المحاكاة الحالية.


النطاقات الزمنية

تتحكم في الأعمدة المشاركة في الاختبار الرجعي بواسطة تاريخ البدء وتاريخ الانتهاء واختياريًا التهيئة.

النطاق التقويمي (start_date + end_date)

عندما تضبط التاريخين معًا في علامة تبويب Simulation (الصيغة YYYY-MM-DD، وتُفسَّر كـأيام تقويمية UTC):

  • يحتفظ المحرك فقط بالأعمدة الواقعة في تلك النافذة.
  • يُعامَل النطاق كفترة نصف مفتوحة: من بداية يوم البدء حتى نهاية يوم الانتهاء وفق عُرف المنتج المعتاد (تُضمَّن أعمدة اليوم التقويمي الأخير بحسب ضبط المحرك).

مصدر الوسيط المتصل: تُطلب الشموع لتلك الفترة التقويمية.

تخزين QuantCraft: تُنزَّل السلسلة الكاملة للملف ثم تُصفّى إلى نافذة الأيام التقويمية نفسها.

إذا أغفلت التاريخين معًا:

  • يستخدم مصدر الوسيط المتصل تتبعًا قديمًا إلى الخلف: يرجع المحرك في الزمن حتى يحمّل سجلًا كافيًا (مع مراعاة حدود الإطار الزمني)، بدل نافذة تقويمية كتبتها أنت.
  • يستخدم تخزين QuantCraft كل أعمدة الملف (دون مرشّح إضافي).

أعمدة التهيئة (warmup_bars)

عدد صحيح غير سالب اختياري: أعمدة إضافية تُحمَّل قبل تاريخ بدئك لتتمكن المؤشرات من النظر إلى الوراء دون نفاد السجل.

  • تظهر أعمدة التهيئة عبر bar.close[1] و**bar.close[2]** … و**bar.bars_back** في أول عمود تنفيذ.
  • تظل on_bar / on_tick / on_timer تعمل فقط داخل نافذة التنفيذ التي اخترتها — فالتهيئة للسجل فقط، لا تضيف "أيام تداول" محاكاة إضافية إلى النتيجة.

bar_index مقابل التقويم

  • bar_index يعدّ أعمدة التنفيذ فقط (أول عمود داخل نطاقك المحدد هو 0 ثم 1 …). ولا يعدّ أعمدة التهيئة فقط.
  • تُحاكى الأعمدة من الأقدم إلى الأحدث داخل نافذة التنفيذ.

بيانات العمود داخل دوال الاستدعاء (bar)

في كل on_bar و**on_tick** (و**on_timer** في عمليات التشغيل الأمامية عند ضبطه) يمرّر المحرك bar: عرض عمود OHLC (OhlcvBarView) للرمز الذي تخصه دالة الاستدعاء. ويتصرّف كخريطة للقراءة فقط، لكن isinstance(bar, dict) خاطئ — استخدم bar["close"] أو الوصول بالسمات لا واجهات dict وحدها.

في الاختبار الرجعي يتلقى on_tick أسعارًا اصطناعية من OHLC كل عمود (أربعة استدعاءات لكل عمود، دون سجل تيكات حقيقي). وفي عمليات التشغيل الأمامية يُطلَق on_tick مع كل تسعيرة حيّة من الوسيط المتصل بينما يتتبع الوسيط price أحدث علامة — راجع دورة حياة الاستراتيجية.

يمكنك استخدامه كخريطة للقراءة فقط:

o = float(bar["open"]) h = float(bar["high"]) l = float(bar["low"]) c = float(bar["close"]) v = float(bar["volume"]) t = bar["t"] # ISO timestamp string (QuantCraft B2 daily bars: a date like "2024-01-02", UTC)

ويمكنك أيضًا قراءة السجل بالنسبة إلى العمود الحالي بالفهرسة بالإزاحة (العمود نفسه وإغلاقات سابقة وهكذا):

current_close = bar.close[0] prev_close = bar.close[1]
  • bar.close[0] هو إغلاق سياق العمود الحالي (الفكرة نفسها كـ float(bar["close"]) في on_bar الاختبار الرجعي) — راجع فهارس الأعمدة في on_bar مقابل on_tick لمعرفة أي عمود هو في كل دالة.
  • الفهارس الأكبر تمشي إلى الوراء في الزمن؛ و**bar.bars_back** يخبرك إلى أي مدى يمكنك النظر.

فهارس الأعمدة في on_bar مقابل on_tick

الإزاحات مثل bar.close[0] وbar.close[1] … تُعدّ دائمًا إلى الوراء بدءًا من أحدث عمود تستطيع الدالة رؤيته — لكن أي عمود هو "الأحدث" يعتمد على الدالة:

مخطط لثلاث شموع مغلقة وشمعة قيد التكوّن. في on_bar تكون الشمعة التي أُغلقت للتو هي العمود 0 والشموع الأقدم هي العمودان 1 و2. وفي on_tick تكون الشمعة قيد التكوّن هي العمود 0 والشمعة التي أُغلقت للتو هي العمود 1 والشموع الأقدم هي العمودان 2 و3.

  • يُطلَق on_bar عندما يُغلق عمود. الفهرس [0] هو ذلك العمود الذي أُغلق للتو، و[1] العمود الذي قبله، و[2] الذي قبله، وهكذا. كل فهرس يشير إلى عمود مكتمل.
  • يُطلَق on_tick بينما العمود ما زال قيد التكوّن. الفهرس [0] هو العمود قيد التكوّن (تتغير قيمه مع كل تيك)، و**[1] هو آخر عمود مغلق**، و[2] الذي قبله، وهكذا.

فالشمعة نفسها تقع في فهرس أعلى بواحد في on_tick عنها في on_bar:

الشمعةفي on_barفي on_tick
قيد التكوّن (لم تُغلق بعد)غير مرئية[0]
أُغلقت للتو[0][1]
التي قبلها[1][2]
قبلها باثنتين[2][3]
def on_bar(bar_index, bar, fundamentals=None, symbol=None): last_closed = bar.close[0] # the bar that just closed one_before = bar.close[1] def on_tick(bar_index, tick_in_bar, price, bar, fundamentals=None, symbol=None): forming = bar.close[0] # still forming — latest price so far last_closed = bar.close[1] # same candle on_bar saw as [0]

ينطبق الإزاحة نفسها على كل سلسلة في العرض (open وhigh وlow وclose وvolume). وإذا نقلت منطقًا من on_bar إلى on_tick فـأضف 1 إلى كل إزاحة لتواصل قراءة الشموع نفسها.

الاختبار الرجعي: يعيد on_tick تشغيل العمود الحالي كأربعة تيكات اصطناعية، لذا فإن [0] هناك هو العمود المحاكى، يُقرأ من صفّه الكامل (راجع الحجم عند [0] أدناه) — وليس شمعة مبنية جزئيًا كما في التشغيل الأمامي.

دقة البيانات الحيّة (عمليات التشغيل الأمامية)

تدفق الأسعار الحي من وسيطك تقريب، لا سجل كامل للسوق:

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

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

الفهرسما هوالاستخدام
bar.close[0]الشمعة قيد التكوّن، مبنية من تيكات حيةتقدير السعر الحالي
bar.close[1]العمود الذي أُغلق للتو — قد يبقى مبنيًا من التيكات في أول ~10–30 ثانيةاستخدمه بحذر بعد فتح عمود جديد مباشرةً
bar.close[2]عمود مُنجَز بالكاملالإشارات التي تحتاج إغلاقًا مؤكدًا

للإشارات التي تعتمد على إغلاق مؤكد في أعمدة الدقيقة الواحدة فضّل bar.close[2].

الحجم عند [0]:

  • on_tick في التشغيل الأمامي: volume[0] في الشمعة قيد التكوّن مؤقت (غالبًا حجم تيك واحد). استخدم volume[1] لحجم آخر عمود مكتمل.
  • الاختبار الرجعي: تستخدم التيكات الاصطناعية الأربعة الصف الكامل للعمود — volume[0] هو حجم العمود الكامل لا حجم تيك مؤقتًا.

هذا هو المكان المناسب لمنطق التداول لكل خطوة: الدخول والخروج عند إغلاق العمود والمتوسطات المتحركة البسيطة وكل ما يحتاج العمود الحالي فقط مع النظر إلى الوراء.


الإطار الزمني الأساسي والإطارات الإضافية (get_bar)

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

from quantcraft import Timeframe import quantcraft.runtime as rt def on_bar(bar_index, bar, fundamentals=None, symbol=None): # Primary TF works without listing it under Additional timeframes # (use the Timeframe member that matches the modal primary, e.g. M5): prev_primary = rt.get_bar(Timeframe.M5, shift=1) daily = rt.get_bar(Timeframe.DAILY, shift=1) if daily and bar.close[0] > daily.close: ... # primary bar closed above yesterday's daily close

اضبط Additional timeframes في الاختبارات الرجعية؛ واحفظ الاختيارات في إعدادات التشغيل المسبقة (.qcs) ضمن secondaryTimeframes.

حقول BarSnapshot

يُرجع get_bar كائن BarSnapshot (أو None) فيه: open وhigh وlow وclose وvolume وt.

دلالات shift

shift.close.high / .low / .open
0سعر التنفيذ الحالي — متطابق عبر كل الأطر الزمنية في دالة الاستدعاء نفسها (الاختبار الرجعي؛ راجع ملاحظة التشغيل الأمامي أدناه)من العمود المخزَّن لذلك الإطار — غير موحّد مع الإطار الأساسي
>= 1إغلاق العمود المكتمل في ذلك الإطارOHLC الكامل للعمود المكتمل — مفضَّل لفتائل الشمعة السابقة

الاختبار الرجعي: لا يرى get_bar إلا الأعمدة حتى خطوة المحاكاة الحالية — لا اللاحقة أبدًا — في الإطار الأساسي وفي كل إطار إضافي. عند shift=0 تُحاذى high/low الثانوية زمنيًا مع ساعة المحاكاة لكل إطار. ويقرأ get_bar أعمدة رمز الساعة؛ وفي التشغيل متعدد الرموز استخدم bar.close[i] الخاص بكل رمز لسجله.

التشغيل الأمامي: يتبع bar الأساسي الإطار الزمني في شريط أدوات الرسم البياني. وتتحدّث المخازن الثانوية عندما يكتمل عمود في تدفّق ذلك الإطار — وقد تتأخر high/low عند shift=0 إلى أن تكتمل تلك الحزمة؛ فضّل shift=1 للحصول على OHLC موثوق للعمود السابق. و.close عند shift=0 في التشغيل الأمامي هو آخر إغلاق خاص بكل مخزن، غير موحّد عبر الأطر. وفي on_tick قد يكون volume[0] للعمود الأساسي مؤقتًا (ما زال قيد التكوّن).

يُرجع None عندما لا يكون لذلك الإطار مخزن للتشغيل (ليس الأساسي وغير محدد ضمن Additional timeframes)، أو في اختبار رجعي Screener (لا رمز ساعة — استخدم إزاحات bar.close[i] الخاصة بكل رمز للسجل)، أو عندما تكون البيانات غير متاحة. استثناء واحد في الاختبار الرجعي: shift=0 على إطار لم تحدده يُرجع اللقطة الحالية للإطار الأساسي بدل None.

يمكن أن يكون tf عضوًا في Timeframe أو سلسلة مثل "1D" / "5Min".

التعداد Timeframe

استورده بـ from quantcraft import Timeframe:

العضوالقيمة النصيةالوصف
M1"1Min"أعمدة دقيقة واحدة
M5"5Min"أعمدة 5 دقائق
M15"15Min"أعمدة 15 دقيقة
M30"30Min"أعمدة 30 دقيقة
H1"1Hour"أعمدة ساعية
H4"4Hour"أعمدة 4 ساعات
DAILY"1D"أعمدة يومية
WEEKLY"1Week"أعمدة أسبوعية

بعض أطر QuantCraft B2 الزمنية (دقيقتان وساعتان وثانية واحدة والشهري m والربع سنوي q والسنوي y) ليس لها عضو في Timeframe — مرّرها إلى get_bar كسلاسل نصية.


السلسلة الكاملة الاختيارية: on_finish(bars, …)

عند انتهاء المحاكاة يستدعي المحرك on_finish مرة واحدة. وإذا عرّفت استراتيجيتك التوقيع الموسّع فإنك تتلقى صفوف OHLC كاملة السلسلة للمعالجة اللاحقة — مؤشرات على كامل التشغيل وتصدير السلاسل والعلامات النهائية لـ refresh_metrics وغيرها.

def on_finish(bars, symbol=None, bars_by_symbol=None): ...

bars — رمز الساعة، الأقدم أولًا

  • bars هي list من القواميس لـرمز الساعة (SYMBOL في النص إن كان ذلك الرمز محمَّلًا، وإلا فأول رمز محمَّل — فالنافذة بلا عنصر تحكم بالرمز الأساسي). وفي تشغيل Screener لا يوجد رمز ساعة: bars تساوي [] وsymbol تساوي ""، لذا استخدم bars_by_symbol.
  • الترتيب زمني: أقدم عمود أولًا والأحدث أخيرًا — عكس عُرف الفهرس [0] = الأحدث في QcOhlcv بواجهات نمط الدفاتر.
  • يتضمن كل صف على الأقل open و**high** و**low** و**close** و**volume** و**t** عند وجود الطوابع الزمنية. وعند تفعيل البيانات الأساسية قد تتضمن الصفوف أيضًا لقطة fundamentals لذلك العمود.

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

def on_finish(bars, symbol=None, bars_by_symbol=None): if not bars: return closes = [float(b["close"]) for b in bars] last = float(bars[-1]["close"]) sym = (symbol or "AAPL").strip().upper() metrics = account.refresh_metrics({sym: last}) chart_indicators.add(...)

استخدم bars[-1]["close"] (أو حقول الصف الأخير) علامةً نهائية عند استدعاء account.refresh_metrics({symbol: last_price}) لتُقيَّم المراكز المفتوحة في نهاية التشغيل.

بالنسبة إلى chart_indicators فضّل القيم التي راكمتها لكل رمز أثناء مرور التشغيل على الأعمدة، واستخدم on_finish لتسليمها فقط؛ ولا تعِد الحساب من bars إلا للمؤشرات التي لم تتتبّعها عمودًا بعمود — راجع سلاسل المؤشرات.

bars_by_symbol — عمليات التشغيل متعددة الرموز

عندما تجري اختبارًا رجعيًا على أكثر من رمز تظل bars تشير إلى رمز الساعة فقط. وللسلسلة الكاملة المحاذاة لكل رمز استخدم bars_by_symbol:

  • خريطة من الرمز بأحرف كبيرة ← قائمة بالشكل نفسه كـ bars (قواميس زمنية لكل رمز).
  • استخدمها حين تحتاج إلى سجلات كاملة مقطعية أو لكل رمز عند الانتهاء (الارتباط والقوة النسبية والمؤشرات لكل رمز).

متى لا تحتاج إلى on_finish

إذا كانت استراتيجيتك تحتاج فقط إلى العمود الحالي وإزاحات النظر إلى الوراء فيمكنك تنفيذ on_bar / on_tick فقط وتجنّب عمل السلسلة الكاملة الثقيل. on_finish اختياري للمنطق — لكنه يبقى المكان الذي تُسلَّم فيه سلاسل chart_indicators والذي يتلقى فيه refresh_metrics آخر سعر. لاحظ أن كل return في on_finish صامت: يظل التشغيل ناجحًا، ويتخطى فقط ما كان بعده.


كيف يرتبط هذا بـ Test Results

تتضمن نتيجة الاختبار الرجعي المنظّمة قائمة ohlcv.bars (أو ما يعادلها): صفًّا لكل خطوة تنفيذ محاكاة، بحقول OHLC ولقطات fundamentals اختيارية — محاذاة لما رأيته في دوال الاستدعاء. و**on_finish(bars, …)** هي السلسلة الزمنية نفسها التي يستخدمها المحرك لحسابات "التشغيل الكامل" لرمز الساعة، فتطابق شيفرة نهاية التشغيل لديك ما يظهر في النتائج والرسوم.


مرجع سريع

الموضوعملخص للمستخدم
المحمِّلاتمصدر الوسيط المتصل (مفاتيح + نطاق واسع خلال اليوم) مقابل تخزين QuantCraft (بتسجيل دخول؛ يومي / أسبوعي / شهري، وأكثر مع Premium).
التواريخبدء + انتهاء YYYY-MM-DD ← نافذة مصفّاة بالتقويم؛ إغفال الاثنين ← تتبع قديم لمصدر الوسيط أو الملف الكامل لتخزين QuantCraft.
التهيئةسجل إضافي قبل البدء لـإزاحات bar؛ دوال الاستدعاء داخل نافذة التنفيذ فقط.
لكل خطوةاستخدم bar / bar["close"] / bar.close[k] في on_bar / on_tick. [0] = آخر عمود مغلق في on_bar، والعمود قيد التكوّن في on_tick.
الأطر الأساسية / الإضافيةالأساسي دائمًا عبر rt.get_bar؛ والإضافية عبر Additional timeframes + rt.get_bar(Timeframe.X, shift).
السلسلة الكاملةاستخدم on_finish(bars, symbol=..., bars_by_symbol=...) — bars الأقدم أولًا لرمز الساعة؛ و**bars_by_symbol** لكل الرموز في التشغيل متعدد الرموز.
عوائد العوامل العالميةليست على QcOhlcv ولا على bar — استخدم عوامل فاما-فرينش (fama_french.qc). rows الشهرية قاموس YYYYMM؛ استخدم latest_row لا rows[0].
13 دقائق للقراءةاقترح تعديلًا ↗
بيانات OHLCV والأعمدة — الوثائق (1.0 (latest)) | QuantCraft