inditech/indicators/
sma.rs

1use num_traits::Float;
2use ringvec::RingVec;
3use std::fmt::Debug;
4use std::iter::Sum;
5
6use crate::named::Named;
7use crate::slider::Slider;
8
9use super::identity::Identity;
10
11#[derive(Debug)]
12pub struct SMA<F> {
13    internal: Box<dyn Slider<F>>,
14    buffer: RingVec<F>,
15}
16
17impl<F> SMA<F>
18where
19    F: Float + Default + Debug + 'static,
20{
21    pub fn new(capacity: usize) -> Self {
22        let internal: Box<Identity<F>> = Box::new(Identity::new());
23
24        Self {
25            internal,
26            buffer: RingVec::new(capacity),
27        }
28    }
29
30    pub fn wrap(capacity: usize, internal: Box<dyn Slider<F>>) -> Self {
31        Self {
32            internal,
33            buffer: RingVec::new(capacity),
34        }
35    }
36}
37
38impl<F> Slider<F> for SMA<F>
39where
40    F: Float + Default + Sum<F> + Debug,
41{
42    fn last(&self) -> Option<F> {
43        if self.buffer.is_empty() {
44            None
45        } else {
46            let len_float = F::from(self.buffer.len()).unwrap();
47            Some(self.buffer.iter().cloned().sum::<F>() / len_float)
48        }
49    }
50
51    fn push(&mut self, item: F) {
52        self.internal.push(item);
53
54        if let Some(item) = self.internal.last() {
55            self.buffer.push_force(item);
56        };
57    }
58}
59
60impl<F> Named for SMA<F>
61where
62    F: Default,
63{
64    fn name(&self) -> String {
65        format!("sma{}", self.buffer.capacity())
66    }
67}
68
69#[cfg(test)]
70mod tests {
71    use super::*;
72
73    #[test]
74    fn sma() {
75        let mut sma = SMA::new(3);
76
77        sma.push(1.);
78        sma.push(2.);
79        sma.push(3.);
80
81        assert_eq!(sma.last(), Some(2.));
82    }
83
84    #[test]
85    fn sma_not_full() {
86        let mut sma = SMA::new(3);
87
88        sma.push(1.);
89        sma.push(2.);
90
91        assert_eq!(sma.last(), Some(1.5));
92    }
93
94    #[test]
95    fn sma_empty() {
96        let sma: SMA<f32> = SMA::new(3);
97
98        assert_eq!(sma.last(), None);
99    }
100
101    #[test]
102    fn sma_recursive() {
103        let capacity = 10;
104        let mut sma = SMA::wrap(capacity, Box::new(SMA::new(capacity)));
105
106        for i in 1..=capacity {
107            sma.push(i as f32);
108        }
109
110        assert_eq!(sma.last(), Some(3.25));
111    }
112}