diff --git a/crates/fidc-core/src/data.rs b/crates/fidc-core/src/data.rs index 177e41b..04ff857 100644 --- a/crates/fidc-core/src/data.rs +++ b/crates/fidc-core/src/data.rs @@ -1326,6 +1326,7 @@ pub struct DataSet { benchmark_series_cache: Arc, symbol_id_by_code: Arc>, symbol_by_id: Arc>>, + symbol_is_bjse_by_id: Arc>, eligible_universe_by_date: Arc>>>, benchmark_code: String, futures_params_by_symbol: Arc>>, @@ -1774,6 +1775,10 @@ impl DataSet { for (symbol, symbol_id) in &symbol_id_by_code { symbol_by_id[*symbol_id as usize] = Arc::::from(symbol.as_str()); } + let symbol_is_bjse_by_id = symbol_by_id + .iter() + .map(|symbol| symbol_is_bjse(symbol)) + .collect::>(); let mut instruments_by_symbol_id = vec![None; symbol_id_by_code.len()]; for (symbol, instrument) in &instruments { if let Some(symbol_id) = symbol_id_by_code.get(symbol).copied() { @@ -1863,6 +1868,7 @@ impl DataSet { benchmark_series_cache: Arc::new(benchmark_series_cache), symbol_id_by_code: Arc::new(symbol_id_by_code), symbol_by_id: Arc::new(symbol_by_id), + symbol_is_bjse_by_id: Arc::new(symbol_is_bjse_by_id), eligible_universe_by_date: Arc::new(OnceLock::new()), benchmark_code, futures_params_by_symbol: Arc::new(futures_params_by_symbol), @@ -1921,6 +1927,13 @@ impl DataSet { (!symbol.is_empty()).then(|| Arc::clone(symbol)) } + pub(crate) fn symbol_is_bjse_by_id(&self, symbol_id: u32) -> bool { + self.symbol_is_bjse_by_id + .get(symbol_id as usize) + .copied() + .unwrap_or(false) + } + pub(crate) fn symbol_count(&self) -> usize { self.symbol_id_by_code.len() } @@ -4087,6 +4100,18 @@ fn normalized_field(field: &str) -> Cow<'_, str> { } } +pub(crate) fn symbol_is_bjse(symbol: &str) -> bool { + let normalized = symbol.trim(); + normalized + .get(normalized.len().saturating_sub(3)..) + .is_some_and(|suffix| { + suffix.eq_ignore_ascii_case(".BJ") || suffix.eq_ignore_ascii_case(".BE") + }) + || normalized + .get(normalized.len().saturating_sub(4)..) + .is_some_and(|suffix| suffix.eq_ignore_ascii_case(".BSE")) +} + fn normalize_factor_snapshots(factors: Vec) -> Vec { factors .into_iter() diff --git a/crates/fidc-core/src/platform_expr_strategy.rs b/crates/fidc-core/src/platform_expr_strategy.rs index 6a41155..db6844f 100644 --- a/crates/fidc-core/src/platform_expr_strategy.rs +++ b/crates/fidc-core/src/platform_expr_strategy.rs @@ -4284,7 +4284,7 @@ impl PlatformExprStrategy { is_st: candidate.is_st, is_star_st: candidate.is_star_st, is_kcb: candidate.is_kcb, - is_bjse: Self::symbol_is_bjse(symbol), + is_bjse: ctx.data.symbol_is_bjse_by_id(symbol_id), is_one_yuan: candidate.is_one_yuan || market.day_open <= 1.0, is_new_listing: candidate.is_new_listing, allow_buy: candidate.allow_buy, @@ -9533,18 +9533,6 @@ impl PlatformExprStrategy { None } - fn symbol_is_bjse(symbol: &str) -> bool { - let normalized = symbol.trim(); - normalized - .get(normalized.len().saturating_sub(3)..) - .is_some_and(|suffix| { - suffix.eq_ignore_ascii_case(".BJ") || suffix.eq_ignore_ascii_case(".BE") - }) - || normalized - .get(normalized.len().saturating_sub(4)..) - .is_some_and(|suffix| suffix.eq_ignore_ascii_case(".BSE")) - } - fn stock_numeric_field_value( &self, candidate: &EligibleUniverseSnapshot, @@ -12912,12 +12900,12 @@ mod tests { #[test] fn bjse_symbol_detection_is_case_insensitive_without_normalizing_all_symbols() { - assert!(PlatformExprStrategy::symbol_is_bjse("920508.BJ")); - assert!(PlatformExprStrategy::symbol_is_bjse(" 920508.bj ")); - assert!(PlatformExprStrategy::symbol_is_bjse("430001.BSE")); - assert!(PlatformExprStrategy::symbol_is_bjse("430001.be")); - assert!(!PlatformExprStrategy::symbol_is_bjse("688001.SH")); - assert!(!PlatformExprStrategy::symbol_is_bjse("BJ")); + assert!(crate::data::symbol_is_bjse("920508.BJ")); + assert!(crate::data::symbol_is_bjse(" 920508.bj ")); + assert!(crate::data::symbol_is_bjse("430001.BSE")); + assert!(crate::data::symbol_is_bjse("430001.be")); + assert!(!crate::data::symbol_is_bjse("688001.SH")); + assert!(!crate::data::symbol_is_bjse("BJ")); } #[test] diff --git a/crates/fidc-core/src/risk_control.rs b/crates/fidc-core/src/risk_control.rs index 47f7f35..2107ce0 100644 --- a/crates/fidc-core/src/risk_control.rs +++ b/crates/fidc-core/src/risk_control.rs @@ -4,7 +4,7 @@ use chrono::NaiveDate; use serde::{Deserialize, Serialize}; use crate::OrderSide; -use crate::data::{CandidateEligibility, DailyMarketSnapshot, PriceField}; +use crate::data::{CandidateEligibility, DailyMarketSnapshot, PriceField, symbol_is_bjse}; use crate::instrument::Instrument; use crate::portfolio::Position; @@ -602,11 +602,6 @@ fn symbol_is_kcb(symbol: &str) -> bool { (normalized.starts_with("688") || normalized.starts_with("689")) && normalized.ends_with(".SH") } -fn symbol_is_bjse(symbol: &str) -> bool { - let normalized = symbol.trim().to_ascii_uppercase(); - normalized.ends_with(".BJ") || normalized.ends_with(".BSE") || normalized.ends_with(".BE") -} - fn candidate_active_status_rejection( candidate: &CandidateEligibility, config: &FidcRiskControlConfig,