perf: avoid caching transient selection states
This commit is contained in:
@@ -4008,7 +4008,7 @@ impl PlatformExprStrategy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[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,
|
&self,
|
||||||
ctx: &StrategyContext<'a>,
|
ctx: &StrategyContext<'a>,
|
||||||
date: NaiveDate,
|
date: NaiveDate,
|
||||||
@@ -4017,14 +4017,15 @@ impl PlatformExprStrategy {
|
|||||||
symbol: &str,
|
symbol: &str,
|
||||||
execution_day: &DailySnapshotView<'a>,
|
execution_day: &DailySnapshotView<'a>,
|
||||||
factor_day: &DailySnapshotView<'a>,
|
factor_day: &DailySnapshotView<'a>,
|
||||||
) -> Result<Arc<StockExpressionState>, BacktestError> {
|
) -> Result<StockExpressionState, BacktestError> {
|
||||||
let source = ViewStockStateSnapshotSource {
|
let source = ViewStockStateSnapshotSource {
|
||||||
execution: execution_day,
|
execution: execution_day,
|
||||||
factor: factor_day,
|
factor: factor_day,
|
||||||
same_date: factor_date == date,
|
same_date: factor_date == date,
|
||||||
};
|
};
|
||||||
let use_intraday_quote = self.selection_quote_usage != StockFilterQuoteUsage::DailyOnly;
|
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,
|
ctx,
|
||||||
date,
|
date,
|
||||||
factor_date,
|
factor_date,
|
||||||
@@ -4032,6 +4033,7 @@ impl PlatformExprStrategy {
|
|||||||
symbol,
|
symbol,
|
||||||
None,
|
None,
|
||||||
use_intraday_quote,
|
use_intraday_quote,
|
||||||
|
calendar_index,
|
||||||
&source,
|
&source,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -4202,6 +4204,61 @@ impl PlatformExprStrategy {
|
|||||||
use_intraday_quote: bool,
|
use_intraday_quote: bool,
|
||||||
source: &S,
|
source: &S,
|
||||||
) -> Result<Arc<StockExpressionState>, BacktestError>
|
) -> 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
|
where
|
||||||
S: StockStateSnapshotSource<'a>,
|
S: StockStateSnapshotSource<'a>,
|
||||||
{
|
{
|
||||||
@@ -4212,19 +4269,6 @@ impl PlatformExprStrategy {
|
|||||||
symbol: symbol.to_string(),
|
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(|| {
|
let market = source.execution_market(symbol_id).ok_or_else(|| {
|
||||||
BacktestError::Data(crate::data::DataSetError::MissingSnapshot {
|
BacktestError::Data(crate::data::DataSetError::MissingSnapshot {
|
||||||
@@ -4406,7 +4450,7 @@ impl PlatformExprStrategy {
|
|||||||
BTreeMap::new()
|
BTreeMap::new()
|
||||||
};
|
};
|
||||||
|
|
||||||
let state = Arc::new(StockExpressionState {
|
let state = StockExpressionState {
|
||||||
symbol: shared_symbol,
|
symbol: shared_symbol,
|
||||||
symbol_id,
|
symbol_id,
|
||||||
market_cap,
|
market_cap,
|
||||||
@@ -4483,10 +4527,7 @@ impl PlatformExprStrategy {
|
|||||||
} else {
|
} else {
|
||||||
BTreeMap::new()
|
BTreeMap::new()
|
||||||
},
|
},
|
||||||
});
|
};
|
||||||
self.stock_state_cache
|
|
||||||
.borrow_mut()
|
|
||||||
.insert(cache_key, Arc::clone(&state));
|
|
||||||
Ok(state)
|
Ok(state)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -10115,7 +10156,7 @@ impl PlatformExprStrategy {
|
|||||||
.factor(symbol_id)
|
.factor(symbol_id)
|
||||||
.expect("market-cap order references missing factor row");
|
.expect("market-cap order references missing factor row");
|
||||||
let symbol = factor.symbol.as_str();
|
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,
|
ctx,
|
||||||
date,
|
date,
|
||||||
stock_factor_date,
|
stock_factor_date,
|
||||||
@@ -13101,6 +13142,20 @@ mod tests {
|
|||||||
};
|
};
|
||||||
let strategy = PlatformExprStrategy::new(PlatformExprStrategyConfig::microcap_rotation());
|
let strategy = PlatformExprStrategy::new(PlatformExprStrategyConfig::microcap_rotation());
|
||||||
let first_context = context(dates[0], 0);
|
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
|
let first = strategy
|
||||||
.stock_state(&first_context, dates[0], symbol)
|
.stock_state(&first_context, dates[0], symbol)
|
||||||
.expect("first state");
|
.expect("first state");
|
||||||
|
|||||||
Reference in New Issue
Block a user