Skip to main content

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