use crate::{KandError, TAFloat};
pub const fn lookback() -> Result<usize, KandError> {
Ok(1)
}
pub fn trange(
input_high: &[TAFloat],
input_low: &[TAFloat],
input_close: &[TAFloat],
output_trange: &mut [TAFloat],
) -> Result<(), KandError> {
let len = input_high.len();
let lookback = lookback()?;
#[cfg(feature = "check")]
{
if len == 0 {
return Err(KandError::InvalidData);
}
if len != input_low.len() || len != input_close.len() || len != output_trange.len() {
return Err(KandError::LengthMismatch);
}
if len <= lookback {
return Err(KandError::InsufficientData);
}
}
#[cfg(feature = "deep-check")]
{
for i in 0..len {
if input_high[i].is_nan() || input_low[i].is_nan() || input_close[i].is_nan() {
return Err(KandError::NaNDetected);
}
}
}
output_trange[0] = TAFloat::NAN;
for i in 1..len {
let h_l = input_high[i] - input_low[i];
let h_pc = (input_high[i] - input_close[i - 1]).abs();
let l_pc = (input_low[i] - input_close[i - 1]).abs();
output_trange[i] = h_l.max(h_pc).max(l_pc);
}
for value in output_trange.iter_mut().take(lookback) {
*value = TAFloat::NAN;
}
Ok(())
}
pub fn trange_inc(
input_high: TAFloat,
input_low: TAFloat,
prev_close: TAFloat,
) -> Result<TAFloat, KandError> {
#[cfg(feature = "deep-check")]
{
if input_high.is_nan() || input_low.is_nan() || prev_close.is_nan() {
return Err(KandError::NaNDetected);
}
}
let h_l = input_high - input_low;
let h_pc = (input_high - prev_close).abs();
let l_pc = (input_low - prev_close).abs();
Ok(h_l.max(h_pc).max(l_pc))
}
#[cfg(test)]
mod tests {
use approx::assert_relative_eq;
use super::*;
#[test]
fn test_trange_calculation() {
let input_high = vec![35266.0, 35247.5, 35235.7, 35190.8, 35182.0];
let input_low = vec![35216.1, 35206.5, 35180.0, 35130.7, 35153.6];
let input_close = vec![35216.1, 35221.4, 35190.7, 35170.0, 35181.5];
let mut output_trange = vec![0.0; 5];
trange(&input_high, &input_low, &input_close, &mut output_trange).unwrap();
assert!(output_trange[0].is_nan());
assert_relative_eq!(output_trange[1], 41.0, epsilon = 0.00001);
assert_relative_eq!(output_trange[2], 55.7, epsilon = 0.00001);
assert_relative_eq!(output_trange[3], 60.1, epsilon = 0.00001);
assert_relative_eq!(output_trange[4], 28.4, epsilon = 0.00001);
for i in 1..5 {
let result = trange_inc(input_high[i], input_low[i], input_close[i - 1]).unwrap();
assert_relative_eq!(result, output_trange[i], epsilon = 0.00001);
}
}
}