egui_charts/studies/builtin/
dema.rs1use super::smoothing::Smoothing;
19use crate::model::Bar;
20use crate::studies::palette;
21use crate::studies::stepper::Stepper;
22use crate::studies::{Indicator, IndicatorValue, IndicatorValues};
23use egui::Color32;
24
25#[derive(Clone)]
27pub struct DEMA {
28 period: usize,
29 values: IndicatorValues,
30 stepper: Stepper<[Smoothing; 2]>,
31 color: Color32,
32 visible: bool,
33}
34
35impl DEMA {
36 pub fn new(period: usize) -> Self {
41 Self {
42 period: period.max(1),
43 values: IndicatorValues::new(),
44 stepper: Stepper::default(),
45 color: palette::DARK_GREEN,
46 visible: true,
47 }
48 }
49
50 pub fn with_color(mut self, color: Color32) -> Self {
52 self.color = color;
53 self
54 }
55}
56
57impl Default for DEMA {
59 fn default() -> Self {
60 Self::new(9)
61 }
62}
63
64impl Indicator for DEMA {
65 fn source(&self) -> Option<crate::studies::StudySource> {
66 Some(crate::studies::StudySource::Price(
67 crate::model::PriceSource::Close,
68 ))
69 }
70
71 crate::studies::inputs::study_inputs!(self;
72 period: length("Period", 1, usize::MAX)
73 ; {});
74
75 fn name(&self) -> &str {
76 "DEMA"
77 }
78
79 fn desc(&self) -> &str {
80 "Double Exponential Moving Avg - Reduces lag compared to EMA"
81 }
82
83 fn calculate(&mut self, data: &[Bar]) {
84 self.update(data, 0);
85 }
86
87 fn update(&mut self, data: &[Bar], from: usize) {
88 self.stepper
89 .run(data, from, &mut self.values, |state, bar| {
90 if !bar.close.is_finite() {
91 return IndicatorValue::None;
92 }
93 let alpha = 2.0 / (self.period as f64 + 1.0);
94 let ema1 = state[0].next(bar.close, self.period, alpha);
95 let ema2 = state[1].next(ema1, self.period, alpha);
96 IndicatorValue::Single(2.0 * ema1 - ema2)
97 });
98 }
99
100 fn is_incremental(&self) -> bool {
101 true
102 }
103
104 fn values(&self) -> &IndicatorValues {
105 &self.values
106 }
107
108 fn colors(&self) -> Vec<Color32> {
109 vec![self.color]
110 }
111
112 fn set_colors(&mut self, colors: Vec<Color32>) {
113 if !colors.is_empty() {
114 self.color = colors[0];
115 }
116 }
117
118 fn is_overlay(&self) -> bool {
119 true
120 }
121
122 fn line_count(&self) -> usize {
123 1
124 }
125
126 fn is_visible(&self) -> bool {
127 self.visible
128 }
129
130 fn set_visible(&mut self, visible: bool) {
131 self.visible = visible;
132 }
133
134 fn clone_box(&self) -> Box<dyn Indicator> {
135 Box::new(self.clone())
136 }
137
138 fn line_names(&self) -> Vec<String> {
139 vec![format!("DEMA({})", self.period)]
140 }
141}