quantaxis_rs/indicators/
exponential_moving_average.rs

1use std::fmt;
2
3use crate::errors::*;
4use crate::{Close, Next, Reset, Update};
5use std::f64::INFINITY;
6
7/// An exponential moving average (EMA), also known as an exponentially weighted moving average
8/// (EWMA).
9///
10/// It is a type of infinite impulse response filter that applies weighting factors which decrease exponentially.
11/// The weighting for each older datum decreases exponentially, never reaching zero.
12///
13/// # Formula
14///
15/// ![EMA formula](https://wikimedia.org/api/rest_v1/media/math/render/svg/05d06bdbee2c14031fd91ead6f5f772aec1ec964)
16///
17/// Where:
18///
19/// * _EMA<sub>t</sub>_ - is the value of the EMA at any time period _t_.
20/// * _EMA<sub>t-1</sub>_ - is the value of the EMA at the previous period _t-1_.
21/// * _p<sub>t</sub>_ - is the input value at a time period t.
22/// * _α_ - is the coefficient that represents the degree of weighting decrease, a constant smoothing factor between 0 and 1.
23///
24/// _α_ is calculated with the following formula:
25///
26/// ![alpha formula](https://wikimedia.org/api/rest_v1/media/math/render/svg/d9f6258e152db0644af548972bd6c50a8becf7ee)
27///
28/// Where:
29///
30/// * _length_ - number of periods
31///
32/// # Parameters
33///
34/// * _length_ - number of periods (integer greater than 0)
35///
36/// # Example
37///
38/// ```
39/// use quantaxis_rs::indicators::ExponentialMovingAverage;
40/// use quantaxis_rs::Next;
41///
42/// let mut ema = ExponentialMovingAverage::new(3).unwrap();
43/// assert_eq!(ema.next(2.0), 2.0);
44/// assert_eq!(ema.next(5.0), 3.5);
45/// assert_eq!(ema.next(1.0), 2.25);
46/// assert_eq!(ema.next(6.25), 4.25);
47/// ```
48///
49/// # Links
50///
51/// * [Exponential moving average, Wikipedia](https://en.wikipedia.org/wiki/Moving_average#Exponential_moving_average)
52///
53
54#[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                // ensure Default trait is implemented
171                let mut indicator = $i::default();
172
173                // ensure Next<f64> is implemented
174                let first_output = indicator.next(12.3);
175
176                // ensure next accepts &DataItem as well
177                indicator.next(&bar);
178
179                // ensure Reset is implemented and works correctly
180                indicator.reset();
181                assert_eq!(indicator.next(12.3), first_output);
182
183                // ensure Display is implemented
184                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        // assert_eq!(ema.next(1.0), 2.25);
204        // assert_eq!(ema.next(6.25), 4.875);
205
206        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        // let mut ema = ExponentialMovingAverage::new(3).unwrap();
223        // let bar1 = Bar::new().close(2);
224        // let bar2 = Bar::new().close(5);
225        // assert_eq!(ema.next(&bar1), 2.0);
226        // assert_eq!(ema.next(&bar2), 3.5);
227    }
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}