الصفحاتبيانات التقويم · 13 / 29
وحدة التقويم
تمنح وحدة التقويم استراتيجيتك سجل توزيعات الأرباح وسجل التجزئات ومواعيد الأرباح وتاريخ الاكتتاب العام وأحدث إيداعات SEC لشركة ما — وتتيح للاختبار الرجعي تطبيق التجزئات وتوزيعات الأرباح على مراكزك تلقائيًا.
فعّل Include calendar data في علامة تبويب Symbol & data بنافذة Run backtest. وهو مفعّل افتراضيًا، ويُحفظ اختيارك (مع الخيارين الفرعيين) للتشغيل التالي. تُحمَّل التقاويم تلقائيًا لكل رمز يتداوله التشغيل، بما في ذلك عالم يحدّده ماسح — ولا يوجد منتقٍ لكل رمز. ولنافذة Test الخاصة بالوكيل الخيار نفسه — Include calendar data (dividends, splits) (راجع الوكلاء).
الاختبارات الرجعية فقط. تُحمَّل بيانات التقويم للاختبارات الرجعية وDebug Test واختبارات الوكلاء. أما عمليات التشغيل الأمامي — اختبارات chart forward وعمليات bulk في AutoTrading وQuantCloud — فلا تحصل على تقويم أبدًا، لذا تكون calendar فيها دائمًا None.
لماذا يهم: أعمدة الأسعار خام
شموع الاختبار الرجعي غير معدّلة. فبدون بيانات التقويم:
- يبدو تجزئة 4 إلى 1 كأنه انهيار بنسبة 75% في السعر بين ليلة وضحاها، وينهار مركزك المحاكى معه.
- لا تصل توزيعات الأرباح أبدًا، مما يقلّل بهدوء من العائد الإجمالي لأي مركز يُحتفظ به طويلًا — نحو 2% سنويًا لدافع أرباح نموذجي.
ويصلح الخياران الفرعيان كليهما دون الحاجة إلى أي تغيير في الشيفرة.
معامل دالة الاستدعاء calendar
أضف معامل 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 # sit out the earnings print
divs = calendar.dividends(bar["t"], symbol)
if divs and (divs[-1].amount or 0) > 0.5: # amount can be None
...يعمل في on_bar وon_tick وon_timer. ويُطابَق وسيط calendar بالاسم، فيتصرف النص الذي لا يحتوي معامل calendar تمامًا كما كان، ويتلقى calendar المُصرَّح عنه إما المقبض أو None — ولا يتلقى كائنًا آخر أبدًا، أيًّا كان ما يقبله توقيعك. وإذا كنت تقرأ البيانات الأساسية أيضًا، فالتوقيع الموصى به هو def on_bar(bar_index, bar, fundamentals=None, calendar=None, symbol=None).
ويمكنك أيضًا الوصول إلى المقبض نفسه دون معامل: المتغير العام في النص qc_calendar أو quantcraft.process.runtime.qc_calendar.
الدوال
| الدالة | تُرجع |
|---|---|
dividends(bar_time, symbol=None) | توزيعات الأرباح المعلنة عند ذلك العمود |
splits(bar_time, symbol=None) | التجزئات المعلنة حتى ذلك العمود |
filings(bar_time, symbol=None) | إيداعات SEC المعلنة عند ذلك العمود |
next_earnings(bar_time, symbol=None) | {date, basis, estimated, …} أو None |
days_to_earnings(bar_time, symbol=None) | int أو None |
ipo_date(symbol=None) | date أو None |
current(bar_time, symbol=None) | قاموس لقطة بكل ما سبق عند ذلك العمود، أو None |
dividends_between(start, end, symbol=None) | توزيعات الأرباح التي يقع تاريخ الاستحقاق (ex-date) لها في (start, end] |
splits_between(start, end, symbol=None) | التجزئات التي يقع تاريخ سريانها في (start, end] |
has(symbol=None) | هل لهذا الرمز بيانات تقويم أصلًا |
symbols / primary_symbol() / get(symbol=None) | الرموز المحمَّلة والافتراضي والتقويم الخام لكل رمز (أو None) |
تستخدم دوال _between تواريخ التأثير («متى يمسّ ذلك مركزي؟»)، بخلاف دوال وقت العمود أعلاه التي تستخدم تواريخ «هل كان بإمكاني أن أعرف؟» — راجع القسم التالي.
يقبل bar_time القيم bar["t"] وbar.t[0] وdatetime وdate أو ثواني epoch.
القوائم مرتبة من الأقدم إلى الأحدث — dividends(...)[-1] هي الأحدث. وهذا عكس البيانات الأساسية التي يكون فيها الفهرس 0 هو أحدث فترة.
الرمز الذي لا بيانات تقويم له يُرجع [] أو None، ولا يُرجع خطأً أبدًا. ومعظم الرموز خارج الشركات الكبرى ليس لها تقويم على الخادم، فتحقق من الفراغ بدل توقّع الاستثناءات.
تاريخان لكل حدث — استخدم الصحيح
يحمل كل توزيع أرباح وكل تجزئة تاريخين، واختيار الخاطئ منهما يُدخل انحياز النظر المسبق:
| «هل كان بإمكاني أن أعرف؟» | «متى يؤثر في مركزي؟» | |
|---|---|---|
| توزيع الأرباح | declaration_date | ex_date |
| التجزئة | filing_date | effective_date |
تصفّي dividends() / splits() / filings() بحسب العمود الأول — فتُرجع فقط ما كان معلنًا عند عمودك. وغالبًا ما تكون التجزئة مرئية قبل أسابيع من سريانها، لأن النموذج 8-K يُودَع مسبقًا:
from datetime import date
bar_date = date.fromisoformat(str(bar["t"])[:10])
splits = calendar.splits(bar["t"], symbol)
upcoming = [s for s in splits
if s.effective_date and s.effective_date > bar_date] # announced, not yet effectiveحقول الأحداث
DividendEvent: ex_date, amount, estimated, type, declaration_date,
record_date, payment_date, period_end
SplitEvent: effective_date, ratio, type ("forward" | "reverse"), filing_date, form
FilingEvent: form, filing_date, report_date, items, category,
accession_number, primary_document, primary_document_description
IpoInfo: date, first_trade_date, sourceيمكن أن تكون amount (توزيعات الأرباح) وeffective_date (التجزئات) None — تحقق قبل المقارنة.
تكون category الخاصة بالإيداع إحدى القيم: earnings وacquisition وofficer-director وcharter-amendment وagreement وregulation-fd وauditor-change وshareholder-vote وcybersecurity وother.
العلامة estimated
لا تنشر EDGAR تواريخ الاستحقاق (ex-dividend). وما لم تتوفر بيانات من البورصة، يُقدَّر تاريخ الاستحقاق بتاريخ الإعلان + 10 أيام وهو دقيق إلى نحو ±7 أيام، مع estimated is True. وافتراضيًا تواصل المحاكاة قيد التوزيعات التقديرية (السياسة best_available)؛ ويمكن لـإعداد تشغيل مسبق (.qcs) أن يضبط dividendDatePolicy على exact_only (تخطّي التقديرية) أو off — ولا يوجد عنصر تحكم في النافذة لذلك. صفِّ بحسبها في منطقك الخاص إن كانت استراتيجيتك حساسة لتاريخ الاستحقاق:
exact = [d for d in calendar.dividends(bar["t"], symbol) if not d.estimated]الإجراءات المؤسسية في المحاكاة
الخياران الفرعيان مفعّلان افتراضيًا عند تفعيل بيانات التقويم، وكلاهما يعمل قبل دوال الاستدعاء لديك عند كل عمود — لذا ترى on_bar دائمًا مركزًا معدَّلًا بالفعل.
تعديل المراكز لتجزئات الأسهم — في تاريخ السريان، يُضرب عدد الأسهم في النسبة وتُقسم تكلفة الأساس عليها. وتُعاد أيضًا مقايسة أسعار الإيقاف والهدف. ولأن qty × entry_price لا يتغير، يبقى منحنى حقوق الملكية متصلًا عبر التجزئة.
وتبقى أعمدة الأسعار غير معدّلة عمدًا، فـ bar["close"] هو السعر التاريخي الحقيقي. وسيظل المؤشر المحسوب على سلسلة الإغلاق الخام يرى فجوة التجزئة — عدّل سلسلتك الخاصة باستخدام calendar.splits(...) إن كان ذلك مهمًا.
قيد توزيعات الأرباح نقدًا — في تاريخ الاستحقاق، يُضاف qty × amount إلى النقد للمراكز الشرائية ويُخصم من المراكز القصيرة (فبائع المكشوف مدين بالتوزيع للمُقرِض). ويتدفق ذلك إلى حقوق الملكية وكل مقاييس العائد، لكن ليس إلى realized_pnl الذي يظل للصفقات فقط. اقرأ الإجماليات من مقاييس الحساب:
def on_finish(bars, symbol=None, bars_by_symbol=None):
from quantcraft.process.runtime import account
m = account.refresh_metrics({})
print(m["total_dividend_income"], m["total_splits_applied"])أين ترى الإجراءات المؤسسية
لا شيء يغيّر مركزك أو نقدك بصمت:
- لوحة المخرجات — سطر
[calendar]واحد لكل إجراء مؤسسي مطبَّق، مع ملخص في النهاية:[calendar] 2024-01-10 AAPL — SPLIT 4:1 applied to 1 position(s): 100 -> 400 shares (cost basis unchanged; bars stay unadjusted) [calendar] 2024-02-09 AAPL — DIVIDEND $0.2400/share on 400 share(s): +$96.00 cash … [calendar] corporate actions — 1 split(s) applied; 1 dividend(s) applied (0 exact ex-date, 1 estimated +/-7d) - Test Results — يظهر صف Split أو Dividend ضمن الصفقات المغلقة (وتحمل البطاقة حينئذٍ عنوان Closed trades & events)، ويعرض النسبة أو المبلغ للسهم وأثره النقدي. ويُوسَم تاريخ الاستحقاق التقديري بـ
est.ولا تحمل هذه الصفوف علامة#على المخطط وتُستثنى من تصدير CSV.
next_earnings عند لحظة زمنية محددة
في الاختبار الرجعي، لا تُرجع next_earnings أبدًا «تاريخ الأرباح التالي» من الخادم محسوبًا بتاريخ اليوم — فذلك نظر مسبق عند عمود تاريخي. وإنما تُعاد بناؤه من آخر إيداع أرباح مرئي عند عمودك مع وتيرة إعداد التقارير لدى الشركة، فتكون basis == "filing-cadence" وestimated is True.
وتُرجع None عندما لا يكون أي إيداع أرباح مرئيًا بعد — في بداية التشغيل، أو لرمز لا يمتد سجل إيداعاته إلى ذلك الحد. تحقق من ذلك دائمًا.
عندما لا ترى توزيعات أرباح
يوضّح التشغيل الذي لا يطبّق شيئًا السبب في لوحة المخرجات:
| ما يقوله السجل | المعنى |
|---|---|
loaded 3/5 symbol(s); 2 without calendar data | يُطبع في البداية: كم رمزًا حصل على تقويم |
none of 5 symbol(s) returned calendar data: … | لا رمز في التشغيل لديه بيانات تقويم — لا يمكن تطبيق شيء |
no calendar data on the server | لم تُشغَّل مهمة التقويم لذلك الرمز |
calendar has no dividend or split history | لا يدفع أرباحًا ولا تجزئات مسجّلة |
… ex-dates 2019-05-10..2020-05-08 | يدفع أرباحًا لكن ليس داخل نطاقك الزمني المختبَر |
N with no ex-date, which can never be applied | يوجد سجل لكن لا يمكن وضعه على الساعة |
no positions were held … | لم يكن شيء مفتوحًا عندما حلّ موعد إجراء |
إذا لم يظهر أي سطر [calendar]، فلم تُرفَق بيانات التقويم بالتشغيل — تحقق من مفتاح Include calendar data في علامة تبويب Symbol & data.
انظر أيضًا
- الاختبارات الرجعية — نافذة Run backtest وخيار Include calendar data
- دورة حياة الاستراتيجية — معامل الاستدعاء
calendarوالمتغير العام وقت التشغيلqc_calendar - نموذج الحساب — أين يستقر نقد التوزيعات وتعديلات التجزئة
- الماسح (Screener) — كيف تُحمَّل التقاويم عندما يحدّد ماسح قائمة الرموز
- نتائج الاختبار — صفوف Split / Dividend في جدول الصفقات المغلقة
- لوحة المخرجات — أسطر السجل
[calendar]

