الوثائق1.0 (latest)
الصفحاتبيانات التقويم · 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_dateex_date
التجزئةfiling_dateeffective_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.


انظر أيضًا

7 دقائق للقراءةاقترح تعديلًا ↗
بيانات التقويم — الوثائق (1.0 (latest)) | QuantCraft