让分钟行情按流式迭代器处理

This commit is contained in:
boris
2026-08-27 13:25:28 +08:00
parent ed126a3630
commit c86a0e2339
3 changed files with 137 additions and 45 deletions
+27 -15
View File
@@ -2723,10 +2723,16 @@ where
&mut minute_symbols,
)?;
}
let minute_quotes = self.data.execution_quotes_on_date_for_symbols(
execution_date,
(!self.subscriptions.is_empty()).then_some(&self.subscriptions),
);
// Keep the iterator attached to an O(1) DataSet clone. This
// preserves the immutable quote snapshot for the day while
// allowing lazy quote loads and broker state updates on self.
let quote_data = self.data.clone();
let mut minute_quotes = quote_data
.execution_quotes_iter_on_date_for_symbols(
execution_date,
(!self.subscriptions.is_empty()).then_some(&self.subscriptions),
)
.peekable();
let requires_minute_callbacks = self.strategy.requires_minute_callbacks();
let has_minute_process_listeners = self.process_event_bus.has_listeners_for(&[
ProcessEventKind::PreMinute,
@@ -2741,17 +2747,22 @@ where
.filter(|rule| rule.stage == ScheduleStage::Minute)
.filter_map(|rule| rule.time_rule.as_ref()?.minute_of_day())
.collect::<BTreeSet<_>>();
let mut minute_cursor = 0usize;
while minute_cursor < minute_quotes.len() {
let minute_timestamp = minute_quotes[minute_cursor].timestamp;
let mut minute_group = Vec::new();
while let Some(first_quote) = minute_quotes.next() {
let minute_timestamp = first_quote.timestamp;
let minute_time = minute_timestamp.time();
let mut minute_end = minute_cursor + 1;
while minute_end < minute_quotes.len()
&& minute_quotes[minute_end].timestamp == minute_timestamp
minute_group.clear();
minute_group.push(first_quote);
while minute_quotes
.peek()
.is_some_and(|quote| quote.timestamp == minute_timestamp)
{
minute_end += 1;
minute_group.push(
minute_quotes
.next()
.expect("peeked minute quote must be available"),
);
}
let minute_group = &minute_quotes[minute_cursor..minute_end];
let schedule_candidate = minute_schedule_all_times
|| minute_schedule_minutes
.contains(&(minute_time.hour() * 60 + minute_time.minute()));
@@ -2760,7 +2771,6 @@ where
&& !schedule_candidate
&& !self.has_open_orders()
{
minute_cursor = minute_end;
continue;
}
let minute_open_orders = self.open_order_views();
@@ -2802,7 +2812,7 @@ where
result.fills.as_slice(),
)?;
if requires_minute_callbacks {
for quote in minute_group {
for &quote in &minute_group {
minute_decision.merge_from(self.strategy.on_minute(
&StrategyContext {
execution_date,
@@ -2907,8 +2917,10 @@ where
ProcessEventKind::PostMinute,
format!("minute:{minute_timestamp}:post"),
)?;
minute_cursor = minute_end;
}
drop(minute_group);
drop(minute_quotes);
drop(quote_data);
self.data.remove_execution_quotes_on_date(execution_date);
}