quantwave_core/indicators/
overlap.rs1talib_1_in_1_out!(DEMA, talib_rs::overlap::dema, timeperiod: usize);
2impl From<usize> for DEMA {
3 fn from(p: usize) -> Self {
4 Self::new(p)
5 }
6}
7talib_1_in_1_out!(TRIMA, talib_rs::overlap::trima, timeperiod: usize);
8impl From<usize> for TRIMA {
9 fn from(p: usize) -> Self {
10 Self::new(p)
11 }
12}
13talib_1_in_1_out!(KAMA, talib_rs::overlap::kama, timeperiod: usize);
14impl From<usize> for KAMA {
15 fn from(p: usize) -> Self {
16 Self::new(p)
17 }
18}
19talib_1_in_1_out!(T3, talib_rs::overlap::t3, timeperiod: usize, v_factor: f64);
20talib_1_in_2_out!(MAMA, talib_rs::overlap::mama, fastlimit: f64, slowlimit: f64);
21talib_1_in_3_out!(BBANDS, talib_rs::overlap::bbands, timeperiod: usize, nbdevup: f64, nbdevdn: f64, matype: talib_rs::MaType);
22talib_2_in_1_out!(SAR, talib_rs::overlap::sar, acceleration: f64, maximum: f64);
23talib_2_in_1_out!(SAREXT, talib_rs::overlap::sar_ext, startvalue: f64, offsetonreverse: f64, accelerationinitlong: f64, accelerationlong: f64, accelerationmaxlong: f64, accelerationinitshort: f64, accelerationshort: f64, accelerationmaxshort: f64);
24talib_1_in_1_out!(MIDPOINT, talib_rs::overlap::midpoint, timeperiod: usize);
25impl From<usize> for MIDPOINT {
26 fn from(p: usize) -> Self {
27 Self::new(p)
28 }
29}
30talib_2_in_1_out!(MIDPRICE, talib_rs::overlap::midprice, timeperiod: usize);
31impl From<usize> for MIDPRICE {
32 fn from(p: usize) -> Self {
33 Self::new(p)
34 }
35}
36talib_2_in_1_out!(MAVP, talib_rs::overlap::mavp, minperiod: usize, maxperiod: usize, matype: talib_rs::MaType);
37talib_1_in_1_out!(HT_TRENDLINE, talib_rs::overlap::ht_trendline);
38impl Default for HT_TRENDLINE {
39 fn default() -> Self {
40 Self::new()
41 }
42}
43
44#[cfg(test)]
45mod tests {
46 use super::*;
47 use crate::traits::Next;
48 use proptest::prelude::*;
49
50 proptest! {
51 #[test]
52 fn test_dema_parity(input in prop::collection::vec(0.1..100.0, 1..100)) {
53 let period = 10;
54 let mut dema = DEMA::new(period);
55 let streaming_results: Vec<f64> = input.iter().map(|&x| dema.next(x)).collect();
56 let batch_results = talib_rs::overlap::dema(&input, period).unwrap_or_else(|_| vec![f64::NAN; input.len()]);
57
58 for (s, b) in streaming_results.iter().zip(batch_results.iter()) {
59 if s.is_nan() {
60 assert!(b.is_nan());
61 } else {
62 approx::assert_relative_eq!(s, b, epsilon = 1e-6);
63 }
64 }
65 }
66
67 #[test]
68 fn test_trima_parity(input in prop::collection::vec(0.1..100.0, 1..100)) {
69 let period = 10;
70 let mut trima = TRIMA::new(period);
71 let streaming_results: Vec<f64> = input.iter().map(|&x| trima.next(x)).collect();
72 let batch_results = talib_rs::overlap::trima(&input, period).unwrap_or_else(|_| vec![f64::NAN; input.len()]);
73
74 for (s, b) in streaming_results.iter().zip(batch_results.iter()) {
75 if s.is_nan() {
76 assert!(b.is_nan());
77 } else {
78 approx::assert_relative_eq!(s, b, epsilon = 1e-6);
79 }
80 }
81 }
82
83 #[test]
84 fn test_kama_parity(input in prop::collection::vec(0.1..100.0, 1..100)) {
85 let period = 10;
86 let mut kama = KAMA::new(period);
87 let streaming_results: Vec<f64> = input.iter().map(|&x| kama.next(x)).collect();
88 let batch_results = talib_rs::overlap::kama(&input, period).unwrap_or_else(|_| vec![f64::NAN; input.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_t3_parity(input in prop::collection::vec(0.1..100.0, 1..100)) {
101 let period = 10;
102 let v_factor = 0.7;
103 let mut t3 = T3::new(period, v_factor);
104 let streaming_results: Vec<f64> = input.iter().map(|&x| t3.next(x)).collect();
105 let batch_results = talib_rs::overlap::t3(&input, period, v_factor).unwrap_or_else(|_| vec![f64::NAN; input.len()]);
106
107 for (s, b) in streaming_results.iter().zip(batch_results.iter()) {
108 if s.is_nan() {
109 assert!(b.is_nan());
110 } else {
111 approx::assert_relative_eq!(s, b, epsilon = 1e-6);
112 }
113 }
114 }
115
116 #[test]
117 fn test_bbands_parity(input in prop::collection::vec(0.1..100.0, 1..100)) {
118 let period = 10;
119 let nbdevup = 2.0;
120 let nbdevdn = 2.0;
121 let matype = talib_rs::MaType::Sma;
122 let mut bbands = BBANDS::new(period, nbdevup, nbdevdn, matype);
123 let streaming_results: Vec<(f64, f64, f64)> = input.iter().map(|&x| bbands.next(x)).collect();
124 let (b_upper, b_middle, b_lower) = talib_rs::overlap::bbands(&input, period, nbdevup, nbdevdn, matype).unwrap_or_else(|_| {
125 (vec![f64::NAN; input.len()], vec![f64::NAN; input.len()], vec![f64::NAN; input.len()])
126 });
127
128 for (i, (s_upper, s_middle, s_lower)) in streaming_results.into_iter().enumerate() {
129 if s_upper.is_nan() {
130 assert!(b_upper[i].is_nan());
131 } else {
132 approx::assert_relative_eq!(s_upper, b_upper[i], epsilon = 1e-6);
133 }
134 if s_middle.is_nan() {
135 assert!(b_middle[i].is_nan());
136 } else {
137 approx::assert_relative_eq!(s_middle, b_middle[i], epsilon = 1e-6);
138 }
139 if s_lower.is_nan() {
140 assert!(b_lower[i].is_nan());
141 } else {
142 approx::assert_relative_eq!(s_lower, b_lower[i], epsilon = 1e-6);
143 }
144 }
145 }
146
147 #[test]
148 fn test_sar_parity(
149 h in prop::collection::vec(10.0..100.0, 1..100),
150 l in prop::collection::vec(10.0..100.0, 1..100)
151 ) {
152 let len = h.len().min(l.len());
153 if len == 0 { return Ok(()); }
154 let mut high = Vec::with_capacity(len);
155 let mut low = Vec::with_capacity(len);
156 for i in 0..len {
157 let v_h: f64 = h[i];
158 let v_l: f64 = l[i];
159 high.push(v_h.max(v_l));
160 low.push(v_h.min(v_l));
161 }
162
163 let accel = 0.02;
164 let max = 0.2;
165 let mut sar = SAR::new(accel, max);
166 let streaming_results: Vec<f64> = (0..len).map(|i| sar.next((high[i], low[i]))).collect();
167 let batch_results = talib_rs::overlap::sar(&high, &low, accel, max).unwrap_or_else(|_| vec![f64::NAN; len]);
168
169 for (s, b) in streaming_results.iter().zip(batch_results.iter()) {
170 if s.is_nan() {
171 assert!(b.is_nan());
172 } else {
173 approx::assert_relative_eq!(s, b, epsilon = 1e-6);
174 }
175 }
176 }
177 }
178}