Revert "perf: skip unused explicit-action stock state"
This reverts commit b5934085da.
This commit is contained in:
@@ -1130,7 +1130,6 @@ pub struct PlatformExprStrategy {
|
||||
numeric_vm_scratch: RefCell<NumericVmScratch>,
|
||||
numeric_vm_hits: RefCell<u64>,
|
||||
numeric_vm_fallbacks: RefCell<u64>,
|
||||
explicit_action_stock_state_required: Vec<bool>,
|
||||
prelude_dependency_plan: PreludeDependencyPlan,
|
||||
prelude_identifier_candidates: BTreeSet<String>,
|
||||
prelude_declared_identifiers: BTreeSet<String>,
|
||||
@@ -1438,7 +1437,7 @@ impl PlatformExprStrategy {
|
||||
.portfolio_drawdown_control
|
||||
.clone()
|
||||
.map(PlatformPortfolioDrawdownController::new);
|
||||
let mut strategy = Self {
|
||||
Self {
|
||||
config,
|
||||
engine,
|
||||
rebalance_day_counter: 0,
|
||||
@@ -1458,7 +1457,6 @@ impl PlatformExprStrategy {
|
||||
numeric_vm_scratch: RefCell::new(NumericVmScratch::default()),
|
||||
numeric_vm_hits: RefCell::new(0),
|
||||
numeric_vm_fallbacks: RefCell::new(0),
|
||||
explicit_action_stock_state_required: Vec::new(),
|
||||
prelude_dependency_plan,
|
||||
prelude_identifier_candidates,
|
||||
prelude_declared_identifiers,
|
||||
@@ -1476,14 +1474,7 @@ impl PlatformExprStrategy {
|
||||
stock_state_cache_date: RefCell::new(None),
|
||||
stock_state_cache_calendar_index: RefCell::new(None),
|
||||
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 缓存命中次数(仅用于测试与诊断)。
|
||||
@@ -8650,140 +8641,6 @@ impl PlatformExprStrategy {
|
||||
|| 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(
|
||||
&self,
|
||||
ctx: &StrategyContext<'_>,
|
||||
@@ -8805,7 +8662,7 @@ impl PlatformExprStrategy {
|
||||
) -> Result<(Vec<OrderIntent>, Vec<String>), BacktestError> {
|
||||
let mut intents = 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 {
|
||||
PlatformTradeAction::Order {
|
||||
kind,
|
||||
@@ -8818,11 +8675,7 @@ impl PlatformExprStrategy {
|
||||
when_expr,
|
||||
reason,
|
||||
} => {
|
||||
let stock_state = if self.explicit_action_stock_state_required[action_index] {
|
||||
self.action_stock_state(ctx, date, Some(symbol))?
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let stock_state = self.action_stock_state(ctx, date, Some(symbol))?;
|
||||
if !self.action_when_matches(
|
||||
ctx,
|
||||
day,
|
||||
@@ -9286,11 +9139,7 @@ impl PlatformExprStrategy {
|
||||
when_expr,
|
||||
reason,
|
||||
} => {
|
||||
let stock_state = if self.explicit_action_stock_state_required[action_index] {
|
||||
self.action_stock_state(ctx, date, symbol.as_deref())?
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let stock_state = self.action_stock_state(ctx, date, symbol.as_deref())?;
|
||||
if !self.action_when_matches(
|
||||
ctx,
|
||||
day,
|
||||
@@ -9340,11 +9189,7 @@ impl PlatformExprStrategy {
|
||||
when_expr,
|
||||
reason,
|
||||
} => {
|
||||
let stock_state = if self.explicit_action_stock_state_required[action_index] {
|
||||
self.action_stock_state(ctx, date, symbol.as_deref())?
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let stock_state = self.action_stock_state(ctx, date, symbol.as_deref())?;
|
||||
if !self.action_when_matches(
|
||||
ctx,
|
||||
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]
|
||||
fn expression_plan_only_executes_prelude_when_expression_depends_on_it() {
|
||||
let mut cfg = PlatformExprStrategyConfig::microcap_rotation();
|
||||
|
||||
Reference in New Issue
Block a user