perf: reuse rolling window boundaries

This commit is contained in:
boris
2026-09-05 12:40:40 +08:00
parent c225d8484f
commit 6b5d57675e
+44 -8
View File
@@ -686,7 +686,15 @@ impl AdjustedCloseSeries {
end: usize, end: usize,
lookbacks: &[usize; N], lookbacks: &[usize; N],
) -> [Option<f64>; N] { ) -> [Option<f64>; N] {
std::array::from_fn(|index| self.moving_average_at_end(end, lookbacks[index])) let Some(base_factor) = end
.checked_sub(1)
.and_then(|index| self.backward_factors.get(index).copied().flatten())
else {
return [None; N];
};
std::array::from_fn(|index| {
self.moving_average_at_end_with_base_factor(end, lookbacks[index], base_factor)
})
} }
fn moving_average_at_end(&self, end: usize, lookback: usize) -> Option<f64> { fn moving_average_at_end(&self, end: usize, lookback: usize) -> Option<f64> {
@@ -694,6 +702,18 @@ impl AdjustedCloseSeries {
return None; return None;
} }
let base_factor = self.backward_factors.get(end - 1).copied().flatten()?; let base_factor = self.backward_factors.get(end - 1).copied().flatten()?;
self.moving_average_at_end_with_base_factor(end, lookback, base_factor)
}
fn moving_average_at_end_with_base_factor(
&self,
end: usize,
lookback: usize,
base_factor: f64,
) -> Option<f64> {
if lookback == 0 || end < lookback {
return None;
}
let start = end - lookback; let start = end - lookback;
if self.missing_back_adjusted_close_prefix[end] if self.missing_back_adjusted_close_prefix[end]
!= self.missing_back_adjusted_close_prefix[start] != self.missing_back_adjusted_close_prefix[start]
@@ -1022,15 +1042,19 @@ impl SymbolPriceSeries {
end: usize, end: usize,
lookbacks: &[usize; N], lookbacks: &[usize; N],
) -> [Option<f64>; N] { ) -> [Option<f64>; N] {
let Some(valid_count) = self.valid_volume_count_prefix.get(end).copied() else {
return [None; N];
};
std::array::from_fn(|index| { std::array::from_fn(|index| {
let lookback = lookbacks[index]; let lookback = lookbacks[index];
self.valid_volume_window(end, lookback).map(|(start, end)| { self.valid_volume_window_with_count(end, lookback, valid_count)
normalize_rolling_factor( .map(|(start, end)| {
(self.valid_volume_sum_prefix[end] - self.valid_volume_sum_prefix[start]) normalize_rolling_factor(
/ lookback as f64, (self.valid_volume_sum_prefix[end] - self.valid_volume_sum_prefix[start])
12, / lookback as f64,
) 12,
}) )
})
}) })
} }
@@ -1049,6 +1073,18 @@ impl SymbolPriceSeries {
return None; return None;
} }
let valid_count = *self.valid_volume_count_prefix.get(end)?; let valid_count = *self.valid_volume_count_prefix.get(end)?;
self.valid_volume_window_with_count(end, lookback, valid_count)
}
fn valid_volume_window_with_count(
&self,
end: usize,
lookback: usize,
valid_count: usize,
) -> Option<(usize, usize)> {
if lookback == 0 || end > self.volumes.len() {
return None;
}
if valid_count < lookback { if valid_count < lookback {
return None; return None;
} }