Add rqalpha-style scheduler primitives

This commit is contained in:
boris
2026-04-23 01:49:24 -07:00
parent 452eb3324d
commit e5fe1f0432
5 changed files with 533 additions and 3 deletions

View File

@@ -9,6 +9,7 @@ use crate::events::{AccountEvent, FillEvent, OrderEvent, OrderSide, OrderStatus,
use crate::metrics::{BacktestMetrics, compute_backtest_metrics};
use crate::portfolio::{CashReceivable, HoldingSummary, PortfolioState};
use crate::rules::EquityRuleHooks;
use crate::scheduler::{ScheduleRule, ScheduleStage, Scheduler};
use crate::strategy::{Strategy, StrategyContext};
#[derive(Debug, Error)]
@@ -124,6 +125,8 @@ where
F: FnMut(&BacktestDayProgress),
{
let mut portfolio = PortfolioState::new(self.config.initial_cash);
let scheduler_calendar = self.data.calendar().clone();
let scheduler = Scheduler::new(&scheduler_calendar);
let execution_dates = self
.data
.calendar()
@@ -202,8 +205,17 @@ where
data: &self.data,
portfolio: &portfolio,
};
let schedule_rules = self.strategy.schedule_rules();
self.strategy.before_trading(&daily_context)?;
let auction_decision = self.strategy.open_auction(&daily_context)?;
let mut auction_decision = collect_scheduled_decisions(
&mut self.strategy,
&scheduler,
execution_date,
ScheduleStage::OpenAuction,
&schedule_rules,
&daily_context,
)?;
auction_decision.merge_from(self.strategy.open_auction(&daily_context)?);
let mut report = self.broker.execute(
execution_date,
&mut portfolio,
@@ -211,7 +223,7 @@ where
&auction_decision,
)?;
let decision = decision_slot
let mut decision = decision_slot
.map(|(decision_idx, decision_date)| {
self.strategy.on_day(&StrategyContext {
execution_date,
@@ -223,6 +235,20 @@ where
})
.transpose()?
.unwrap_or_default();
decision.merge_from(collect_scheduled_decisions(
&mut self.strategy,
&scheduler,
execution_date,
ScheduleStage::OnDay,
&schedule_rules,
&StrategyContext {
execution_date,
decision_date,
decision_index,
data: &self.data,
portfolio: &portfolio,
},
)?);
let intraday_report =
self.broker
@@ -635,6 +661,21 @@ where
}
}
fn collect_scheduled_decisions<S: Strategy>(
strategy: &mut S,
scheduler: &Scheduler<'_>,
execution_date: NaiveDate,
stage: ScheduleStage,
rules: &[ScheduleRule],
ctx: &StrategyContext<'_>,
) -> Result<crate::strategy::StrategyDecision, BacktestError> {
let mut combined = crate::strategy::StrategyDecision::default();
for rule in scheduler.triggered_rules(execution_date, stage, rules) {
combined.merge_from(strategy.on_scheduled(ctx, rule)?);
}
Ok(combined)
}
mod date_format {
use chrono::NaiveDate;
use serde::Serializer;