cxmr_ta_core/indicators/
true_range.rs1use std::fmt;
2
3use crate::helpers::max3;
4use crate::{Calculate, Close, High, Low, Next, Reset};
5
6#[derive(Debug, Clone)]
51pub struct TrueRange {
52 prev_close: Option<f64>,
53}
54
55impl TrueRange {
56 pub fn new() -> Self {
57 Self { prev_close: None }
58 }
59}
60
61impl Default for TrueRange {
62 fn default() -> Self {
63 Self::new()
64 }
65}
66
67impl fmt::Display for TrueRange {
68 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
69 write!(f, "TRUE_RANGE()")
70 }
71}
72
73impl Calculate for TrueRange {
74 fn calc(&mut self, input: f64) -> f64 {
75 let distance = match self.prev_close {
76 Some(prev) => (input - prev).abs(),
77 None => 0.0,
78 };
79 self.prev_close = Some(input);
80 distance
81 }
82}
83
84impl<T: High + Low + Close> Next<T> for TrueRange {
85 fn next(&mut self, bar: &T) -> f64 {
86 let max_dist = match self.prev_close {
87 Some(prev_close) => {
88 let dist1 = bar.high() - bar.low();
89 let dist2 = (bar.high() - prev_close).abs();
90 let dist3 = (bar.low() - prev_close).abs();
91 max3(dist1, dist2, dist3)
92 }
93 None => bar.high() - bar.low(),
94 };
95 self.prev_close = Some(bar.close());
96 max_dist
97 }
98}
99
100impl Reset for TrueRange {
101 fn reset(&mut self) {
102 self.prev_close = None;
103 }
104}
105
106#[cfg(test)]
107mod tests {
108 use super::*;
109 use crate::test_helper::*;
110
111 test_indicator!(TrueRange);
112
113 #[test]
114 fn test_next_f64() {
115 let mut tr = TrueRange::new();
116 assert_eq!(round(tr.calc(2.5)), 0.0);
117 assert_eq!(round(tr.calc(3.6)), 1.1);
118 assert_eq!(round(tr.calc(3.3)), 0.3);
119 }
120
121 #[test]
122 fn test_next_bar() {
123 let mut tr = TrueRange::new();
124
125 let bar1 = Bar::new().high(10).low(7.5).close(9);
126 let bar2 = Bar::new().high(11).low(9).close(9.5);
127 let bar3 = Bar::new().high(9).low(5).close(8);
128
129 assert_eq!(tr.next(&bar1), 2.5);
130 assert_eq!(tr.next(&bar2), 2.0);
131 assert_eq!(tr.next(&bar3), 4.5);
132 }
133
134 #[test]
135 fn test_reset() {
136 let mut tr = TrueRange::new();
137
138 let bar1 = Bar::new().high(10).low(7.5).close(9);
139 let bar2 = Bar::new().high(11).low(9).close(9.5);
140
141 tr.next(&bar1);
142 tr.next(&bar2);
143
144 tr.reset();
145 let bar3 = Bar::new().high(60).low(15).close(51);
146 assert_eq!(tr.next(&bar3), 45.0);
147 }
148
149 #[test]
150 fn test_default() {
151 TrueRange::default();
152 }
153
154 #[test]
155 fn test_display() {
156 let indicator = TrueRange::new();
157 assert_eq!(format!("{}", indicator), "TRUE_RANGE()");
158 }
159}