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}