quantaxis_rs/indicators/
average_true_range.rs

1use std::fmt;
2
3use crate::errors::*;
4use crate::indicators::{MovingAverage, TrueRange};
5use crate::{Close, High, Low, Next, Reset, Update};
6use std::f64::INFINITY;
7
8/// Average true range (ATR).
9///
10/// A technical analysis volatility indicator, originally developed by J. Welles Wilder.
11/// The average true range is an N-day smoothed moving average of the true range values.
12/// This implementation uses exponential moving average.
13///
14/// # Formula
15///
16/// ATR(length)<sub>t</sub> = EMA(length) of TR<sub>t</sub>
17///
18/// Where:
19///
20/// * _EMA(n)_ - [exponential moving average](struct.ExponentialMovingAverage.html) with smoothing period _length_
21/// * _TR<sub>t</sub>_ - [true range](struct.TrueRange.html) for period _t_
22///
23/// # Parameters
24///
25/// * _length_ - smoothing period of EMA (integer greater than 0)
26///
27/// }
28#[derive(Debug, Clone)]
29pub struct AverageTrueRange {
30    true_range: TrueRange,
31    ma: MovingAverage,
32    length: usize,
33    pub cached: Vec<f64>
34}
35
36impl AverageTrueRange {
37    pub fn new(length: u32) -> Result<Self> {
38        let indicator = Self {
39            true_range: TrueRange::new(),
40            ma: MovingAverage::new(length)?,
41            length: length as usize,
42            cached: vec![-INFINITY; length as usize]
43        };
44        Ok(indicator)
45    }
46}
47
48impl Next<f64> for AverageTrueRange {
49    type Output = f64;
50
51    fn next(&mut self, input: f64) -> Self::Output {
52        let res = self.ma.next(self.true_range.next(input));
53        self.cached.push(res);
54        self.cached.remove(0);
55        res
56    }
57}
58impl Update<f64> for AverageTrueRange {
59    type Output = f64;
60
61    fn update(&mut self, input: f64) -> Self::Output {
62        let res = self.ma.update(self.true_range.update(input));
63        let x = self.cached.last_mut().unwrap();
64        *x = res;
65        res
66    }
67}
68
69impl<'a, T: High + Low + Close> Next<&'a T> for AverageTrueRange {
70    type Output = f64;
71
72    fn next(&mut self, input: &'a T) -> Self::Output {
73        let res = self.ma.next(self.true_range.next(input));
74        self.cached.push(res);
75        self.cached.remove(0);
76        res
77    }
78}
79
80impl<'a, T: High + Low + Close> Update<&'a T> for AverageTrueRange {
81    type Output = f64;
82
83    fn update(&mut self, input: &'a T) -> Self::Output {
84        let res  = self.ma.update(self.true_range.update(input));
85        let x = self.cached.last_mut().unwrap();
86        *x = res;
87        res
88    }
89}
90
91impl Reset for AverageTrueRange {
92    fn reset(&mut self) {
93        self.true_range.reset();
94        self.ma.reset();
95    }
96}
97
98impl Default for AverageTrueRange {
99    fn default() -> Self {
100        Self::new(14).unwrap()
101    }
102}
103
104impl fmt::Display for AverageTrueRange {
105    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
106        write!(f, "ATR({})", self.ma.n)
107    }
108}
109
110#[cfg(test)]
111mod tests {
112    use super::*;
113    use crate::test_helper::*;
114    macro_rules! test_indicator {
115        ($i:tt) => {
116            #[test]
117            fn test_indicator() {
118                let bar = Bar::new();
119
120                // ensure Default trait is implemented
121                let mut indicator = $i::default();
122
123                // ensure Next<f64> is implemented
124                let first_output = indicator.next(12.3);
125
126                // ensure next accepts &DataItem as well
127                indicator.next(&bar);
128
129                // ensure Reset is implemented and works correctly
130                indicator.reset();
131                assert_eq!(indicator.next(12.3), first_output);
132
133                // ensure Display is implemented
134                format!("{}", indicator);
135            }
136        };
137    }
138    test_indicator!(AverageTrueRange);
139
140    #[test]
141    fn test_new() {
142        assert!(AverageTrueRange::new(0).is_err());
143        assert!(AverageTrueRange::new(1).is_ok());
144    }
145    #[test]
146    fn test_next() {
147        let mut atr = AverageTrueRange::new(3).unwrap();
148
149        let bar1 = Bar::new().high(10).low(7.5).close(9);
150        let bar2 = Bar::new().high(11).low(9).close(9.5);
151        let bar3 = Bar::new().high(9).low(5).close(8);
152
153        assert_eq!(atr.next(&bar1), 0f64);
154        assert_eq!(atr.next(&bar2), 0f64);
155        assert_eq!(atr.next(&bar3), 3f64);
156    }
157
158    #[test]
159    fn test_reset() {
160        let mut atr = AverageTrueRange::new(9).unwrap();
161
162        let bar1 = Bar::new().high(10).low(7.5).close(9);
163        let bar2 = Bar::new().high(11).low(9).close(9.5);
164
165        atr.next(&bar1);
166        atr.next(&bar2);
167
168        atr.reset();
169        let bar3 = Bar::new().high(60).low(15).close(51);
170        assert_eq!(atr.next(&bar3), 0.0);
171    }
172
173    #[test]
174    fn test_default() {
175        AverageTrueRange::default();
176    }
177
178    #[test]
179    fn test_display() {
180        let indicator = AverageTrueRange::new(8).unwrap();
181        assert_eq!(format!("{}", indicator), "ATR(8)");
182    }
183}