fix(stock-pool): separate cumulative condition facts from quote capacity
This commit is contained in:
@@ -284,6 +284,8 @@ pub struct CorporateAction {
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct IntradayExecutionQuote {
|
||||
#[serde(default)]
|
||||
pub observation_kind: QuoteObservationKind,
|
||||
#[serde(with = "date_format")]
|
||||
pub date: NaiveDate,
|
||||
pub symbol: String,
|
||||
@@ -301,6 +303,14 @@ pub struct IntradayExecutionQuote {
|
||||
pub trading_phase: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum QuoteObservationKind {
|
||||
#[default]
|
||||
Unspecified,
|
||||
MinuteBar,
|
||||
}
|
||||
|
||||
/// Sparse same-day fields layered onto an already-built immutable daily panel.
|
||||
///
|
||||
/// These fields do not participate in daily price series, adjustment series,
|
||||
@@ -1407,6 +1417,7 @@ pub struct DataSet {
|
||||
corporate_actions_by_date: Arc<BTreeMap<NaiveDate, Vec<CorporateAction>>>,
|
||||
execution_quotes_by_date: Arc<HashMap<NaiveDate, HashMap<String, Vec<IntradayExecutionQuote>>>>,
|
||||
execution_quote_dates: Arc<Vec<NaiveDate>>,
|
||||
condition_totals: Arc<std::sync::Mutex<crate::stock_pool_quote_facts::SessionTotalsCache>>,
|
||||
order_book_depth_index: Arc<HashMap<(NaiveDate, String), Vec<IntradayOrderBookDepthLevel>>>,
|
||||
benchmark_by_date: Arc<BTreeMap<NaiveDate, BenchmarkSnapshot>>,
|
||||
market_series_by_symbol: Arc<AHashMap<String, Arc<SymbolPriceSeries>>>,
|
||||
@@ -1941,6 +1952,7 @@ impl DataSet {
|
||||
candidate_row_positions_by_date: Arc::new(candidate_row_positions_by_date),
|
||||
corporate_actions_by_date: Arc::new(corporate_actions_by_date),
|
||||
execution_quotes_by_date: Arc::new(execution_quotes_by_date),
|
||||
condition_totals: Arc::new(std::sync::Mutex::new(Default::default())),
|
||||
execution_quote_dates: Arc::new(execution_quote_dates),
|
||||
order_book_depth_index: Arc::new(order_book_depth_index),
|
||||
benchmark_by_date: Arc::new(benchmark_by_date),
|
||||
@@ -2279,6 +2291,15 @@ impl DataSet {
|
||||
.unwrap_or(&[])
|
||||
}
|
||||
|
||||
pub fn execution_session_totals(&self, symbol: &str, at: NaiveDateTime) -> Result<(rust_decimal::Decimal, rust_decimal::Decimal), String> {
|
||||
let mut cache = self.condition_totals.lock().map_err(|_| "stock_pool_session_prefix_cache_poisoned")?;
|
||||
if cache.date != Some(at.date()) {
|
||||
cache.date = Some(at.date());
|
||||
cache.symbols.clear();
|
||||
}
|
||||
cache.symbols.entry(symbol.into()).or_insert_with(|| crate::stock_pool_quote_facts::MinutePrefix::build(at.date(), symbol, self.execution_quotes_on(at.date(), symbol))).at(at)
|
||||
}
|
||||
|
||||
pub fn has_execution_quotes_on_date(&self, date: NaiveDate) -> bool {
|
||||
self.execution_quotes_by_date
|
||||
.get(&date)
|
||||
@@ -2451,6 +2472,7 @@ impl DataSet {
|
||||
/// Replaces the run-local execution quote layer without touching the
|
||||
/// immutable daily panel.
|
||||
pub fn replace_execution_quotes(&mut self, quotes: Vec<IntradayExecutionQuote>) -> usize {
|
||||
self.condition_totals = Arc::new(std::sync::Mutex::new(Default::default()));
|
||||
let execution_quotes_by_date = build_execution_quote_index(quotes);
|
||||
let quote_count = execution_quotes_by_date
|
||||
.values()
|
||||
@@ -2466,6 +2488,7 @@ impl DataSet {
|
||||
}
|
||||
|
||||
pub fn add_execution_quotes(&mut self, quotes: Vec<IntradayExecutionQuote>) -> usize {
|
||||
self.condition_totals = Arc::new(std::sync::Mutex::new(Default::default()));
|
||||
let mut grouped = HashMap::<NaiveDate, HashMap<String, Vec<IntradayExecutionQuote>>>::new();
|
||||
for quote in quotes {
|
||||
grouped
|
||||
@@ -2566,6 +2589,7 @@ impl DataSet {
|
||||
}
|
||||
|
||||
pub fn remove_execution_quotes_on_date(&mut self, date: NaiveDate) -> usize {
|
||||
self.condition_totals = Arc::new(std::sync::Mutex::new(Default::default()));
|
||||
let removed = Arc::make_mut(&mut self.execution_quotes_by_date).remove(&date);
|
||||
let Some(rows_by_symbol) = removed else {
|
||||
return 0;
|
||||
@@ -2578,6 +2602,7 @@ impl DataSet {
|
||||
}
|
||||
|
||||
pub fn release_execution_quotes_on_date(&mut self, date: NaiveDate) -> usize {
|
||||
self.condition_totals = Arc::new(std::sync::Mutex::new(Default::default()));
|
||||
let row_count = self
|
||||
.execution_quotes_by_date
|
||||
.get(&date)
|
||||
@@ -5158,7 +5183,7 @@ mod tests {
|
||||
&run_data.execution_quote_dates
|
||||
));
|
||||
|
||||
run_data.add_execution_quotes(vec![IntradayExecutionQuote {
|
||||
run_data.add_execution_quotes(vec![IntradayExecutionQuote { observation_kind: Default::default(),
|
||||
date,
|
||||
timestamp: NaiveDateTime::parse_from_str("2025-01-02 10:18:00", "%Y-%m-%d %H:%M:%S")
|
||||
.unwrap(),
|
||||
@@ -5301,7 +5326,7 @@ mod tests {
|
||||
vec![benchmark_row("2025-01-02", 12.0)],
|
||||
)
|
||||
.unwrap();
|
||||
let quote = IntradayExecutionQuote {
|
||||
let quote = IntradayExecutionQuote { observation_kind: Default::default(),
|
||||
date,
|
||||
symbol: "000001.SZ".to_string(),
|
||||
timestamp,
|
||||
@@ -5403,7 +5428,7 @@ mod tests {
|
||||
successor_cash: None,
|
||||
};
|
||||
corporate_actions.push(corporate_action.clone());
|
||||
execution_quotes.push(IntradayExecutionQuote {
|
||||
execution_quotes.push(IntradayExecutionQuote { observation_kind: Default::default(),
|
||||
date,
|
||||
symbol: symbols[0].to_string(),
|
||||
timestamp: date.and_hms_opt(10, 18, 0).unwrap(),
|
||||
@@ -6114,7 +6139,7 @@ mod tests {
|
||||
vec![benchmark_row("2025-01-02", 12.0)],
|
||||
)
|
||||
.unwrap();
|
||||
let quote = |symbol: &str, time: &str| IntradayExecutionQuote {
|
||||
let quote = |symbol: &str, time: &str| IntradayExecutionQuote { observation_kind: Default::default(),
|
||||
date,
|
||||
timestamp: NaiveDateTime::parse_from_str(
|
||||
&format!("2025-01-02 {time}"),
|
||||
@@ -6193,7 +6218,7 @@ mod tests {
|
||||
#[test]
|
||||
fn shared_execution_quote_release_does_not_clone_the_base_map() {
|
||||
let date = NaiveDate::parse_from_str("2025-01-02", "%Y-%m-%d").unwrap();
|
||||
let quote = IntradayExecutionQuote {
|
||||
let quote = IntradayExecutionQuote { observation_kind: Default::default(),
|
||||
date,
|
||||
timestamp: NaiveDateTime::parse_from_str("2025-01-02 10:18:00", "%Y-%m-%d %H:%M:%S")
|
||||
.unwrap(),
|
||||
|
||||
Reference in New Issue
Block a user