quantwave_core/indicators/
math.rs1talib_1_in_1_out_no_result!(ACOS, talib_rs::math_transform::acos);
3impl Default for ACOS {
4 fn default() -> Self {
5 Self::new()
6 }
7}
8talib_1_in_1_out_no_result!(ASIN, talib_rs::math_transform::asin);
9impl Default for ASIN {
10 fn default() -> Self {
11 Self::new()
12 }
13}
14talib_1_in_1_out_no_result!(ATAN, talib_rs::math_transform::atan);
15impl Default for ATAN {
16 fn default() -> Self {
17 Self::new()
18 }
19}
20talib_1_in_1_out_no_result!(CEIL, talib_rs::math_transform::ceil);
21impl Default for CEIL {
22 fn default() -> Self {
23 Self::new()
24 }
25}
26talib_1_in_1_out_no_result!(COS, talib_rs::math_transform::cos);
27impl Default for COS {
28 fn default() -> Self {
29 Self::new()
30 }
31}
32talib_1_in_1_out_no_result!(COSH, talib_rs::math_transform::cosh);
33impl Default for COSH {
34 fn default() -> Self {
35 Self::new()
36 }
37}
38talib_1_in_1_out_no_result!(EXP, talib_rs::math_transform::exp);
39impl Default for EXP {
40 fn default() -> Self {
41 Self::new()
42 }
43}
44talib_1_in_1_out_no_result!(FLOOR, talib_rs::math_transform::floor);
45impl Default for FLOOR {
46 fn default() -> Self {
47 Self::new()
48 }
49}
50talib_1_in_1_out_no_result!(LN, talib_rs::math_transform::ln);
51impl Default for LN {
52 fn default() -> Self {
53 Self::new()
54 }
55}
56talib_1_in_1_out_no_result!(LOG10, talib_rs::math_transform::log10);
57impl Default for LOG10 {
58 fn default() -> Self {
59 Self::new()
60 }
61}
62talib_1_in_1_out_no_result!(SIN, talib_rs::math_transform::sin);
63impl Default for SIN {
64 fn default() -> Self {
65 Self::new()
66 }
67}
68talib_1_in_1_out_no_result!(SINH, talib_rs::math_transform::sinh);
69impl Default for SINH {
70 fn default() -> Self {
71 Self::new()
72 }
73}
74talib_1_in_1_out_no_result!(SQRT, talib_rs::math_transform::sqrt);
75impl Default for SQRT {
76 fn default() -> Self {
77 Self::new()
78 }
79}
80talib_1_in_1_out_no_result!(TAN, talib_rs::math_transform::tan);
81impl Default for TAN {
82 fn default() -> Self {
83 Self::new()
84 }
85}
86talib_1_in_1_out_no_result!(TANH, talib_rs::math_transform::tanh);
87impl Default for TANH {
88 fn default() -> Self {
89 Self::new()
90 }
91}
92
93#[derive(Debug, Clone)]
95pub struct RMS {
96 period: usize,
97 history: std::collections::VecDeque<f64>,
98 sum_sq: f64,
99}
100
101impl RMS {
102 pub fn new(period: usize) -> Self {
103 Self {
104 period,
105 history: std::collections::VecDeque::with_capacity(period),
106 sum_sq: 0.0,
107 }
108 }
109}
110
111impl crate::traits::Next<f64> for RMS {
112 type Output = f64;
113
114 fn next(&mut self, input: f64) -> Self::Output {
115 let input_sq = input * input;
116 self.sum_sq += input_sq;
117 self.history.push_back(input_sq);
118
119 if self.history.len() > self.period {
120 if let Some(old) = self.history.pop_front() {
121 self.sum_sq -= old;
122 }
123 }
124
125 if self.history.is_empty() {
126 0.0
127 } else {
128 (self.sum_sq / self.history.len() as f64).sqrt()
129 }
130 }
131}
132
133talib_2_in_1_out!(ADD, talib_rs::math_operator::add);
135impl Default for ADD {
136 fn default() -> Self {
137 Self::new()
138 }
139}
140talib_2_in_1_out!(SUB, talib_rs::math_operator::sub);
141impl Default for SUB {
142 fn default() -> Self {
143 Self::new()
144 }
145}
146talib_2_in_1_out!(MULT, talib_rs::math_operator::mult);
147impl Default for MULT {
148 fn default() -> Self {
149 Self::new()
150 }
151}
152talib_2_in_1_out!(DIV, talib_rs::math_operator::div);
153impl Default for DIV {
154 fn default() -> Self {
155 Self::new()
156 }
157}
158talib_1_in_1_out!(MAX, talib_rs::math_operator::max, timeperiod: usize);
159impl From<usize> for MAX {
160 fn from(p: usize) -> Self {
161 Self::new(p)
162 }
163}
164
165talib_1_in_1_out!(MAXINDEX, talib_rs::math_operator::maxindex, timeperiod: usize);
166impl From<usize> for MAXINDEX {
167 fn from(p: usize) -> Self {
168 Self::new(p)
169 }
170}
171
172talib_1_in_1_out!(MIN, talib_rs::math_operator::min, timeperiod: usize);
173impl From<usize> for MIN {
174 fn from(p: usize) -> Self {
175 Self::new(p)
176 }
177}
178
179talib_1_in_1_out!(MININDEX, talib_rs::math_operator::minindex, timeperiod: usize);
180impl From<usize> for MININDEX {
181 fn from(p: usize) -> Self {
182 Self::new(p)
183 }
184}
185
186talib_1_in_1_out!(SUM, talib_rs::math_operator::sum, timeperiod: usize);
187impl From<usize> for SUM {
188 fn from(p: usize) -> Self {
189 Self::new(p)
190 }
191}
192
193#[cfg(test)]
194mod tests {
195 use super::*;
196 use crate::traits::Next;
197 use proptest::prelude::*;
198
199 proptest! {
200 #[test]
201 fn test_sqrt_parity(input in prop::collection::vec(0.1..100.0, 1..100)) {
202 let mut sqrt = SQRT::new();
203 let streaming_results: Vec<f64> = input.iter().map(|&x| sqrt.next(x)).collect();
204 let batch_results = talib_rs::math_transform::sqrt(&input);
205
206 for (s, b) in streaming_results.iter().zip(batch_results.iter()) {
207 if s.is_nan() {
208 assert!(b.is_nan());
209 } else {
210 approx::assert_relative_eq!(s, b, epsilon = 1e-6);
211 }
212 }
213 }
214
215 #[test]
216 fn test_add_parity(
217 in1 in prop::collection::vec(0.1..100.0, 1..100),
218 in2 in prop::collection::vec(0.1..100.0, 1..100)
219 ) {
220 let len = in1.len().min(in2.len());
221 if len == 0 { return Ok(()); }
222
223 let mut add = ADD::new();
224 let streaming_results: Vec<f64> = (0..len).map(|i| add.next((in1[i], in2[i]))).collect();
225 let batch_results = talib_rs::math_operator::add(&in1[..len], &in2[..len]).unwrap_or_else(|_| vec![f64::NAN; len]);
226
227 for (s, b) in streaming_results.iter().zip(batch_results.iter()) {
228 if s.is_nan() {
229 assert!(b.is_nan());
230 } else {
231 approx::assert_relative_eq!(s, b, epsilon = 1e-6);
232 }
233 }
234 }
235
236 #[test]
237 fn test_rms_parity(input in prop::collection::vec(0.1..100.0, 10..100)) {
238 let period = 10;
239 let mut rms = RMS::new(period);
240 let streaming_results: Vec<f64> = input.iter().map(|&x| rms.next(x)).collect();
241
242 let mut batch_results = Vec::with_capacity(input.len());
243 for i in 0..input.len() {
244 let start = if i + 1 > period { i + 1 - period } else { 0 };
245 let window = &input[start..i+1];
246 let sum_sq: f64 = window.iter().map(|&x| x*x).sum();
247 batch_results.push((sum_sq / window.len() as f64).sqrt());
248 }
249
250 for (s, b) in streaming_results.iter().zip(batch_results.iter()) {
251 approx::assert_relative_eq!(s, b, epsilon = 1e-10);
252 }
253 }
254 }
255}