Skip to main content

quantwave_core/indicators/
talib_wrapper.rs

1/// O(1) unary pointwise transform — no history buffer.
2#[macro_export]
3macro_rules! native_pointwise_1 {
4    ($name:ident, $op:expr) => {
5        #[derive(Debug, Clone, Default)]
6        #[allow(non_camel_case_types)]
7        pub struct $name;
8
9        impl $name {
10            pub fn new() -> Self {
11                Self
12            }
13        }
14
15        impl $crate::traits::Next<f64> for $name {
16            type Output = f64;
17
18            fn next(&mut self, input: f64) -> Self::Output {
19                ($op)(input)
20            }
21
22            fn next_batch(&mut self, inputs: &[f64]) -> Vec<Self::Output>
23            where
24                f64: Copy,
25            {
26                inputs.iter().map(|&x| ($op)(x)).collect()
27            }
28        }
29    };
30}
31
32/// O(1) binary element-wise operator.
33#[macro_export]
34macro_rules! native_binary_2 {
35    ($name:ident, $op:expr) => {
36        #[derive(Debug, Clone, Default)]
37        #[allow(non_camel_case_types)]
38        pub struct $name;
39
40        impl $name {
41            pub fn new() -> Self {
42                Self
43            }
44        }
45
46        impl $crate::traits::Next<(f64, f64)> for $name {
47            type Output = f64;
48
49            fn next(&mut self, (a, b): (f64, f64)) -> Self::Output {
50                ($op)(a, b)
51            }
52
53            fn next_batch(&mut self, inputs: &[(f64, f64)]) -> Vec<Self::Output>
54            where
55                (f64, f64): Copy,
56            {
57                inputs.iter().map(|&(a, b)| ($op)(a, b)).collect()
58            }
59        }
60    };
61}
62
63/// O(1) CDL streaming: bounded OHLC window + single talib batch per bar.
64#[macro_export]
65macro_rules! native_cdl {
66    ($name:ident, $talib_func:path) => {
67        #[derive(Debug, Clone)]
68        #[allow(non_camel_case_types)]
69        pub struct $name {
70            open: Vec<f64>,
71            high: Vec<f64>,
72            low: Vec<f64>,
73            close: Vec<f64>,
74        }
75
76        impl $name {
77            const MAX_WINDOW: usize = 32;
78
79            pub fn new() -> Self {
80                Self {
81                    open: Vec::with_capacity(Self::MAX_WINDOW),
82                    high: Vec::with_capacity(Self::MAX_WINDOW),
83                    low: Vec::with_capacity(Self::MAX_WINDOW),
84                    close: Vec::with_capacity(Self::MAX_WINDOW),
85                }
86            }
87
88            #[inline]
89            fn trim_window(o: &mut Vec<f64>, h: &mut Vec<f64>, l: &mut Vec<f64>, c: &mut Vec<f64>) {
90                let max = Self::MAX_WINDOW;
91                if o.len() > max {
92                    let drop = o.len() - max;
93                    o.drain(0..drop);
94                    h.drain(0..drop);
95                    l.drain(0..drop);
96                    c.drain(0..drop);
97                }
98            }
99
100            #[inline]
101            fn last_signal(o: &[f64], h: &[f64], l: &[f64], c: &[f64]) -> f64 {
102                $talib_func(o, h, l, c)
103                    .ok()
104                    .and_then(|res| res.last().copied())
105                    .unwrap_or(0) as f64
106            }
107        }
108
109        impl $crate::traits::Next<(f64, f64, f64, f64)> for $name {
110            type Output = f64;
111
112            fn next(&mut self, (open, high, low, close): (f64, f64, f64, f64)) -> Self::Output {
113                self.open.push(open);
114                self.high.push(high);
115                self.low.push(low);
116                self.close.push(close);
117                Self::trim_window(
118                    &mut self.open,
119                    &mut self.high,
120                    &mut self.low,
121                    &mut self.close,
122                );
123                Self::last_signal(&self.open, &self.high, &self.low, &self.close)
124            }
125
126            fn next_batch(&mut self, inputs: &[(f64, f64, f64, f64)]) -> Vec<Self::Output>
127            where
128                (f64, f64, f64, f64): Copy,
129            {
130                self.open.clear();
131                self.high.clear();
132                self.low.clear();
133                self.close.clear();
134                for &(o, h, l, c) in inputs {
135                    self.open.push(o);
136                    self.high.push(h);
137                    self.low.push(l);
138                    self.close.push(c);
139                }
140                $talib_func(&self.open, &self.high, &self.low, &self.close)
141                    .unwrap_or_default()
142                    .into_iter()
143                    .map(|v| v as f64)
144                    .collect()
145            }
146        }
147    };
148}
149
150#[macro_export]
151macro_rules! talib_cdl {
152    ($name:ident, $talib_func:path) => {
153        #[derive(Debug, Clone)]
154        #[allow(non_camel_case_types)]
155        pub struct $name {
156            history_open: Vec<f64>,
157            history_high: Vec<f64>,
158            history_low: Vec<f64>,
159            history_close: Vec<f64>,
160        }
161
162        impl $name {
163            pub fn new() -> Self {
164                Self {
165                    history_open: Vec::new(),
166                    history_high: Vec::new(),
167                    history_low: Vec::new(),
168                    history_close: Vec::new(),
169                }
170            }
171        }
172
173        impl $crate::traits::Next<(f64, f64, f64, f64)> for $name {
174            type Output = f64;
175
176            fn next(&mut self, (open, high, low, close): (f64, f64, f64, f64)) -> Self::Output {
177                self.history_open.push(open);
178                self.history_high.push(high);
179                self.history_low.push(low);
180                self.history_close.push(close);
181                if let Ok(res) = $talib_func(
182                    &self.history_open,
183                    &self.history_high,
184                    &self.history_low,
185                    &self.history_close,
186                ) {
187                    *res.last().unwrap_or(&0) as f64
188                } else {
189                    0.0
190                }
191            }
192
193            fn next_batch(&mut self, inputs: &[(f64, f64, f64, f64)]) -> Vec<Self::Output>
194            where
195                (f64, f64, f64, f64): Copy,
196            {
197                self.history_open.clear();
198                self.history_high.clear();
199                self.history_low.clear();
200                self.history_close.clear();
201                for &(o, h, l, c) in inputs {
202                    self.history_open.push(o);
203                    self.history_high.push(h);
204                    self.history_low.push(l);
205                    self.history_close.push(c);
206                }
207                $talib_func(
208                    &self.history_open,
209                    &self.history_high,
210                    &self.history_low,
211                    &self.history_close,
212                )
213                .unwrap_or_default()
214                .into_iter()
215                .map(|v| v as f64)
216                .collect()
217            }
218        }
219    };
220}
221
222#[macro_export]
223macro_rules! talib_1_in_1_out_i32 {
224    ($name:ident, $talib_func:path $(, $param:ident: $ptype:ty)*) => {
225        #[derive(Debug, Clone)]
226        #[allow(non_camel_case_types)]
227        pub struct $name {
228            $( pub $param: $ptype, )*
229            history: Vec<f64>,
230        }
231
232        impl $name {
233            pub fn new($( $param: $ptype ),*) -> Self {
234                Self {
235                    $( $param, )*
236                    history: Vec::new(),
237                }
238            }
239        }
240
241        impl $crate::traits::Next<f64> for $name {
242            type Output = f64;
243
244            fn next(&mut self, input: f64) -> Self::Output {
245                self.history.push(input);
246                if let Ok(res) = $talib_func(&self.history, $( self.$param.clone() ),*) {
247                    *res.last().unwrap_or(&0) as f64
248                } else {
249                    0.0
250                }
251            }
252        }
253    };
254}
255
256#[macro_export]
257macro_rules! talib_1_in_1_out_no_result {
258    ($name:ident, $talib_func:path) => {
259        #[derive(Debug, Clone)]
260        #[allow(non_camel_case_types)]
261        pub struct $name {
262            history: Vec<f64>,
263        }
264
265        impl $name {
266            pub fn new() -> Self {
267                Self {
268                    history: Vec::new(),
269                }
270            }
271        }
272
273        impl $crate::traits::Next<f64> for $name {
274            type Output = f64;
275
276            fn next(&mut self, input: f64) -> Self::Output {
277                self.history.push(input);
278                let res = $talib_func(&self.history);
279                *res.last().unwrap_or(&f64::NAN)
280            }
281        }
282    };
283}
284
285#[macro_export]
286macro_rules! talib_1_in_1_out {
287    ($name:ident, $talib_func:path $(, $param:ident: $ptype:ty)*) => {
288        #[derive(Debug, Clone)]
289        #[allow(non_camel_case_types)]
290        pub struct $name {
291            $( pub $param: $ptype, )*
292            history: Vec<f64>,
293        }
294
295        impl $name {
296            pub fn new($( $param: $ptype ),*) -> Self {
297                Self {
298                    $( $param, )*
299                    history: Vec::new(),
300                }
301            }
302        }
303
304        impl $crate::traits::Next<f64> for $name {
305            type Output = f64;
306
307            fn next(&mut self, input: f64) -> Self::Output {
308                self.history.push(input);
309                let res = $talib_func(&self.history, $( self.$param.clone() ),*).unwrap_or_default();
310                *res.last().unwrap_or(&f64::NAN)
311            }
312
313            fn next_batch(&mut self, inputs: &[f64]) -> Vec<Self::Output>
314            where
315                f64: Copy,
316            {
317                self.history.clear();
318                self.history.extend_from_slice(inputs);
319                $talib_func(&self.history, $( self.$param.clone() ),*).unwrap_or_default()
320            }
321        }
322    };
323}
324
325#[macro_export]
326macro_rules! talib_2_in_1_out {
327    ($name:ident, $talib_func:path $(, $param:ident: $ptype:ty)*) => {
328        #[derive(Debug, Clone)]
329        #[allow(non_camel_case_types)]
330        pub struct $name {
331            $( pub $param: $ptype, )*
332            history_high: Vec<f64>,
333            history_low: Vec<f64>,
334        }
335
336        impl $name {
337            #[allow(clippy::too_many_arguments)]
338            pub fn new($( $param: $ptype ),*) -> Self {
339                Self {
340                    $( $param, )*
341                    history_high: Vec::new(),
342                    history_low: Vec::new(),
343                }
344            }
345        }
346
347        impl $crate::traits::Next<(f64, f64)> for $name {
348            type Output = f64;
349
350            fn next(&mut self, (high, low): (f64, f64)) -> Self::Output {
351                self.history_high.push(high);
352                self.history_low.push(low);
353                let res = $talib_func(&self.history_high, &self.history_low, $( self.$param.clone() ),*).unwrap_or_default();
354                *res.last().unwrap_or(&f64::NAN)
355            }
356
357            fn next_batch(&mut self, inputs: &[(f64, f64)]) -> Vec<Self::Output>
358            where
359                (f64, f64): Copy,
360            {
361                self.history_high.clear();
362                self.history_low.clear();
363                for &(h, l) in inputs {
364                    self.history_high.push(h);
365                    self.history_low.push(l);
366                }
367                $talib_func(&self.history_high, &self.history_low, $( self.$param.clone() ),*).unwrap_or_default()
368            }
369        }
370    };
371}
372
373#[macro_export]
374macro_rules! talib_1_in_2_out {
375    ($name:ident, $talib_func:path $(, $param:ident: $ptype:ty)*) => {
376        #[derive(Debug, Clone)]
377        #[allow(non_camel_case_types)]
378        pub struct $name {
379            $( pub $param: $ptype, )*
380            history: Vec<f64>,
381        }
382
383        impl $name {
384            pub fn new($( $param: $ptype ),*) -> Self {
385                Self {
386                    $( $param, )*
387                    history: Vec::new(),
388                }
389            }
390        }
391
392        impl $crate::traits::Next<f64> for $name {
393            type Output = (f64, f64);
394
395            fn next(&mut self, input: f64) -> Self::Output {
396                self.history.push(input);
397                if let Ok((res1, res2)) = $talib_func(&self.history, $( self.$param.clone() ),*) {
398                    (*res1.last().unwrap_or(&f64::NAN), *res2.last().unwrap_or(&f64::NAN))
399                } else {
400                    (f64::NAN, f64::NAN)
401                }
402            }
403
404            fn next_batch(&mut self, inputs: &[f64]) -> Vec<Self::Output>
405            where
406                f64: Copy,
407            {
408                self.history.clear();
409                self.history.extend_from_slice(inputs);
410                if let Ok((r1, r2)) = $talib_func(&self.history, $( self.$param.clone() ),*) {
411                    r1.into_iter().zip(r2).map(|(a, b)| (a, b)).collect()
412                } else {
413                    vec![(f64::NAN, f64::NAN); inputs.len()]
414                }
415            }
416        }
417    };
418}
419
420#[macro_export]
421macro_rules! talib_1_in_3_out {
422    ($name:ident, $talib_func:path $(, $param:ident: $ptype:ty)*) => {
423        #[derive(Debug, Clone)]
424        #[allow(non_camel_case_types)]
425        pub struct $name {
426            $( pub $param: $ptype, )*
427            history: Vec<f64>,
428        }
429
430        impl $name {
431            pub fn new($( $param: $ptype ),*) -> Self {
432                Self {
433                    $( $param, )*
434                    history: Vec::new(),
435                }
436            }
437        }
438
439        impl $crate::traits::Next<f64> for $name {
440            type Output = (f64, f64, f64);
441
442            fn next(&mut self, input: f64) -> Self::Output {
443                self.history.push(input);
444                if let Ok((res1, res2, res3)) = $talib_func(&self.history, $( self.$param.clone() ),*) {
445                    (*res1.last().unwrap_or(&f64::NAN), *res2.last().unwrap_or(&f64::NAN), *res3.last().unwrap_or(&f64::NAN))
446                } else {
447                    (f64::NAN, f64::NAN, f64::NAN)
448                }
449            }
450
451            fn next_batch(&mut self, inputs: &[f64]) -> Vec<Self::Output>
452            where
453                f64: Copy,
454            {
455                self.history.clear();
456                self.history.extend_from_slice(inputs);
457                if let Ok((r1, r2, r3)) = $talib_func(&self.history, $( self.$param.clone() ),*) {
458                    r1.into_iter()
459                        .zip(r2)
460                        .zip(r3)
461                        .map(|((a, b), c)| (a, b, c))
462                        .collect()
463                } else {
464                    vec![(f64::NAN, f64::NAN, f64::NAN); inputs.len()]
465                }
466            }
467        }
468    };
469}
470
471#[macro_export]
472macro_rules! talib_2_in_2_out {
473    ($name:ident, $talib_func:path $(, $param:ident: $ptype:ty)*) => {
474        #[derive(Debug, Clone)]
475        #[allow(non_camel_case_types)]
476        pub struct $name {
477            $( pub $param: $ptype, )*
478            history_1: Vec<f64>,
479            history_2: Vec<f64>,
480        }
481
482        impl $name {
483            pub fn new($( $param: $ptype ),*) -> Self {
484                Self {
485                    $( $param, )*
486                    history_1: Vec::new(),
487                    history_2: Vec::new(),
488                }
489            }
490        }
491
492        impl $crate::traits::Next<(f64, f64)> for $name {
493            type Output = (f64, f64);
494
495            fn next(&mut self, (in1, in2): (f64, f64)) -> Self::Output {
496                self.history_1.push(in1);
497                self.history_2.push(in2);
498                if let Ok((res1, res2)) = $talib_func(&self.history_1, &self.history_2, $( self.$param.clone() ),*) {
499                    (*res1.last().unwrap_or(&f64::NAN), *res2.last().unwrap_or(&f64::NAN))
500                } else {
501                    (f64::NAN, f64::NAN)
502                }
503            }
504
505            fn next_batch(&mut self, inputs: &[(f64, f64)]) -> Vec<Self::Output>
506            where
507                (f64, f64): Copy,
508            {
509                self.history_1.clear();
510                self.history_2.clear();
511                for &(a, b) in inputs {
512                    self.history_1.push(a);
513                    self.history_2.push(b);
514                }
515                if let Ok((r1, r2)) = $talib_func(&self.history_1, &self.history_2, $( self.$param.clone() ),*) {
516                    r1.into_iter().zip(r2).map(|(x, y)| (x, y)).collect()
517                } else {
518                    vec![(f64::NAN, f64::NAN); inputs.len()]
519                }
520            }
521        }
522    };
523}
524
525#[macro_export]
526macro_rules! talib_3_in_1_out {
527    ($name:ident, $talib_func:path $(, $param:ident: $ptype:ty)*) => {
528        #[derive(Debug, Clone)]
529        #[allow(non_camel_case_types)]
530        pub struct $name {
531            $( pub $param: $ptype, )*
532            history_high: Vec<f64>,
533            history_low: Vec<f64>,
534            history_close: Vec<f64>,
535        }
536
537        impl $name {
538            pub fn new($( $param: $ptype ),*) -> Self {
539                Self {
540                    $( $param, )*
541                    history_high: Vec::new(),
542                    history_low: Vec::new(),
543                    history_close: Vec::new(),
544                }
545            }
546        }
547
548        impl $crate::traits::Next<(f64, f64, f64)> for $name {
549            type Output = f64;
550
551            fn next(&mut self, (high, low, close): (f64, f64, f64)) -> Self::Output {
552                self.history_high.push(high);
553                self.history_low.push(low);
554                self.history_close.push(close);
555                let res = $talib_func(&self.history_high, &self.history_low, &self.history_close, $( self.$param.clone() ),*).unwrap_or_default();
556                *res.last().unwrap_or(&f64::NAN)
557            }
558
559            fn next_batch(&mut self, inputs: &[(f64, f64, f64)]) -> Vec<Self::Output>
560            where
561                (f64, f64, f64): Copy,
562            {
563                self.history_high.clear();
564                self.history_low.clear();
565                self.history_close.clear();
566                for &(h, l, c) in inputs {
567                    self.history_high.push(h);
568                    self.history_low.push(l);
569                    self.history_close.push(c);
570                }
571                $talib_func(
572                    &self.history_high,
573                    &self.history_low,
574                    &self.history_close,
575                    $( self.$param.clone() ),*
576                )
577                .unwrap_or_default()
578            }
579        }
580    };
581}
582
583#[macro_export]
584macro_rules! talib_3_in_2_out {
585    ($name:ident, $talib_func:path $(, $param:ident: $ptype:ty)*) => {
586        #[derive(Debug, Clone)]
587        #[allow(non_camel_case_types)]
588        pub struct $name {
589            $( pub $param: $ptype, )*
590            history_high: Vec<f64>,
591            history_low: Vec<f64>,
592            history_close: Vec<f64>,
593        }
594
595        impl $name {
596            pub fn new($( $param: $ptype ),*) -> Self {
597                Self {
598                    $( $param, )*
599                    history_high: Vec::new(),
600                    history_low: Vec::new(),
601                    history_close: Vec::new(),
602                }
603            }
604        }
605
606        impl $crate::traits::Next<(f64, f64, f64)> for $name {
607            type Output = (f64, f64);
608
609            fn next(&mut self, (high, low, close): (f64, f64, f64)) -> Self::Output {
610                self.history_high.push(high);
611                self.history_low.push(low);
612                self.history_close.push(close);
613                if let Ok((res1, res2)) = $talib_func(&self.history_high, &self.history_low, &self.history_close, $( self.$param.clone() ),*) {
614                    (*res1.last().unwrap_or(&f64::NAN), *res2.last().unwrap_or(&f64::NAN))
615                } else {
616                    (f64::NAN, f64::NAN)
617                }
618            }
619
620            fn next_batch(&mut self, inputs: &[(f64, f64, f64)]) -> Vec<Self::Output>
621            where
622                (f64, f64, f64): Copy,
623            {
624                self.history_high.clear();
625                self.history_low.clear();
626                self.history_close.clear();
627                for &(h, l, c) in inputs {
628                    self.history_high.push(h);
629                    self.history_low.push(l);
630                    self.history_close.push(c);
631                }
632                if let Ok((r1, r2)) = $talib_func(
633                    &self.history_high,
634                    &self.history_low,
635                    &self.history_close,
636                    $( self.$param.clone() ),*
637                ) {
638                    r1.into_iter().zip(r2).map(|(a, b)| (a, b)).collect()
639                } else {
640                    vec![(f64::NAN, f64::NAN); inputs.len()]
641                }
642            }
643        }
644    };
645}
646
647#[macro_export]
648macro_rules! talib_4_in_1_out {
649    ($name:ident, $talib_func:path $(, $param:ident: $ptype:ty)*) => {
650        #[derive(Debug, Clone)]
651        #[allow(non_camel_case_types)]
652        pub struct $name {
653            $( pub $param: $ptype, )*
654            history_1: Vec<f64>,
655            history_2: Vec<f64>,
656            history_3: Vec<f64>,
657            history_4: Vec<f64>,
658        }
659
660        impl $name {
661            pub fn new($( $param: $ptype ),*) -> Self {
662                Self {
663                    $( $param, )*
664                    history_1: Vec::new(),
665                    history_2: Vec::new(),
666                    history_3: Vec::new(),
667                    history_4: Vec::new(),
668                }
669            }
670        }
671
672        impl $crate::traits::Next<(f64, f64, f64, f64)> for $name {
673            type Output = f64;
674
675            fn next(&mut self, (in1, in2, in3, in4): (f64, f64, f64, f64)) -> Self::Output {
676                self.history_1.push(in1);
677                self.history_2.push(in2);
678                self.history_3.push(in3);
679                self.history_4.push(in4);
680                let res = $talib_func(&self.history_1, &self.history_2, &self.history_3, &self.history_4, $( self.$param.clone() ),*).unwrap_or_default();
681                *res.last().unwrap_or(&f64::NAN)
682            }
683
684            fn next_batch(&mut self, inputs: &[(f64, f64, f64, f64)]) -> Vec<Self::Output>
685            where
686                (f64, f64, f64, f64): Copy,
687            {
688                self.history_1.clear();
689                self.history_2.clear();
690                self.history_3.clear();
691                self.history_4.clear();
692                for &(a, b, c, d) in inputs {
693                    self.history_1.push(a);
694                    self.history_2.push(b);
695                    self.history_3.push(c);
696                    self.history_4.push(d);
697                }
698                $talib_func(
699                    &self.history_1,
700                    &self.history_2,
701                    &self.history_3,
702                    &self.history_4,
703                    $( self.$param.clone() ),*
704                )
705                .unwrap_or_default()
706            }
707        }
708    };
709}