流式构建总市值行情计划

This commit is contained in:
boris
2026-09-07 12:17:26 +08:00
parent 950bcaa7aa
commit c934a948c6
+92 -1
View File
@@ -11509,6 +11509,88 @@ impl PlatformExprStrategy {
let universe_factor_day = ctx.data.daily_snapshot_view(universe_factor_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);
if self.rank_reuses_market_cap_order() {
let candidate_range = self.market_cap_ordered_selection_range(
&universe_factor_day,
&universe_symbol_ids,
band_low,
band_high,
);
let mut quote_candidate_symbols = Vec::new();
let mut selected_symbols = Vec::new();
let mut processed_scope = 0usize;
for &symbol_id in &universe_symbol_ids[candidate_range] {
let factor = universe_factor_day
.factor(symbol_id)
.expect("market-cap order references missing factor row");
let symbol = factor.symbol.as_str();
let market_cap_bn = decision_market_cap_bn(factor);
let free_float_cap_bn = decision_free_float_cap_bn(factor);
let stock = self.uncached_selection_stock_state_from_views_by_symbol_id(
ctx,
date,
stock_factor_date,
symbol_id,
symbol,
&execution_day,
&factor_day,
)?;
let field_value = self.selection_field_value_from_caps(
market_cap_bn,
free_float_cap_bn,
&stock,
);
if !field_value.is_finite() {
if diagnostics.len() < 12 {
diagnostics.push(format!(
"{symbol} quote_plan rejected by missing selection field"
));
}
continue;
}
if field_value < band_low || field_value > band_high {
continue;
}
processed_scope += 1;
if !self.stock_passes_quote_plan_filter(ctx, day, &stock, quote_usage)? {
if diagnostics.len() < 12 {
diagnostics.push(format!("{symbol} quote_plan rejected by stock_expr"));
}
continue;
}
if quote_candidate_symbols.len() < quote_candidate_limit {
quote_candidate_symbols.push(factor.symbol.clone());
}
if !ctx.is_lagged_execution()
&& let Some(reason) = self.stock_selection_limit_rejection_reason(&stock)
{
if diagnostics.len() < 12 {
diagnostics.push(format!("{symbol} quote_plan rejected by {reason}"));
}
continue;
}
if quote_usage == StockFilterQuoteUsage::IntradayQuote
&& !self.stock_passes_expr(ctx, day, &stock)?
{
if diagnostics.len() < 12 {
diagnostics.push(format!("{symbol} quote_plan rejected by stock_expr"));
}
continue;
}
selected_symbols.push(factor.symbol.clone());
if selected_symbols.len() >= selection_limit
&& quote_candidate_symbols.len() >= quote_candidate_limit
{
break;
}
}
return Ok((
quote_candidate_symbols,
selected_symbols,
processed_scope,
diagnostics,
));
}
for symbol_id in universe_symbol_ids { for symbol_id in universe_symbol_ids {
let factor = universe_factor_day let factor = universe_factor_day
.factor(symbol_id) .factor(symbol_id)
@@ -36132,7 +36214,7 @@ let target_exposure = csi_ready ? dynamic_exposure : 0.0;
cfg.stock_filter_expr = "last_price > 0".to_string(); cfg.stock_filter_expr = "last_price > 0".to_string();
cfg.rank_by = "market_cap".to_string(); cfg.rank_by = "market_cap".to_string();
cfg.risk_config.static_rules.reject_paused_selection = true; cfg.risk_config.static_rules.reject_paused_selection = true;
let strategy = PlatformExprStrategy::new(cfg); let strategy = PlatformExprStrategy::new(cfg.clone());
let plan = strategy.selection_quote_plan(&ctx, 0).expect("quote plan"); let plan = strategy.selection_quote_plan(&ctx, 0).expect("quote plan");
@@ -36143,6 +36225,15 @@ let target_exposure = csi_ready ? dynamic_exposure : 0.0;
plan.order_symbols, plan.order_symbols,
vec!["000001.SZ".to_string(), "000003.SZ".to_string()] vec!["000001.SZ".to_string(), "000003.SZ".to_string()]
); );
cfg.rank_expr = "market_cap".to_string();
let generic_plan = PlatformExprStrategy::new(cfg)
.selection_quote_plan(&ctx, 0)
.expect("generic quote plan");
assert_eq!(plan.candidate_symbols, generic_plan.candidate_symbols);
assert_eq!(plan.order_symbols, generic_plan.order_symbols);
assert_eq!(plan.processed_scope, generic_plan.processed_scope);
assert_eq!(plan.diagnostics, generic_plan.diagnostics);
} }
#[test] #[test]