ta/indicators/
true_range.rs

1use std::fmt;
2
3use crate::helpers::max3;
4use crate::{Close, High, Low, Next, Reset};
5#[cfg(feature = "serde")]
6use serde::{Deserialize, Serialize};
7
8/// The range of a day's trading is simply _high_ - _low_.
9/// The true range extends it to yesterday's closing price if it was outside of today's range.
10///
11/// The true range is the largest of one the following:
12///
13/// * Most recent period's high minus the most recent period's low
14/// * Absolute value of the most recent period's high minus the previous close
15/// * Absolute value of the most recent period's low minus the previous close
16///
17/// # Formula
18///
19/// TR = max[(high - low), abs(high - close<sub>prev</sub>), abs(low - close<sub>prev</sub>)]
20///
21/// # Example
22///
23/// ```
24/// extern crate ta;
25/// #[macro_use] extern crate assert_approx_eq;
26///
27/// use ta::{Next, DataItem};
28/// use ta::indicators::TrueRange;
29///
30/// fn main() {
31///     let data = vec![
32///         // open, high, low, close, tr
33///         (9.7   , 10.0, 9.0, 9.5  , 1.0),  // tr = high - low = 10.0 - 9.0 = 1.0
34///         (9.9   , 10.4, 9.8, 10.2 , 0.9),  // tr = high - prev_close = 10.4 - 9.5 = 0.9
35///         (10.1  , 10.7, 9.4, 9.7  , 1.3),  // tr = high - low = 10.7 - 9.4 = 1.3
36///         (9.1   , 9.2 , 8.1, 8.4  , 1.6),  // tr = prev_close - low = 9.7 - 8.1 = 1.6
37///     ];
38///     let mut indicator = TrueRange::new();
39///
40///     for (open, high, low, close, tr) in data {
41///         let di = DataItem::builder()
42///             .high(high)
43///             .low(low)
44///             .close(close)
45///             .open(open)
46///             .volume(1000.0)
47///             .build().unwrap();
48///         assert_approx_eq!(indicator.next(&di), tr);
49///     }
50/// }
51/// ```
52#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
53#[derive(Debug, Clone)]
54pub struct TrueRange {
55    prev_close: Option<f64>,
56}
57
58impl TrueRange {
59    pub fn new() -> Self {
60        Self { prev_close: None }
61    }
62}
63
64impl Default for TrueRange {
65    fn default() -> Self {
66        Self::new()
67    }
68}
69
70impl fmt::Display for TrueRange {
71    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
72        write!(f, "TRUE_RANGE()")
73    }
74}
75
76impl Next<f64> for TrueRange {
77    type Output = f64;
78
79    fn next(&mut self, input: f64) -> Self::Output {
80        let distance = match self.prev_close {
81            Some(prev) => (input - prev).abs(),
82            None => 0.0,
83        };
84        self.prev_close = Some(input);
85        distance
86    }
87}
88
89impl<T: High + Low + Close> Next<&T> for TrueRange {
90    type Output = f64;
91
92    fn next(&mut self, bar: &T) -> Self::Output {
93        let max_dist = match self.prev_close {
94            Some(prev_close) => {
95                let dist1 = bar.high() - bar.low();
96                let dist2 = (bar.high() - prev_close).abs();
97                let dist3 = (bar.low() - prev_close).abs();
98                max3(dist1, dist2, dist3)
99            }
100            None => bar.high() - bar.low(),
101        };
102        self.prev_close = Some(bar.close());
103        max_dist
104    }
105}
106
107impl Reset for TrueRange {
108    fn reset(&mut self) {
109        self.prev_close = None;
110    }
111}
112
113#[cfg(test)]
114mod tests {
115    use super::*;
116    use crate::test_helper::*;
117
118    test_indicator!(TrueRange);
119
120    #[test]
121    fn test_next_f64() {
122        let mut tr = TrueRange::new();
123        assert_eq!(round(tr.next(2.5)), 0.0);
124        assert_eq!(round(tr.next(3.6)), 1.1);
125        assert_eq!(round(tr.next(3.3)), 0.3);
126    }
127
128    #[test]
129    fn test_next_bar() {
130        let mut tr = TrueRange::new();
131
132        let bar1 = Bar::new().high(10).low(7.5).close(9);
133        let bar2 = Bar::new().high(11).low(9).close(9.5);
134        let bar3 = Bar::new().high(9).low(5).close(8);
135
136        assert_eq!(tr.next(&bar1), 2.5);
137        assert_eq!(tr.next(&bar2), 2.0);
138        assert_eq!(tr.next(&bar3), 4.5);
139    }
140
141    #[test]
142    fn test_reset() {
143        let mut tr = TrueRange::new();
144
145        let bar1 = Bar::new().high(10).low(7.5).close(9);
146        let bar2 = Bar::new().high(11).low(9).close(9.5);
147
148        tr.next(&bar1);
149        tr.next(&bar2);
150
151        tr.reset();
152        let bar3 = Bar::new().high(60).low(15).close(51);
153        assert_eq!(tr.next(&bar3), 45.0);
154    }
155
156    #[test]
157    fn test_default() {
158        TrueRange::default();
159    }
160
161    #[test]
162    fn test_display() {
163        let indicator = TrueRange::new();
164        assert_eq!(format!("{}", indicator), "TRUE_RANGE()");
165    }
166}