流式构建总市值行情计划
This commit is contained in:
@@ -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]
|
||||||
|
|||||||
Reference in New Issue
Block a user