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