vector_ta/indicators/moving_averages/
ma_stream.rs

1use crate::indicators::alma::{AlmaParams, AlmaStream};
2use crate::indicators::cwma::{CwmaParams, CwmaStream};
3use crate::indicators::dema::{DemaParams, DemaStream};
4use crate::indicators::edcf::{EdcfParams, EdcfStream};
5use crate::indicators::ehlers_itrend::{EhlersITrendParams, EhlersITrendStream};
6use crate::indicators::ema::{EmaParams, EmaStream};
7use crate::indicators::epma::{EpmaParams, EpmaStream};
8use crate::indicators::frama::{FramaParams, FramaStream};
9use crate::indicators::fwma::{FwmaParams, FwmaStream};
10use crate::indicators::gaussian::{GaussianParams, GaussianStream};
11use crate::indicators::highpass::{HighPassParams, HighPassStream};
12use crate::indicators::highpass_2_pole::{HighPass2Params, HighPass2Stream};
13use crate::indicators::hma::{HmaParams, HmaStream};
14use crate::indicators::hwma::{HwmaParams, HwmaStream};
15use crate::indicators::jma::{JmaParams, JmaStream};
16use crate::indicators::jsa::{JsaParams, JsaStream};
17use crate::indicators::kama::{KamaParams, KamaStream};
18use crate::indicators::linreg::{LinRegParams, LinRegStream};
19use crate::indicators::maaq::{MaaqParams, MaaqStream};
20use crate::indicators::mama::{MamaParams, MamaStream};
21use crate::indicators::moving_averages::dma::{DmaParams, DmaStream};
22use crate::indicators::moving_averages::ehlers_ecema::{EhlersEcemaParams, EhlersEcemaStream};
23use crate::indicators::moving_averages::ehlers_kama::{EhlersKamaParams, EhlersKamaStream};
24use crate::indicators::moving_averages::ehma::{EhmaParams, EhmaStream};
25use crate::indicators::moving_averages::nama::{NamaParams, NamaStream};
26use crate::indicators::moving_averages::sama::{SamaParams, SamaStream};
27use crate::indicators::moving_averages::volatility_adjusted_ma::{VamaParams, VamaStream};
28use crate::indicators::mwdx::{MwdxParams, MwdxStream};
29use crate::indicators::nma::{NmaParams, NmaStream};
30use crate::indicators::pwma::{PwmaParams, PwmaStream};
31use crate::indicators::reflex::{ReflexParams, ReflexStream};
32use crate::indicators::sinwma::{SinWmaParams, SinWmaStream};
33use crate::indicators::sma::{SmaParams, SmaStream};
34use crate::indicators::smma::{SmmaParams, SmmaStream};
35use crate::indicators::sqwma::{SqwmaParams, SqwmaStream};
36use crate::indicators::srwma::{SrwmaParams, SrwmaStream};
37use crate::indicators::supersmoother::{SuperSmootherParams, SuperSmootherStream};
38use crate::indicators::supersmoother_3_pole::{SuperSmoother3PoleParams, SuperSmoother3PoleStream};
39use crate::indicators::swma::{SwmaParams, SwmaStream};
40use crate::indicators::tema::{TemaParams, TemaStream};
41use crate::indicators::tilson::{TilsonParams, TilsonStream};
42use crate::indicators::trendflex::{TrendFlexParams, TrendFlexStream};
43use crate::indicators::trima::{TrimaParams, TrimaStream};
44use crate::indicators::vpwma::{VpwmaParams, VpwmaStream};
45use crate::indicators::vwap::{VwapParams, VwapStream};
46use crate::indicators::vwma::{VwmaParams, VwmaStream};
47use crate::indicators::wilders::{WildersParams, WildersStream};
48use crate::indicators::wma::{WmaParams, WmaStream};
49use crate::indicators::zlema::{ZlemaParams, ZlemaStream};
50
51use std::error::Error;
52
53#[derive(Debug, Clone)]
54pub enum MaStream {
55    Sma(SmaStream),
56    Ema(EmaStream),
57    Dema(DemaStream),
58    Tema(TemaStream),
59    Smma(SmmaStream),
60    Zlema(ZlemaStream),
61    Alma(AlmaStream),
62    Cwma(CwmaStream),
63    Edcf(EdcfStream),
64    Fwma(FwmaStream),
65    Gaussian(GaussianStream),
66    HighPass(HighPassStream),
67    HighPass2(HighPass2Stream),
68    Hma(HmaStream),
69    Hwma(HwmaStream),
70    Jma(JmaStream),
71    Jsa(JsaStream),
72    Kama(KamaStream),
73    LinReg(LinRegStream),
74    Maaq(MaaqStream),
75    Mama(MamaStream),
76    Mwdx(MwdxStream),
77    Nma(NmaStream),
78    Pwma(PwmaStream),
79    Reflex(ReflexStream),
80    SinWma(SinWmaStream),
81    SqWma(SqwmaStream),
82    SrWma(SrwmaStream),
83    SuperSmoother(SuperSmootherStream),
84    SuperSmoother3Pole(SuperSmoother3PoleStream),
85    Swma(SwmaStream),
86    Tilson(TilsonStream),
87    TrendFlex(TrendFlexStream),
88    Trima(TrimaStream),
89    Wilders(WildersStream),
90    Wma(WmaStream),
91    VpWma(VpwmaStream),
92    Vwap(VwapStream),
93    Vwma(VwmaStream),
94    EhlersITrend(EhlersITrendStream),
95    Frama(FramaStream),
96    Epma(EpmaStream),
97    Dma(DmaStream),
98    EhlersEcema(EhlersEcemaStream),
99    EhlersKama(EhlersKamaStream),
100    Ehma(EhmaStream),
101    Nama(NamaStream),
102    Sama(SamaStream),
103    Vama(VamaStream),
104}
105
106impl MaStream {
107    #[inline]
108    pub fn update(&mut self, value: f64) -> Option<f64> {
109        match self {
110            MaStream::Sma(s) => s.update(value),
111            MaStream::Ema(s) => s.update(value),
112            MaStream::Dema(s) => s.update(value),
113            MaStream::Tema(s) => s.update(value),
114            MaStream::Smma(s) => s.update(value),
115            MaStream::Zlema(s) => s.update(value),
116            MaStream::Alma(s) => s.update(value),
117            MaStream::Cwma(s) => s.update(value),
118            MaStream::Edcf(s) => s.update(value),
119            MaStream::Fwma(s) => s.update(value),
120            MaStream::Gaussian(s) => Some(s.update(value)),
121            MaStream::HighPass(s) => Some(s.update(value)),
122            MaStream::HighPass2(s) => s.update(value),
123            MaStream::Hma(s) => s.update(value),
124            MaStream::Hwma(s) => s.update(value),
125            MaStream::Jma(s) => s.update(value),
126            MaStream::Jsa(s) => s.update(value),
127            MaStream::Kama(s) => s.update(value),
128            MaStream::LinReg(s) => s.update(value),
129            MaStream::Maaq(s) => s.update(value),
130            MaStream::Mama(s) => s.update(value).map(|(mama, _fama)| mama),
131            MaStream::Mwdx(s) => Some(s.update(value)),
132            MaStream::Nma(s) => s.update(value),
133            MaStream::Pwma(s) => s.update(value),
134            MaStream::Reflex(s) => s.update(value),
135            MaStream::SinWma(s) => s.update(value),
136            MaStream::SqWma(s) => s.update(value),
137            MaStream::SrWma(s) => s.update(value),
138            MaStream::SuperSmoother(s) => s.update(value, None),
139            MaStream::SuperSmoother3Pole(s) => Some(s.update(value)),
140            MaStream::Swma(s) => s.update(value),
141            MaStream::Tilson(s) => s.update(value),
142            MaStream::TrendFlex(s) => s.update(value),
143            MaStream::Trima(s) => s.update(value),
144            MaStream::Wilders(s) => s.update(value),
145            MaStream::Wma(s) => s.update(value),
146            MaStream::VpWma(s) => s.update(value),
147            MaStream::Vwap(s) => None,
148            MaStream::Vwma(s) => None,
149            MaStream::EhlersITrend(s) => s.update(value),
150            MaStream::Frama(s) => None,
151            MaStream::Epma(s) => s.update(value),
152            MaStream::Dma(s) => s.update(value),
153            MaStream::EhlersEcema(s) => Some(s.next(value)),
154            MaStream::EhlersKama(s) => s.update(value),
155            MaStream::Ehma(s) => s.update(value),
156            MaStream::Nama(s) => s.update_source(value),
157            MaStream::Sama(s) => s.update(value),
158            MaStream::Vama(s) => s.update(value),
159        }
160    }
161
162    #[inline]
163    pub fn update_with_volume(&mut self, value: f64, volume: f64) -> Option<f64> {
164        match self {
165            MaStream::VpWma(s) => s.update(value * volume),
166            MaStream::Vwap(_s) => None,
167            MaStream::Vwma(s) => s.update(value, volume),
168            _ => self.update(value),
169        }
170    }
171}
172
173#[inline]
174pub fn ma_stream(ma_type: &str, period: usize) -> Result<MaStream, Box<dyn Error>> {
175    match ma_type.to_lowercase().as_str() {
176        "sma" => {
177            let stream = SmaStream::try_new(SmaParams {
178                period: Some(period),
179            })?;
180            Ok(MaStream::Sma(stream))
181        }
182
183        "ema" => {
184            let stream = EmaStream::try_new(EmaParams {
185                period: Some(period),
186            })?;
187            Ok(MaStream::Ema(stream))
188        }
189
190        "dema" => {
191            let stream = DemaStream::try_new(DemaParams {
192                period: Some(period),
193            })?;
194            Ok(MaStream::Dema(stream))
195        }
196
197        "tema" => {
198            let stream = TemaStream::try_new(TemaParams {
199                period: Some(period),
200            })?;
201            Ok(MaStream::Tema(stream))
202        }
203
204        "smma" => {
205            let stream = SmmaStream::try_new(SmmaParams {
206                period: Some(period),
207            })?;
208            Ok(MaStream::Smma(stream))
209        }
210
211        "zlema" => {
212            let stream = ZlemaStream::try_new(ZlemaParams {
213                period: Some(period),
214            })?;
215            Ok(MaStream::Zlema(stream))
216        }
217
218        "alma" => {
219            let stream = AlmaStream::try_new(AlmaParams {
220                period: Some(period),
221                offset: None,
222                sigma: None,
223            })?;
224            Ok(MaStream::Alma(stream))
225        }
226
227        "cwma" => {
228            let stream = CwmaStream::try_new(CwmaParams {
229                period: Some(period),
230            })?;
231            Ok(MaStream::Cwma(stream))
232        }
233
234        "edcf" => {
235            let stream = EdcfStream::try_new(EdcfParams {
236                period: Some(period),
237            })?;
238            Ok(MaStream::Edcf(stream))
239        }
240
241        "fwma" => {
242            let stream = FwmaStream::try_new(FwmaParams {
243                period: Some(period),
244            })?;
245            Ok(MaStream::Fwma(stream))
246        }
247
248        "gaussian" => {
249            let stream = GaussianStream::try_new(GaussianParams {
250                period: Some(period),
251                poles: None,
252            })?;
253            Ok(MaStream::Gaussian(stream))
254        }
255
256        "highpass" => {
257            let stream = HighPassStream::try_new(HighPassParams {
258                period: Some(period),
259            })?;
260            Ok(MaStream::HighPass(stream))
261        }
262
263        "highpass2" => {
264            let stream = HighPass2Stream::try_new(HighPass2Params {
265                period: Some(period),
266                k: Some(0.707),
267            })?;
268            Ok(MaStream::HighPass2(stream))
269        }
270
271        "hma" => {
272            let stream = HmaStream::try_new(HmaParams {
273                period: Some(period),
274            })?;
275            Ok(MaStream::Hma(stream))
276        }
277
278        "hwma" => {
279            let stream = HwmaStream::try_new(HwmaParams {
280                na: None,
281                nb: None,
282                nc: None,
283            })?;
284            Ok(MaStream::Hwma(stream))
285        }
286
287        "jma" => {
288            let stream = JmaStream::try_new(JmaParams {
289                period: Some(period),
290                phase: None,
291                power: None,
292            })?;
293            Ok(MaStream::Jma(stream))
294        }
295
296        "jsa" => {
297            let stream = JsaStream::try_new(JsaParams {
298                period: Some(period),
299            })?;
300            Ok(MaStream::Jsa(stream))
301        }
302
303        "kama" => {
304            let stream = KamaStream::try_new(KamaParams {
305                period: Some(period),
306            })?;
307            Ok(MaStream::Kama(stream))
308        }
309
310        "linreg" => {
311            let stream = LinRegStream::try_new(LinRegParams {
312                period: Some(period),
313            })?;
314            Ok(MaStream::LinReg(stream))
315        }
316
317        "maaq" => {
318            let stream = MaaqStream::try_new(MaaqParams {
319                period: Some(period),
320                fast_period: Some(period / 2),
321                slow_period: Some(period * 2),
322            })?;
323            Ok(MaStream::Maaq(stream))
324        }
325
326        "mama" => {
327            let _fast_limit = (10.0 / period as f64).clamp(0.0, 1.0);
328            let stream = MamaStream::try_new(MamaParams {
329                fast_limit: Some(_fast_limit),
330                slow_limit: None,
331            })?;
332            Ok(MaStream::Mama(stream))
333        }
334
335        "mwdx" => {
336            let stream = MwdxStream::try_new(MwdxParams { factor: None })?;
337            Ok(MaStream::Mwdx(stream))
338        }
339
340        "nma" => {
341            let stream = NmaStream::try_new(NmaParams {
342                period: Some(period),
343            })?;
344            Ok(MaStream::Nma(stream))
345        }
346
347        "pwma" => {
348            let stream = PwmaStream::try_new(PwmaParams {
349                period: Some(period),
350            })?;
351            Ok(MaStream::Pwma(stream))
352        }
353
354        "reflex" => {
355            let stream = ReflexStream::try_new(ReflexParams {
356                period: Some(period),
357            })?;
358            Ok(MaStream::Reflex(stream))
359        }
360
361        "sinwma" => {
362            let stream = SinWmaStream::try_new(SinWmaParams {
363                period: Some(period),
364            })?;
365            Ok(MaStream::SinWma(stream))
366        }
367
368        "sqwma" => {
369            let stream = SqwmaStream::try_new(SqwmaParams {
370                period: Some(period),
371            })?;
372            Ok(MaStream::SqWma(stream))
373        }
374
375        "srwma" => {
376            let stream = SrwmaStream::try_new(SrwmaParams {
377                period: Some(period),
378            })?;
379            Ok(MaStream::SrWma(stream))
380        }
381
382        "supersmoother" => {
383            let stream = SuperSmootherStream::try_new(SuperSmootherParams {
384                period: Some(period),
385            })?;
386            Ok(MaStream::SuperSmoother(stream))
387        }
388
389        "supersmoother_3_pole" => {
390            let stream = SuperSmoother3PoleStream::try_new(SuperSmoother3PoleParams {
391                period: Some(period),
392            })?;
393            Ok(MaStream::SuperSmoother3Pole(stream))
394        }
395
396        "swma" => {
397            let stream = SwmaStream::try_new(SwmaParams {
398                period: Some(period),
399            })?;
400            Ok(MaStream::Swma(stream))
401        }
402
403        "tilson" => {
404            let stream = TilsonStream::try_new(TilsonParams {
405                period: Some(period),
406                volume_factor: None,
407            })?;
408            Ok(MaStream::Tilson(stream))
409        }
410
411        "trendflex" => {
412            let stream = TrendFlexStream::try_new(TrendFlexParams {
413                period: Some(period),
414            })?;
415            Ok(MaStream::TrendFlex(stream))
416        }
417
418        "trima" => {
419            let stream = TrimaStream::try_new(TrimaParams {
420                period: Some(period),
421            })?;
422            Ok(MaStream::Trima(stream))
423        }
424
425        "wilders" => {
426            let stream = WildersStream::try_new(WildersParams {
427                period: Some(period),
428            })?;
429            Ok(MaStream::Wilders(stream))
430        }
431
432        "wma" => {
433            let stream = WmaStream::try_new(WmaParams {
434                period: Some(period),
435            })?;
436            Ok(MaStream::Wma(stream))
437        }
438
439        "vpwma" => {
440            let stream = VpwmaStream::try_new(VpwmaParams {
441                period: Some(period),
442                power: None,
443            })?;
444            Ok(MaStream::VpWma(stream))
445        }
446
447        "vwap" => {
448            let stream = VwapStream::try_new(VwapParams { anchor: None })?;
449            Ok(MaStream::Vwap(stream))
450        }
451
452        "vwma" => {
453            let stream = VwmaStream::try_new(VwmaParams {
454                period: Some(period),
455            })?;
456            Ok(MaStream::Vwma(stream))
457        }
458
459        "ehlers_itrend" => {
460            let stream = EhlersITrendStream::try_new(EhlersITrendParams {
461                warmup_bars: Some(20),
462                max_dc_period: Some(period),
463            })?;
464            Ok(MaStream::EhlersITrend(stream))
465        }
466
467        "frama" => {
468            let stream = FramaStream::try_new(FramaParams {
469                window: Some(period),
470                sc: None,
471                fc: None,
472            })?;
473            Ok(MaStream::Frama(stream))
474        }
475
476        "epma" => {
477            let stream = EpmaStream::try_new(EpmaParams {
478                period: Some(period),
479                offset: None,
480            })?;
481            Ok(MaStream::Epma(stream))
482        }
483
484        "dma" => {
485            let stream = DmaStream::try_new(DmaParams {
486                ema_length: Some(period),
487                ..Default::default()
488            })?;
489            Ok(MaStream::Dma(stream))
490        }
491
492        "ehlers_ecema" => {
493            let stream = EhlersEcemaStream::try_new(EhlersEcemaParams {
494                length: Some(period),
495                ..Default::default()
496            })?;
497            Ok(MaStream::EhlersEcema(stream))
498        }
499
500        "ehlers_kama" => {
501            let stream = EhlersKamaStream::try_new(EhlersKamaParams {
502                period: Some(period),
503            })?;
504            Ok(MaStream::EhlersKama(stream))
505        }
506
507        "ehma" => {
508            let stream = EhmaStream::try_new(EhmaParams {
509                period: Some(period),
510            })?;
511            Ok(MaStream::Ehma(stream))
512        }
513
514        "nama" => {
515            let stream = NamaStream::try_new(NamaParams {
516                period: Some(period),
517                ..Default::default()
518            })?;
519            Ok(MaStream::Nama(stream))
520        }
521
522        "sama" => {
523            let stream = SamaStream::try_new(SamaParams {
524                length: Some(period),
525                ..Default::default()
526            })?;
527            Ok(MaStream::Sama(stream))
528        }
529
530        "volatility_adjusted_ma" | "vama" => {
531            let stream = VamaStream::try_new(VamaParams {
532                base_period: Some(period),
533                ..Default::default()
534            })?;
535            Ok(MaStream::Vama(stream))
536        }
537
538        _ => {
539            eprintln!("Unknown indicator '{ma_type}'. Defaulting to 'sma'.");
540            let stream = SmaStream::try_new(SmaParams {
541                period: Some(period),
542            })?;
543            Ok(MaStream::Sma(stream))
544        }
545    }
546}
547
548#[cfg(test)]
549mod tests {
550    use super::*;
551
552    #[test]
553    fn test_ma_stream_creation() {
554        let ma_types = vec![
555            "sma",
556            "ema",
557            "dema",
558            "tema",
559            "smma",
560            "zlema",
561            "alma",
562            "cwma",
563            "edcf",
564            "fwma",
565            "gaussian",
566            "highpass",
567            "highpass2",
568            "hma",
569            "hwma",
570            "jma",
571            "jsa",
572            "kama",
573            "linreg",
574            "maaq",
575            "mwdx",
576            "nma",
577            "pwma",
578            "reflex",
579            "sinwma",
580            "sqwma",
581            "srwma",
582            "supersmoother",
583            "supersmoother_3_pole",
584            "swma",
585            "tilson",
586            "trendflex",
587            "trima",
588            "wilders",
589            "wma",
590            "vpwma",
591            "vwap",
592            "vwma",
593            "mama",
594            "ehlers_itrend",
595            "frama",
596            "epma",
597        ];
598
599        for ma_type in ma_types {
600            let result = ma_stream(ma_type, 14);
601            assert!(result.is_ok(), "Failed to create stream for {}", ma_type);
602        }
603    }
604
605    #[test]
606    fn test_ma_stream_update() {
607        let test_data = vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0];
608
609        let mut stream = ma_stream("sma", 3).expect("Failed to create SMA stream");
610
611        let mut results = Vec::new();
612        for &value in &test_data {
613            if let Some(result) = stream.update(value) {
614                results.push(result);
615            }
616        }
617
618        assert!(!results.is_empty(), "SMA stream should produce values");
619
620        let expected = 9.0;
621        let actual = results.last().unwrap();
622        assert!(
623            (actual - expected).abs() < 1e-10,
624            "SMA(3) last value mismatch: expected {}, got {}",
625            expected,
626            actual
627        );
628    }
629
630    #[test]
631    fn test_volume_based_streams() {
632        let mut vwma = ma_stream("vwma", 3).expect("Failed to create VWMA stream");
633        let mut vpwma = ma_stream("vpwma", 3).expect("Failed to create VPWMA stream");
634        let mut vwap = ma_stream("vwap", 3).expect("Failed to create VWAP stream");
635
636        let prices = vec![100.0, 102.0, 101.0, 103.0, 105.0];
637        let volumes = vec![1000.0, 1500.0, 1200.0, 2000.0, 1800.0];
638
639        for (&price, &volume) in prices.iter().zip(volumes.iter()) {
640            vwma.update_with_volume(price, volume);
641            vpwma.update_with_volume(price, volume);
642            vwap.update_with_volume(price, volume);
643        }
644    }
645
646    #[test]
647    fn test_unknown_ma_type_defaults_to_sma() {
648        let stream = ma_stream("unknown_type", 5);
649        assert!(stream.is_ok(), "Should default to SMA for unknown type");
650
651        let mut s = stream.unwrap();
652
653        let test_values = vec![1.0, 2.0, 3.0, 4.0, 5.0];
654        let mut last_result = None;
655
656        for value in test_values {
657            last_result = s.update(value);
658        }
659
660        assert_eq!(last_result, Some(3.0));
661    }
662}