use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{Height, Indexes, StoredF32, Version};
use vecdb::{Database, Exit, ReadableVec, Rw, StorageMode};
use crate::{blocks, indexes, internal::PerBlock};
use super::period_suffix;
#[derive(Traversable)]
pub struct StdDevPerBlock<M: StorageMode = Rw> {
days: usize,
pub sma: PerBlock<StoredF32, M>,
pub sd: PerBlock<StoredF32, M>,
}
impl StdDevPerBlock {
pub(crate) fn forced_import(
db: &Database,
name: &str,
period: &str,
days: usize,
parent_version: Version,
indexes: &indexes::Vecs,
) -> Result<Self> {
let version = parent_version + Version::TWO;
let p = period_suffix(period);
let sma = PerBlock::forced_import(db, &format!("{name}_sma{p}"), version, indexes)?;
let sd = PerBlock::forced_import(db, &format!("{name}_sd{p}"), version, indexes)?;
Ok(Self { days, sma, sd })
}
pub(crate) fn compute_all(
&mut self,
blocks: &blocks::Vecs,
starting_indexes: &Indexes,
exit: &Exit,
source: &impl ReadableVec<Height, StoredF32>,
) -> Result<()> {
if self.days == usize::MAX {
self.sma.height.compute_sma_(
starting_indexes.height,
source,
usize::MAX,
exit,
None,
)?;
self.sd.height.compute_expanding_sd(
starting_indexes.height,
source,
&self.sma.height,
exit,
)?;
return Ok(());
}
let window_starts = blocks.lookback.start_vec(self.days);
self.sma.height.compute_rolling_average(
starting_indexes.height,
window_starts,
source,
exit,
)?;
self.sd.height.compute_rolling_sd(
starting_indexes.height,
window_starts,
source,
&self.sma.height,
exit,
)?;
Ok(())
}
}