cxmr_ta_core/indicators/
standard_deviation.rs

1use std::fmt;
2
3use crate::errors::*;
4use crate::{Calculate, 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 ta::indicators::StandardDeviation;
28/// use ta::{Calculate, Next};
29///
30/// let mut sd = StandardDeviation::new(3).unwrap();
31/// assert_eq!(sd.calc(10.0), 0.0);
32/// assert_eq!(sd.calc(20.0), 5.0);
33/// ```
34///
35/// # Links
36///
37/// * [Standard Deviation, Wikipedia](https://en.wikipedia.org/wiki/Standard_deviation)
38///
39#[derive(Debug, Clone)]
40pub struct StandardDeviation {
41    n: u32,
42    index: usize,
43    count: u32,
44    m: f64,
45    m2: f64,
46    vec: Vec<f64>,
47}
48
49impl StandardDeviation {
50    pub fn new(n: u32) -> Result<Self> {
51        match n {
52            0 => Err(Error::from_kind(ErrorKind::InvalidParameter)),
53            _ => {
54                let std = StandardDeviation {
55                    n,
56                    index: 0,
57                    count: 0,
58                    m: 0.0,
59                    m2: 0.0,
60                    vec: vec![0.0; n as usize],
61                };
62                Ok(std)
63            }
64        }
65    }
66}
67
68impl Calculate for StandardDeviation {
69    fn calc(&mut self, input: f64) -> f64 {
70        self.index = (self.index + 1) % (self.n as usize);
71
72        let old_val = self.vec[self.index];
73        self.vec[self.index] = input;
74
75        if self.count < self.n {
76            self.count += 1;
77            let delta = input - self.m;
78            self.m += delta / self.count as f64;
79            let delta2 = input - self.m;
80            self.m2 += delta * delta2;
81        } else {
82            let delta = input - old_val;
83            let old_m = self.m;
84            self.m += delta / self.n as f64;
85            let delta2 = input - self.m + old_val - old_m;
86            self.m2 += delta * delta2;
87        }
88
89        (self.m2 / self.count as f64).sqrt()
90    }
91}
92
93impl<T: Close> Next<T> for StandardDeviation {
94    fn next(&mut self, input: &T) -> f64 {
95        self.calc(input.close())
96    }
97}
98
99impl Reset for StandardDeviation {
100    fn reset(&mut self) {
101        self.index = 0;
102        self.count = 0;
103        self.m = 0.0;
104        self.m2 = 0.0;
105        for i in 0..(self.n as usize) {
106            self.vec[i] = 0.0;
107        }
108    }
109}
110
111impl Default for StandardDeviation {
112    fn default() -> Self {
113        Self::new(9).unwrap()
114    }
115}
116
117impl fmt::Display for StandardDeviation {
118    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
119        write!(f, "SD({})", self.n)
120    }
121}
122
123#[cfg(test)]
124mod tests {
125    use super::*;
126    use crate::test_helper::*;
127
128    test_indicator!(StandardDeviation);
129
130    #[test]
131    fn test_new() {
132        assert!(StandardDeviation::new(0).is_err());
133        assert!(StandardDeviation::new(1).is_ok());
134    }
135
136    #[test]
137    fn test_next() {
138        let mut sd = StandardDeviation::new(4).unwrap();
139        assert_eq!(sd.calc(10.0), 0.0);
140        assert_eq!(sd.calc(20.0), 5.0);
141        assert_eq!(round(sd.calc(30.0)), 8.165);
142        assert_eq!(round(sd.calc(20.0)), 7.071);
143        assert_eq!(round(sd.calc(10.0)), 7.071);
144        assert_eq!(round(sd.calc(100.0)), 35.355);
145    }
146
147    #[test]
148    fn test_next_with_bars() {
149        fn bar(close: f64) -> Bar {
150            Bar::new().close(close)
151        }
152
153        let mut sd = StandardDeviation::new(4).unwrap();
154        assert_eq!(sd.next(&bar(10.0)), 0.0);
155        assert_eq!(sd.next(&bar(20.0)), 5.0);
156        assert_eq!(round(sd.next(&bar(30.0))), 8.165);
157        assert_eq!(round(sd.next(&bar(20.0))), 7.071);
158        assert_eq!(round(sd.next(&bar(10.0))), 7.071);
159        assert_eq!(round(sd.next(&bar(100.0))), 35.355);
160    }
161
162    #[test]
163    fn test_next_same_values() {
164        let mut sd = StandardDeviation::new(3).unwrap();
165        assert_eq!(sd.calc(4.2), 0.0);
166        assert_eq!(sd.calc(4.2), 0.0);
167        assert_eq!(sd.calc(4.2), 0.0);
168        assert_eq!(sd.calc(4.2), 0.0);
169    }
170
171    #[test]
172    fn test_reset() {
173        let mut sd = StandardDeviation::new(4).unwrap();
174        assert_eq!(sd.calc(10.0), 0.0);
175        assert_eq!(sd.calc(20.0), 5.0);
176        assert_eq!(round(sd.calc(30.0)), 8.165);
177
178        sd.reset();
179        assert_eq!(sd.calc(20.0), 0.0);
180    }
181
182    #[test]
183    fn test_default() {
184        StandardDeviation::default();
185    }
186
187    #[test]
188    fn test_display() {
189        let sd = StandardDeviation::new(5).unwrap();
190        assert_eq!(format!("{}", sd), "SD(5)");
191    }
192}