use crate::indicators::trend::ma::ema_k;
use crate::kernels;
fn cascade_warmup<const S: usize>(
data: &[f64],
period: usize,
k: f64,
) -> Option<(usize, [f64; S])> {
let n = data.len();
if period == 0 {
return None;
}
let start = data.iter().position(|x| !x.is_nan()).unwrap_or(n);
let lookback = start + S * (period - 1);
if lookback >= n {
return None;
}
let mut e = [0.0f64; S];
let mut acc = [0.0f64; S];
let mut cnt = [0usize; S];
let mut seeded = [false; S];
for &raw in &data[..=lookback] {
let mut x = raw;
for s in 0..S {
if seeded[s] {
e[s] = (x - e[s]).mul_add(k, e[s]);
x = e[s];
} else if !x.is_nan() {
acc[s] += x;
cnt[s] += 1;
if cnt[s] == period {
e[s] = acc[s] / period as f64;
seeded[s] = true;
x = e[s];
} else {
x = f64::NAN;
}
} else {
x = f64::NAN;
}
}
}
Some((lookback, e))
}
pub fn dema(data: &[f64], period: usize) -> Vec<f64> {
let n = data.len();
let mut out = vec![f64::NAN; n];
let k = 2.0 / (period as f64 + 1.0);
let Some((lookback, e)) = cascade_warmup::<2>(data, period, k) else {
return out;
};
out[lookback] = 2.0 * e[0] - e[1];
let (mut e0, mut e1) = (e[0], e[1]);
for i in (lookback + 1)..n {
e0 = (data[i] - e0).mul_add(k, e0);
e1 = (e0 - e1).mul_add(k, e1);
out[i] = 2.0 * e0 - e1;
}
out
}
pub fn tema(data: &[f64], period: usize) -> Vec<f64> {
let n = data.len();
let mut out = vec![f64::NAN; n];
let k = 2.0 / (period as f64 + 1.0);
let Some((lookback, e)) = cascade_warmup::<3>(data, period, k) else {
return out;
};
out[lookback] = 3.0 * e[0] - 3.0 * e[1] + e[2];
let (mut e0, mut e1, mut e2) = (e[0], e[1], e[2]);
for i in (lookback + 1)..n {
e0 = (data[i] - e0).mul_add(k, e0);
e1 = (e0 - e1).mul_add(k, e1);
e2 = (e1 - e2).mul_add(k, e2);
out[i] = 3.0 * e0 - 3.0 * e1 + e2;
}
out
}
pub fn trima(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 = trima(&data[start..], period);
out[start..].copy_from_slice(&sub);
return out;
}
let (a, b) = if period % 2 == 1 {
let m = period.div_ceil(2);
(m, m)
} else {
let m = period / 2;
(m, m + 1)
};
let af = a as f64;
let bf = b as f64;
let mut sum1 = 0.0;
let mut sum2 = 0.0;
let mut ring = vec![0.0; b];
let mut slot = 0usize;
let mut inner_cnt = 0usize;
for i in 0..n {
sum1 += data[i];
if i >= a {
sum1 -= data[i - a];
}
if i + 1 >= a {
let inner = sum1 / af;
sum2 += inner;
if inner_cnt >= b {
sum2 -= ring[slot]; }
ring[slot] = inner;
slot += 1;
if slot == b {
slot = 0;
}
inner_cnt += 1;
if inner_cnt >= b {
out[i] = sum2 / bf;
}
}
}
out
}
pub fn t3(data: &[f64], period: usize, vfactor: f64) -> Vec<f64> {
let n = data.len();
let mut out = vec![f64::NAN; n];
let v2 = vfactor * vfactor;
let c1 = -(v2 * vfactor);
let c2 = 3.0 * (v2 - c1);
let c3 = -6.0 * v2 - 3.0 * (vfactor - c1);
let c4 = 1.0 + 3.0 * vfactor - c1 + 3.0 * v2;
let k = 2.0 / (period as f64 + 1.0);
let Some((lookback, e)) = cascade_warmup::<6>(data, period, k) else {
return out;
};
out[lookback] = c1 * e[5] + c2 * e[4] + c3 * e[3] + c4 * e[2];
let (mut e0, mut e1, mut e2, mut e3, mut e4, mut e5) = (e[0], e[1], e[2], e[3], e[4], e[5]);
for i in (lookback + 1)..n {
e0 = (data[i] - e0).mul_add(k, e0);
e1 = (e0 - e1).mul_add(k, e1);
e2 = (e1 - e2).mul_add(k, e2);
e3 = (e2 - e3).mul_add(k, e3);
e4 = (e3 - e4).mul_add(k, e4);
e5 = (e4 - e5).mul_add(k, e5);
out[i] = c1 * e5 + c2 * e4 + c3 * e3 + c4 * e2;
}
out
}
pub fn dema_final_state(data: &[f64], period: usize) -> Option<Vec<f64>> {
let e = kernels::ema_cascade_final::<2>(data, period)?;
Some(e.to_vec())
}
pub fn dema_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], state[1]];
let mut out = Vec::with_capacity(n.saturating_sub(from));
for &x in &data[from..n] {
kernels::ema_cascade_step(&mut e, x, k);
out.push(2.0 * e[0] - e[1]);
}
(out, e.to_vec())
}
pub fn tema_final_state(data: &[f64], period: usize) -> Option<Vec<f64>> {
let e = kernels::ema_cascade_final::<3>(data, period)?;
Some(e.to_vec())
}
pub fn tema_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], state[1], state[2]];
let mut out = Vec::with_capacity(n.saturating_sub(from));
for &x in &data[from..n] {
kernels::ema_cascade_step(&mut e, x, k);
out.push(3.0 * e[0] - 3.0 * e[1] + e[2]);
}
(out, e.to_vec())
}
pub fn t3_final_state(data: &[f64], period: usize) -> Option<Vec<f64>> {
let e = kernels::ema_cascade_final::<6>(data, period)?;
Some(e.to_vec())
}
pub fn t3_resume(
data: &[f64],
period: usize,
vfactor: f64,
from: usize,
state: &[f64],
) -> (Vec<f64>, Vec<f64>) {
let v2 = vfactor * vfactor;
let c1 = -(v2 * vfactor);
let c2 = 3.0 * (v2 - c1);
let c3 = -6.0 * v2 - 3.0 * (vfactor - c1);
let c4 = 1.0 + 3.0 * vfactor - c1 + 3.0 * v2;
let k = ema_k(period);
let n = data.len();
let mut e = [state[0], state[1], state[2], state[3], state[4], state[5]];
let mut out = Vec::with_capacity(n.saturating_sub(from));
for &x in &data[from..n] {
kernels::ema_cascade_step(&mut e, x, k);
out.push(c1 * e[5] + c2 * e[4] + c3 * e[3] + c4 * e[2]);
}
(out, e.to_vec())
}
pub fn dema_resume_one(data: &[f64], period: usize, row: usize, state: &[f64]) -> Option<f64> {
if state.len() < 2 || row >= data.len() {
return None;
}
let k = ema_k(period);
let mut e = [state[0], state[1]];
kernels::ema_cascade_step(&mut e, data[row], k);
Some(2.0 * e[0] - e[1])
}
pub fn tema_resume_one(data: &[f64], period: usize, row: usize, state: &[f64]) -> Option<f64> {
if state.len() < 3 || row >= data.len() {
return None;
}
let k = ema_k(period);
let mut e = [state[0], state[1], state[2]];
kernels::ema_cascade_step(&mut e, data[row], k);
Some(3.0 * e[0] - 3.0 * e[1] + e[2])
}
pub fn t3_resume_one(
data: &[f64],
period: usize,
vfactor: f64,
row: usize,
state: &[f64],
) -> Option<f64> {
if state.len() < 6 || row >= data.len() {
return None;
}
let v2 = vfactor * vfactor;
let c1 = -(v2 * vfactor);
let c2 = 3.0 * (v2 - c1);
let c3 = -6.0 * v2 - 3.0 * (vfactor - c1);
let c4 = 1.0 + 3.0 * vfactor - c1 + 3.0 * v2;
let k = ema_k(period);
let mut e = [
state[0], state[1], state[2], state[3], state[4], state[5],
];
kernels::ema_cascade_step(&mut e, data[row], k);
Some(c1 * e[5] + c2 * e[4] + c3 * e[3] + c4 * e[2])
}