quantwave_core/indicators/incremental/
dema.rs1use crate::indicators::incremental::talib_ema::TalibEma;
4use crate::traits::Next;
5
6#[derive(Debug, Clone)]
8#[allow(non_camel_case_types)]
9pub struct DEMA {
10 pub timeperiod: usize,
11 ema1: TalibEma,
12 ema2: TalibEma,
13}
14
15impl DEMA {
16 pub fn new(timeperiod: usize) -> Self {
17 Self {
18 timeperiod,
19 ema1: TalibEma::new(timeperiod),
20 ema2: TalibEma::new(timeperiod),
21 }
22 }
23}
24
25impl Next<f64> for DEMA {
26 type Output = f64;
27
28 fn next(&mut self, input: f64) -> Self::Output {
29 let e1 = self.ema1.next(input);
30 if e1.is_nan() {
31 return f64::NAN;
32 }
33 let e2 = self.ema2.next(e1);
34 if e2.is_nan() {
35 return f64::NAN;
36 }
37 2.0 * e1 - e2
38 }
39}
40
41#[cfg(test)]
42mod tests {
43 use super::*;
44 use proptest::prelude::*;
45
46 proptest! {
47 #[test]
48 fn test_dema_parity(input in prop::collection::vec(0.1..100.0, 1..100)) {
49 let period = 10;
50 let mut dema = DEMA::new(period);
51 let streaming: Vec<f64> = input.iter().map(|&x| dema.next(x)).collect();
52 let batch = talib_rs::overlap::dema(&input, period)
53 .unwrap_or_else(|_| vec![f64::NAN; input.len()]);
54 for (s, b) in streaming.iter().zip(batch.iter()) {
55 if s.is_nan() {
56 assert!(b.is_nan());
57 } else {
58 approx::assert_relative_eq!(s, b, epsilon = 1e-6);
59 }
60 }
61 }
62 }
63}