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_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();
|
||||||
|
|||||||
Reference in New Issue
Block a user