finlib_ta/indicators/
mean_absolute_deviation.rs

1use core::fmt;
2use alloc::boxed::Box;
3use alloc::vec;
4
5#[cfg(feature = "serde")]
6use serde::{Deserialize, Serialize};
7
8use crate::errors::{Result, TaError};
9use crate::{Close, Next, Period, Reset};
10
11/// Mean Absolute Deviation (MAD)
12///
13/// The mean absolute deviation of a data set is the average of the absolute deviations from a
14/// central point. It is a summary statistic of statistical dispersion or variability.
15/// In the general form, the central point can be a mean, median, mode, or the result of any other
16/// measure of central tendency or any random data point related to the given data set.
17/// The absolute values of the differences between the data points and their central tendency are
18/// totaled and divided by the number of data points.
19///
20/// # Formula
21///
22/// MAD(_period_) = { x<sub>1</sub> - ABS(AVG(_period_)), ..., x<sub>_period_</sub> - ABS(AVG(_period_)) } / _period_
23///
24/// # Parameters
25///
26/// * _period_ - number of periods (integer greater than 0). Default is 9.
27///
28/// # Links
29///
30/// * [Mean Absolute Deviation, Wikipedia](https://en.wikipedia.org/wiki/Mean_absolute_deviation)
31///
32#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
33#[derive(Debug, Clone)]
34pub struct MeanAbsoluteDeviation {
35    period: usize,
36    index: usize,
37    count: usize,
38    sum: f64,
39    deque: Box<[f64]>,
40}
41
42impl MeanAbsoluteDeviation {
43    pub fn new(period: usize) -> Result<Self> {
44        match period {
45            0 => Err(TaError::InvalidParameter),
46            _ => Ok(Self {
47                period,
48                index: 0,
49                count: 0,
50                sum: 0.0,
51                deque: vec![0.0; period].into_boxed_slice(),
52            }),
53        }
54    }
55}
56
57impl Period for MeanAbsoluteDeviation {
58    fn period(&self) -> usize {
59        self.period
60    }
61}
62
63impl Next<f64> for MeanAbsoluteDeviation {
64    type Output = f64;
65
66    fn next(&mut self, input: f64) -> Self::Output {
67        self.sum = if self.count < self.period {
68            self.count = self.count + 1;
69            self.sum + input
70        } else {
71            self.sum + input - self.deque[self.index]
72        };
73
74        self.deque[self.index] = input;
75        self.index = if self.index + 1 < self.period {
76            self.index + 1
77        } else {
78            0
79        };
80
81        let mean = self.sum / self.count as f64;
82
83        let mut mad = 0.0;
84        for value in &self.deque[..self.count] {
85            mad += (value - mean).abs();
86        }
87        mad / self.count as f64
88    }
89}
90
91impl<T: Close> Next<&T> for MeanAbsoluteDeviation {
92    type Output = f64;
93
94    fn next(&mut self, input: &T) -> Self::Output {
95        self.next(input.close())
96    }
97}
98
99impl Reset for MeanAbsoluteDeviation {
100    fn reset(&mut self) {
101        self.index = 0;
102        self.count = 0;
103        self.sum = 0.0;
104        for i in 0..self.period {
105            self.deque[i] = 0.0;
106        }
107    }
108}
109
110impl Default for MeanAbsoluteDeviation {
111    fn default() -> Self {
112        Self::new(9).unwrap()
113    }
114}
115
116impl fmt::Display for MeanAbsoluteDeviation {
117    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
118        write!(f, "MAD({})", self.period)
119    }
120}
121
122#[cfg(test)]
123mod tests {
124    use super::*;
125    use crate::test_helper::*;
126    use alloc::format;
127
128    test_indicator!(MeanAbsoluteDeviation);
129
130    #[test]
131    fn test_new() {
132        assert!(MeanAbsoluteDeviation::new(0).is_err());
133        assert!(MeanAbsoluteDeviation::new(1).is_ok());
134    }
135
136    #[test]
137    fn test_next() {
138        let mut mad = MeanAbsoluteDeviation::new(5).unwrap();
139
140        assert_eq!(round(mad.next(1.5)), 0.0);
141        assert_eq!(round(mad.next(4.0)), 1.25);
142        assert_eq!(round(mad.next(8.0)), 2.333);
143        assert_eq!(round(mad.next(4.0)), 1.813);
144        assert_eq!(round(mad.next(4.0)), 1.48);
145        assert_eq!(round(mad.next(1.5)), 1.48);
146    }
147
148    #[test]
149    fn test_reset() {
150        let mut mad = MeanAbsoluteDeviation::new(5).unwrap();
151
152        assert_eq!(round(mad.next(1.5)), 0.0);
153        assert_eq!(round(mad.next(4.0)), 1.25);
154
155        mad.reset();
156
157        assert_eq!(round(mad.next(1.5)), 0.0);
158        assert_eq!(round(mad.next(4.0)), 1.25);
159    }
160
161    #[test]
162    fn test_default() {
163        MeanAbsoluteDeviation::default();
164    }
165
166    #[test]
167    fn test_display() {
168        let indicator = MeanAbsoluteDeviation::new(10).unwrap();
169        assert_eq!(format!("{}", indicator), "MAD(10)");
170    }
171}