finlib_ta/indicators/
true_range.rs

1use core::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 finlib_ta;
25/// #[macro_use] extern crate assert_approx_eq;
26///
27/// use finlib_ta::{Next, DataItem};
28/// use finlib_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    use alloc::format;
118
119    test_indicator!(TrueRange);
120
121    #[test]
122    fn test_next_f64() {
123        let mut tr = TrueRange::new();
124        assert_eq!(round(tr.next(2.5)), 0.0);
125        assert_eq!(round(tr.next(3.6)), 1.1);
126        assert_eq!(round(tr.next(3.3)), 0.3);
127    }
128
129    #[test]
130    fn test_next_bar() {
131        let mut tr = TrueRange::new();
132
133        let bar1 = Bar::new().high(10).low(7.5).close(9);
134        let bar2 = Bar::new().high(11).low(9).close(9.5);
135        let bar3 = Bar::new().high(9).low(5).close(8);
136
137        assert_eq!(tr.next(&bar1), 2.5);
138        assert_eq!(tr.next(&bar2), 2.0);
139        assert_eq!(tr.next(&bar3), 4.5);
140    }
141
142    #[test]
143    fn test_reset() {
144        let mut tr = TrueRange::new();
145
146        let bar1 = Bar::new().high(10).low(7.5).close(9);
147        let bar2 = Bar::new().high(11).low(9).close(9.5);
148
149        tr.next(&bar1);
150        tr.next(&bar2);
151
152        tr.reset();
153        let bar3 = Bar::new().high(60).low(15).close(51);
154        assert_eq!(tr.next(&bar3), 45.0);
155    }
156
157    #[test]
158    fn test_default() {
159        TrueRange::default();
160    }
161
162    #[test]
163    fn test_display() {
164        let indicator = TrueRange::new();
165        assert_eq!(format!("{}", indicator), "TRUE_RANGE()");
166    }
167}