Expose process event context to strategy runtime

This commit is contained in:
boris
2026-04-23 05:12:07 -07:00
parent 4d43d1b176
commit 2857f72d84
8 changed files with 742 additions and 92 deletions

View File

@@ -232,31 +232,42 @@ where
.map(|decision_idx| (decision_idx, execution_dates[decision_idx]));
let (decision_index, decision_date) =
decision_slot.unwrap_or((execution_idx, execution_date));
let mut process_events = Vec::new();
let pre_open_orders = self.broker.open_order_views();
let daily_context = StrategyContext {
let schedule_rules = self.strategy.schedule_rules();
publish_phase_event(
&mut self.strategy,
&mut self.process_event_bus,
execution_date,
decision_date,
decision_index,
&self.data,
&portfolio,
&pre_open_orders,
&mut process_events,
execution_date,
ProcessEventKind::PreBeforeTrading,
"before_trading:pre",
)?;
self.strategy.before_trading(&StrategyContext {
execution_date,
decision_date,
decision_index,
data: &self.data,
portfolio: &portfolio,
open_orders: &pre_open_orders,
};
let schedule_rules = self.strategy.schedule_rules();
let mut process_events = Vec::new();
process_events: &process_events,
active_process_event: None,
})?;
publish_phase_event(
&mut self.strategy,
&mut self.process_event_bus,
&daily_context,
&mut process_events,
execution_date,
ProcessEventKind::PreBeforeTrading,
"before_trading:pre",
)?;
self.strategy.before_trading(&daily_context)?;
publish_phase_event(
&mut self.strategy,
&mut self.process_event_bus,
&daily_context,
decision_date,
decision_index,
&self.data,
&portfolio,
&pre_open_orders,
&mut process_events,
execution_date,
ProcessEventKind::BeforeTrading,
@@ -265,7 +276,12 @@ where
publish_phase_event(
&mut self.strategy,
&mut self.process_event_bus,
&daily_context,
execution_date,
decision_date,
decision_index,
&self.data,
&portfolio,
&pre_open_orders,
&mut process_events,
execution_date,
ProcessEventKind::PostBeforeTrading,
@@ -274,7 +290,12 @@ where
publish_phase_event(
&mut self.strategy,
&mut self.process_event_bus,
&daily_context,
execution_date,
decision_date,
decision_index,
&self.data,
&portfolio,
&pre_open_orders,
&mut process_events,
execution_date,
ProcessEventKind::PreOpenAuction,
@@ -286,15 +307,33 @@ where
execution_date,
ScheduleStage::OpenAuction,
&schedule_rules,
&daily_context,
decision_date,
decision_index,
&self.data,
&portfolio,
&pre_open_orders,
&mut process_events,
&mut self.process_event_bus,
)?;
auction_decision.merge_from(self.strategy.open_auction(&daily_context)?);
auction_decision.merge_from(self.strategy.open_auction(&StrategyContext {
execution_date,
decision_date,
decision_index,
data: &self.data,
portfolio: &portfolio,
open_orders: &pre_open_orders,
process_events: &process_events,
active_process_event: None,
})?);
publish_phase_event(
&mut self.strategy,
&mut self.process_event_bus,
&daily_context,
execution_date,
decision_date,
decision_index,
&self.data,
&portfolio,
&pre_open_orders,
&mut process_events,
execution_date,
ProcessEventKind::OpenAuction,
@@ -307,25 +346,27 @@ where
&auction_decision,
)?;
let post_auction_open_orders = self.broker.open_order_views();
let post_auction_context = StrategyContext {
execution_date,
decision_date,
decision_index,
data: &self.data,
portfolio: &portfolio,
open_orders: &post_auction_open_orders,
};
publish_process_events(
&mut self.strategy,
&mut self.process_event_bus,
&post_auction_context,
execution_date,
decision_date,
decision_index,
&self.data,
&portfolio,
&post_auction_open_orders,
&mut process_events,
&mut report.process_events,
)?;
publish_phase_event(
&mut self.strategy,
&mut self.process_event_bus,
&post_auction_context,
execution_date,
decision_date,
decision_index,
&self.data,
&portfolio,
&post_auction_open_orders,
&mut process_events,
execution_date,
ProcessEventKind::PostOpenAuction,
@@ -335,7 +376,12 @@ where
publish_phase_event(
&mut self.strategy,
&mut self.process_event_bus,
&post_auction_context,
execution_date,
decision_date,
decision_index,
&self.data,
&portfolio,
&post_auction_open_orders,
&mut process_events,
execution_date,
ProcessEventKind::PreOnDay,
@@ -351,6 +397,8 @@ where
data: &self.data,
portfolio: &portfolio,
open_orders: &on_day_open_orders,
process_events: &process_events,
active_process_event: None,
})
})
.transpose()?
@@ -361,29 +409,23 @@ where
execution_date,
ScheduleStage::OnDay,
&schedule_rules,
&StrategyContext {
execution_date,
decision_date,
decision_index,
data: &self.data,
portfolio: &portfolio,
open_orders: &on_day_open_orders,
},
decision_date,
decision_index,
&self.data,
&portfolio,
&on_day_open_orders,
&mut process_events,
&mut self.process_event_bus,
)?);
let on_day_context = StrategyContext {
execution_date,
decision_date,
decision_index,
data: &self.data,
portfolio: &portfolio,
open_orders: &on_day_open_orders,
};
publish_phase_event(
&mut self.strategy,
&mut self.process_event_bus,
&on_day_context,
execution_date,
decision_date,
decision_index,
&self.data,
&portfolio,
&on_day_open_orders,
&mut process_events,
execution_date,
ProcessEventKind::OnDay,
@@ -394,18 +436,15 @@ where
self.broker
.execute(execution_date, &mut portfolio, &self.data, &decision)?;
let post_intraday_open_orders = self.broker.open_order_views();
let post_intraday_context = StrategyContext {
execution_date,
decision_date,
decision_index,
data: &self.data,
portfolio: &portfolio,
open_orders: &post_intraday_open_orders,
};
publish_process_events(
&mut self.strategy,
&mut self.process_event_bus,
&post_intraday_context,
execution_date,
decision_date,
decision_index,
&self.data,
&portfolio,
&post_intraday_open_orders,
&mut process_events,
&mut intraday_report.process_events,
)?;
@@ -419,7 +458,12 @@ where
publish_phase_event(
&mut self.strategy,
&mut self.process_event_bus,
&post_intraday_context,
execution_date,
decision_date,
decision_index,
&self.data,
&portfolio,
&post_intraday_open_orders,
&mut process_events,
execution_date,
ProcessEventKind::PostOnDay,
@@ -429,28 +473,39 @@ where
portfolio.update_prices(execution_date, &self.data, PriceField::Close)?;
let post_trade_open_orders = self.broker.open_order_views();
let post_trade_context = StrategyContext {
publish_phase_event(
&mut self.strategy,
&mut self.process_event_bus,
execution_date,
decision_date,
decision_index,
&self.data,
&portfolio,
&post_trade_open_orders,
&mut process_events,
execution_date,
ProcessEventKind::PreAfterTrading,
"after_trading:pre",
)?;
self.strategy.after_trading(&StrategyContext {
execution_date,
decision_date,
decision_index,
data: &self.data,
portfolio: &portfolio,
open_orders: &post_trade_open_orders,
};
process_events: &process_events,
active_process_event: None,
})?;
publish_phase_event(
&mut self.strategy,
&mut self.process_event_bus,
&post_trade_context,
&mut process_events,
execution_date,
ProcessEventKind::PreAfterTrading,
"after_trading:pre",
)?;
self.strategy.after_trading(&post_trade_context)?;
publish_phase_event(
&mut self.strategy,
&mut self.process_event_bus,
&post_trade_context,
decision_date,
decision_index,
&self.data,
&portfolio,
&post_trade_open_orders,
&mut process_events,
execution_date,
ProcessEventKind::AfterTrading,
@@ -460,7 +515,12 @@ where
publish_process_events(
&mut self.strategy,
&mut self.process_event_bus,
&post_trade_context,
execution_date,
decision_date,
decision_index,
&self.data,
&portfolio,
&post_trade_open_orders,
&mut process_events,
&mut close_report.process_events,
)?;
@@ -470,18 +530,15 @@ where
report.account_events.extend(close_report.account_events);
report.diagnostics.extend(close_report.diagnostics);
let post_close_open_orders = self.broker.open_order_views();
let post_close_context = StrategyContext {
execution_date,
decision_date,
decision_index,
data: &self.data,
portfolio: &portfolio,
open_orders: &post_close_open_orders,
};
publish_phase_event(
&mut self.strategy,
&mut self.process_event_bus,
&post_close_context,
execution_date,
decision_date,
decision_index,
&self.data,
&portfolio,
&post_close_open_orders,
&mut process_events,
execution_date,
ProcessEventKind::PostAfterTrading,
@@ -490,17 +547,36 @@ where
publish_phase_event(
&mut self.strategy,
&mut self.process_event_bus,
&post_close_context,
execution_date,
decision_date,
decision_index,
&self.data,
&portfolio,
&post_close_open_orders,
&mut process_events,
execution_date,
ProcessEventKind::PreSettlement,
"settlement:pre",
)?;
self.strategy.on_settlement(&post_close_context)?;
self.strategy.on_settlement(&StrategyContext {
execution_date,
decision_date,
decision_index,
data: &self.data,
portfolio: &portfolio,
open_orders: &post_close_open_orders,
process_events: &process_events,
active_process_event: None,
})?;
publish_phase_event(
&mut self.strategy,
&mut self.process_event_bus,
&post_close_context,
execution_date,
decision_date,
decision_index,
&self.data,
&portfolio,
&post_close_open_orders,
&mut process_events,
execution_date,
ProcessEventKind::Settlement,
@@ -509,7 +585,12 @@ where
publish_phase_event(
&mut self.strategy,
&mut self.process_event_bus,
&post_close_context,
execution_date,
decision_date,
decision_index,
&self.data,
&portfolio,
&post_close_open_orders,
&mut process_events,
execution_date,
ProcessEventKind::PostSettlement,
@@ -1005,7 +1086,11 @@ fn collect_scheduled_decisions<S: Strategy>(
execution_date: NaiveDate,
stage: ScheduleStage,
rules: &[ScheduleRule],
ctx: &StrategyContext<'_>,
decision_date: NaiveDate,
decision_index: usize,
data: &crate::data::DataSet,
portfolio: &PortfolioState,
open_orders: &[crate::strategy::OpenOrderView],
process_events: &mut Vec<ProcessEvent>,
process_event_bus: &mut ProcessEventBus,
) -> Result<crate::strategy::StrategyDecision, BacktestError> {
@@ -1014,17 +1099,39 @@ fn collect_scheduled_decisions<S: Strategy>(
publish_phase_event(
strategy,
process_event_bus,
ctx,
execution_date,
decision_date,
decision_index,
data,
portfolio,
open_orders,
process_events,
execution_date,
ProcessEventKind::PreScheduled,
format!("scheduled:{}:{}:pre", rule.name, stage_label(stage)),
)?;
combined.merge_from(strategy.on_scheduled(ctx, rule)?);
combined.merge_from(strategy.on_scheduled(
&StrategyContext {
execution_date,
decision_date,
decision_index,
data,
portfolio,
open_orders,
process_events: process_events.as_slice(),
active_process_event: None,
},
rule,
)?);
publish_phase_event(
strategy,
process_event_bus,
ctx,
execution_date,
decision_date,
decision_index,
data,
portfolio,
open_orders,
process_events,
execution_date,
ProcessEventKind::PostScheduled,
@@ -1037,7 +1144,12 @@ fn collect_scheduled_decisions<S: Strategy>(
fn publish_phase_event<S: Strategy>(
strategy: &mut S,
process_event_bus: &mut ProcessEventBus,
ctx: &StrategyContext<'_>,
execution_date: NaiveDate,
decision_date: NaiveDate,
decision_index: usize,
data: &crate::data::DataSet,
portfolio: &PortfolioState,
open_orders: &[crate::strategy::OpenOrderView],
events: &mut Vec<ProcessEvent>,
date: NaiveDate,
kind: ProcessEventKind,
@@ -1052,7 +1164,18 @@ fn publish_phase_event<S: Strategy>(
detail: detail.into(),
};
process_event_bus.publish(&event);
strategy.on_process_event(ctx, &event)?;
let process_events = events.as_slice();
let event_ctx = StrategyContext {
execution_date,
decision_date,
decision_index,
data,
portfolio,
open_orders,
process_events,
active_process_event: Some(&event),
};
strategy.on_process_event(&event_ctx, &event)?;
events.push(event);
Ok(())
}
@@ -1060,13 +1183,29 @@ fn publish_phase_event<S: Strategy>(
fn publish_process_events<S: Strategy>(
strategy: &mut S,
process_event_bus: &mut ProcessEventBus,
ctx: &StrategyContext<'_>,
execution_date: NaiveDate,
decision_date: NaiveDate,
decision_index: usize,
data: &crate::data::DataSet,
portfolio: &PortfolioState,
open_orders: &[crate::strategy::OpenOrderView],
target: &mut Vec<ProcessEvent>,
incoming: &mut Vec<ProcessEvent>,
) -> Result<(), BacktestError> {
for event in incoming.drain(..) {
process_event_bus.publish(&event);
strategy.on_process_event(ctx, &event)?;
let process_events = target.as_slice();
let event_ctx = StrategyContext {
execution_date,
decision_date,
decision_index,
data,
portfolio,
open_orders,
process_events,
active_process_event: Some(&event),
};
strategy.on_process_event(&event_ctx, &event)?;
target.push(event);
}
Ok(())