finlib_ta/indicators/
standard_deviation.rs

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