finance_query/indicators/
true_range.rs1use super::{IndicatorError, Result};
4
5pub fn true_range(highs: &[f64], lows: &[f64], closes: &[f64]) -> Result<Vec<Option<f64>>> {
26 let len = highs.len();
27 if lows.len() != len || closes.len() != len {
28 return Err(IndicatorError::InvalidPeriod(
29 "Data lengths must match".to_string(),
30 ));
31 }
32 if len < 2 {
33 return Err(IndicatorError::InsufficientData { need: 2, got: len });
34 }
35
36 let mut result = vec![None; len];
37
38 result[0] = Some(highs[0] - lows[0]);
39
40 for i in 1..len {
41 let high_low = highs[i] - lows[i];
42 let high_close = (highs[i] - closes[i - 1]).abs();
43 let low_close = (lows[i] - closes[i - 1]).abs();
44 let tr = high_low.max(high_close).max(low_close);
45 result[i] = Some(tr);
46 }
47
48 Ok(result)
49}
50
51#[cfg(test)]
52mod tests {
53 use super::*;
54
55 #[test]
56 fn test_true_range() {
57 let highs = vec![10.0, 11.0, 12.0];
58 let lows = vec![8.0, 9.0, 10.0];
59 let closes = vec![9.0, 10.0, 11.0];
60 let result = true_range(&highs, &lows, &closes).unwrap();
61
62 assert_eq!(result.len(), 3);
63 assert!(result[0].is_some());
64 assert!(result[1].is_some());
65 assert!(result[2].is_some());
66 }
67}