egui_charts/studies/builtin/
smoothed_ma.rs1use crate::model::Bar;
2use crate::studies::palette;
3use crate::studies::stepper::Stepper;
4use crate::studies::{Indicator, IndicatorValue, IndicatorValues};
5use egui::Color32;
6
7#[derive(Clone)]
9pub struct SmoothedMA {
10 period: usize,
11 values: IndicatorValues,
12 stepper: Stepper<(usize, f64)>,
13 color: Color32,
14 visible: bool,
15}
16
17impl SmoothedMA {
18 pub fn new(period: usize) -> Self {
20 Self {
21 period: period.max(1),
22 values: IndicatorValues::new(),
23 stepper: Stepper::default(),
24 color: palette::DEEP_PURPLE,
25 visible: true,
26 }
27 }
28
29 pub fn with_color(mut self, color: Color32) -> Self {
31 self.color = color;
32 self
33 }
34}
35
36impl Default for SmoothedMA {
37 fn default() -> Self {
38 Self::new(7)
39 }
40}
41
42impl Indicator for SmoothedMA {
43 fn source(&self) -> Option<crate::studies::StudySource> {
44 Some(crate::studies::StudySource::Price(
45 crate::model::PriceSource::Close,
46 ))
47 }
48
49 crate::studies::inputs::study_inputs!(self;
50 period: length("Period", 1, usize::MAX)
51 ; {});
52
53 fn name(&self) -> &str {
54 "SMMA"
55 }
56
57 fn desc(&self) -> &str {
58 "Smoothed Moving Average - Wilder's smoothing method"
59 }
60
61 fn calculate(&mut self, data: &[Bar]) {
62 self.update(data, 0);
63 }
64
65 fn update(&mut self, data: &[Bar], from: usize) {
66 self.stepper
67 .run(data, from, &mut self.values, |state, bar| {
68 if !bar.close.is_finite() {
69 return IndicatorValue::None;
70 }
71 if state.0 == 0 {
72 state.1 = -0.0;
73 }
74 if state.0 < self.period {
75 state.0 += 1;
76 state.1 += bar.close;
77 if state.0 < self.period {
78 return IndicatorValue::None;
79 }
80 state.1 /= self.period as f64;
81 } else {
82 state.1 =
83 (state.1 * (self.period as f64 - 1.0) + bar.close) / self.period as f64;
84 }
85 IndicatorValue::Single(state.1)
86 });
87 }
88
89 fn is_incremental(&self) -> bool {
90 true
91 }
92
93 fn values(&self) -> &IndicatorValues {
94 &self.values
95 }
96
97 fn colors(&self) -> Vec<Color32> {
98 vec![self.color]
99 }
100
101 fn set_colors(&mut self, colors: Vec<Color32>) {
102 if !colors.is_empty() {
103 self.color = colors[0];
104 }
105 }
106
107 fn is_overlay(&self) -> bool {
108 true
109 }
110
111 fn is_visible(&self) -> bool {
112 self.visible
113 }
114
115 fn set_visible(&mut self, visible: bool) {
116 self.visible = visible;
117 }
118
119 fn clone_box(&self) -> Box<dyn Indicator> {
120 Box::new(self.clone())
121 }
122
123 fn line_names(&self) -> Vec<String> {
124 vec![format!("SMMA({})", self.period)]
125 }
126}