quantaxis_rs/indicators/
standard_deviation.rs

1use std::fmt;
2
3use crate::errors::*;
4use crate::{Close, Next, Reset};
5
6/// Standard deviation (SD).
7///
8/// Returns the standard deviation of the last n values.
9///
10/// # Formula
11///
12/// ![SD formula](https://wikimedia.org/api/rest_v1/media/math/render/svg/2845de27edc898d2a2a4320eda5f57e0dac6f650)
13///
14/// Where:
15///
16/// * _σ_ - value of standard deviation for N given probes.
17/// * _N_ - number of probes in observation.
18/// * _x<sub>i</sub>_ - i-th observed value from N elements observation.
19///
20/// # Parameters
21///
22/// * _n_ - number of periods (integer greater than 0)
23///
24/// # Example
25///
26/// ```
27/// use quantaxis_rs::indicators::StandardDeviation;
28/// use quantaxis_rs::Next;
29///
30/// let mut sd = StandardDeviation::new(3).unwrap();
31/// assert_eq!(sd.next(10.0), 0.0);
32/// assert_eq!(sd.next(20.0), 5.0);
33/// ```
34///
35
36#[derive(Debug, Clone)]
37pub struct StandardDeviation {
38    n: u32,
39    index: usize,
40    count: u32,
41    m: f64,
42    m2: f64,
43    vec: Vec<f64>,
44}
45
46impl StandardDeviation {
47    pub fn new(n: u32) -> Result<Self> {
48        match n {
49            0 => Err(Error::from_kind(ErrorKind::InvalidParameter)),
50            _ => {
51                let std = StandardDeviation {
52                    n,
53                    index: 0,
54                    count: 0,
55                    m: 0.0,
56                    m2: 0.0,
57                    vec: vec![0.0; n as usize],
58                };
59                Ok(std)
60            }
61        }
62    }
63
64    pub(super) fn mean(&self) -> f64 {
65        self.m
66    }
67}
68
69impl Next<f64> for StandardDeviation {
70    type Output = f64;
71
72    fn next(&mut self, input: f64) -> Self::Output {
73        self.index = (self.index + 1) % (self.n as usize);
74
75        let old_val = self.vec[self.index];
76        self.vec[self.index] = input;
77
78        if self.count < self.n {
79            self.count += 1;
80            let delta = input - self.m;
81            self.m += delta / self.count as f64;
82            let delta2 = input - self.m;
83            self.m2 += delta * delta2;
84        } else {
85            let delta = input - old_val;
86            let old_m = self.m;
87            self.m += delta / self.n as f64;
88            let delta2 = input - self.m + old_val - old_m;
89            self.m2 += delta * delta2;
90        }
91
92        (self.m2 / self.count as f64).sqrt()
93    }
94}
95
96impl<'a, T: Close> Next<&'a T> for StandardDeviation {
97    type Output = f64;
98
99    fn next(&mut self, input: &'a T) -> Self::Output {
100        self.next(input.close())
101    }
102}
103
104impl Reset for StandardDeviation {
105    fn reset(&mut self) {
106        self.index = 0;
107        self.count = 0;
108        self.m = 0.0;
109        self.m2 = 0.0;
110        for i in 0..(self.n as usize) {
111            self.vec[i] = 0.0;
112        }
113    }
114}
115
116impl Default for StandardDeviation {
117    fn default() -> Self {
118        Self::new(9).unwrap()
119    }
120}
121
122impl fmt::Display for StandardDeviation {
123    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
124        write!(f, "SD({})", self.n)
125    }
126}
127
128#[cfg(test)]
129mod tests {
130    use super::*;
131    use crate::test_helper::*;
132    macro_rules! test_indicator {
133        ($i:tt) => {
134            #[test]
135            fn test_indicator() {
136                let bar = Bar::new();
137
138                // ensure Default trait is implemented
139                let mut indicator = $i::default();
140
141                // ensure Next<f64> is implemented
142                let first_output = indicator.next(12.3);
143
144                // ensure next accepts &DataItem as well
145                indicator.next(&bar);
146
147                // ensure Reset is implemented and works correctly
148                indicator.reset();
149                assert_eq!(indicator.next(12.3), first_output);
150
151                // ensure Display is implemented
152                format!("{}", indicator);
153            }
154        };
155    }
156    test_indicator!(StandardDeviation);
157
158    #[test]
159    fn test_new() {
160        assert!(StandardDeviation::new(0).is_err());
161        assert!(StandardDeviation::new(1).is_ok());
162    }
163
164    #[test]
165    fn test_next() {
166        let mut sd = StandardDeviation::new(4).unwrap();
167        assert_eq!(sd.next(10.0), 0.0);
168        assert_eq!(sd.next(20.0), 5.0);
169        assert_eq!(round(sd.next(30.0)), 8.165);
170        assert_eq!(round(sd.next(20.0)), 7.071);
171        assert_eq!(round(sd.next(10.0)), 7.071);
172        assert_eq!(round(sd.next(100.0)), 35.355);
173    }
174
175    #[test]
176    fn test_next_with_bars() {
177        fn bar(close: f64) -> Bar {
178            Bar::new().close(close)
179        }
180
181        let mut sd = StandardDeviation::new(4).unwrap();
182        assert_eq!(sd.next(&bar(10.0)), 0.0);
183        assert_eq!(sd.next(&bar(20.0)), 5.0);
184        assert_eq!(round(sd.next(&bar(30.0))), 8.165);
185        assert_eq!(round(sd.next(&bar(20.0))), 7.071);
186        assert_eq!(round(sd.next(&bar(10.0))), 7.071);
187        assert_eq!(round(sd.next(&bar(100.0))), 35.355);
188    }
189
190    #[test]
191    fn test_next_same_values() {
192        let mut sd = StandardDeviation::new(3).unwrap();
193        assert_eq!(sd.next(4.2), 0.0);
194        assert_eq!(sd.next(4.2), 0.0);
195        assert_eq!(sd.next(4.2), 0.0);
196        assert_eq!(sd.next(4.2), 0.0);
197    }
198
199    #[test]
200    fn test_reset() {
201        let mut sd = StandardDeviation::new(4).unwrap();
202        assert_eq!(sd.next(10.0), 0.0);
203        assert_eq!(sd.next(20.0), 5.0);
204        assert_eq!(round(sd.next(30.0)), 8.165);
205
206        sd.reset();
207        assert_eq!(sd.next(20.0), 0.0);
208    }
209
210    #[test]
211    fn test_default() {
212        StandardDeviation::default();
213    }
214
215    #[test]
216    fn test_display() {
217        let sd = StandardDeviation::new(5).unwrap();
218        assert_eq!(format!("{}", sd), "SD(5)");
219    }
220}