Skip to main content

egui_charts/studies/builtin/
average_price.rs

1//! Avg Price Indicators
2//! Simple price calculations useful for analysis
3
4use super::over_finite_bars;
5use crate::model::Bar;
6use crate::studies::palette;
7use crate::studies::stepper::{update_window, usable_behind};
8use crate::studies::{Indicator, IndicatorValue, IndicatorValues};
9use egui::Color32;
10
11/// OHLC4 - Avg of Open, High, Low, Close
12#[derive(Clone)]
13pub struct OHLC4 {
14    values: IndicatorValues,
15    color: Color32,
16    visible: bool,
17}
18
19impl OHLC4 {
20    /// Create with the default plot colors.
21    pub fn new() -> Self {
22        Self {
23            values: IndicatorValues::new(),
24            color: palette::LIGHT_BLUE,
25            visible: true,
26        }
27    }
28
29    /// Set the plot color.
30    pub fn with_color(mut self, color: Color32) -> Self {
31        self.color = color;
32        self
33    }
34}
35
36impl Default for OHLC4 {
37    fn default() -> Self {
38        Self::new()
39    }
40}
41
42impl Indicator for OHLC4 {
43    fn name(&self) -> &str {
44        "OHLC4"
45    }
46
47    fn desc(&self) -> &str {
48        "OHLC4 - (Open + High + Low + Close) / 4"
49    }
50
51    fn calculate(&mut self, data: &[Bar]) {
52        self.update(data, 0);
53    }
54
55    fn update(&mut self, data: &[Bar], from: usize) {
56        let from = from.min(self.values.len()).min(data.len());
57        self.values.truncate(from);
58        for bar in &data[from..] {
59            let ohlc4 = (bar.open + bar.high + bar.low + bar.close) / 4.0;
60            self.values.push(IndicatorValue::Single(ohlc4));
61        }
62    }
63
64    fn is_incremental(&self) -> bool {
65        true
66    }
67
68    fn values(&self) -> &IndicatorValues {
69        &self.values
70    }
71
72    fn colors(&self) -> Vec<Color32> {
73        vec![self.color]
74    }
75
76    fn set_colors(&mut self, colors: Vec<Color32>) {
77        if !colors.is_empty() {
78            self.color = colors[0];
79        }
80    }
81
82    fn is_overlay(&self) -> bool {
83        true
84    }
85
86    fn is_visible(&self) -> bool {
87        self.visible
88    }
89
90    fn set_visible(&mut self, visible: bool) {
91        self.visible = visible;
92    }
93
94    fn clone_box(&self) -> Box<dyn Indicator> {
95        Box::new(self.clone())
96    }
97
98    fn line_names(&self) -> Vec<String> {
99        vec!["OHLC4".to_string()]
100    }
101}
102
103/// HLC3 - Avg of High, Low, Close
104/// Note: Same formula as [`TypicalPrice`](super::TypicalPrice); this variant
105/// uses the common HLC3 name.
106#[derive(Clone)]
107pub struct HLC3 {
108    values: IndicatorValues,
109    color: Color32,
110    visible: bool,
111}
112
113impl HLC3 {
114    /// Create with the default plot colors.
115    pub fn new() -> Self {
116        Self {
117            values: IndicatorValues::new(),
118            color: palette::ORANGE,
119            visible: true,
120        }
121    }
122
123    /// Set the plot color.
124    pub fn with_color(mut self, color: Color32) -> Self {
125        self.color = color;
126        self
127    }
128}
129
130impl Default for HLC3 {
131    fn default() -> Self {
132        Self::new()
133    }
134}
135
136impl Indicator for HLC3 {
137    fn name(&self) -> &str {
138        "HLC3"
139    }
140
141    fn desc(&self) -> &str {
142        "HLC3 - (High + Low + Close) / 3"
143    }
144
145    fn calculate(&mut self, data: &[Bar]) {
146        self.update(data, 0);
147    }
148
149    fn update(&mut self, data: &[Bar], from: usize) {
150        let from = from.min(self.values.len()).min(data.len());
151        self.values.truncate(from);
152        for bar in &data[from..] {
153            let hlc3 = (bar.high + bar.low + bar.close) / 3.0;
154            self.values.push(IndicatorValue::Single(hlc3));
155        }
156    }
157
158    fn is_incremental(&self) -> bool {
159        true
160    }
161
162    fn values(&self) -> &IndicatorValues {
163        &self.values
164    }
165
166    fn colors(&self) -> Vec<Color32> {
167        vec![self.color]
168    }
169
170    fn set_colors(&mut self, colors: Vec<Color32>) {
171        if !colors.is_empty() {
172            self.color = colors[0];
173        }
174    }
175
176    fn is_overlay(&self) -> bool {
177        true
178    }
179
180    fn is_visible(&self) -> bool {
181        self.visible
182    }
183
184    fn set_visible(&mut self, visible: bool) {
185        self.visible = visible;
186    }
187
188    fn clone_box(&self) -> Box<dyn Indicator> {
189        Box::new(self.clone())
190    }
191
192    fn line_names(&self) -> Vec<String> {
193        vec!["HLC3".to_string()]
194    }
195}
196
197/// HL2 - Avg of High and Low (Midpoint)
198/// Note: Same formula as [`MedianPrice`](super::MedianPrice); this variant
199/// uses the common HL2 name.
200#[derive(Clone)]
201pub struct HL2 {
202    values: IndicatorValues,
203    color: Color32,
204    visible: bool,
205}
206
207impl HL2 {
208    /// Create with the default plot colors.
209    pub fn new() -> Self {
210        Self {
211            values: IndicatorValues::new(),
212            color: palette::ORANGE,
213            visible: true,
214        }
215    }
216
217    /// Set the plot color.
218    pub fn with_color(mut self, color: Color32) -> Self {
219        self.color = color;
220        self
221    }
222}
223
224impl Default for HL2 {
225    fn default() -> Self {
226        Self::new()
227    }
228}
229
230impl Indicator for HL2 {
231    fn name(&self) -> &str {
232        "HL2"
233    }
234
235    fn desc(&self) -> &str {
236        "HL2 - (High + Low) / 2 - Midpoint price"
237    }
238
239    fn calculate(&mut self, data: &[Bar]) {
240        self.update(data, 0);
241    }
242
243    fn update(&mut self, data: &[Bar], from: usize) {
244        let from = from.min(self.values.len()).min(data.len());
245        self.values.truncate(from);
246        for bar in &data[from..] {
247            let hl2 = (bar.high + bar.low) / 2.0;
248            self.values.push(IndicatorValue::Single(hl2));
249        }
250    }
251
252    fn is_incremental(&self) -> bool {
253        true
254    }
255
256    fn values(&self) -> &IndicatorValues {
257        &self.values
258    }
259
260    fn colors(&self) -> Vec<Color32> {
261        vec![self.color]
262    }
263
264    fn set_colors(&mut self, colors: Vec<Color32>) {
265        if !colors.is_empty() {
266            self.color = colors[0];
267        }
268    }
269
270    fn is_overlay(&self) -> bool {
271        true
272    }
273
274    fn is_visible(&self) -> bool {
275        self.visible
276    }
277
278    fn set_visible(&mut self, visible: bool) {
279        self.visible = visible;
280    }
281
282    fn clone_box(&self) -> Box<dyn Indicator> {
283        Box::new(self.clone())
284    }
285
286    fn line_names(&self) -> Vec<String> {
287        vec!["HL2".to_string()]
288    }
289}
290
291/// True Range (not avgd)
292#[derive(Clone)]
293pub struct TrueRange {
294    values: IndicatorValues,
295    color: Color32,
296    visible: bool,
297}
298
299impl TrueRange {
300    /// Create with the default plot colors.
301    pub fn new() -> Self {
302        Self {
303            values: IndicatorValues::new(),
304            color: palette::RED,
305            visible: true,
306        }
307    }
308
309    /// Set the plot color.
310    pub fn with_color(mut self, color: Color32) -> Self {
311        self.color = color;
312        self
313    }
314}
315
316impl Default for TrueRange {
317    fn default() -> Self {
318        Self::new()
319    }
320}
321
322impl TrueRange {
323    /// The values over `data`, every bar of which has finite inputs.
324    fn compute(&self, data: &[Bar]) -> IndicatorValues {
325        let mut values = IndicatorValues::new();
326        if data.is_empty() {
327            return values;
328        }
329
330        // First bar: just H-L
331        values.push(IndicatorValue::Single(data[0].high - data[0].low));
332
333        for i in 1..data.len() {
334            let prev_close = data[i - 1].close;
335            let hl = data[i].high - data[i].low;
336            let hc = (data[i].high - prev_close).abs();
337            let lc = (data[i].low - prev_close).abs();
338            let tr = hl.max(hc).max(lc);
339            values.push(IndicatorValue::Single(tr));
340        }
341
342        values
343    }
344}
345
346impl Indicator for TrueRange {
347    fn value_format(&self) -> crate::scales::StudyFormat {
348        crate::scales::StudyFormat::Price
349    }
350
351    fn name(&self) -> &str {
352        "TR"
353    }
354
355    fn desc(&self) -> &str {
356        "True Range - Max of H-L, |H-Cp|, |L-Cp|"
357    }
358
359    fn calculate(&mut self, data: &[Bar]) {
360        self.update(data, 0);
361    }
362
363    fn update(&mut self, data: &[Bar], from: usize) {
364        let mut values = std::mem::take(&mut self.values);
365        update_window(
366            &mut values,
367            data,
368            from,
369            usable_behind(1, |b| {
370                b.high.is_finite() && b.low.is_finite() && b.close.is_finite()
371            }),
372            |data| {
373                over_finite_bars(
374                    data,
375                    |b| b.high.is_finite() && b.low.is_finite() && b.close.is_finite(),
376                    |data| self.compute(data),
377                )
378            },
379        );
380        self.values = values;
381    }
382
383    fn is_incremental(&self) -> bool {
384        true
385    }
386
387    fn values(&self) -> &IndicatorValues {
388        &self.values
389    }
390
391    fn colors(&self) -> Vec<Color32> {
392        vec![self.color]
393    }
394
395    fn set_colors(&mut self, colors: Vec<Color32>) {
396        if !colors.is_empty() {
397            self.color = colors[0];
398        }
399    }
400
401    fn is_overlay(&self) -> bool {
402        false
403    }
404
405    fn is_visible(&self) -> bool {
406        self.visible
407    }
408
409    fn set_visible(&mut self, visible: bool) {
410        self.visible = visible;
411    }
412
413    fn clone_box(&self) -> Box<dyn Indicator> {
414        Box::new(self.clone())
415    }
416
417    fn line_names(&self) -> Vec<String> {
418        vec!["TR".to_string()]
419    }
420}