pub fn kama(data: &[f64], period: usize) -> Vec<f64> {
let n = data.len();
let mut out = vec![f64::NAN; n];
if period == 0 || period + 1 > n {
return out;
}
let start = data.iter().position(|x| !x.is_nan()).unwrap_or(n);
if start > 0 {
let sub = kama(&data[start..], period);
out[start..].copy_from_slice(&sub);
return out;
}
let mut sum_roc1 = 0.0;
for j in 0..period {
sum_roc1 += (data[j] - data[j + 1]).abs();
}
let mut trailing_idx = 0usize;
let mut today = period;
let mut prev_kama = data[today - 1];
let mut trailing_value = data[trailing_idx];
let period_roc = data[today] - trailing_value;
trailing_idx += 1;
let sc = kama_sc(period_roc, sum_roc1);
prev_kama = (data[today] - prev_kama).mul_add(sc, prev_kama);
out[today] = prev_kama;
today += 1;
while today < n {
let tr2 = data[trailing_idx];
trailing_idx += 1;
let period_roc = data[today] - tr2;
sum_roc1 -= (trailing_value - tr2).abs(); sum_roc1 += (data[today] - data[today - 1]).abs(); trailing_value = tr2;
let sc = kama_sc(period_roc, sum_roc1);
prev_kama = (data[today] - prev_kama).mul_add(sc, prev_kama);
out[today] = prev_kama;
today += 1;
}
out
}
#[inline]
fn kama_sc(period_roc: f64, sum_roc1: f64) -> f64 {
const CONST_MAX: f64 = 2.0 / (30.0 + 1.0); let const_diff = 2.0 / (2.0 + 1.0) - CONST_MAX; let er = if sum_roc1 <= period_roc || sum_roc1.abs() < 1e-14 {
1.0
} else {
(period_roc / sum_roc1).abs()
};
let sc = er.mul_add(const_diff, CONST_MAX);
sc * sc
}
pub fn kama_final_state(data: &[f64], period: usize) -> Option<Vec<f64>> {
let n = data.len();
if period == 0 || period + 1 > n {
return None;
}
let start = data.iter().position(|x| !x.is_nan()).unwrap_or(n);
if start > 0 {
return kama_final_state(&data[start..], period);
}
let mut sum_roc1 = 0.0;
for j in 0..period {
sum_roc1 += (data[j] - data[j + 1]).abs();
}
let mut trailing_idx = 0usize;
let mut today = period;
let mut prev_kama = data[today - 1];
let mut trailing_value = data[trailing_idx];
let period_roc = data[today] - trailing_value;
trailing_idx += 1;
prev_kama = (data[today] - prev_kama).mul_add(kama_sc(period_roc, sum_roc1), prev_kama);
today += 1;
while today < n {
let tr2 = data[trailing_idx];
trailing_idx += 1;
let period_roc = data[today] - tr2;
sum_roc1 -= (trailing_value - tr2).abs();
sum_roc1 += (data[today] - data[today - 1]).abs();
trailing_value = tr2;
prev_kama = (data[today] - prev_kama).mul_add(kama_sc(period_roc, sum_roc1), prev_kama);
today += 1;
}
Some(vec![prev_kama, sum_roc1])
}
pub fn kama_resume(
data: &[f64],
period: usize,
from: usize,
state: &[f64],
) -> Option<(Vec<f64>, Vec<f64>)> {
let n = data.len();
if period == 0 || from <= period || from > n {
return None;
}
let mut prev_kama = state[0];
let mut sum_roc1 = state[1];
let mut trailing_value = data[from - period - 1];
let mut trailing_idx = from - period;
let mut out = Vec::with_capacity(n - from);
#[allow(clippy::explicit_counter_loop)] for today in from..n {
let tr2 = data[trailing_idx];
trailing_idx += 1;
let period_roc = data[today] - tr2;
sum_roc1 -= (trailing_value - tr2).abs();
sum_roc1 += (data[today] - data[today - 1]).abs();
trailing_value = tr2;
prev_kama = (data[today] - prev_kama).mul_add(kama_sc(period_roc, sum_roc1), prev_kama);
out.push(prev_kama);
}
Some((out, vec![prev_kama, sum_roc1]))
}
pub fn kama_resume_one(data: &[f64], period: usize, row: usize, state: &[f64]) -> Option<f64> {
let n = data.len();
if period == 0 || row <= period || row >= n || state.len() < 2 {
return None;
}
let prev_kama = state[0];
let mut sum_roc1 = state[1];
let trailing_value = data[row - period - 1];
let tr2 = data[row - period];
let period_roc = data[row] - tr2;
sum_roc1 -= (trailing_value - tr2).abs();
sum_roc1 += (data[row] - data[row - 1]).abs();
let sc = kama_sc(period_roc, sum_roc1);
Some((data[row] - prev_kama).mul_add(sc, prev_kama))
}