quantwave_core/indicators/
price_transform.rs1use crate::traits::Next;
2
3talib_4_in_1_out!(AVGPRICE, talib_rs::price_transform::avgprice);
4impl Default for AVGPRICE {
5 fn default() -> Self {
6 Self::new()
7 }
8}
9talib_2_in_1_out!(MEDPRICE, talib_rs::price_transform::medprice);
10impl Default for MEDPRICE {
11 fn default() -> Self {
12 Self::new()
13 }
14}
15talib_3_in_1_out!(TYPPRICE, talib_rs::price_transform::typprice);
16impl Default for TYPPRICE {
17 fn default() -> Self {
18 Self::new()
19 }
20}
21talib_3_in_1_out!(WCLPRICE, talib_rs::price_transform::wclprice);
22impl Default for WCLPRICE {
23 fn default() -> Self {
24 Self::new()
25 }
26}
27
28#[derive(Debug, Clone, Default)]
33pub struct OC2;
34
35impl OC2 {
36 pub fn new() -> Self {
37 Self
38 }
39}
40
41impl Next<(f64, f64)> for OC2 {
42 type Output = f64;
43 fn next(&mut self, input: (f64, f64)) -> Self::Output {
44 (input.0 + input.1) / 2.0
45 }
46}
47
48#[cfg(test)]
49mod tests {
50 use super::*;
51 use crate::traits::Next;
52 use proptest::prelude::*;
53
54 proptest! {
55 #[test]
56 fn test_avgprice_parity(
57 o in prop::collection::vec(0.1..100.0, 1..100),
58 h in prop::collection::vec(0.1..100.0, 1..100),
59 l in prop::collection::vec(0.1..100.0, 1..100),
60 c in prop::collection::vec(0.1..100.0, 1..100)
61 ) {
62 let len = o.len().min(h.len()).min(l.len()).min(c.len());
63 if len == 0 { return Ok(()); }
64
65 let mut avgprice = AVGPRICE::new();
66 let streaming_results: Vec<f64> = (0..len).map(|i| avgprice.next((o[i], h[i], l[i], c[i]))).collect();
67 let batch_results = talib_rs::price_transform::avgprice(&o[..len], &h[..len], &l[..len], &c[..len]).unwrap_or_else(|_| vec![f64::NAN; len]);
68
69 for (s, b) in streaming_results.iter().zip(batch_results.iter()) {
70 if s.is_nan() {
71 assert!(b.is_nan());
72 } else {
73 approx::assert_relative_eq!(s, b, epsilon = 1e-6);
74 }
75 }
76 }
77
78 #[test]
79 fn test_medprice_parity(
80 h in prop::collection::vec(0.1..100.0, 1..100),
81 l in prop::collection::vec(0.1..100.0, 1..100)
82 ) {
83 let len = h.len().min(l.len());
84 if len == 0 { return Ok(()); }
85
86 let mut medprice = MEDPRICE::new();
87 let streaming_results: Vec<f64> = (0..len).map(|i| medprice.next((h[i], l[i]))).collect();
88 let batch_results = talib_rs::price_transform::medprice(&h[..len], &l[..len]).unwrap_or_else(|_| vec![f64::NAN; len]);
89
90 for (s, b) in streaming_results.iter().zip(batch_results.iter()) {
91 if s.is_nan() {
92 assert!(b.is_nan());
93 } else {
94 approx::assert_relative_eq!(s, b, epsilon = 1e-6);
95 }
96 }
97 }
98
99 #[test]
100 fn test_oc2_parity(
101 o in prop::collection::vec(0.1..100.0, 1..100),
102 c in prop::collection::vec(0.1..100.0, 1..100)
103 ) {
104 let len = o.len().min(c.len());
105 if len == 0 { return Ok(()); }
106
107 let mut oc2 = OC2::new();
108 let streaming_results: Vec<f64> = (0..len).map(|i| oc2.next((o[i], c[i]))).collect();
109 let batch_results: Vec<f64> = (0..len).map(|i| (o[i] + c[i]) / 2.0).collect();
110
111 for (s, b) in streaming_results.iter().zip(batch_results.iter()) {
112 approx::assert_relative_eq!(s, b, epsilon = 1e-10);
113 }
114 }
115 }
116}