perf: reuse immutable fundamental universe
This commit is contained in:
@@ -8982,6 +8982,28 @@ impl PlatformExprStrategy {
|
||||
selection_risk_deferral: SelectionRiskDeferral,
|
||||
collect_risk_decisions: bool,
|
||||
) -> (Vec<EligibleUniverseSnapshot>, Vec<FidcRiskDecisionAudit>) {
|
||||
// The immutable DataSet already builds the same stable market-cap
|
||||
// ordered fundamental universe. Reuse it when this strategy has no
|
||||
// selection-stage risk or explicit universe exclusion. This preserves
|
||||
// the full path for every strategy that enables a selection rule while
|
||||
// avoiding a daily scan, candidate/market lookup, and stable sort for
|
||||
// the common execution-risk-only contract.
|
||||
if date == factor_date
|
||||
&& matches!(selection_risk_deferral, SelectionRiskDeferral::None)
|
||||
&& self.selection_risk_is_noop()
|
||||
&& self.normalized_universe_exclude.is_empty()
|
||||
{
|
||||
let base = ctx.data.eligible_universe_on(date);
|
||||
let rows = if ctx.has_dynamic_universe() {
|
||||
base.iter()
|
||||
.filter(|row| ctx.dynamic_universe_contains(&row.symbol))
|
||||
.cloned()
|
||||
.collect()
|
||||
} else {
|
||||
base.to_vec()
|
||||
};
|
||||
return (rows, Vec::new());
|
||||
}
|
||||
let factor_rows = ctx.data.factor_snapshot_rows_on(factor_date);
|
||||
let mut rows = Vec::with_capacity(factor_rows.len());
|
||||
let mut decisions = if collect_risk_decisions {
|
||||
@@ -9160,6 +9182,21 @@ impl PlatformExprStrategy {
|
||||
None
|
||||
}
|
||||
|
||||
fn selection_risk_is_noop(&self) -> bool {
|
||||
let rules = &self.config.risk_config.static_rules;
|
||||
!rules.reject_st_selection
|
||||
&& !rules.reject_star_st_selection
|
||||
&& !rules.reject_paused_selection
|
||||
&& !rules.reject_inactive_selection
|
||||
&& !rules.reject_new_listing_selection
|
||||
&& !rules.reject_kcb_selection
|
||||
&& !rules.reject_bjse_selection
|
||||
&& !rules.reject_one_yuan_selection
|
||||
&& !rules.reject_upper_limit_selection
|
||||
&& !rules.reject_lower_limit_selection
|
||||
&& (!rules.blacklist_enabled || rules.blacklisted_symbols.is_empty())
|
||||
}
|
||||
|
||||
fn stock_passes_universe_exclude(
|
||||
&self,
|
||||
_candidate: &crate::data::CandidateEligibility,
|
||||
@@ -13414,6 +13451,26 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn selection_universe_cache_gate_only_accepts_pure_fundamental_contracts() {
|
||||
let strategy =
|
||||
PlatformExprStrategy::new(PlatformExprStrategyConfig::microcap_rotation());
|
||||
assert!(strategy.selection_risk_is_noop());
|
||||
|
||||
let mut config = PlatformExprStrategyConfig::microcap_rotation();
|
||||
config.risk_config.static_rules.reject_st_selection = true;
|
||||
assert!(!PlatformExprStrategy::new(config).selection_risk_is_noop());
|
||||
|
||||
let mut config = PlatformExprStrategyConfig::microcap_rotation();
|
||||
config.risk_config.static_rules.blacklisted_symbols.insert("000001.SZ".to_string());
|
||||
assert!(!PlatformExprStrategy::new(config).selection_risk_is_noop());
|
||||
|
||||
let mut config = PlatformExprStrategyConfig::microcap_rotation();
|
||||
config.risk_config.static_rules.blacklist_enabled = false;
|
||||
config.risk_config.static_rules.blacklisted_symbols.insert("000001.SZ".to_string());
|
||||
assert!(PlatformExprStrategy::new(config).selection_risk_is_noop());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn platform_selection_uses_complete_static_risk_policy_before_universe_output() {
|
||||
let date = d(2025, 1, 2);
|
||||
|
||||
Reference in New Issue
Block a user