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