trading_toolkit/indicator/
macd.rs1use super::MovingAverage;
2use crate::types::{data::BaseData, error::ToolkitError};
3
4#[derive(Debug, Clone, Copy)]
5pub struct MovingAverageConvergenceDivergence {
6 signal: f64,
7 ema_12: f64,
8 ema_26: f64,
9}
10
11impl MovingAverageConvergenceDivergence {
12 pub fn new<T>(data: &[T]) -> Result<Self, ToolkitError>
13 where
14 T: BaseData + Clone,
15 {
16 if data.len() < 34 {
17 return Err(ToolkitError::DataNotEnough);
18 }
19 let mut data = data.to_vec();
20 data.sort_by_key(|k| k.epoch_time());
21 data = data.split_at(data.len() - 34).1.to_vec();
22 let n = data.len();
23 let ema_26 = MovingAverage::exponential(&data[n - 26..n].to_vec());
24 let ema_12 = MovingAverage::exponential(&data[n - 12..n].to_vec());
25 let macd_series: Vec<_> = (0..9)
26 .map(|i| {
27 let end = n - (8 - i); let e26 = MovingAverage::exponential(&data[end - 26..end].to_vec()).inner();
29 let e12 = MovingAverage::exponential(&data[end - 12..end].to_vec()).inner();
30 e12 - e26
31 })
32 .collect();
33
34 #[derive(Debug, Clone, Copy)]
37 struct MacdPoint(f64, u128);
38 impl BaseData for MacdPoint {
39 fn value(&self) -> f64 {
40 self.0
41 }
42 fn weight(&self) -> u64 {
43 1
44 }
45 fn epoch_time(&self) -> u128 {
46 self.1
47 }
48 }
49 let macd_data: Vec<MacdPoint> = macd_series
50 .iter()
51 .enumerate()
52 .map(|(i, v)| MacdPoint(*v, i as u128))
53 .collect();
54
55 let signal = MovingAverage::exponential(&macd_data).inner();
56 Ok(Self {
57 signal: signal,
58 ema_12: ema_12.inner(),
59 ema_26: ema_26.inner(),
60 })
61 }
62
63 pub fn fast(&self) -> f64 {
65 self.ema_12 - self.ema_26
66 }
67
68 pub fn slow(&self) -> f64 {
70 self.signal
71 }
72
73 pub fn macd_histogram(&self) -> f64 {
75 self.fast() - self.slow()
76 }
77}