stock-trek 0.2.8

Stock Trek time-series analysis
Documentation
use crate::{
    aligned_window::AlignedWindow,
    dto::{raw_market_candle::RawMarketCandle, raw_market_ohlcv::RawMarketOhlcv},
    market_data::extract::dec_to_f64,
};
use rust_decimal::Decimal;
use std::{collections::HashMap, sync::OnceLock};
use strum::IntoEnumIterator;

#[derive(Debug, Clone)]
pub struct MarketAlignedWindow {
    exact: HashMap<AlignedWindow, Vec<RawMarketCandle>>,
    opens: OnceLock<HashMap<AlignedWindow, OnceLock<Vec<f64>>>>,
    highs: OnceLock<HashMap<AlignedWindow, OnceLock<Vec<f64>>>>,
    lows: OnceLock<HashMap<AlignedWindow, OnceLock<Vec<f64>>>>,
    closes: OnceLock<HashMap<AlignedWindow, OnceLock<Vec<f64>>>>,
    volumes: OnceLock<HashMap<AlignedWindow, OnceLock<Vec<f64>>>>,
    quote_volumes: OnceLock<HashMap<AlignedWindow, OnceLock<Vec<f64>>>>,
    vwaps: OnceLock<HashMap<AlignedWindow, OnceLock<Vec<f64>>>>,
}

impl MarketAlignedWindow {
    pub fn new(exact: HashMap<AlignedWindow, Vec<RawMarketCandle>>) -> Self {
        Self {
            exact,
            opens: OnceLock::new(),
            highs: OnceLock::new(),
            lows: OnceLock::new(),
            closes: OnceLock::new(),
            volumes: OnceLock::new(),
            quote_volumes: OnceLock::new(),
            vwaps: OnceLock::new(),
        }
    }
    pub fn exact(&self) -> &HashMap<AlignedWindow, Vec<RawMarketCandle>> {
        &self.exact
    }
    pub fn opens(&self, window: AlignedWindow) -> &Vec<f64> {
        self.opens
            .get_or_init(windows_map)
            .get(&window)
            .unwrap()
            .get_or_init(|| self.aligned_values(window, |ohlcv| ohlcv.open()))
    }
    pub fn highs(&self, window: AlignedWindow) -> &Vec<f64> {
        self.highs
            .get_or_init(windows_map)
            .get(&window)
            .unwrap()
            .get_or_init(|| self.aligned_values(window, |ohlcv| ohlcv.high()))
    }
    pub fn lows(&self, window: AlignedWindow) -> &Vec<f64> {
        self.lows
            .get_or_init(windows_map)
            .get(&window)
            .unwrap()
            .get_or_init(|| self.aligned_values(window, |ohlcv| ohlcv.low()))
    }
    pub fn closes(&self, window: AlignedWindow) -> &Vec<f64> {
        self.closes
            .get_or_init(windows_map)
            .get(&window)
            .unwrap()
            .get_or_init(|| self.aligned_values(window, |ohlcv| ohlcv.close()))
    }
    pub fn volumes(&self, window: AlignedWindow) -> &Vec<f64> {
        self.volumes
            .get_or_init(windows_map)
            .get(&window)
            .unwrap()
            .get_or_init(|| self.aligned_values(window, |ohlcv| ohlcv.volume()))
    }
    pub fn quote_volumes(&self, window: AlignedWindow) -> &Vec<f64> {
        self.quote_volumes
            .get_or_init(windows_map)
            .get(&window)
            .unwrap()
            .get_or_init(|| self.aligned_values(window, |ohlcv| ohlcv.quote_volume()))
    }
    pub fn vwaps(&self, window: AlignedWindow) -> &Vec<f64> {
        self.vwaps
            .get_or_init(windows_map)
            .get(&window)
            .unwrap()
            .get_or_init(|| self.aligned_values(window, |ohlcv| ohlcv.vwap()))
    }

    fn aligned_values(
        &self,
        window: AlignedWindow,
        to_value: impl Fn(&RawMarketOhlcv) -> Decimal,
    ) -> Vec<f64> {
        self.exact
            .get(&window)
            .unwrap()
            .iter()
            .map(|candle| dec_to_f64(to_value(candle.ohlcv())))
            .collect()
    }
}

fn windows_map() -> HashMap<AlignedWindow, OnceLock<Vec<f64>>> {
    AlignedWindow::iter()
        .map(|window| (window, OnceLock::new()))
        .collect()
}