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 let n = data.len();
22
23 #[derive(Debug, Clone, Copy)]
25 struct MacdPoint(f64, u128);
26 impl BaseData for MacdPoint {
27 fn value(&self) -> f64 {
28 self.0
29 }
30 fn weight(&self) -> u64 {
31 1
32 }
33 fn epoch_time(&self) -> u128 {
34 self.1
35 }
36 }
37
38 let mut ema26 = MovingAverage::simple(&data[0..26]);
40 let mut ema12 = MovingAverage::simple(&data[0..12]);
42 for i in 12..26 {
43 ema12 = MovingAverage::exponential_from(12, &ema12, &data[i]);
44 }
45
46 let mut macd_for_seed = vec![MacdPoint(
48 ema12.inner() - ema26.inner(),
49 data[25].epoch_time(),
50 )];
51
52 for i in 26..34 {
54 ema12 = MovingAverage::exponential_from(12, &ema12, &data[i]);
55 ema26 = MovingAverage::exponential_from(26, &ema26, &data[i]);
56 macd_for_seed.push(MacdPoint(
57 ema12.inner() - ema26.inner(),
58 data[i].epoch_time(),
59 ));
60 }
61
62 let mut signal = MovingAverage::simple(&macd_for_seed);
64 for i in 34..n {
65 ema12 = MovingAverage::exponential_from(12, &ema12, &data[i]);
66 ema26 = MovingAverage::exponential_from(26, &ema26, &data[i]);
67 let macd_point = MacdPoint(ema12.inner() - ema26.inner(), data[i].epoch_time());
68 signal = MovingAverage::exponential_from(9, &signal, &macd_point);
69 }
70
71 Ok(Self {
72 signal: signal.inner(),
73 ema_12: ema12.inner(),
74 ema_26: ema26.inner(),
75 })
76 }
77
78 pub fn fast(&self) -> f64 {
80 self.ema_12 - self.ema_26
81 }
82
83 pub fn slow(&self) -> f64 {
85 self.signal
86 }
87
88 pub fn macd_histogram(&self) -> f64 {
90 self.fast() - self.slow()
91 }
92}