quantaxis_rs/indicators/
moving_average_convergence_divergence.rs1use std::fmt;
2
3use crate::errors::*;
4use crate::indicators::ExponentialMovingAverage as Ema;
5use crate::{Close, Next, Reset};
6
7#[derive(Debug, Clone)]
52pub struct MovingAverageConvergenceDivergence {
53 fast_ema: Ema,
54 slow_ema: Ema,
55 signal_ema: Ema,
56}
57
58impl MovingAverageConvergenceDivergence {
59 pub fn new(fast_length: u32, slow_length: u32, signal_length: u32) -> Result<Self> {
60 let indicator = Self {
61 fast_ema: Ema::new(fast_length)?,
62 slow_ema: Ema::new(slow_length)?,
63 signal_ema: Ema::new(signal_length)?,
64 };
65 Ok(indicator)
66 }
67}
68
69impl Next<f64> for MovingAverageConvergenceDivergence {
70 type Output = (f64, f64, f64);
71
72 fn next(&mut self, input: f64) -> Self::Output {
73 let fast_val = self.fast_ema.next(input);
74 let slow_val = self.slow_ema.next(input);
75
76 let macd = fast_val - slow_val;
77 let signal = self.signal_ema.next(macd);
78 let histogram = macd - signal;
79
80 (macd, signal, histogram)
81 }
82}
83
84impl<'a, T: Close> Next<&'a T> for MovingAverageConvergenceDivergence {
85 type Output = (f64, f64, f64);
86
87 fn next(&mut self, input: &'a T) -> Self::Output {
88 self.next(input.close())
89 }
90}
91
92impl Reset for MovingAverageConvergenceDivergence {
93 fn reset(&mut self) {
94 self.fast_ema.reset();
95 self.slow_ema.reset();
96 self.signal_ema.reset();
97 }
98}
99
100impl Default for MovingAverageConvergenceDivergence {
101 fn default() -> Self {
102 Self::new(12, 26, 9).unwrap()
103 }
104}
105
106impl fmt::Display for MovingAverageConvergenceDivergence {
107 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
108 write!(
109 f,
110 "MACD({}, {}, {})",
111 self.fast_ema.length(),
112 self.slow_ema.length(),
113 self.signal_ema.length()
114 )
115 }
116}
117
118#[cfg(test)]
119mod tests {
120 use super::*;
121 use crate::test_helper::*;
122 type Macd = MovingAverageConvergenceDivergence;
123 macro_rules! test_indicator {
124 ($i:tt) => {
125 #[test]
126 fn test_indicator() {
127 let bar = Bar::new();
128
129 let mut indicator = $i::default();
131
132 let first_output = indicator.next(12.3);
134
135 indicator.next(&bar);
137
138 indicator.reset();
140 assert_eq!(indicator.next(12.3), first_output);
141
142 format!("{}", indicator);
144 }
145 };
146 }
147 test_indicator!(Macd);
148
149 fn round(nums: (f64, f64, f64)) -> (f64, f64, f64) {
150 let n0 = (nums.0 * 100.0).round() / 100.0;
151 let n1 = (nums.1 * 100.0).round() / 100.0;
152 let n2 = (nums.2 * 100.0).round() / 100.0;
153 (n0, n1, n2)
154 }
155
156 #[test]
157 fn test_new() {
158 assert!(Macd::new(0, 1, 1).is_err());
159 assert!(Macd::new(1, 0, 1).is_err());
160 assert!(Macd::new(1, 1, 0).is_err());
161 assert!(Macd::new(1, 1, 1).is_ok());
162 }
163
164 #[test]
165 fn test_macd() {
166 let mut macd = Macd::new(3, 6, 4).unwrap();
167
168 assert_eq!(round(macd.next(2.0)), (0.0, 0.0, 0.0));
169 assert_eq!(round(macd.next(3.0)), (0.21, 0.09, 0.13));
170 assert_eq!(round(macd.next(4.2)), (0.52, 0.26, 0.26));
171 assert_eq!(round(macd.next(7.0)), (1.15, 0.62, 0.54));
172 assert_eq!(round(macd.next(6.7)), (1.15, 0.83, 0.32));
173 assert_eq!(round(macd.next(6.5)), (0.94, 0.87, 0.07));
174 }
175
176 #[test]
177 fn test_reset() {
178 let mut macd = Macd::new(3, 6, 4).unwrap();
179
180 assert_eq!(round(macd.next(2.0)), (0.0, 0.0, 0.0));
181 assert_eq!(round(macd.next(3.0)), (0.21, 0.09, 0.13));
182
183 macd.reset();
184
185 assert_eq!(round(macd.next(2.0)), (0.0, 0.0, 0.0));
186 assert_eq!(round(macd.next(3.0)), (0.21, 0.09, 0.13));
187 }
188
189 #[test]
190 fn test_default() {
191 Macd::default();
192 }
193
194 #[test]
195 fn test_display() {
196 let indicator = Macd::new(13, 30, 10).unwrap();
197 assert_eq!(format!("{}", indicator), "MACD(13, 30, 10)");
198 }
199}