优化策略选股的索引查找路径
This commit is contained in:
@@ -1335,13 +1335,6 @@ pub struct DataSet {
|
|||||||
futures_params_by_symbol: Arc<HashMap<String, Vec<FuturesTradingParameter>>>,
|
futures_params_by_symbol: Arc<HashMap<String, Vec<FuturesTradingParameter>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
|
||||||
pub(crate) struct SymbolSnapshotRefs<'a> {
|
|
||||||
pub market: Option<&'a DailyMarketSnapshot>,
|
|
||||||
pub factor: Option<&'a DailyFactorSnapshot>,
|
|
||||||
pub candidate: Option<&'a CandidateEligibility>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub(crate) struct StandardRollingMeans {
|
pub(crate) struct StandardRollingMeans {
|
||||||
pub close: [Option<f64>; 7],
|
pub close: [Option<f64>; 7],
|
||||||
@@ -1963,68 +1956,6 @@ impl DataSet {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn symbol_snapshots_by_id(
|
|
||||||
&self,
|
|
||||||
date: NaiveDate,
|
|
||||||
symbol_id: u32,
|
|
||||||
) -> SymbolSnapshotRefs<'_> {
|
|
||||||
let market_rows = self.market_by_date.get(&date).map(Vec::as_slice);
|
|
||||||
let market_symbol_ids = self
|
|
||||||
.market_symbol_ids_by_date
|
|
||||||
.get(&date)
|
|
||||||
.map(Vec::as_slice);
|
|
||||||
let market_index = dense_row_position(
|
|
||||||
&self.market_row_positions_by_date,
|
|
||||||
date,
|
|
||||||
symbol_id,
|
|
||||||
)
|
|
||||||
.or_else(|| {
|
|
||||||
market_rows
|
|
||||||
.zip(market_symbol_ids)
|
|
||||||
.and_then(|(rows, symbol_ids)| symbol_id_index(rows.len(), symbol_ids, symbol_id))
|
|
||||||
});
|
|
||||||
let market = market_index.and_then(|index| market_rows?.get(index));
|
|
||||||
|
|
||||||
let factor = self.factor_by_date.get(&date).and_then(|rows| {
|
|
||||||
dense_row_position(&self.factor_row_positions_by_date, date, symbol_id)
|
|
||||||
.and_then(|index| rows.get(index))
|
|
||||||
.or_else(|| {
|
|
||||||
self.factor_symbol_ids_by_date
|
|
||||||
.get(&date)
|
|
||||||
.and_then(|symbol_ids| {
|
|
||||||
find_by_symbol_id_with_preferred_index(
|
|
||||||
rows,
|
|
||||||
symbol_ids,
|
|
||||||
symbol_id,
|
|
||||||
market_index,
|
|
||||||
)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
});
|
|
||||||
let candidate = self.candidate_by_date.get(&date).and_then(|rows| {
|
|
||||||
dense_row_position(&self.candidate_row_positions_by_date, date, symbol_id)
|
|
||||||
.and_then(|index| rows.get(index))
|
|
||||||
.or_else(|| {
|
|
||||||
self.candidate_symbol_ids_by_date
|
|
||||||
.get(&date)
|
|
||||||
.and_then(|symbol_ids| {
|
|
||||||
find_by_symbol_id_with_preferred_index(
|
|
||||||
rows,
|
|
||||||
symbol_ids,
|
|
||||||
symbol_id,
|
|
||||||
market_index,
|
|
||||||
)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
SymbolSnapshotRefs {
|
|
||||||
market,
|
|
||||||
factor,
|
|
||||||
candidate,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn market_standard_rolling_means_by_symbol_id(
|
pub(crate) fn market_standard_rolling_means_by_symbol_id(
|
||||||
&self,
|
&self,
|
||||||
date: NaiveDate,
|
date: NaiveDate,
|
||||||
@@ -4155,13 +4086,6 @@ fn find_by_symbol_id<'a, T>(rows: &'a [T], symbol_ids: &[u32], symbol_id: u32) -
|
|||||||
find_by_symbol_id_with_preferred_index(rows, symbol_ids, symbol_id, None)
|
find_by_symbol_id_with_preferred_index(rows, symbol_ids, symbol_id, None)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn symbol_id_index(rows_len: usize, symbol_ids: &[u32], symbol_id: u32) -> Option<usize> {
|
|
||||||
if rows_len != symbol_ids.len() {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
symbol_ids.binary_search(&symbol_id).ok()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn find_by_symbol_id_with_preferred_index<'a, T>(
|
fn find_by_symbol_id_with_preferred_index<'a, T>(
|
||||||
rows: &'a [T],
|
rows: &'a [T],
|
||||||
symbol_ids: &[u32],
|
symbol_ids: &[u32],
|
||||||
@@ -4786,7 +4710,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn combined_symbol_snapshot_lookup_uses_alignment_and_falls_back_for_sparse_rows() {
|
fn direct_symbol_id_snapshot_lookups_preserve_alignment_for_sparse_rows() {
|
||||||
let date = NaiveDate::parse_from_str("2025-01-02", "%Y-%m-%d").unwrap();
|
let date = NaiveDate::parse_from_str("2025-01-02", "%Y-%m-%d").unwrap();
|
||||||
let instrument = |symbol: &str| Instrument {
|
let instrument = |symbol: &str| Instrument {
|
||||||
symbol: symbol.to_string(),
|
symbol: symbol.to_string(),
|
||||||
@@ -4848,29 +4772,30 @@ mod tests {
|
|||||||
|
|
||||||
for symbol in ["000001.SZ", "600000.SH"] {
|
for symbol in ["000001.SZ", "600000.SH"] {
|
||||||
let symbol_id = data.symbol_id(symbol).unwrap();
|
let symbol_id = data.symbol_id(symbol).unwrap();
|
||||||
let combined = data.symbol_snapshots_by_id(date, symbol_id);
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
combined.market.map(|row| row.symbol.as_str()),
|
|
||||||
data.market_by_symbol_id(date, symbol_id)
|
data.market_by_symbol_id(date, symbol_id)
|
||||||
.map(|row| row.symbol.as_str())
|
.map(|row| row.symbol.as_str()),
|
||||||
|
Some(symbol)
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
combined.factor.map(|row| row.symbol.as_str()),
|
|
||||||
data.factor_by_symbol_id(date, symbol_id)
|
data.factor_by_symbol_id(date, symbol_id)
|
||||||
.map(|row| row.symbol.as_str())
|
.map(|row| row.symbol.as_str()),
|
||||||
|
Some(symbol)
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
combined.candidate.map(|row| row.symbol.as_str()),
|
|
||||||
data.candidate_by_symbol_id(date, symbol_id)
|
data.candidate_by_symbol_id(date, symbol_id)
|
||||||
.map(|row| row.symbol.as_str())
|
.map(|row| row.symbol.as_str()),
|
||||||
|
Some(symbol)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let signal_id = data.symbol_id("000300.SH").unwrap();
|
let signal_id = data.symbol_id("000300.SH").unwrap();
|
||||||
let signal = data.symbol_snapshots_by_id(date, signal_id);
|
assert_eq!(
|
||||||
assert_eq!(signal.market.map(|row| row.symbol.as_str()), Some("000300.SH"));
|
data.market_by_symbol_id(date, signal_id).map(|row| row.symbol.as_str()),
|
||||||
assert!(signal.factor.is_none());
|
Some("000300.SH")
|
||||||
assert!(signal.candidate.is_none());
|
);
|
||||||
|
assert!(data.factor_by_symbol_id(date, signal_id).is_none());
|
||||||
|
assert!(data.candidate_by_symbol_id(date, signal_id).is_none());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -3900,28 +3900,28 @@ impl PlatformExprStrategy {
|
|||||||
return Ok(Arc::clone(state));
|
return Ok(Arc::clone(state));
|
||||||
}
|
}
|
||||||
|
|
||||||
let execution_snapshots = ctx.data.symbol_snapshots_by_id(date, symbol_id);
|
let market = ctx.data.market_by_symbol_id(date, symbol_id).ok_or_else(|| {
|
||||||
let market = execution_snapshots.market.ok_or_else(|| {
|
|
||||||
BacktestError::Data(crate::data::DataSetError::MissingSnapshot {
|
BacktestError::Data(crate::data::DataSetError::MissingSnapshot {
|
||||||
kind: "market",
|
kind: "market",
|
||||||
date,
|
date,
|
||||||
symbol: symbol.to_string(),
|
symbol: symbol.to_string(),
|
||||||
})
|
})
|
||||||
})?;
|
})?;
|
||||||
let candidate = execution_snapshots.candidate.ok_or_else(|| {
|
let candidate = ctx.data.candidate_by_symbol_id(date, symbol_id).ok_or_else(|| {
|
||||||
BacktestError::Data(crate::data::DataSetError::MissingSnapshot {
|
BacktestError::Data(crate::data::DataSetError::MissingSnapshot {
|
||||||
kind: "candidate",
|
kind: "candidate",
|
||||||
date,
|
date,
|
||||||
symbol: symbol.to_string(),
|
symbol: symbol.to_string(),
|
||||||
})
|
})
|
||||||
})?;
|
})?;
|
||||||
let factor_snapshots = if factor_date == date {
|
let feature_market = if factor_date == date {
|
||||||
execution_snapshots
|
market
|
||||||
} else {
|
} else {
|
||||||
ctx.data.symbol_snapshots_by_id(factor_date, symbol_id)
|
ctx.data
|
||||||
|
.market_by_symbol_id(factor_date, symbol_id)
|
||||||
|
.unwrap_or(market)
|
||||||
};
|
};
|
||||||
let feature_market = factor_snapshots.market.unwrap_or(market);
|
let factor = ctx.data.factor_by_symbol_id(factor_date, symbol_id).ok_or_else(|| {
|
||||||
let factor = factor_snapshots.factor.ok_or_else(|| {
|
|
||||||
BacktestError::Data(crate::data::DataSetError::MissingSnapshot {
|
BacktestError::Data(crate::data::DataSetError::MissingSnapshot {
|
||||||
kind: "factor",
|
kind: "factor",
|
||||||
date: factor_date,
|
date: factor_date,
|
||||||
|
|||||||
Reference in New Issue
Block a user