quantaxis_rs/indicators/
standard_deviation.rs1use std::fmt;
2
3use crate::errors::*;
4use crate::{Close, Next, Reset};
5
6#[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 let mut indicator = $i::default();
140
141 let first_output = indicator.next(12.3);
143
144 indicator.next(&bar);
146
147 indicator.reset();
149 assert_eq!(indicator.next(12.3), first_output);
150
151 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}