修复策略显式排除股票匹配

This commit is contained in:
boris
2026-07-07 07:19:10 +08:00
parent e37b8e1265
commit b37ebb81f1
+55 -11
View File
@@ -6420,11 +6420,28 @@ impl PlatformExprStrategy {
_candidate: &crate::data::CandidateEligibility, _candidate: &crate::data::CandidateEligibility,
market: &DailyMarketSnapshot, market: &DailyMarketSnapshot,
) -> bool { ) -> bool {
let excludes = &self.config.universe_exclude; Self::universe_exclude_reason(&self.config.universe_exclude, &market.symbol).is_none()
if excludes.iter().any(|item| item == "bjse") && market.symbol.ends_with(".BJ") {
return false;
} }
true
fn universe_exclude_reason(excludes: &[String], symbol: &str) -> Option<&'static str> {
let normalized_symbol = symbol.trim().to_ascii_lowercase();
if normalized_symbol.is_empty() {
return None;
}
let symbol_base = normalized_symbol.split('.').next().unwrap_or("");
for raw_item in excludes {
let item = raw_item.trim().to_ascii_lowercase();
if item.is_empty() {
continue;
}
if item == "bjse" && normalized_symbol.ends_with(".bj") {
return Some("bjse");
}
if item == normalized_symbol || (!symbol_base.is_empty() && item == symbol_base) {
return Some("universe_exclude");
}
}
None
} }
fn stock_numeric_field_value( fn stock_numeric_field_value(
@@ -6652,14 +6669,10 @@ impl PlatformExprStrategy {
let market = ctx.data.require_market(date, symbol)?; let market = ctx.data.require_market(date, symbol)?;
let candidate = ctx.data.require_candidate(date, symbol)?; let candidate = ctx.data.require_candidate(date, symbol)?;
if self if let Some(reason) =
.config Self::universe_exclude_reason(&self.config.universe_exclude, &market.symbol)
.universe_exclude
.iter()
.any(|item| item == "bjse")
&& market.symbol.ends_with(".BJ")
{ {
return Ok(Some("bjse".to_string())); return Ok(Some(reason.to_string()));
} }
let upper_limit_check_price = let upper_limit_check_price =
self.projected_risk_check_price(ctx, date, symbol, &market, OrderSide::Buy, None); self.projected_risk_check_price(ctx, date, symbol, &market, OrderSide::Buy, None);
@@ -9093,6 +9106,37 @@ mod tests {
NaiveDate::from_ymd_opt(year, month, day).expect("valid date") NaiveDate::from_ymd_opt(year, month, day).expect("valid date")
} }
#[test]
fn universe_exclude_matches_explicit_symbols_and_bjse_alias() {
let excludes = vec![
"920149.bj".to_string(),
"688555.sh".to_string(),
"000001".to_string(),
"bjse".to_string(),
];
assert_eq!(
PlatformExprStrategy::universe_exclude_reason(&excludes, "920149.BJ"),
Some("universe_exclude")
);
assert_eq!(
PlatformExprStrategy::universe_exclude_reason(&excludes, "688555.SH"),
Some("universe_exclude")
);
assert_eq!(
PlatformExprStrategy::universe_exclude_reason(&excludes, "000001.SZ"),
Some("universe_exclude")
);
assert_eq!(
PlatformExprStrategy::universe_exclude_reason(&["bjse".to_string()], "920508.BJ"),
Some("bjse")
);
assert_eq!(
PlatformExprStrategy::universe_exclude_reason(&excludes, "300001.SZ"),
None
);
}
#[test] #[test]
fn platform_expr_rewrites_nested_ternary() { fn platform_expr_rewrites_nested_ternary() {
let expr = "pct_change(\"close\", 10) + (((close / rolling_mean(\"close\", 20)) - 1) > 0 ? 0.04 : -0.04)"; let expr = "pct_change(\"close\", 10) + (((close / rolling_mean(\"close\", 20)) - 1) > 0 ? 0.04 : -0.04)";