stock-trek 0.2.0

Stock Trek time-series analysis
Documentation
use std::sync::OnceLock;

use crate::data::{
    market_data::{
        extract::dec_to_f64, raw_market_quote::RawMarketQuote, raw_market_tick::RawMarketTick,
    },
    timestamp::TimestampMillis,
};

#[derive(Debug, Clone)]
pub struct MarketTicks {
    exact: Vec<RawMarketTick>,
    bids: OnceLock<Vec<(TimestampMillis, f64, f64)>>,
    asks: OnceLock<Vec<(TimestampMillis, f64, f64)>>,
    lasts: OnceLock<Vec<(TimestampMillis, f64, f64)>>,
}

impl MarketTicks {
    pub fn new(exact: Vec<RawMarketTick>) -> Self {
        Self {
            exact,
            bids: OnceLock::new(),
            asks: OnceLock::new(),
            lasts: OnceLock::new(),
        }
    }
    pub fn exact(&self) -> &Vec<RawMarketTick> {
        &self.exact
    }
    pub fn bids(&self) -> &Vec<(TimestampMillis, f64, f64)> {
        self.bids.get_or_init(|| self.values(|tick| tick.bid()))
    }
    pub fn asks(&self) -> &Vec<(TimestampMillis, f64, f64)> {
        self.asks.get_or_init(|| self.values(|tick| tick.ask()))
    }
    pub fn lasts(&self) -> &Vec<(TimestampMillis, f64, f64)> {
        self.lasts.get_or_init(|| self.values(|tick| tick.last()))
    }

    fn values(
        &self,
        to_quote: impl Fn(&RawMarketTick) -> &RawMarketQuote,
    ) -> Vec<(TimestampMillis, f64, f64)> {
        self.exact
            .iter()
            .map(|tick| to_tick_tuple(tick, &to_quote))
            .collect()
    }
}

fn to_tick_tuple(
    tick: &RawMarketTick,
    to_quote: impl Fn(&RawMarketTick) -> &RawMarketQuote,
) -> (TimestampMillis, f64, f64) {
    let timestamp = tick.timestamp_millis();
    let quote = to_quote(tick);
    let price = dec_to_f64(quote.price());
    let quantity = dec_to_f64(quote.quantity());
    (timestamp, price, quantity)
}