use ndarray::Array1;
use crate::indicators::av;
use crate::indicators::trend::ma::{ema_k, ema_seed_idx};
use crate::kernels;
fn macd_line(close: &[f64], fast: usize, slow: usize) -> Array1<f64> {
kernels::ema_diff_seeded(av(close), fast, slow)
}
pub fn macd(close: &[f64], fast: usize, slow: usize) -> Vec<f64> {
macd_line(close, fast, slow).to_vec()
}
pub fn macd_signal(close: &[f64], fast: usize, slow: usize, signal: usize) -> Vec<f64> {
let line = macd_line(close, fast, slow);
kernels::ema_seeded(line.view(), signal).to_vec()
}
pub fn macd_histogram(close: &[f64], fast: usize, slow: usize, signal: usize) -> Vec<f64> {
let line = macd_line(close, fast, slow);
let sig = kernels::ema_seeded(line.view(), signal);
(&line - &sig).to_vec()
}
fn macd_emas_final(close: &[f64], fast: usize, slow: usize) -> Option<(f64, f64)> {
let (kf, ks) = (ema_k(fast), ema_k(slow));
let sf = ema_seed_idx(close, fast)?;
let ss = ema_seed_idx(close, slow)?;
let mut pf = close[sf + 1 - fast..=sf].iter().sum::<f64>() / fast as f64;
for &x in &close[sf + 1..] {
pf = (x - pf).mul_add(kf, pf);
}
let mut ps = close[ss + 1 - slow..=ss].iter().sum::<f64>() / slow as f64;
for &x in &close[ss + 1..] {
ps = (x - ps).mul_add(ks, ps);
}
Some((pf, ps))
}
pub fn macd_final_state(close: &[f64], fast: usize, slow: usize) -> Option<Vec<f64>> {
let (pf, ps) = macd_emas_final(close, fast, slow)?;
Some(vec![pf, ps])
}
pub fn macd_resume(
close: &[f64],
fast: usize,
slow: usize,
from: usize,
state: &[f64],
) -> (Vec<f64>, Vec<f64>) {
let (kf, ks) = (ema_k(fast), ema_k(slow));
let n = close.len();
let (mut pf, mut ps) = (state[0], state[1]);
let mut out = Vec::with_capacity(n.saturating_sub(from));
for &x in &close[from..n] {
pf = (x - pf).mul_add(kf, pf);
ps = (x - ps).mul_add(ks, ps);
out.push(pf - ps);
}
(out, vec![pf, ps])
}
pub fn macd_signal_final_state(
close: &[f64],
fast: usize,
slow: usize,
signal: usize,
) -> Option<Vec<f64>> {
let line = macd_line(close, fast, slow);
let line = line.as_slice().expect("macd line is contiguous");
let (pf, ps) = macd_emas_final(close, fast, slow)?;
let ksig = ema_k(signal);
let si = ema_seed_idx(line, signal)?;
let mut sig = line[si + 1 - signal..=si].iter().sum::<f64>() / signal as f64;
for &x in &line[si + 1..] {
sig = (x - sig).mul_add(ksig, sig);
}
Some(vec![pf, ps, sig])
}
pub fn macd_signal_resume(
close: &[f64],
fast: usize,
slow: usize,
signal: usize,
histogram: bool,
from: usize,
state: &[f64],
) -> (Vec<f64>, Vec<f64>) {
let (kf, ks, ksig) = (ema_k(fast), ema_k(slow), ema_k(signal));
let n = close.len();
let (mut pf, mut ps, mut sig) = (state[0], state[1], state[2]);
let mut out = Vec::with_capacity(n.saturating_sub(from));
for &x in &close[from..n] {
pf = (x - pf).mul_add(kf, pf);
ps = (x - ps).mul_add(ks, ps);
let line = pf - ps;
sig = (line - sig).mul_add(ksig, sig);
out.push(if histogram { line - sig } else { sig });
}
(out, vec![pf, ps, sig])
}
pub fn macd_resume_one(
close: &[f64],
fast: usize,
slow: usize,
row: usize,
state: &[f64],
) -> Option<f64> {
if row == 0 || state.len() < 2 || row >= close.len() {
return None;
}
let (kf, ks) = (ema_k(fast), ema_k(slow));
let (pf, ps) = (state[0], state[1]);
let x = close[row];
let pf = (x - pf).mul_add(kf, pf);
let ps = (x - ps).mul_add(ks, ps);
Some(pf - ps)
}
pub fn macd_signal_resume_one(
close: &[f64],
fast: usize,
slow: usize,
signal: usize,
histogram: bool,
row: usize,
state: &[f64],
) -> Option<f64> {
if row == 0 || state.len() < 3 || row >= close.len() {
return None;
}
let (kf, ks, ksig) = (ema_k(fast), ema_k(slow), ema_k(signal));
let (pf, ps, sig) = (state[0], state[1], state[2]);
let x = close[row];
let pf = (x - pf).mul_add(kf, pf);
let ps = (x - ps).mul_add(ks, ps);
let line = pf - ps;
let sig = (line - sig).mul_add(ksig, sig);
Some(if histogram { line - sig } else { sig })
}