inditech 0.1.0

A set of technical indicators for time series analysis
Documentation
use num_traits::Float;
use ringvec::RingVec;
use std::fmt::Debug;
use std::iter::Sum;

use crate::named::Named;
use crate::slider::Slider;

use super::identity::Identity;

#[derive(Debug)]
pub struct SMA<F> {
    internal: Box<dyn Slider<F>>,
    buffer: RingVec<F>,
}

impl<F> SMA<F>
where
    F: Float + Default + Debug + 'static,
{
    pub fn new(capacity: usize) -> Self {
        let internal: Box<Identity<F>> = Box::new(Identity::new());

        Self {
            internal,
            buffer: RingVec::new(capacity),
        }
    }

    pub fn wrap(capacity: usize, internal: Box<dyn Slider<F>>) -> Self {
        Self {
            internal,
            buffer: RingVec::new(capacity),
        }
    }
}

impl<F> Slider<F> for SMA<F>
where
    F: Float + Default + Sum<F> + Debug,
{
    fn last(&self) -> Option<F> {
        if self.buffer.is_empty() {
            None
        } else {
            let len_float = F::from(self.buffer.len()).unwrap();
            Some(self.buffer.iter().cloned().sum::<F>() / len_float)
        }
    }

    fn push(&mut self, item: F) {
        self.internal.push(item);

        if let Some(item) = self.internal.last() {
            self.buffer.push_force(item);
        };
    }
}

impl<F> Named for SMA<F>
where
    F: Default,
{
    fn name(&self) -> String {
        format!("sma{}", self.buffer.capacity())
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn sma() {
        let mut sma = SMA::new(3);

        sma.push(1.);
        sma.push(2.);
        sma.push(3.);

        assert_eq!(sma.last(), Some(2.));
    }

    #[test]
    fn sma_not_full() {
        let mut sma = SMA::new(3);

        sma.push(1.);
        sma.push(2.);

        assert_eq!(sma.last(), Some(1.5));
    }

    #[test]
    fn sma_empty() {
        let sma: SMA<f32> = SMA::new(3);

        assert_eq!(sma.last(), None);
    }

    #[test]
    fn sma_recursive() {
        let capacity = 10;
        let mut sma = SMA::wrap(capacity, Box::new(SMA::new(capacity)));

        for i in 1..=capacity {
            sma.push(i as f32);
        }

        assert_eq!(sma.last(), Some(3.25));
    }
}