按策略引用投影额外因子字段
This commit is contained in:
@@ -990,6 +990,7 @@ pub struct PlatformExprStrategy {
|
||||
stock_rolling_requirements: StockRollingRequirements,
|
||||
stock_extra_factors_required: bool,
|
||||
stock_extra_factor_identifiers: BTreeSet<String>,
|
||||
stock_extra_factor_map_required: bool,
|
||||
stock_text_factors_required: bool,
|
||||
stock_state_cache_date: RefCell<Option<NaiveDate>>,
|
||||
stock_state_cache: RefCell<
|
||||
@@ -1267,6 +1268,7 @@ impl PlatformExprStrategy {
|
||||
Self::stock_extra_factors_required_for_config(&config, &prelude_declared_identifiers);
|
||||
let stock_extra_factor_identifiers =
|
||||
Self::stock_extra_factor_identifiers_for_config(&config, &prelude_declared_identifiers);
|
||||
let stock_extra_factor_map_required = Self::stock_extra_factor_map_required_for_config(&config);
|
||||
let stock_text_factors_required = Self::stock_text_factors_required_for_config(
|
||||
&config,
|
||||
&normalized_stock_filter_expr,
|
||||
@@ -1304,6 +1306,7 @@ impl PlatformExprStrategy {
|
||||
stock_rolling_requirements,
|
||||
stock_extra_factors_required,
|
||||
stock_extra_factor_identifiers,
|
||||
stock_extra_factor_map_required,
|
||||
stock_text_factors_required,
|
||||
stock_state_cache_date: RefCell::new(None),
|
||||
stock_state_cache: RefCell::new(AHashMap::new()),
|
||||
@@ -4055,6 +4058,10 @@ impl PlatformExprStrategy {
|
||||
factor
|
||||
.extra_factors
|
||||
.iter()
|
||||
.filter(|(field, _)| {
|
||||
self.stock_extra_factor_map_required
|
||||
|| self.stock_extra_factor_identifiers.contains(field.as_ref())
|
||||
})
|
||||
.map(|(field, value)| (field.to_string(), *value))
|
||||
.collect()
|
||||
} else {
|
||||
@@ -9665,6 +9672,30 @@ impl PlatformExprStrategy {
|
||||
.any(|expr| Self::expr_requires_stock_extra_factors(expr, prelude_declared_identifiers))
|
||||
}
|
||||
|
||||
fn stock_extra_factor_map_required_for_config(config: &PlatformExprStrategyConfig) -> bool {
|
||||
// A dynamic factors/factor map is part of the expression contract: its
|
||||
// caller may access any published field by key. Keep the full map for
|
||||
// that case and for explicit actions whose predicates are evaluated at
|
||||
// runtime; direct field references use the projected identifier set.
|
||||
if Self::has_stock_explicit_actions(config) {
|
||||
return true;
|
||||
}
|
||||
[
|
||||
config.prelude.as_str(),
|
||||
config.stock_filter_expr.as_str(),
|
||||
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()
|
||||
.map(Self::normalize_expr)
|
||||
.map(|expr| Self::extract_identifier_candidates(&expr))
|
||||
.any(|identifiers| identifiers.contains("factors") || identifiers.contains("factor"))
|
||||
}
|
||||
|
||||
fn stock_extra_factor_identifiers_for_config(
|
||||
config: &PlatformExprStrategyConfig,
|
||||
prelude_declared_identifiers: &BTreeSet<String>,
|
||||
@@ -13921,7 +13952,10 @@ mod tests {
|
||||
pe_ttm: 8.0,
|
||||
turnover_ratio: Some(1.0),
|
||||
effective_turnover_ratio: Some(1.0),
|
||||
extra_factors: BTreeMap::from([("model_score".into(), 2.0)]),
|
||||
extra_factors: BTreeMap::from([
|
||||
("model_score".into(), 2.0),
|
||||
("unused_factor".into(), 9.0),
|
||||
]),
|
||||
},
|
||||
],
|
||||
symbols
|
||||
@@ -13991,6 +14025,25 @@ mod tests {
|
||||
.stock_passes_expr(&ctx, &day, &present_stock)
|
||||
.expect("present stock filter")
|
||||
);
|
||||
assert!(!strategy.stock_extra_factor_map_required);
|
||||
assert!(present_stock.extra_factors.contains_key("model_score"));
|
||||
assert!(!present_stock.extra_factors.contains_key("unused_factor"));
|
||||
|
||||
let mut map_cfg = PlatformExprStrategyConfig::microcap_rotation();
|
||||
map_cfg.signal_symbol = present_symbol.to_string();
|
||||
map_cfg.stock_filter_expr = "factors[\"unused_factor\"] > 0".to_string();
|
||||
let map_strategy = PlatformExprStrategy::new(map_cfg);
|
||||
assert!(map_strategy.stock_extra_factor_map_required);
|
||||
let map_stock = map_strategy
|
||||
.stock_state_with_factor_date(&ctx, date, date, present_symbol)
|
||||
.expect("factor map stock state");
|
||||
assert!(map_stock.extra_factors.contains_key("unused_factor"));
|
||||
let map_day = map_strategy.day_state(&ctx, date).expect("factor map day state");
|
||||
assert!(
|
||||
map_strategy
|
||||
.stock_passes_expr(&ctx, &map_day, &map_stock)
|
||||
.expect("factor map filter")
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user