use super::MovingAverage;
use crate::types::{data::BaseData, error::ToolkitError};
#[derive(Debug, Clone, Copy)]
pub struct MovingAverageConvergenceDivergence {
signal: f64,
ema_12: f64,
ema_26: f64,
}
impl MovingAverageConvergenceDivergence {
pub fn new<T>(data: &[T]) -> Result<Self, ToolkitError>
where
T: BaseData + Clone,
{
if data.len() < 34 {
return Err(ToolkitError::DataNotEnough);
}
let mut data = data.to_vec();
data.sort_by_key(|k| k.epoch_time());
data = data.split_at(data.len() - 34).1.to_vec();
let n = data.len();
let ema_26 = MovingAverage::exponential(&data[n - 26..n].to_vec());
let ema_12 = MovingAverage::exponential(&data[n - 12..n].to_vec());
let macd_series: Vec<_> = (0..9)
.map(|i| {
let end = n - (8 - i); let e26 = MovingAverage::exponential(&data[end - 26..end].to_vec()).inner();
let e12 = MovingAverage::exponential(&data[end - 12..end].to_vec()).inner();
e12 - e26
})
.collect();
#[derive(Debug, Clone, Copy)]
struct MacdPoint(f64, u128);
impl BaseData for MacdPoint {
fn value(&self) -> f64 {
self.0
}
fn weight(&self) -> u64 {
1
}
fn epoch_time(&self) -> u128 {
self.1
}
}
let macd_data: Vec<MacdPoint> = macd_series
.iter()
.enumerate()
.map(|(i, v)| MacdPoint(*v, i as u128))
.collect();
let signal = MovingAverage::exponential(&macd_data).inner();
Ok(Self {
signal: signal,
ema_12: ema_12.inner(),
ema_26: ema_26.inner(),
})
}
pub fn fast(&self) -> f64 {
self.ema_12 - self.ema_26
}
pub fn slow(&self) -> f64 {
self.signal
}
pub fn macd_histogram(&self) -> f64 {
self.fast() - self.slow()
}
}