Revert "perf: skip unused explicit-action stock state"

This reverts commit b5934085da.
This commit is contained in:
boris
2026-09-06 20:02:33 +08:00
parent b5934085da
commit c7d213bf35
+6 -202
View File
@@ -1130,7 +1130,6 @@ pub struct PlatformExprStrategy {
numeric_vm_scratch: RefCell<NumericVmScratch>, numeric_vm_scratch: RefCell<NumericVmScratch>,
numeric_vm_hits: RefCell<u64>, numeric_vm_hits: RefCell<u64>,
numeric_vm_fallbacks: RefCell<u64>, numeric_vm_fallbacks: RefCell<u64>,
explicit_action_stock_state_required: Vec<bool>,
prelude_dependency_plan: PreludeDependencyPlan, prelude_dependency_plan: PreludeDependencyPlan,
prelude_identifier_candidates: BTreeSet<String>, prelude_identifier_candidates: BTreeSet<String>,
prelude_declared_identifiers: BTreeSet<String>, prelude_declared_identifiers: BTreeSet<String>,
@@ -1438,7 +1437,7 @@ impl PlatformExprStrategy {
.portfolio_drawdown_control .portfolio_drawdown_control
.clone() .clone()
.map(PlatformPortfolioDrawdownController::new); .map(PlatformPortfolioDrawdownController::new);
let mut strategy = Self { Self {
config, config,
engine, engine,
rebalance_day_counter: 0, rebalance_day_counter: 0,
@@ -1458,7 +1457,6 @@ impl PlatformExprStrategy {
numeric_vm_scratch: RefCell::new(NumericVmScratch::default()), numeric_vm_scratch: RefCell::new(NumericVmScratch::default()),
numeric_vm_hits: RefCell::new(0), numeric_vm_hits: RefCell::new(0),
numeric_vm_fallbacks: RefCell::new(0), numeric_vm_fallbacks: RefCell::new(0),
explicit_action_stock_state_required: Vec::new(),
prelude_dependency_plan, prelude_dependency_plan,
prelude_identifier_candidates, prelude_identifier_candidates,
prelude_declared_identifiers, prelude_declared_identifiers,
@@ -1476,14 +1474,7 @@ impl PlatformExprStrategy {
stock_state_cache_date: RefCell::new(None), stock_state_cache_date: RefCell::new(None),
stock_state_cache_calendar_index: RefCell::new(None), stock_state_cache_calendar_index: RefCell::new(None),
stock_state_cache: RefCell::new(AHashMap::new()), stock_state_cache: RefCell::new(AHashMap::new()),
}; }
strategy.explicit_action_stock_state_required = strategy
.config
.explicit_actions
.iter()
.map(|action| strategy.explicit_action_requires_stock_state(action))
.collect();
strategy
} }
/// AST 缓存命中次数(仅用于测试与诊断)。 /// AST 缓存命中次数(仅用于测试与诊断)。
@@ -8650,140 +8641,6 @@ impl PlatformExprStrategy {
|| self.config.signal_rebalance_dates.contains(&decision_date) || self.config.signal_rebalance_dates.contains(&decision_date)
} }
fn numeric_vm_identifier_requires_stock_state(identifier: &str) -> bool {
!matches!(
identifier,
"trade_date"
| "current_date"
| "date"
| "decision_date"
| "execution_date"
| "signal_open"
| "signal_close"
| "benchmark_open"
| "benchmark_close"
| "benchmark_signal_close"
| "signal_ma5"
| "signal_ma10"
| "signal_ma20"
| "signal_ma30"
| "signal_ma_short"
| "signal_ma_long"
| "benchmark_ma5"
| "benchmark_ma10"
| "benchmark_ma20"
| "benchmark_ma30"
| "benchmark_ma_short"
| "benchmark_ma_long"
| "cash"
| "available_cash"
| "frozen_cash"
| "market_value"
| "total_equity"
| "total_value"
| "portfolio_value"
| "starting_cash"
| "unit_net_value"
| "static_unit_net_value"
| "daily_pnl"
| "daily_returns"
| "total_returns"
| "transaction_cost"
| "trading_pnl"
| "position_pnl"
| "cash_liabilities"
| "management_fee_rate"
| "management_fees"
| "current_exposure"
| "position_count"
| "max_positions"
| "refresh_rate"
| "year"
| "month"
| "quarter"
| "day_of_month"
| "day_of_year"
| "week_of_year"
| "weekday"
| "is_month_start"
| "is_month_end"
| "has_open_orders"
| "open_order_count"
| "open_buy_order_count"
| "open_sell_order_count"
| "open_buy_qty"
| "open_sell_qty"
| "latest_open_order_id"
| "latest_open_order_unfilled_qty"
| "has_dynamic_universe"
| "dynamic_universe_count"
| "has_subscriptions"
| "subscription_count"
| "subscription_guard_required"
| "has_process_events"
| "process_event_count"
| "current_process_order_id"
| "latest_process_order_id"
)
}
fn expression_requires_stock_state(&self, expression: &str) -> bool {
let plan = self.expression_eval_plan(expression);
let Some(numeric_vm) = plan.numeric_vm.as_ref() else {
return true;
};
numeric_vm
.program
.variables()
.iter()
.zip(&numeric_vm.helper_bindings)
.any(|(identifier, helper)| {
helper.is_some() || Self::numeric_vm_identifier_requires_stock_state(identifier)
})
}
fn explicit_action_requires_stock_state(&self, action: &PlatformTradeAction) -> bool {
match action {
PlatformTradeAction::Order {
amount_expr,
limit_price_expr,
start_time_expr,
end_time_expr,
when_expr,
..
} => std::iter::once(amount_expr.as_str())
.chain(limit_price_expr.as_deref())
.chain(start_time_expr.as_deref())
.chain(end_time_expr.as_deref())
.chain(when_expr.as_deref())
.any(|expression| self.expression_requires_stock_state(expression)),
PlatformTradeAction::Cancel {
order_id_expr,
when_expr,
..
} => order_id_expr
.as_deref()
.into_iter()
.chain(when_expr.as_deref())
.any(|expression| self.expression_requires_stock_state(expression)),
PlatformTradeAction::Modify {
order_id_expr,
new_total_quantity_expr,
new_limit_price_expr,
when_expr,
..
} => std::iter::once(order_id_expr.as_str())
.chain(new_total_quantity_expr.as_deref())
.chain(new_limit_price_expr.as_deref())
.chain(when_expr.as_deref())
.any(|expression| self.expression_requires_stock_state(expression)),
PlatformTradeAction::TargetPortfolioSmart { .. }
| PlatformTradeAction::Universe { .. }
| PlatformTradeAction::Account { .. }
| PlatformTradeAction::Futures { .. } => false,
}
}
fn action_when_matches( fn action_when_matches(
&self, &self,
ctx: &StrategyContext<'_>, ctx: &StrategyContext<'_>,
@@ -8805,7 +8662,7 @@ impl PlatformExprStrategy {
) -> Result<(Vec<OrderIntent>, Vec<String>), BacktestError> { ) -> Result<(Vec<OrderIntent>, Vec<String>), BacktestError> {
let mut intents = Vec::new(); let mut intents = Vec::new();
let mut diagnostics = Vec::new(); let mut diagnostics = Vec::new();
for (action_index, action) in self.config.explicit_actions.iter().enumerate() { for action in &self.config.explicit_actions {
match action { match action {
PlatformTradeAction::Order { PlatformTradeAction::Order {
kind, kind,
@@ -8818,11 +8675,7 @@ impl PlatformExprStrategy {
when_expr, when_expr,
reason, reason,
} => { } => {
let stock_state = if self.explicit_action_stock_state_required[action_index] { let stock_state = self.action_stock_state(ctx, date, Some(symbol))?;
self.action_stock_state(ctx, date, Some(symbol))?
} else {
None
};
if !self.action_when_matches( if !self.action_when_matches(
ctx, ctx,
day, day,
@@ -9286,11 +9139,7 @@ impl PlatformExprStrategy {
when_expr, when_expr,
reason, reason,
} => { } => {
let stock_state = if self.explicit_action_stock_state_required[action_index] { let stock_state = self.action_stock_state(ctx, date, symbol.as_deref())?;
self.action_stock_state(ctx, date, symbol.as_deref())?
} else {
None
};
if !self.action_when_matches( if !self.action_when_matches(
ctx, ctx,
day, day,
@@ -9340,11 +9189,7 @@ impl PlatformExprStrategy {
when_expr, when_expr,
reason, reason,
} => { } => {
let stock_state = if self.explicit_action_stock_state_required[action_index] { let stock_state = self.action_stock_state(ctx, date, symbol.as_deref())?;
self.action_stock_state(ctx, date, symbol.as_deref())?
} else {
None
};
if !self.action_when_matches( if !self.action_when_matches(
ctx, ctx,
day, day,
@@ -34576,47 +34421,6 @@ mod tests {
); );
} }
#[test]
fn explicit_action_stock_state_dependency_is_compiled_conservatively() {
let mut config = PlatformExprStrategyConfig::generic();
config.explicit_actions = vec![
PlatformTradeAction::Order {
kind: PlatformExplicitOrderKind::TargetPercent,
symbol: "000001.SZ".to_string(),
amount_expr: "if decision_date == \"2025-02-03\" { 0.5 } else { 0.0 }".to_string(),
limit_price_expr: None,
time_in_force: None,
start_time_expr: None,
end_time_expr: None,
when_expr: None,
reason: "date_only".to_string(),
},
PlatformTradeAction::Order {
kind: PlatformExplicitOrderKind::TargetPercent,
symbol: "000002.SZ".to_string(),
amount_expr: "allow_buy ? 0.5 : 0.0".to_string(),
limit_price_expr: None,
time_in_force: None,
start_time_expr: None,
end_time_expr: None,
when_expr: None,
reason: "stock_dependent".to_string(),
},
];
let strategy = PlatformExprStrategy::new(config);
assert_eq!(
strategy.explicit_action_stock_state_required,
vec![false, true]
);
assert!(!strategy.expression_requires_stock_state(
"if decision_date == \"2025-02-03\" { cash * 0.1 } else { 0.0 }"
));
assert!(!strategy.expression_requires_stock_state("cash * 0.1"));
assert!(strategy.expression_requires_stock_state("allow_buy"));
assert!(strategy.expression_requires_stock_state("factor_value(\"quality\") > 0"));
assert!(strategy.expression_requires_stock_state("symbol == \"000001.SZ\""));
}
#[test] #[test]
fn expression_plan_only_executes_prelude_when_expression_depends_on_it() { fn expression_plan_only_executes_prelude_when_expression_depends_on_it() {
let mut cfg = PlatformExprStrategyConfig::microcap_rotation(); let mut cfg = PlatformExprStrategyConfig::microcap_rotation();