Skip to main content

quantwave_core/indicators/
talib_wrapper.rs

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