From bb721ab258889674a668237049280571c5d217b5 Mon Sep 17 00:00:00 2001 From: boris Date: Sat, 29 Aug 2026 20:16:53 +0800 Subject: [PATCH] =?UTF-8?q?=E5=85=B1=E4=BA=AB=E6=8C=89=E6=97=A5=E6=9C=9F?= =?UTF-8?q?=E5=B8=82=E5=80=BC=E6=8E=92=E5=BA=8F=E7=B4=A2=E5=BC=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- crates/fidc-core/src/data.rs | 31 ++++++++++++++++++ .../fidc-core/src/platform_expr_strategy.rs | 32 +++++++++++++++---- 2 files changed, 56 insertions(+), 7 deletions(-) diff --git a/crates/fidc-core/src/data.rs b/crates/fidc-core/src/data.rs index 153e97a..7588b66 100644 --- a/crates/fidc-core/src/data.rs +++ b/crates/fidc-core/src/data.rs @@ -1312,6 +1312,7 @@ pub struct DataSet { market_row_positions_by_date: Arc>, factor_by_date: Arc>>, factor_symbol_ids_by_date: Arc>>, + factor_market_cap_order_by_date: Arc>>>, factor_row_positions_by_date: Arc>, factor_text_by_date: Arc>>, factor_text_symbol_indices_by_date: @@ -1794,6 +1795,7 @@ impl DataSet { market_row_positions_by_date: Arc::new(market_row_positions_by_date), factor_by_date: Arc::new(factor_by_date), factor_symbol_ids_by_date: Arc::new(factor_symbol_ids_by_date), + factor_market_cap_order_by_date: Arc::new(OnceLock::new()), factor_row_positions_by_date: Arc::new(factor_row_positions_by_date), factor_text_by_date: Arc::new(factor_text_by_date), factor_text_symbol_indices_by_date: Arc::new(factor_text_symbol_indices_by_date), @@ -2899,6 +2901,15 @@ impl DataSet { .unwrap_or(&[]) } + /// Returns the immutable factor-row order for ascending decision market cap. + /// The index is built once per DataSet and shared by all cloned run views. + pub fn factor_market_cap_order_on(&self, date: NaiveDate) -> Option<&[usize]> { + self.factor_market_cap_order_by_date + .get_or_init(|| build_factor_market_cap_order(&self.factor_by_date)) + .get(&date) + .map(Vec::as_slice) + } + pub fn factor_text_snapshots_on(&self, date: NaiveDate) -> Vec<&FactorTextValue> { self.factor_text_by_date .get(&date) @@ -4037,6 +4048,26 @@ where .collect() } +fn build_factor_market_cap_order( + factor_by_date: &BTreeMap>, +) -> BTreeMap> { + factor_by_date + .iter() + .map(|(date, rows)| { + let mut indices = (0..rows.len()).collect::>(); + indices.sort_unstable_by(|left, right| { + rows[*left] + .market_cap_bn + .partial_cmp(&rows[*right].market_cap_bn) + .unwrap_or(std::cmp::Ordering::Equal) + .then_with(|| rows[*left].symbol.cmp(&rows[*right].symbol)) + .then_with(|| left.cmp(right)) + }); + (*date, indices) + }) + .collect() +} + fn build_dense_row_positions( groups: &BTreeMap>, symbol_ids_by_date: &BTreeMap>, diff --git a/crates/fidc-core/src/platform_expr_strategy.rs b/crates/fidc-core/src/platform_expr_strategy.rs index 21f6da6..7c9c4a6 100644 --- a/crates/fidc-core/src/platform_expr_strategy.rs +++ b/crates/fidc-core/src/platform_expr_strategy.rs @@ -8991,7 +8991,23 @@ impl PlatformExprStrategy { }; let factor_symbol_ids = ctx.data.factor_symbol_ids_on(factor_date); debug_assert_eq!(factor_rows.len(), factor_symbol_ids.len()); - for (factor, symbol_id) in factor_rows.iter().zip(factor_symbol_ids.iter().copied()) { + let market_cap_order = ctx.data.factor_market_cap_order_on(factor_date); + let mut fallback_factor_rows = + factor_rows.iter().zip(factor_symbol_ids.iter().copied()); + let mut ordered_factor_row_index = 0usize; + let factor_rows = std::iter::from_fn(|| { + if let Some(indices) = market_cap_order { + let row_index = *indices.get(ordered_factor_row_index)?; + ordered_factor_row_index += 1; + Some(( + factor_rows.get(row_index)?, + *factor_symbol_ids.get(row_index)?, + )) + } else { + fallback_factor_rows.next() + } + }); + for (factor, symbol_id) in factor_rows { if ctx.has_dynamic_universe() && !ctx.dynamic_universe_contains(&factor.symbol) { continue; } @@ -9059,12 +9075,14 @@ impl PlatformExprStrategy { free_float_cap_bn, }); } - rows.sort_unstable_by(|left, right| { - left.market_cap_bn - .partial_cmp(&right.market_cap_bn) - .unwrap_or(std::cmp::Ordering::Equal) - .then_with(|| left.symbol.cmp(&right.symbol)) - }); + if market_cap_order.is_none() { + rows.sort_unstable_by(|left, right| { + left.market_cap_bn + .partial_cmp(&right.market_cap_bn) + .unwrap_or(std::cmp::Ordering::Equal) + .then_with(|| left.symbol.cmp(&right.symbol)) + }); + } (rows, decisions) }