quantwave_core/indicators/
volume.rs1talib_4_in_1_out!(AD, talib_rs::volume::ad);
2impl Default for AD {
3 fn default() -> Self {
4 Self::new()
5 }
6}
7talib_4_in_1_out!(ADOSC, talib_rs::volume::adosc, fastperiod: usize, slowperiod: usize);
8talib_2_in_1_out!(OBV, talib_rs::volume::obv);
9impl Default for OBV {
10 fn default() -> Self {
11 Self::new()
12 }
13}
14
15#[cfg(test)]
16mod tests {
17 use super::*;
18 use crate::traits::Next;
19 use proptest::prelude::*;
20
21 proptest! {
22 #[test]
23 fn test_ad_parity(
24 h in prop::collection::vec(10.0..100.0, 1..100),
25 l in prop::collection::vec(10.0..100.0, 1..100),
26 c in prop::collection::vec(10.0..100.0, 1..100),
27 v in prop::collection::vec(1.0..1000.0, 1..100)
28 ) {
29 let len = h.len().min(l.len()).min(c.len()).min(v.len());
30 if len == 0 { return Ok(()); }
31 let mut high = Vec::with_capacity(len);
32 let mut low = Vec::with_capacity(len);
33 let mut close = Vec::with_capacity(len);
34 let mut volume = Vec::with_capacity(len);
35 for i in 0..len {
36 let v_h: f64 = h[i];
37 let v_l: f64 = l[i];
38 let v_c: f64 = c[i];
39 let v_v: f64 = v[i];
40 high.push(v_h.max(v_l).max(v_c));
41 low.push(v_h.min(v_l).min(v_c));
42 close.push(v_c);
43 volume.push(v_v);
44 }
45
46 let mut ad = AD::new();
47 let streaming_results: Vec<f64> = (0..len).map(|i| ad.next((high[i], low[i], close[i], volume[i]))).collect();
48 let batch_results = talib_rs::volume::ad(&high, &low, &close, &volume).unwrap_or_else(|_| vec![f64::NAN; len]);
49
50 for (s, b) in streaming_results.iter().zip(batch_results.iter()) {
51 if s.is_nan() {
52 assert!(b.is_nan());
53 } else {
54 approx::assert_relative_eq!(s, b, epsilon = 1e-6);
55 }
56 }
57 }
58
59 #[test]
60 fn test_obv_parity(
61 c in prop::collection::vec(10.0..100.0, 1..100),
62 v in prop::collection::vec(1.0..1000.0, 1..100)
63 ) {
64 let len = c.len().min(v.len());
65 if len == 0 { return Ok(()); }
66 let close = c[..len].to_vec();
67 let volume = v[..len].to_vec();
68
69 let mut obv = OBV::new();
70 let streaming_results: Vec<f64> = (0..len).map(|i| obv.next((close[i], volume[i]))).collect();
71 let batch_results = talib_rs::volume::obv(&close, &volume).unwrap_or_else(|_| vec![f64::NAN; len]);
72
73 for (s, b) in streaming_results.iter().zip(batch_results.iter()) {
74 if s.is_nan() {
75 assert!(b.is_nan());
76 } else {
77 approx::assert_relative_eq!(s, b, epsilon = 1e-6);
78 }
79 }
80 }
81 }
82}