From d264e39285319ac22a1f6de1b794ad21a0da03ac Mon Sep 17 00:00:00 2001 From: boris Date: Sun, 21 Jun 2026 01:42:06 +0800 Subject: [PATCH] =?UTF-8?q?=E6=87=92=E5=8A=A0=E8=BD=BD=E7=AD=96=E7=95=A5?= =?UTF-8?q?=E9=A2=9D=E5=A4=96=E5=9B=A0=E5=AD=90=E7=8A=B6=E6=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../fidc-core/src/platform_expr_strategy.rs | 97 +++++++++++++++---- 1 file changed, 78 insertions(+), 19 deletions(-) diff --git a/crates/fidc-core/src/platform_expr_strategy.rs b/crates/fidc-core/src/platform_expr_strategy.rs index 936a5cc..0d1426d 100644 --- a/crates/fidc-core/src/platform_expr_strategy.rs +++ b/crates/fidc-core/src/platform_expr_strategy.rs @@ -556,6 +556,7 @@ pub struct PlatformExprStrategy { selection_quote_usage: StockFilterQuoteUsage, stock_rolling_requirements: StockRollingRequirements, stock_extra_factors_required: bool, + stock_text_factors_required: bool, stock_state_cache_date: RefCell>, stock_state_cache: RefCell< HashMap<(NaiveDate, NaiveDate, String, Option, bool), StockExpressionState>, @@ -656,6 +657,11 @@ impl PlatformExprStrategy { &normalized_stock_filter_expr, &prelude_declared_identifiers, ); + let stock_text_factors_required = Self::stock_text_factors_required_for_config( + &config, + &normalized_stock_filter_expr, + &prelude_declared_identifiers, + ); Self { config, engine, @@ -675,6 +681,7 @@ impl PlatformExprStrategy { selection_quote_usage, stock_rolling_requirements, stock_extra_factors_required, + stock_text_factors_required, stock_state_cache_date: RefCell::new(None), stock_state_cache: RefCell::new(HashMap::new()), } @@ -2162,18 +2169,24 @@ impl PlatformExprStrategy { weekday: date.weekday().number_from_monday() as i64, is_month_start: date.day() == 1, is_month_end, - available_factor_names: ctx - .data - .factor_snapshots_on(date) - .into_iter() - .flat_map(|row| row.extra_factors.keys().cloned()) - .collect(), - available_text_factor_names: ctx - .data - .factor_text_snapshots_on(date) - .into_iter() - .map(|row| row.field.clone()) - .collect(), + available_factor_names: if self.stock_extra_factors_required { + ctx.data + .factor_snapshots_on(date) + .into_iter() + .flat_map(|row| row.extra_factors.keys().cloned()) + .collect() + } else { + BTreeSet::new() + }, + available_text_factor_names: if self.stock_text_factors_required { + ctx.data + .factor_text_snapshots_on(date) + .into_iter() + .map(|row| row.field.clone()) + .collect() + } else { + BTreeSet::new() + }, }) } @@ -2506,13 +2519,16 @@ impl PlatformExprStrategy { } else { BTreeMap::new() }, - extra_text_factors: ctx - .data - .factor_text_snapshots_on(date) - .into_iter() - .filter(|row| row.symbol == symbol) - .map(|row| (row.field.clone(), row.value.clone())) - .collect(), + extra_text_factors: if self.stock_text_factors_required { + ctx.data + .factor_text_snapshots_on(date) + .into_iter() + .filter(|row| row.symbol == symbol) + .map(|row| (row.field.clone(), row.value.clone())) + .collect() + } else { + BTreeMap::new() + }, }; self.stock_state_cache .borrow_mut() @@ -6403,6 +6419,49 @@ impl PlatformExprStrategy { }) } + fn stock_text_factors_required_for_config( + config: &PlatformExprStrategyConfig, + normalized_stock_filter_expr: &str, + prelude_declared_identifiers: &BTreeSet, + ) -> bool { + if !config.explicit_actions.is_empty() { + return true; + } + [ + config.prelude.as_str(), + normalized_stock_filter_expr, + config.buy_scale_expr.as_str(), + config.stop_loss_expr.as_str(), + config.take_profit_expr.as_str(), + config.rank_expr.as_str(), + config.market_cap_field.as_str(), + config.rank_by.as_str(), + ] + .into_iter() + .any(|expr| Self::expr_may_use_stock_text_factors(expr, prelude_declared_identifiers)) + } + + fn expr_may_use_stock_text_factors( + expr: &str, + prelude_declared_identifiers: &BTreeSet, + ) -> bool { + let normalized = Self::normalize_expr(expr); + let identifiers = Self::extract_identifier_candidates(&normalized); + if identifiers.contains("factors") + || identifiers.contains("factor") + || identifiers.contains("factor_text") + || identifiers.contains("get_factor_text") + { + return true; + } + identifiers.into_iter().any(|name| { + !Self::is_expression_keyword(&name) + && !Self::is_runtime_helper(&name) + && !Self::is_reserved_scope_name(&name) + && !prelude_declared_identifiers.contains(&name) + }) + } + fn expr_requires_stock_extra_factors( expr: &str, prelude_declared_identifiers: &BTreeSet,