ux_indicators/indicators/
ema.rs

1#![allow(dead_code)]
2
3use std::fmt;
4
5use crate::errors::*;
6use crate::{Close, Next, Reset};
7
8use crate::{Factory};
9use crate::indicators::SimpleMovingAverage;
10
11pub struct EmaFactory {
12}
13
14impl EmaFactory {
15    pub fn new() -> Self {
16        Self{}
17    }
18}
19
20impl Factory for EmaFactory {
21    fn create() -> Box<dyn Next<f64, Output = Box<[f64]>>> {
22        Box::new(SimpleMovingAverage::default())
23    }
24}
25
26/// An exponential moving average (EMA), also known as an exponentially weighted moving average
27/// (EWMA).
28///
29/// It is a type of infinite impulse response filter that applies weighting factors which decrease exponentially.
30/// The weighting for each older datum decreases exponentially, never reaching zero.
31///
32/// # Formula
33///
34/// ![EMA formula](https://wikimedia.org/api/rest_v1/media/math/render/svg/05d06bdbee2c14031fd91ead6f5f772aec1ec964)
35///
36/// Where:
37///
38/// * _EMA<sub>t</sub>_ - is the value of the EMA at any time period _t_.
39/// * _EMA<sub>t-1</sub>_ - is the value of the EMA at the previous period _t-1_.
40/// * _p<sub>t</sub>_ - is the input value at a time period t.
41/// * _α_ - is the coefficient that represents the degree of weighting decrease, a constant smoothing factor between 0 and 1.
42///
43/// _α_ is calculated with the following formula:
44///
45/// ![alpha formula](https://wikimedia.org/api/rest_v1/media/math/render/svg/d9f6258e152db0644af548972bd6c50a8becf7ee)
46///
47/// Where:
48///
49/// * _length_ - number of periods
50///
51/// # Parameters
52///
53/// * _length_ - number of periods (integer greater than 0)
54///
55/// # Example
56///
57/// ```
58/// use core::indicators::ExponentialMovingAverage;
59/// use core::Next;
60///
61/// let mut ema = ExponentialMovingAverage::new(3).unwrap();
62/// assert_eq!(ema.next(2.0), 2.0);
63/// assert_eq!(ema.next(5.0), 3.5);
64/// assert_eq!(ema.next(1.0), 2.25);
65/// assert_eq!(ema.next(6.25), 4.25);
66/// ```
67///
68/// # Links
69///
70/// * [Exponential moving average, Wikipedia](https://en.wikipedia.org/wiki/Moving_average#Exponential_moving_average)
71///
72
73#[derive(Debug, Clone)]
74pub struct ExponentialMovingAverage {
75    length: u32,
76    k: f64,
77    current: f64,
78    is_new: bool,
79}
80
81impl ExponentialMovingAverage {
82    pub fn new(length: u32) -> Result<Self> {
83        match length {
84            0 => Err(Error::from_kind(ErrorKind::InvalidParameter)),
85            _ => {
86                let k = 2f64 / (length as f64 + 1f64);
87                let indicator = Self {
88                    length,
89                    k,
90                    current: 0f64,
91                    is_new: true,
92                };
93                Ok(indicator)
94            }
95        }
96    }
97
98    pub fn length(&self) -> u32 {
99        self.length
100    }
101}
102
103impl Next<f64> for ExponentialMovingAverage {
104    type Output = f64;
105
106    fn next(&mut self, input: f64) -> Self::Output {
107        if self.is_new {
108            self.is_new = false;
109            self.current = input;
110        } else {
111            self.current = self.k * input + (1.0 - self.k) * self.current;
112        }
113        self.current
114    }
115}
116
117impl<'a, T: Close> Next<&'a T> for ExponentialMovingAverage {
118    type Output = f64;
119
120    fn next(&mut self, input: &'a T) -> Self::Output {
121        self.next(input.close())
122    }
123}
124
125impl Reset for ExponentialMovingAverage {
126    fn reset(&mut self) {
127        self.current = 0.0;
128        self.is_new = true;
129    }
130}
131
132impl Default for ExponentialMovingAverage {
133    fn default() -> Self {
134        Self::new(9).unwrap()
135    }
136}
137
138impl fmt::Display for ExponentialMovingAverage {
139    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
140        write!(f, "EMA({})", self.length)
141    }
142}
143
144#[cfg(test)]
145mod tests {
146    use super::*;
147    use crate::test_helper::*;
148
149    // test_indicator!(ExponentialMovingAverage);
150
151    #[test]
152    fn test_new() {
153        assert!(ExponentialMovingAverage::new(0).is_err());
154        assert!(ExponentialMovingAverage::new(1).is_ok());
155    }
156
157    #[test]
158    fn test_next() {
159        let mut ema = ExponentialMovingAverage::new(3).unwrap();
160
161        assert_eq!(ema.next(2.0), 2.0);
162        assert_eq!(ema.next(5.0), 3.5);
163        assert_eq!(ema.next(1.0), 2.25);
164        assert_eq!(ema.next(6.25), 4.25);
165
166        let mut ema = ExponentialMovingAverage::new(3).unwrap();
167        let bar1 = Bar::new().close(2);
168        let bar2 = Bar::new().close(5);
169        assert_eq!(ema.next(&bar1), 2.0);
170        assert_eq!(ema.next(&bar2), 3.5);
171    }
172
173    #[test]
174    fn test_reset() {
175        let mut ema = ExponentialMovingAverage::new(5).unwrap();
176
177        assert_eq!(ema.next(4.0), 4.0);
178        ema.next(10.0);
179        ema.next(15.0);
180        ema.next(20.0);
181        assert_ne!(ema.next(4.0), 4.0);
182
183        ema.reset();
184        assert_eq!(ema.next(4.0), 4.0);
185    }
186
187    #[test]
188    fn test_default() {
189        ExponentialMovingAverage::default();
190    }
191
192    #[test]
193    fn test_display() {
194        let ema = ExponentialMovingAverage::new(7).unwrap();
195        assert_eq!(format!("{}", ema), "EMA(7)");
196    }
197}