perf: avoid caching transient selection states
This commit is contained in:
@@ -4008,7 +4008,7 @@ impl PlatformExprStrategy {
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn selection_stock_state_with_factor_date_from_views_by_symbol_id<'a>(
|
||||
fn uncached_selection_stock_state_from_views_by_symbol_id<'a>(
|
||||
&self,
|
||||
ctx: &StrategyContext<'a>,
|
||||
date: NaiveDate,
|
||||
@@ -4017,14 +4017,15 @@ impl PlatformExprStrategy {
|
||||
symbol: &str,
|
||||
execution_day: &DailySnapshotView<'a>,
|
||||
factor_day: &DailySnapshotView<'a>,
|
||||
) -> Result<Arc<StockExpressionState>, BacktestError> {
|
||||
) -> Result<StockExpressionState, BacktestError> {
|
||||
let source = ViewStockStateSnapshotSource {
|
||||
execution: execution_day,
|
||||
factor: factor_day,
|
||||
same_date: factor_date == date,
|
||||
};
|
||||
let use_intraday_quote = self.selection_quote_usage != StockFilterQuoteUsage::DailyOnly;
|
||||
self.stock_state_with_factor_date_and_time_from_source_by_symbol_id(
|
||||
let calendar_index = self.prepare_stock_state_cache_date(ctx, date);
|
||||
self.build_stock_state_with_factor_date_and_time_from_source_by_symbol_id(
|
||||
ctx,
|
||||
date,
|
||||
factor_date,
|
||||
@@ -4032,6 +4033,7 @@ impl PlatformExprStrategy {
|
||||
symbol,
|
||||
None,
|
||||
use_intraday_quote,
|
||||
calendar_index,
|
||||
&source,
|
||||
)
|
||||
}
|
||||
@@ -4202,6 +4204,61 @@ impl PlatformExprStrategy {
|
||||
use_intraday_quote: bool,
|
||||
source: &S,
|
||||
) -> Result<Arc<StockExpressionState>, BacktestError>
|
||||
where
|
||||
S: StockStateSnapshotSource<'a>,
|
||||
{
|
||||
let calendar_index = self.prepare_stock_state_cache_date(ctx, date);
|
||||
let cache_key = (factor_date, symbol_id, execution_time, use_intraday_quote);
|
||||
if let Some(state) = self.stock_state_cache.borrow().get(&cache_key) {
|
||||
return Ok(Arc::clone(state));
|
||||
}
|
||||
|
||||
let state = Arc::new(
|
||||
self.build_stock_state_with_factor_date_and_time_from_source_by_symbol_id(
|
||||
ctx,
|
||||
date,
|
||||
factor_date,
|
||||
symbol_id,
|
||||
symbol,
|
||||
execution_time,
|
||||
use_intraday_quote,
|
||||
calendar_index,
|
||||
source,
|
||||
)?,
|
||||
);
|
||||
self.stock_state_cache
|
||||
.borrow_mut()
|
||||
.insert(cache_key, Arc::clone(&state));
|
||||
Ok(state)
|
||||
}
|
||||
|
||||
fn prepare_stock_state_cache_date(
|
||||
&self,
|
||||
ctx: &StrategyContext<'_>,
|
||||
date: NaiveDate,
|
||||
) -> Option<usize> {
|
||||
let mut cache_date = self.stock_state_cache_date.borrow_mut();
|
||||
if *cache_date != Some(date) {
|
||||
self.stock_state_cache.borrow_mut().clear();
|
||||
*cache_date = Some(date);
|
||||
*self.stock_state_cache_calendar_index.borrow_mut() = ctx.data.calendar_index(date);
|
||||
}
|
||||
*self.stock_state_cache_calendar_index.borrow()
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn build_stock_state_with_factor_date_and_time_from_source_by_symbol_id<'a, S>(
|
||||
&self,
|
||||
ctx: &StrategyContext<'a>,
|
||||
date: NaiveDate,
|
||||
factor_date: NaiveDate,
|
||||
symbol_id: u32,
|
||||
symbol: &str,
|
||||
execution_time: Option<NaiveTime>,
|
||||
use_intraday_quote: bool,
|
||||
calendar_index: Option<usize>,
|
||||
source: &S,
|
||||
) -> Result<StockExpressionState, BacktestError>
|
||||
where
|
||||
S: StockStateSnapshotSource<'a>,
|
||||
{
|
||||
@@ -4212,19 +4269,6 @@ impl PlatformExprStrategy {
|
||||
symbol: symbol.to_string(),
|
||||
})
|
||||
})?;
|
||||
let calendar_index = {
|
||||
let mut cache_date = self.stock_state_cache_date.borrow_mut();
|
||||
if *cache_date != Some(date) {
|
||||
self.stock_state_cache.borrow_mut().clear();
|
||||
*cache_date = Some(date);
|
||||
*self.stock_state_cache_calendar_index.borrow_mut() = ctx.data.calendar_index(date);
|
||||
}
|
||||
*self.stock_state_cache_calendar_index.borrow()
|
||||
};
|
||||
let cache_key = (factor_date, symbol_id, execution_time, use_intraday_quote);
|
||||
if let Some(state) = self.stock_state_cache.borrow().get(&cache_key) {
|
||||
return Ok(Arc::clone(state));
|
||||
}
|
||||
|
||||
let market = source.execution_market(symbol_id).ok_or_else(|| {
|
||||
BacktestError::Data(crate::data::DataSetError::MissingSnapshot {
|
||||
@@ -4406,7 +4450,7 @@ impl PlatformExprStrategy {
|
||||
BTreeMap::new()
|
||||
};
|
||||
|
||||
let state = Arc::new(StockExpressionState {
|
||||
let state = StockExpressionState {
|
||||
symbol: shared_symbol,
|
||||
symbol_id,
|
||||
market_cap,
|
||||
@@ -4483,10 +4527,7 @@ impl PlatformExprStrategy {
|
||||
} else {
|
||||
BTreeMap::new()
|
||||
},
|
||||
});
|
||||
self.stock_state_cache
|
||||
.borrow_mut()
|
||||
.insert(cache_key, Arc::clone(&state));
|
||||
};
|
||||
Ok(state)
|
||||
}
|
||||
|
||||
@@ -10115,7 +10156,7 @@ impl PlatformExprStrategy {
|
||||
.factor(symbol_id)
|
||||
.expect("market-cap order references missing factor row");
|
||||
let symbol = factor.symbol.as_str();
|
||||
let stock = self.selection_stock_state_with_factor_date_from_views_by_symbol_id(
|
||||
let stock = self.uncached_selection_stock_state_from_views_by_symbol_id(
|
||||
ctx,
|
||||
date,
|
||||
stock_factor_date,
|
||||
@@ -13101,6 +13142,20 @@ mod tests {
|
||||
};
|
||||
let strategy = PlatformExprStrategy::new(PlatformExprStrategyConfig::microcap_rotation());
|
||||
let first_context = context(dates[0], 0);
|
||||
let first_day = data.daily_snapshot_view(dates[0]);
|
||||
let uncached = strategy
|
||||
.uncached_selection_stock_state_from_views_by_symbol_id(
|
||||
&first_context,
|
||||
dates[0],
|
||||
dates[0],
|
||||
data.symbol_id(symbol).unwrap(),
|
||||
symbol,
|
||||
&first_day,
|
||||
&first_day,
|
||||
)
|
||||
.expect("uncached first state");
|
||||
assert_eq!(uncached.close, 10.0);
|
||||
assert!(strategy.stock_state_cache.borrow().is_empty());
|
||||
let first = strategy
|
||||
.stock_state(&first_context, dates[0], symbol)
|
||||
.expect("first state");
|
||||
|
||||
Reference in New Issue
Block a user