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}