quantaxis_rs/indicators/
exponential_moving_average.rs1use std::fmt;
2
3use crate::errors::*;
4use crate::{Close, Next, Reset, Update};
5use std::f64::INFINITY;
6
7#[derive(Debug, Clone)]
55pub struct ExponentialMovingAverage {
56 length: u32,
57 k: f64,
58 current: f64,
59 is_new: bool,
60 pub cached: Vec<f64>
61}
62
63impl ExponentialMovingAverage {
64 pub fn new(length: u32) -> Result<Self> {
65 match length {
66 0 => Err(Error::from_kind(ErrorKind::InvalidParameter)),
67 _ => {
68 let k = 2f64 / (length as f64 + 1f64);
69 let indicator = Self {
70 length,
71 k,
72 current: 0f64,
73 is_new: true,
74 cached: vec![-INFINITY; length as usize]
75 };
76 Ok(indicator)
77 }
78 }
79 }
80
81 pub fn length(&self) -> u32 {
82 self.length
83 }
84}
85
86impl Next<f64> for ExponentialMovingAverage {
87 type Output = f64;
88
89 fn next(&mut self, input: f64) -> Self::Output {
90
91 if self.is_new {
92 self.is_new = false;
93 self.current = input;
94 } else {
95 self.current = self.k * input + (1.0 - self.k) * self.current;
96 }
97
98 self.cached.push(self.current.clone());
99 self.cached.remove(0);
100 self.current
101 }
102
103}
104
105impl Update<f64> for ExponentialMovingAverage {
106 type Output = f64;
107
108 fn update(&mut self, input: f64) -> Self::Output {
109 if self.is_new {
110 self.is_new = false;
111 self.current = input;
112 } else {
113 self.current = self.k * input + (1.0 - self.k) * self.cached[(self.length -2) as usize];
114 }
115 self.cached.remove((self.length - 1) as usize);
116 self.cached.push(self.current.clone());
117 self.current
118 }
119
120}
121
122impl<'a, T: Close> Next<&'a T> for ExponentialMovingAverage {
123 type Output = f64;
124
125 fn next(&mut self, input: &'a T) -> Self::Output {
126 self.next(input.close())
127 }
128
129}
130
131
132impl<'a, T: Close> Update<&'a T> for ExponentialMovingAverage {
133 type Output = f64;
134
135 fn update(&mut self, input: &'a T) -> Self::Output {
136 self.update(input.close())
137 }
138
139}
140
141impl Reset for ExponentialMovingAverage {
142 fn reset(&mut self) {
143 self.current = 0.0;
144 self.is_new = true;
145 }
146}
147
148impl Default for ExponentialMovingAverage {
149 fn default() -> Self {
150 Self::new(9).unwrap()
151 }
152}
153
154impl fmt::Display for ExponentialMovingAverage {
155 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
156 write!(f, "EMA({})", self.length)
157 }
158}
159
160#[cfg(test)]
161mod tests {
162 use super::*;
163 use crate::test_helper::*;
164 macro_rules! test_indicator {
165 ($i:tt) => {
166 #[test]
167 fn test_indicator() {
168 let bar = Bar::new();
169
170 let mut indicator = $i::default();
172
173 let first_output = indicator.next(12.3);
175
176 indicator.next(&bar);
178
179 indicator.reset();
181 assert_eq!(indicator.next(12.3), first_output);
182
183 format!("{}", indicator);
185 }
186 };
187 }
188
189 test_indicator!(ExponentialMovingAverage);
190
191 #[test]
192 fn test_new() {
193 assert!(ExponentialMovingAverage::new(0).is_err());
194 assert!(ExponentialMovingAverage::new(1).is_ok());
195 }
196
197 #[test]
198 fn test_next() {
199 let mut ema = ExponentialMovingAverage::new(2).unwrap();
200
201 assert_eq!(ema.next(2.0), 2.0);
202 assert_eq!(ema.next(5.0), 4.0);
203 let mut ema = ExponentialMovingAverage::new(3).unwrap();
207 let bar1 = Bar::new().close(2);
208 let bar2 = Bar::new().close(5);
209 assert_eq!(ema.next(&bar1), 2.0);
210 assert_eq!(ema.next(&bar2), 3.5);
211 }
212
213 #[test]
214 fn test_update() {
215 let mut ema = ExponentialMovingAverage::new(3).unwrap();
216
217 assert_eq!(ema.next(2.0), 2.0);
218 assert_eq!(ema.next(5.0), 3.5);
219 assert_eq!(ema.next(1.0), 2.25);
220 assert_eq!(ema.update(6.25), 4.875);
221
222 }
228
229
230
231 #[test]
232 fn test_reset() {
233 let mut ema = ExponentialMovingAverage::new(5).unwrap();
234
235 assert_eq!(ema.next(4.0), 4.0);
236 ema.next(10.0);
237 ema.next(15.0);
238 ema.next(20.0);
239 assert_ne!(ema.next(4.0), 4.0);
240
241 ema.reset();
242 assert_eq!(ema.next(4.0), 4.0);
243 }
244
245 #[test]
246 fn test_default() {
247 ExponentialMovingAverage::default();
248 }
249
250 #[test]
251 fn test_display() {
252 let ema = ExponentialMovingAverage::new(7).unwrap();
253 assert_eq!(format!("{}", ema), "EMA(7)");
254 }
255}