tindi/moving_averages/
exponential_moving_average.rs

1/// # Exponential Moving Average
2/// An exponential moving average (EMA) is a type of moving average
3/// that places a greater weight and significance on recent data points than
4/// a simple moving average.
5///
6/// ## Example
7/// ```no_run
8/// let data: Vec<f32> = vec![
9///     35.56, 34.96, 33.72, 32.89, 34.36, 33.06, 31.05, 30.36, 30.89, 31.01, 32.19, 34.19,
10///     33.91, 35.87, 35.37, 36.11, 35.93, 34.53, 33.70, 33.95, 34.20, 35.38, 36.12, 35.35,
11///     36.25, 36.59, 36.49, 36.39, 35.66, 35.99, 32.93, 30.98, 30.99, 32.15, 31.99, 32.34,
12/// ];
13///
14/// let result = exponential_moving_average(&data, 12).unwrap();
15/// let expected = 33.297977;
16/// assert_eq!(result, expected);
17/// ```
18
19pub fn exponential_moving_average(data: &[f32]) -> f32 {
20    let period = data.len();
21    let mut ema = 0.0;
22    let alpha = 2.0 / (period as f32 + 1.0);
23
24    // Inital SMA value for data set
25    for i in 0..period {
26        ema += data[i];
27    }
28    ema /= period as f32;
29
30    // EMA calculation
31    for price in data {
32        ema = price * alpha + ema * (1.0 - alpha);
33    }
34
35    ema
36}
37
38#[cfg(test)]
39mod tests {
40    use super::*;
41
42    #[test]
43    fn test_ema_result() {
44        let data: Vec<f32> = vec![
45            35.56, 34.96, 33.72, 32.89, 34.36, 33.06, 31.05, 30.36, 30.89, 31.01, 32.19, 34.19,
46            33.91, 35.87, 35.37, 36.11, 35.93, 34.53, 33.70, 33.95, 34.20, 35.38, 36.12, 35.35,
47            36.25, 36.59, 36.49, 36.39, 35.66, 35.99, 32.93, 30.98, 30.99, 32.15, 31.99, 32.34,
48        ];
49
50        let result = exponential_moving_average(&data);
51        let expected = 33.297977;
52        dbg!(&result);
53        assert_eq!(result, expected);
54    }
55}