finlib_ta/indicators/
average_true_range.rs

1use core::fmt;
2
3use crate::errors::Result;
4use crate::indicators::{ExponentialMovingAverage, TrueRange};
5use crate::{Close, High, Low, Next, Period, Reset};
6
7#[cfg(feature = "serde")]
8use serde::{Deserialize, Serialize};
9
10/// Average true range (ATR).
11///
12/// A technical analysis volatility indicator, originally developed by J. Welles Wilder.
13/// The average true range is an N-day smoothed moving average of the true range values.
14/// This implementation uses exponential moving average.
15///
16/// # Formula
17///
18/// ATR(period)<sub>t</sub> = EMA(period) of TR<sub>t</sub>
19///
20/// Where:
21///
22/// * _EMA(period)_ - [exponential moving average](struct.ExponentialMovingAverage.html) with smoothing period
23/// * _TR<sub>t</sub>_ - [true range](struct.TrueRange.html) for period _t_
24///
25/// # Parameters
26///
27/// * _period_ - smoothing period of EMA (integer greater than 0)
28///
29/// # Example
30///
31/// ```
32/// extern crate finlib_ta;
33/// #[macro_use] extern crate assert_approx_eq;
34///
35/// use finlib_ta::{Next, DataItem};
36/// use finlib_ta::indicators::AverageTrueRange;
37///
38/// fn main() {
39///     let data = vec![
40///         // open, high, low, close, atr
41///         (9.7   , 10.0, 9.0, 9.5  , 1.0),    // tr = high - low = 10.0 - 9.0 = 1.0
42///         (9.9   , 10.4, 9.8, 10.2 , 0.95),   // tr = high - prev_close = 10.4 - 9.5 = 0.9
43///         (10.1  , 10.7, 9.4, 9.7  , 1.125),  // tr = high - low = 10.7 - 9.4 = 1.3
44///         (9.1   , 9.2 , 8.1, 8.4  , 1.3625), // tr = prev_close - low = 9.7 - 8.1 = 1.6
45///     ];
46///     let mut indicator = AverageTrueRange::new(3).unwrap();
47///
48///     for (open, high, low, close, atr) in data {
49///         let di = DataItem::builder()
50///             .high(high)
51///             .low(low)
52///             .close(close)
53///             .open(open)
54///             .volume(1000.0)
55///             .build().unwrap();
56///         assert_approx_eq!(indicator.next(&di), atr);
57///     }
58/// }
59#[doc(alias = "ATR")]
60#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
61#[derive(Debug, Clone)]
62pub struct AverageTrueRange {
63    true_range: TrueRange,
64    ema: ExponentialMovingAverage,
65}
66
67impl AverageTrueRange {
68    pub fn new(period: usize) -> Result<Self> {
69        Ok(Self {
70            true_range: TrueRange::new(),
71            ema: ExponentialMovingAverage::new(period)?,
72        })
73    }
74}
75
76impl Period for AverageTrueRange {
77    fn period(&self) -> usize {
78        self.ema.period()
79    }
80}
81
82impl Next<f64> for AverageTrueRange {
83    type Output = f64;
84
85    fn next(&mut self, input: f64) -> Self::Output {
86        self.ema.next(self.true_range.next(input))
87    }
88}
89
90impl<T: High + Low + Close> Next<&T> for AverageTrueRange {
91    type Output = f64;
92
93    fn next(&mut self, input: &T) -> Self::Output {
94        self.ema.next(self.true_range.next(input))
95    }
96}
97
98impl Reset for AverageTrueRange {
99    fn reset(&mut self) {
100        self.true_range.reset();
101        self.ema.reset();
102    }
103}
104
105impl Default for AverageTrueRange {
106    fn default() -> Self {
107        Self::new(14).unwrap()
108    }
109}
110
111impl fmt::Display for AverageTrueRange {
112    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
113        write!(f, "ATR({})", self.ema.period())
114    }
115}
116
117#[cfg(test)]
118mod tests {
119    use super::*;
120    use crate::test_helper::*;
121    use alloc::format;
122
123    test_indicator!(AverageTrueRange);
124
125    #[test]
126    fn test_new() {
127        assert!(AverageTrueRange::new(0).is_err());
128        assert!(AverageTrueRange::new(1).is_ok());
129    }
130    #[test]
131    fn test_next() {
132        let mut atr = AverageTrueRange::new(3).unwrap();
133
134        let bar1 = Bar::new().high(10).low(7.5).close(9);
135        let bar2 = Bar::new().high(11).low(9).close(9.5);
136        let bar3 = Bar::new().high(9).low(5).close(8);
137
138        assert_eq!(atr.next(&bar1), 2.5);
139        assert_eq!(atr.next(&bar2), 2.25);
140        assert_eq!(atr.next(&bar3), 3.375);
141    }
142
143    #[test]
144    fn test_reset() {
145        let mut atr = AverageTrueRange::new(9).unwrap();
146
147        let bar1 = Bar::new().high(10).low(7.5).close(9);
148        let bar2 = Bar::new().high(11).low(9).close(9.5);
149
150        atr.next(&bar1);
151        atr.next(&bar2);
152
153        atr.reset();
154        let bar3 = Bar::new().high(60).low(15).close(51);
155        assert_eq!(atr.next(&bar3), 45.0);
156    }
157
158    #[test]
159    fn test_default() {
160        AverageTrueRange::default();
161    }
162
163    #[test]
164    fn test_display() {
165        let indicator = AverageTrueRange::new(8).unwrap();
166        assert_eq!(format!("{}", indicator), "ATR(8)");
167    }
168}