use crate::indicators::av;
use crate::kernels;
pub fn ma(close: &[f64], period: usize) -> Vec<f64> {
kernels::sma(av(close), period).into_raw_vec_and_offset().0
}
pub fn ema(close: &[f64], period: usize) -> Vec<f64> {
kernels::ema_seeded(av(close), period)
.into_raw_vec_and_offset()
.0
}
pub fn smma(close: &[f64], period: usize) -> Vec<f64> {
kernels::wilder(av(close), period).to_vec()
}
#[inline]
pub(super) fn ema_k(period: usize) -> f64 {
2.0 / (period as f64 + 1.0)
}
pub(super) fn ema_seed_idx(data: &[f64], period: usize) -> Option<usize> {
if period == 0 {
return None;
}
let mut count = 0usize;
for (i, &x) in data.iter().enumerate() {
if !x.is_nan() {
count += 1;
if count == period {
return Some(i);
}
}
}
None
}
pub fn ema_final_state(data: &[f64], period: usize) -> Option<Vec<f64>> {
let k = ema_k(period);
let si = ema_seed_idx(data, period)?;
let mut e = data[si + 1 - period..=si].iter().sum::<f64>() / period as f64;
for &x in &data[si + 1..] {
e = (x - e).mul_add(k, e);
}
Some(vec![e])
}
pub fn ema_resume(data: &[f64], period: usize, from: usize, state: &[f64]) -> (Vec<f64>, Vec<f64>) {
let k = ema_k(period);
let n = data.len();
let mut e = state[0];
let mut out = Vec::with_capacity(n.saturating_sub(from));
for &x in &data[from..n] {
e = (x - e).mul_add(k, e);
out.push(e);
}
(out, vec![e])
}
pub fn smma_final_state(data: &[f64], period: usize) -> Option<Vec<f64>> {
let pf = period as f64;
let (a, b) = ((pf - 1.0) / pf, 1.0 / pf);
let si = ema_seed_idx(data, period)?;
let mut w = data[si + 1 - period..=si].iter().sum::<f64>() / pf;
for &x in &data[si + 1..] {
w = w.mul_add(a, x * b);
}
Some(vec![w])
}
pub fn smma_resume(
data: &[f64],
period: usize,
from: usize,
state: &[f64],
) -> (Vec<f64>, Vec<f64>) {
let pf = period as f64;
let (a, b) = ((pf - 1.0) / pf, 1.0 / pf);
let n = data.len();
let mut w = state[0];
let mut out = Vec::with_capacity(n.saturating_sub(from));
for &x in &data[from..n] {
w = w.mul_add(a, x * b);
out.push(w);
}
(out, vec![w])
}
pub fn wma(data: &[f64], period: usize) -> Vec<f64> {
let n = data.len();
let mut out = vec![f64::NAN; n];
if period == 0 || period > n {
return out;
}
let start = data.iter().position(|x| !x.is_nan()).unwrap_or(n);
if start > 0 {
let sub = wma(&data[start..], period);
out[start..].copy_from_slice(&sub);
return out;
}
let denom = (period * (period + 1) / 2) as f64; let pf = period as f64;
let mut sum = 0.0; let mut wsum = 0.0; for j in 0..period {
sum += data[j];
wsum += data[j] * (j + 1) as f64;
}
out[period - 1] = wsum / denom;
for i in period..n {
wsum += pf * data[i] - sum;
sum += data[i] - data[i - period];
out[i] = wsum / denom;
}
out
}
pub fn bbi(close: &[f64], a: usize, b: usize, c: usize, d: usize) -> Vec<f64> {
let data = av(close);
let ma_a = kernels::sma(data, a);
let ma_b = kernels::sma(data, b);
let ma_c = kernels::sma(data, c);
let ma_d = kernels::sma(data, d);
((&ma_a + &ma_b + &ma_c + &ma_d) / 4.0).to_vec()
}