use crate::indicators::av;
use crate::kernels;
pub fn tr(high: &[f64], low: &[f64], close: &[f64]) -> Vec<f64> {
let n = high.len();
let mut tr = vec![f64::NAN; n];
for i in 1..n {
let prev_close = close[i - 1];
let hl = high[i] - low[i];
let hc = (high[i] - prev_close).abs();
let lc = (low[i] - prev_close).abs();
tr[i] = hl.max(hc).max(lc);
}
tr
}
pub fn atr(high: &[f64], low: &[f64], close: &[f64], period: usize) -> Vec<f64> {
let tr = tr(high, low, close);
kernels::wilder(av(&tr), period).to_vec()
}
pub fn natr(high: &[f64], low: &[f64], close: &[f64], period: usize) -> Vec<f64> {
let atr = atr(high, low, close, period);
(0..close.len())
.map(|i| atr[i] / close[i] * 100.0)
.collect()
}
#[inline]
fn tr1(high: &[f64], low: &[f64], close: &[f64], i: usize) -> f64 {
let hl = high[i] - low[i];
let hc = (high[i] - close[i - 1]).abs();
let lc = (low[i] - close[i - 1]).abs();
hl.max(hc).max(lc)
}
pub fn atr_final_state(
high: &[f64],
low: &[f64],
close: &[f64],
period: usize,
) -> Option<Vec<f64>> {
let n = high.len();
if period == 0 || period >= n {
return None;
}
let pf = period as f64;
let (a, b) = ((pf - 1.0) / pf, 1.0 / pf);
let mut atr = 0.0;
for i in 1..=period {
atr += tr1(high, low, close, i);
}
atr /= pf;
for i in (period + 1)..n {
atr = atr.mul_add(a, tr1(high, low, close, i) * b);
}
Some(vec![atr])
}
pub fn atr_resume(
high: &[f64],
low: &[f64],
close: &[f64],
period: usize,
from: usize,
state: &[f64],
) -> Option<(Vec<f64>, Vec<f64>)> {
if from == 0 {
return None;
}
let n = high.len();
let pf = period as f64;
let (a, b) = ((pf - 1.0) / pf, 1.0 / pf);
let mut atr = state[0];
let mut out = Vec::with_capacity(n.saturating_sub(from));
for i in from..n {
atr = atr.mul_add(a, tr1(high, low, close, i) * b);
out.push(atr);
}
Some((out, vec![atr]))
}
pub fn atr_resume_one(
high: &[f64],
low: &[f64],
close: &[f64],
period: usize,
row: usize,
state: &[f64],
) -> Option<f64> {
if row == 0 || state.is_empty() || row >= high.len() {
return None;
}
let pf = period as f64;
let (a, b) = ((pf - 1.0) / pf, 1.0 / pf);
Some(state[0].mul_add(a, tr1(high, low, close, row) * b))
}
pub fn natr_resume(
high: &[f64],
low: &[f64],
close: &[f64],
period: usize,
from: usize,
state: &[f64],
) -> Option<(Vec<f64>, Vec<f64>)> {
let (atr_tail, new_state) = atr_resume(high, low, close, period, from, state)?;
let vals = (from..high.len())
.map(|i| atr_tail[i - from] / close[i] * 100.0)
.collect();
Some((vals, new_state))
}