quantwave_core/indicators/incremental/
mavp.rs1use crate::indicators::ma_type::MaType;
4use crate::traits::Next;
5
6#[derive(Debug, Clone)]
13#[allow(non_camel_case_types)]
14pub struct MAVP {
15 pub minperiod: usize,
16 pub maxperiod: usize,
17 pub matype: MaType,
18 prices: Vec<f64>,
19}
20
21impl MAVP {
22 pub fn new(minperiod: usize, maxperiod: usize, matype: MaType) -> Self {
23 Self {
24 minperiod,
25 maxperiod,
26 matype,
27 prices: Vec::new(),
28 }
29 }
30}
31
32impl Next<(f64, f64)> for MAVP {
33 type Output = f64;
34
35 fn next(&mut self, (price, period): (f64, f64)) -> Self::Output {
36 let _ = self.matype;
37 self.prices.push(price);
38 let i = self.prices.len() - 1;
39 let maxp = self.maxperiod;
40 if maxp == 0 || i < maxp - 1 {
41 return f64::NAN;
42 }
43 let p = (period.round() as usize).clamp(self.minperiod, self.maxperiod);
44 if i + 1 >= p {
45 let start = i + 1 - p;
46 let sum: f64 = self.prices[start..=i].iter().sum();
47 sum / p as f64
48 } else {
49 f64::NAN
50 }
51 }
52}
53
54#[cfg(test)]
55mod tests {
56 use super::*;
57 use proptest::prelude::*;
58
59 proptest! {
60 #[test]
61 fn test_mavp_parity(
62 h in prop::collection::vec(10.0..100.0, 10..100),
63 l in prop::collection::vec(10.0..100.0, 10..100)
64 ) {
65 let len = h.len().min(l.len());
66 let in1: Vec<f64> = (0..len)
67 .map(|i| {
68 let hi: f64 = h[i];
69 let lo: f64 = l[i];
70 hi.max(lo)
71 })
72 .collect();
73 let in2: Vec<f64> = (0..len)
74 .map(|i| {
75 let hi: f64 = h[i];
76 let lo: f64 = l[i];
77 hi.min(lo)
78 })
79 .collect();
80 let minperiod = 2usize;
81 let maxperiod = 30usize;
82 let matype = MaType::Sma;
83 let mut mavp = MAVP::new(minperiod, maxperiod, matype);
84 let streaming: Vec<f64> = (0..len)
85 .map(|i| mavp.next((in1[i], in2[i])))
86 .collect();
87 let batch = talib_rs::overlap::mavp(&in1, &in2, minperiod, maxperiod, matype.into())
88 .unwrap_or_else(|_| vec![f64::NAN; len]);
89 for (s, b) in streaming.iter().zip(batch.iter()) {
90 if s.is_nan() {
91 assert!(b.is_nan());
92 } else {
93 approx::assert_relative_eq!(s, b, epsilon = 1e-6);
94 }
95 }
96 }
97 }
98}