From 29fcd67bf878d64f16b6d11dbfab674e67f61d27 Mon Sep 17 00:00:00 2001 From: boris Date: Sat, 1 Aug 2026 21:30:37 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8C=89=E8=A1=A8=E8=BE=BE=E5=BC=8F=E9=9C=80?= =?UTF-8?q?=E6=B1=82=E6=9E=84=E5=BB=BA=E8=BF=90=E8=A1=8C=E4=BD=9C=E7=94=A8?= =?UTF-8?q?=E5=9F=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../fidc-core/src/platform_expr_strategy.rs | 58 ++++++++++++++++--- 1 file changed, 51 insertions(+), 7 deletions(-) diff --git a/crates/fidc-core/src/platform_expr_strategy.rs b/crates/fidc-core/src/platform_expr_strategy.rs index c96325a..e6d635d 100644 --- a/crates/fidc-core/src/platform_expr_strategy.rs +++ b/crates/fidc-core/src/platform_expr_strategy.rs @@ -792,6 +792,49 @@ fn is_precomputed_stock_current_rolling_key(key: &str) -> bool { || has_numeric_window(key, "avg_volume", "_current") } +struct SelectiveExpressionScope<'a> { + inner: Scope<'static>, + expression_identifiers: &'a BTreeSet, + prelude_identifiers: &'a BTreeSet, +} + +impl<'a> SelectiveExpressionScope<'a> { + fn new( + expression_identifiers: &'a BTreeSet, + prelude_identifiers: &'a BTreeSet, + ) -> Self { + Self { + inner: Scope::new(), + expression_identifiers, + prelude_identifiers, + } + } + + fn requires(&self, name: &str) -> bool { + self.expression_identifiers.contains(name) || self.prelude_identifiers.contains(name) + } + + fn push>(&mut self, name: &str, value: T) -> &mut Self { + if self.requires(name) { + self.inner.push_dynamic(name.to_string(), value.into()); + } + self + } + + fn push_required>(&mut self, name: &str, value: T) -> &mut Self { + self.inner.push_dynamic(name.to_string(), value.into()); + self + } + + fn inner_mut(&mut self) -> &mut Scope<'static> { + &mut self.inner + } + + fn into_inner(self) -> Scope<'static> { + self.inner + } +} + pub struct PlatformExprStrategy { config: PlatformExprStrategyConfig, engine: Engine, @@ -3732,7 +3775,8 @@ impl PlatformExprStrategy { include_factors_map: bool, include_process_event_counts: bool, ) -> Scope<'static> { - let mut scope = Scope::new(); + let mut scope = + SelectiveExpressionScope::new(identifiers, &self.prelude_identifier_candidates); let trade_date = day.date.format("%Y-%m-%d").to_string(); let decision_date = ctx.decision_date.format("%Y-%m-%d").to_string(); let execution_date = ctx.execution_date.format("%Y-%m-%d").to_string(); @@ -3765,7 +3809,7 @@ impl PlatformExprStrategy { "price_tick", ] { self.push_market_scope_map( - &mut scope, + scope.inner_mut(), ctx, ctx.decision_date, "decision", @@ -3773,7 +3817,7 @@ impl PlatformExprStrategy { identifiers, ); self.push_market_scope_map( - &mut scope, + scope.inner_mut(), ctx, ctx.execution_date, "execution", @@ -3898,7 +3942,7 @@ impl PlatformExprStrategy { for (key, value) in ctx.process_event_counts() { counts.insert(key.into(), Dynamic::from(value)); } - scope.push("process_event_counts", counts.clone()); + scope.push_required("process_event_counts", counts.clone()); Some(counts) } else { None @@ -4085,7 +4129,7 @@ impl PlatformExprStrategy { if let Some(counts) = process_event_counts { day_factors.insert("process_event_counts".into(), Dynamic::from(counts)); } - scope.push("day_factors", day_factors); + scope.push_required("day_factors", day_factors); } if let Some(stock) = stock { let at_upper_limit = Self::price_is_at_or_above_upper_limit( @@ -4346,7 +4390,7 @@ impl PlatformExprStrategy { for (key, value) in &stock.extra_text_factors { factors.insert(key.clone().into(), Dynamic::from(value.clone())); } - scope.push("factors", factors); + scope.push_required("factors", factors); } } if let Some(position) = position { @@ -4398,7 +4442,7 @@ impl PlatformExprStrategy { ); scope.push("profit_pct", position.holding_return * 100.0); } - scope + scope.into_inner() } fn eval_dynamic(