Revert "revert: benchmark generic transient selection"

This reverts commit b2da70897a.
This commit is contained in:
boris
2026-09-05 05:46:05 +08:00
parent b2da70897a
commit 6a304e2fc2
+83 -61
View File
@@ -3981,32 +3981,6 @@ impl PlatformExprStrategy {
) )
} }
fn selection_stock_state_with_factor_date_from_views<'a>(
&self,
ctx: &StrategyContext<'a>,
date: NaiveDate,
factor_date: NaiveDate,
symbol: &str,
execution_day: &DailySnapshotView<'a>,
factor_day: &DailySnapshotView<'a>,
) -> Result<Arc<StockExpressionState>, BacktestError> {
let source = ViewStockStateSnapshotSource {
execution: execution_day,
factor: factor_day,
same_date: factor_date == date,
};
let use_intraday_quote = self.selection_quote_usage != StockFilterQuoteUsage::DailyOnly;
self.stock_state_with_factor_date_and_time_from_source(
ctx,
date,
factor_date,
symbol,
None,
use_intraday_quote,
&source,
)
}
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
fn uncached_selection_stock_state_from_views_by_symbol_id<'a>( fn uncached_selection_stock_state_from_views_by_symbol_id<'a>(
&self, &self,
@@ -9497,6 +9471,7 @@ impl PlatformExprStrategy {
) )
} }
#[cfg(test)]
fn selectable_universe_on_with_options( fn selectable_universe_on_with_options(
&self, &self,
ctx: &StrategyContext<'_>, ctx: &StrategyContext<'_>,
@@ -9514,6 +9489,7 @@ impl PlatformExprStrategy {
.0 .0
} }
#[cfg(test)]
fn selection_universe_and_risk_decisions_with_options( fn selection_universe_and_risk_decisions_with_options(
&self, &self,
ctx: &StrategyContext<'_>, ctx: &StrategyContext<'_>,
@@ -10141,15 +10117,14 @@ impl PlatformExprStrategy {
universe_factor_date, universe_factor_date,
5, 5,
); );
let execution_day = ctx.data.daily_snapshot_view(date);
let universe_factor_day = ctx.data.daily_snapshot_view(universe_factor_date);
let factor_day = ctx.data.daily_snapshot_view(stock_factor_date);
// The universe is already stably ordered by market cap. When the // The universe is already stably ordered by market cap. When the
// strategy asks for that exact ascending order and does not need a // strategy asks for that exact ascending order and does not need a
// complete ranking for replacement limiting, select directly from the // complete ranking for replacement limiting, select directly from the
// ordered stream instead of materializing a second candidate vector. // ordered stream instead of materializing a second candidate vector.
if self.rank_reuses_market_cap_order() && self.config.daily_replacement_limit == 0 { if self.rank_reuses_market_cap_order() && self.config.daily_replacement_limit == 0 {
let execution_day = ctx.data.daily_snapshot_view(date);
let universe_factor_day = ctx.data.daily_snapshot_view(universe_factor_date);
let factor_day = ctx.data.daily_snapshot_view(stock_factor_date);
let mut selected = Vec::with_capacity(limit.min(universe_symbol_ids.len())); let mut selected = Vec::with_capacity(limit.min(universe_symbol_ids.len()));
for symbol_id in universe_symbol_ids { for symbol_id in universe_symbol_ids {
let factor = universe_factor_day let factor = universe_factor_day
@@ -10190,28 +10165,57 @@ impl PlatformExprStrategy {
return Ok((selected, diagnostics, risk_decisions)); return Ok((selected, diagnostics, risk_decisions));
} }
let universe = universe_symbol_ids let selected = self.select_ranked_symbols(
.into_iter() ctx,
.map(|symbol_id| { date,
let factor = universe_factor_day universe_factor_date,
.factor(symbol_id) stock_factor_date,
.expect("market-cap order references missing factor row"); day,
EligibleUniverseSnapshot { band_low,
symbol: factor.symbol.clone(), band_high,
market_cap_bn: decision_market_cap_bn(factor), limit,
free_float_cap_bn: decision_free_float_cap_bn(factor), universe_symbol_ids,
} &mut diagnostics,
}) )?;
.collect::<Vec<_>>(); Ok((selected, diagnostics, risk_decisions))
}
let mut candidates = Vec::new(); #[inline(never)]
#[allow(clippy::too_many_arguments)]
fn select_ranked_symbols(
&self,
ctx: &StrategyContext<'_>,
date: NaiveDate,
universe_factor_date: NaiveDate,
stock_factor_date: NaiveDate,
day: &DayExpressionState,
band_low: f64,
band_high: f64,
limit: usize,
universe_symbol_ids: Vec<u32>,
diagnostics: &mut Vec<String>,
) -> Result<Vec<String>, BacktestError> {
let execution_day = ctx.data.daily_snapshot_view(date);
let universe_factor_day = ctx.data.daily_snapshot_view(universe_factor_date);
let factor_day = ctx.data.daily_snapshot_view(stock_factor_date);
let mut candidates = Vec::with_capacity(universe_symbol_ids.len());
let mut candidate_states = Vec::with_capacity(universe_symbol_ids.len());
let mut missing_rank_count = 0usize; let mut missing_rank_count = 0usize;
let mut missing_rank_examples = Vec::new(); let mut missing_rank_examples = Vec::new();
for candidate in universe { for symbol_id in universe_symbol_ids {
let stock = self.selection_stock_state_with_factor_date_from_views( let factor = universe_factor_day
.factor(symbol_id)
.expect("market-cap order references missing factor row");
let candidate = EligibleUniverseSnapshot {
symbol: factor.symbol.clone(),
market_cap_bn: decision_market_cap_bn(factor),
free_float_cap_bn: decision_free_float_cap_bn(factor),
};
let stock = self.uncached_selection_stock_state_from_views_by_symbol_id(
ctx, ctx,
date, date,
stock_factor_date, stock_factor_date,
symbol_id,
&candidate.symbol, &candidate.symbol,
&execution_day, &execution_day,
&factor_day, &factor_day,
@@ -10269,12 +10273,14 @@ impl PlatformExprStrategy {
} }
continue; continue;
} }
candidates.push((candidate, stock, rank_value)); let state_index = candidate_states.len();
candidate_states.push(stock);
candidates.push((candidate, rank_value, state_index));
} }
if !self.rank_reuses_market_cap_order() { if !self.rank_reuses_market_cap_order() {
candidates.sort_by(|lhs, rhs| { candidates.sort_by(|lhs, rhs| {
let lhs_value = lhs.2; let lhs_value = lhs.1;
let rhs_value = rhs.2; let rhs_value = rhs.1;
let ordering = if self.config.rank_desc { let ordering = if self.config.rank_desc {
rhs_value rhs_value
.partial_cmp(&lhs_value) .partial_cmp(&lhs_value)
@@ -10293,14 +10299,15 @@ impl PlatformExprStrategy {
} }
let mut selected = Vec::new(); let mut selected = Vec::new();
for (candidate, stock, _) in candidates { for (candidate, _, state_index) in candidates {
let stock = &candidate_states[state_index];
if !self.selection_candidate_passes_filters( if !self.selection_candidate_passes_filters(
ctx, ctx,
date, date,
day, day,
&candidate.symbol, &candidate.symbol,
&stock, stock,
&mut diagnostics, diagnostics,
)? { )? {
continue; continue;
} }
@@ -10317,7 +10324,7 @@ impl PlatformExprStrategy {
)); ));
} }
Ok((selected, diagnostics, risk_decisions)) Ok(selected)
} }
fn stock_filter_quote_usage(&self) -> StockFilterQuoteUsage { fn stock_filter_quote_usage(&self) -> StockFilterQuoteUsage {
@@ -10913,7 +10920,6 @@ impl PlatformExprStrategy {
selection_limit: usize, selection_limit: usize,
) -> Result<(Vec<String>, Vec<String>, usize, Vec<String>), BacktestError> { ) -> Result<(Vec<String>, Vec<String>, usize, Vec<String>), BacktestError> {
let mut diagnostics = Vec::new(); let mut diagnostics = Vec::new();
let mut candidates = Vec::new();
let mut missing_rank_count = 0usize; let mut missing_rank_count = 0usize;
let mut missing_rank_examples = Vec::new(); let mut missing_rank_examples = Vec::new();
let quote_usage = self.stock_filter_quote_usage(); let quote_usage = self.stock_filter_quote_usage();
@@ -10926,20 +10932,33 @@ impl PlatformExprStrategy {
} else { } else {
SelectionRiskDeferral::None SelectionRiskDeferral::None
}; };
let universe = self.selectable_universe_on_with_options( let (universe_symbol_ids, _) = self.selection_symbol_ids_and_risk_decisions_with_options(
ctx, ctx,
date, date,
universe_factor_date, universe_factor_date,
selection_risk_deferral, selection_risk_deferral,
false,
); );
let mut candidates = Vec::with_capacity(universe_symbol_ids.len());
let mut candidate_states = Vec::with_capacity(universe_symbol_ids.len());
let execution_day = ctx.data.daily_snapshot_view(date); let execution_day = ctx.data.daily_snapshot_view(date);
let universe_factor_day = ctx.data.daily_snapshot_view(universe_factor_date);
let factor_day = ctx.data.daily_snapshot_view(stock_factor_date); let factor_day = ctx.data.daily_snapshot_view(stock_factor_date);
let quote_candidate_limit = self.quote_plan_candidate_limit(selection_limit); let quote_candidate_limit = self.quote_plan_candidate_limit(selection_limit);
for candidate in universe { for symbol_id in universe_symbol_ids {
let stock = self.selection_stock_state_with_factor_date_from_views( let factor = universe_factor_day
.factor(symbol_id)
.expect("market-cap order references missing factor row");
let candidate = EligibleUniverseSnapshot {
symbol: factor.symbol.clone(),
market_cap_bn: decision_market_cap_bn(factor),
free_float_cap_bn: decision_free_float_cap_bn(factor),
};
let stock = self.uncached_selection_stock_state_from_views_by_symbol_id(
ctx, ctx,
date, date,
stock_factor_date, stock_factor_date,
symbol_id,
&candidate.symbol, &candidate.symbol,
&execution_day, &execution_day,
&factor_day, &factor_day,
@@ -10977,7 +10996,9 @@ impl PlatformExprStrategy {
} }
continue; continue;
} }
candidates.push((candidate.symbol.clone(), rank_value, stock)); let state_index = candidate_states.len();
candidate_states.push(stock);
candidates.push((candidate.symbol.clone(), rank_value, state_index));
} }
candidates.sort_by(|lhs, rhs| { candidates.sort_by(|lhs, rhs| {
let ordering = if self.config.rank_desc { let ordering = if self.config.rank_desc {
@@ -10999,9 +11020,10 @@ impl PlatformExprStrategy {
let mut quote_candidate_symbols = Vec::new(); let mut quote_candidate_symbols = Vec::new();
let mut selected_symbols = Vec::new(); let mut selected_symbols = Vec::new();
let mut processed_scope = 0usize; let mut processed_scope = 0usize;
for (symbol, _, stock) in &candidates { for (symbol, _, state_index) in &candidates {
let stock = &candidate_states[*state_index];
processed_scope += 1; processed_scope += 1;
if !self.stock_passes_quote_plan_filter(ctx, day, &stock, quote_usage)? { if !self.stock_passes_quote_plan_filter(ctx, day, stock, quote_usage)? {
if diagnostics.len() < 12 { if diagnostics.len() < 12 {
diagnostics.push(format!("{symbol} quote_plan rejected by stock_expr")); diagnostics.push(format!("{symbol} quote_plan rejected by stock_expr"));
} }
@@ -11019,7 +11041,7 @@ impl PlatformExprStrategy {
continue; continue;
} }
if quote_usage == StockFilterQuoteUsage::IntradayQuote if quote_usage == StockFilterQuoteUsage::IntradayQuote
&& !self.stock_passes_expr(ctx, day, &stock)? && !self.stock_passes_expr(ctx, day, stock)?
{ {
if diagnostics.len() < 12 { if diagnostics.len() < 12 {
diagnostics.push(format!("{symbol} quote_plan rejected by stock_expr")); diagnostics.push(format!("{symbol} quote_plan rejected by stock_expr"));