Revert "perf: build expression scope values lazily"

This reverts commit 1b449287fd.
This commit is contained in:
boris
2026-09-05 04:01:40 +08:00
parent 1b449287fd
commit 229ca8332d
+113 -129
View File
@@ -917,17 +917,6 @@ impl<'a> SelectiveExpressionScope<'a> {
self self
} }
fn push_lazy<T, F>(&mut self, name: &str, build: F) -> &mut Self
where
T: Into<Dynamic>,
F: FnOnce() -> T,
{
if self.requires(name) {
self.inner.push_dynamic(name.to_string(), build().into());
}
self
}
fn push_required<T: Into<Dynamic>>(&mut self, name: &str, value: T) -> &mut Self { fn push_required<T: Into<Dynamic>>(&mut self, name: &str, value: T) -> &mut Self {
self.inner.push_dynamic(name.to_string(), value.into()); self.inner.push_dynamic(name.to_string(), value.into());
self self
@@ -4459,15 +4448,14 @@ impl PlatformExprStrategy {
include_process_event_counts: bool, include_process_event_counts: bool,
) -> Scope<'static> { ) -> Scope<'static> {
let mut scope = SelectiveExpressionScope::new(scope_identifiers); let mut scope = SelectiveExpressionScope::new(scope_identifiers);
scope.push_lazy("trade_date", || day.date.format("%Y-%m-%d").to_string()); let trade_date = day.date.format("%Y-%m-%d").to_string();
scope.push_lazy("current_date", || day.date.format("%Y-%m-%d").to_string()); let decision_date = ctx.decision_date.format("%Y-%m-%d").to_string();
scope.push_lazy("date", || day.date.format("%Y-%m-%d").to_string()); let execution_date = ctx.execution_date.format("%Y-%m-%d").to_string();
scope.push_lazy("decision_date", || { scope.push("trade_date", trade_date.clone());
ctx.decision_date.format("%Y-%m-%d").to_string() scope.push("current_date", trade_date.clone());
}); scope.push("date", trade_date);
scope.push_lazy("execution_date", || { scope.push("decision_date", decision_date);
ctx.execution_date.format("%Y-%m-%d").to_string() scope.push("execution_date", execution_date);
});
scope.push("signal_open", day.signal_open); scope.push("signal_open", day.signal_open);
scope.push("signal_close", day.signal_close); scope.push("signal_close", day.signal_close);
scope.push("benchmark_open", day.benchmark_open); scope.push("benchmark_open", day.benchmark_open);
@@ -4554,63 +4542,74 @@ impl PlatformExprStrategy {
scope.push("is_month_start", day.is_month_start); scope.push("is_month_start", day.is_month_start);
scope.push("is_month_end", day.is_month_end); scope.push("is_month_end", day.is_month_end);
scope.push("signal_ma30", day.signal_ma30); scope.push("signal_ma30", day.signal_ma30);
scope.push_lazy("has_open_orders", || ctx.has_open_orders()); scope.push("has_open_orders", ctx.has_open_orders());
scope.push_lazy("open_order_count", || ctx.open_order_count() as i64); scope.push("open_order_count", ctx.open_order_count() as i64);
scope.push_lazy("open_buy_order_count", || ctx.open_buy_order_count() as i64); scope.push("open_buy_order_count", ctx.open_buy_order_count() as i64);
scope.push_lazy("open_sell_order_count", || { scope.push("open_sell_order_count", ctx.open_sell_order_count() as i64);
ctx.open_sell_order_count() as i64 scope.push("open_buy_qty", ctx.open_buy_quantity() as i64);
}); scope.push("open_sell_qty", ctx.open_sell_quantity() as i64);
scope.push_lazy("open_buy_qty", || ctx.open_buy_quantity() as i64); scope.push("latest_open_order_id", ctx.latest_open_order_id() as i64);
scope.push_lazy("open_sell_qty", || ctx.open_sell_quantity() as i64); scope.push(
scope.push_lazy("latest_open_order_id", || ctx.latest_open_order_id() as i64); "latest_open_order_status",
scope.push_lazy("latest_open_order_status", || { ctx.latest_open_order_status().to_string(),
ctx.latest_open_order_status().to_string() );
}); scope.push(
scope.push_lazy("latest_open_order_unfilled_qty", || { "latest_open_order_unfilled_qty",
ctx.latest_open_order_unfilled_quantity() as i64 ctx.latest_open_order_unfilled_quantity() as i64,
}); );
scope.push_lazy("has_dynamic_universe", || ctx.has_dynamic_universe()); scope.push("has_dynamic_universe", ctx.has_dynamic_universe());
scope.push_lazy("dynamic_universe_count", || { scope.push(
ctx.dynamic_universe_count() as i64 "dynamic_universe_count",
}); ctx.dynamic_universe_count() as i64,
scope.push_lazy("has_subscriptions", || ctx.has_subscriptions()); );
scope.push_lazy("subscription_count", || ctx.subscription_count() as i64); scope.push("has_subscriptions", ctx.has_subscriptions());
scope.push("subscription_count", ctx.subscription_count() as i64);
scope.push( scope.push(
"subscription_guard_required", "subscription_guard_required",
self.config.subscription_guard_required, self.config.subscription_guard_required,
); );
scope.push_lazy("has_process_events", || ctx.has_process_events()); scope.push("has_process_events", ctx.has_process_events());
scope.push_lazy("process_event_count", || ctx.process_event_count() as i64); scope.push("process_event_count", ctx.process_event_count() as i64);
scope.push_lazy("current_process_kind", || { scope.push(
ctx.current_process_event_kind().to_string() "current_process_kind",
}); ctx.current_process_event_kind().to_string(),
scope.push_lazy("current_process_order_id", || { );
ctx.current_process_event_order_id() as i64 scope.push(
}); "current_process_order_id",
scope.push_lazy("current_process_symbol", || { ctx.current_process_event_order_id() as i64,
ctx.current_process_event_symbol().to_string() );
}); scope.push(
scope.push_lazy("current_process_side", || { "current_process_symbol",
ctx.current_process_event_side().to_string() ctx.current_process_event_symbol().to_string(),
}); );
scope.push_lazy("current_process_detail", || { scope.push(
ctx.current_process_event_detail().to_string() "current_process_side",
}); ctx.current_process_event_side().to_string(),
scope.push_lazy("latest_process_kind", || { );
ctx.latest_process_event_kind().to_string() scope.push(
}); "current_process_detail",
scope.push_lazy("latest_process_order_id", || { ctx.current_process_event_detail().to_string(),
ctx.latest_process_event_order_id() as i64 );
}); scope.push(
scope.push_lazy("latest_process_symbol", || { "latest_process_kind",
ctx.latest_process_event_symbol().to_string() ctx.latest_process_event_kind().to_string(),
}); );
scope.push_lazy("latest_process_side", || { scope.push(
ctx.latest_process_event_side().to_string() "latest_process_order_id",
}); ctx.latest_process_event_order_id() as i64,
scope.push_lazy("latest_process_detail", || { );
ctx.latest_process_event_detail().to_string() scope.push(
}); "latest_process_symbol",
ctx.latest_process_event_symbol().to_string(),
);
scope.push(
"latest_process_side",
ctx.latest_process_event_side().to_string(),
);
scope.push(
"latest_process_detail",
ctx.latest_process_event_detail().to_string(),
);
let process_event_counts = if include_day_factors || include_process_event_counts { let process_event_counts = if include_day_factors || include_process_event_counts {
let mut counts = Map::new(); let mut counts = Map::new();
for (key, value) in ctx.process_event_counts() { for (key, value) in ctx.process_event_counts() {
@@ -4821,7 +4820,7 @@ impl PlatformExprStrategy {
stock.lower_limit, stock.lower_limit,
stock.price_tick, stock.price_tick,
); );
scope.push_lazy("symbol", || stock.symbol.to_string()); scope.push("symbol", stock.symbol.to_string());
scope.push("market_cap", stock.market_cap); scope.push("market_cap", stock.market_cap);
scope.push("market_cap_bn", stock.market_cap_bn); scope.push("market_cap_bn", stock.market_cap_bn);
scope.push("free_float_cap", stock.free_float_cap); scope.push("free_float_cap", stock.free_float_cap);
@@ -4867,29 +4866,36 @@ impl PlatformExprStrategy {
scope.push("listed_days", stock.listed_days); scope.push("listed_days", stock.listed_days);
scope.push("at_upper_limit", at_upper_limit); scope.push("at_upper_limit", at_upper_limit);
scope.push("at_lower_limit", at_lower_limit); scope.push("at_lower_limit", at_lower_limit);
scope.push_lazy("symbol_open_order_count", || { scope.push(
ctx.symbol_open_order_count(&stock.symbol) as i64 "symbol_open_order_count",
}); ctx.symbol_open_order_count(&stock.symbol) as i64,
scope.push_lazy("symbol_open_buy_qty", || { );
ctx.symbol_open_buy_quantity(&stock.symbol) as i64 scope.push(
}); "symbol_open_buy_qty",
scope.push_lazy("symbol_open_sell_qty", || { ctx.symbol_open_buy_quantity(&stock.symbol) as i64,
ctx.symbol_open_sell_quantity(&stock.symbol) as i64 );
}); scope.push(
scope.push_lazy("latest_symbol_open_order_id", || { "symbol_open_sell_qty",
ctx.latest_symbol_open_order_id(&stock.symbol) as i64 ctx.symbol_open_sell_quantity(&stock.symbol) as i64,
}); );
scope.push_lazy("latest_symbol_open_order_status", || { scope.push(
"latest_symbol_open_order_id",
ctx.latest_symbol_open_order_id(&stock.symbol) as i64,
);
scope.push(
"latest_symbol_open_order_status",
ctx.latest_symbol_open_order_status(&stock.symbol) ctx.latest_symbol_open_order_status(&stock.symbol)
.to_string() .to_string(),
}); );
scope.push_lazy("latest_symbol_open_order_unfilled_qty", || { scope.push(
ctx.latest_symbol_open_order_unfilled_quantity(&stock.symbol) as i64 "latest_symbol_open_order_unfilled_qty",
}); ctx.latest_symbol_open_order_unfilled_quantity(&stock.symbol) as i64,
scope.push_lazy("in_dynamic_universe", || { );
ctx.dynamic_universe_contains(&stock.symbol) scope.push(
}); "in_dynamic_universe",
scope.push_lazy("is_subscribed", || ctx.is_subscribed(&stock.symbol)); ctx.dynamic_universe_contains(&stock.symbol),
);
scope.push("is_subscribed", ctx.is_subscribed(&stock.symbol));
scope.push("stock_ma_short", stock.stock_ma_short); scope.push("stock_ma_short", stock.stock_ma_short);
scope.push("stock_ma_mid", stock.stock_ma_mid); scope.push("stock_ma_mid", stock.stock_ma_mid);
scope.push("stock_ma_long", stock.stock_ma_long); scope.push("stock_ma_long", stock.stock_ma_long);
@@ -5071,7 +5077,7 @@ impl PlatformExprStrategy {
} }
} }
if let Some(position) = position { if let Some(position) = position {
scope.push_lazy("order_book_id", || position.order_book_id.clone()); scope.push("order_book_id", position.order_book_id.clone());
scope.push("avg_cost", position.avg_cost); scope.push("avg_cost", position.avg_cost);
scope.push("avg_price", position.avg_price); scope.push("avg_price", position.avg_price);
scope.push("current_price", position.current_price); scope.push("current_price", position.current_price);
@@ -5105,19 +5111,18 @@ impl PlatformExprStrategy {
scope.push("trading_pnl", position.trading_pnl); scope.push("trading_pnl", position.trading_pnl);
scope.push("position_pnl", position.position_pnl); scope.push("position_pnl", position.position_pnl);
scope.push("dividend_receivable", position.dividend_receivable); scope.push("dividend_receivable", position.dividend_receivable);
scope.push_lazy("available_sellable_qty", || { let available_sellable_qty = stock
stock
.map(|stock| { .map(|stock| {
ctx.available_sellable_qty(&stock.symbol, position.sellable_qty as u32) ctx.available_sellable_qty(&stock.symbol, position.sellable_qty as u32)
as i64
}) })
.unwrap_or(position.sellable_qty.max(0)) .unwrap_or(position.sellable_qty.max(0) as u32);
}); scope.push("available_sellable_qty", available_sellable_qty as i64);
scope.push_lazy("reserved_open_sell_qty", || { scope.push(
"reserved_open_sell_qty",
stock stock
.map(|stock| ctx.symbol_open_sell_quantity(&stock.symbol) as i64) .map(|stock| ctx.symbol_open_sell_quantity(&stock.symbol) as i64)
.unwrap_or(0) .unwrap_or(0),
}); );
scope.push("profit_pct", position.holding_return * 100.0); scope.push("profit_pct", position.holding_return * 100.0);
} }
scope.into_inner() scope.into_inner()
@@ -12828,11 +12833,9 @@ fn code_number_value(value: &str) -> i64 {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use std::cell::Cell;
use std::collections::{BTreeMap, BTreeSet}; use std::collections::{BTreeMap, BTreeSet};
use std::sync::Arc; use std::sync::Arc;
use ahash::AHashSet;
use chrono::{NaiveDate, NaiveTime}; use chrono::{NaiveDate, NaiveTime};
use super::{ use super::{
@@ -12841,9 +12844,9 @@ mod tests {
PlatformExprStrategyConfig, PlatformPortfolioDrawdownControlConfig, PlatformExprStrategyConfig, PlatformPortfolioDrawdownControlConfig,
PlatformPortfolioDrawdownController, PlatformRebalanceSchedule, PlatformScheduleFrequency, PlatformPortfolioDrawdownController, PlatformRebalanceSchedule, PlatformScheduleFrequency,
PlatformStopTakeReferencePriceMode, PlatformTradeAction, PlatformUniverseActionKind, PlatformStopTakeReferencePriceMode, PlatformTradeAction, PlatformUniverseActionKind,
RuntimeHelperResolution, SelectionRiskDeferral, SelectiveExpressionScope, RuntimeHelperResolution, SelectionRiskDeferral, StockFilterQuoteUsage, StockRollingField,
StockFilterQuoteUsage, StockRollingField, StockSnapshotFieldRequirements, StockSnapshotFieldRequirements, framework_stock_rolling_factor_requirement,
framework_stock_rolling_factor_requirement, scheduled_position_exposure, scheduled_position_exposure,
}; };
use crate::{ use crate::{
AlgoOrderStyle, BenchmarkSnapshot, CandidateEligibility, CorporateAction, AlgoOrderStyle, BenchmarkSnapshot, CandidateEligibility, CorporateAction,
@@ -12859,25 +12862,6 @@ mod tests {
NaiveDate::from_ymd_opt(year, month, day).expect("valid date") NaiveDate::from_ymd_opt(year, month, day).expect("valid date")
} }
#[test]
fn selective_expression_scope_does_not_build_unreferenced_values() {
let required = AHashSet::from_iter(["needed".to_string()]);
let builds = Cell::new(0);
let mut scope = SelectiveExpressionScope::new(&required);
scope.push_lazy("unused", || {
builds.set(builds.get() + 1);
"unused".to_string()
});
scope.push_lazy("needed", || {
builds.set(builds.get() + 1);
"value".to_string()
});
assert_eq!(builds.get(), 1);
assert!(scope.into_inner().contains("needed"));
}
#[test] #[test]
fn stock_state_cache_resets_before_reusing_compact_keys_on_another_date() { fn stock_state_cache_resets_before_reusing_compact_keys_on_another_date() {
let dates = [d(2025, 1, 2), d(2025, 1, 3)]; let dates = [d(2025, 1, 2), d(2025, 1, 3)];