懒加载策略额外因子状态

This commit is contained in:
boris
2026-06-21 01:42:06 +08:00
parent 5b34f3b55b
commit d264e39285
+78 -19
View File
@@ -556,6 +556,7 @@ pub struct PlatformExprStrategy {
selection_quote_usage: StockFilterQuoteUsage, selection_quote_usage: StockFilterQuoteUsage,
stock_rolling_requirements: StockRollingRequirements, stock_rolling_requirements: StockRollingRequirements,
stock_extra_factors_required: bool, stock_extra_factors_required: bool,
stock_text_factors_required: bool,
stock_state_cache_date: RefCell<Option<NaiveDate>>, stock_state_cache_date: RefCell<Option<NaiveDate>>,
stock_state_cache: RefCell< stock_state_cache: RefCell<
HashMap<(NaiveDate, NaiveDate, String, Option<NaiveTime>, bool), StockExpressionState>, HashMap<(NaiveDate, NaiveDate, String, Option<NaiveTime>, bool), StockExpressionState>,
@@ -656,6 +657,11 @@ impl PlatformExprStrategy {
&normalized_stock_filter_expr, &normalized_stock_filter_expr,
&prelude_declared_identifiers, &prelude_declared_identifiers,
); );
let stock_text_factors_required = Self::stock_text_factors_required_for_config(
&config,
&normalized_stock_filter_expr,
&prelude_declared_identifiers,
);
Self { Self {
config, config,
engine, engine,
@@ -675,6 +681,7 @@ impl PlatformExprStrategy {
selection_quote_usage, selection_quote_usage,
stock_rolling_requirements, stock_rolling_requirements,
stock_extra_factors_required, stock_extra_factors_required,
stock_text_factors_required,
stock_state_cache_date: RefCell::new(None), stock_state_cache_date: RefCell::new(None),
stock_state_cache: RefCell::new(HashMap::new()), stock_state_cache: RefCell::new(HashMap::new()),
} }
@@ -2162,18 +2169,24 @@ impl PlatformExprStrategy {
weekday: date.weekday().number_from_monday() as i64, weekday: date.weekday().number_from_monday() as i64,
is_month_start: date.day() == 1, is_month_start: date.day() == 1,
is_month_end, is_month_end,
available_factor_names: ctx available_factor_names: if self.stock_extra_factors_required {
.data ctx.data
.factor_snapshots_on(date) .factor_snapshots_on(date)
.into_iter() .into_iter()
.flat_map(|row| row.extra_factors.keys().cloned()) .flat_map(|row| row.extra_factors.keys().cloned())
.collect(), .collect()
available_text_factor_names: ctx } else {
.data BTreeSet::new()
.factor_text_snapshots_on(date) },
.into_iter() available_text_factor_names: if self.stock_text_factors_required {
.map(|row| row.field.clone()) ctx.data
.collect(), .factor_text_snapshots_on(date)
.into_iter()
.map(|row| row.field.clone())
.collect()
} else {
BTreeSet::new()
},
}) })
} }
@@ -2506,13 +2519,16 @@ impl PlatformExprStrategy {
} else { } else {
BTreeMap::new() BTreeMap::new()
}, },
extra_text_factors: ctx extra_text_factors: if self.stock_text_factors_required {
.data ctx.data
.factor_text_snapshots_on(date) .factor_text_snapshots_on(date)
.into_iter() .into_iter()
.filter(|row| row.symbol == symbol) .filter(|row| row.symbol == symbol)
.map(|row| (row.field.clone(), row.value.clone())) .map(|row| (row.field.clone(), row.value.clone()))
.collect(), .collect()
} else {
BTreeMap::new()
},
}; };
self.stock_state_cache self.stock_state_cache
.borrow_mut() .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<String>,
) -> 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<String>,
) -> 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( fn expr_requires_stock_extra_factors(
expr: &str, expr: &str,
prelude_declared_identifiers: &BTreeSet<String>, prelude_declared_identifiers: &BTreeSet<String>,