Skip to main content

egui_charts/studies/builtin/
typical_price.rs

1use crate::model::Bar;
2use crate::studies::palette;
3use crate::studies::{Indicator, IndicatorValue, IndicatorValues};
4use egui::Color32;
5
6/// Typical Price (HLC/3)
7/// Simple avg of high, low, close
8/// Also known as pivot point
9/// Note: Same formula as [`HLC3`](super::HLC3) in average_price; kept for
10/// backwards compatibility under the "TP" indicator name.
11#[derive(Clone)]
12pub struct TypicalPrice {
13    values: IndicatorValues,
14    color: Color32,
15    visible: bool,
16}
17
18impl TypicalPrice {
19    /// Create with the default plot colors.
20    pub fn new() -> Self {
21        Self {
22            values: IndicatorValues::new(),
23            color: palette::ORANGE,
24            visible: true,
25        }
26    }
27
28    /// Set the plot color.
29    pub fn with_color(mut self, color: Color32) -> Self {
30        self.color = color;
31        self
32    }
33}
34
35impl Default for TypicalPrice {
36    fn default() -> Self {
37        Self::new()
38    }
39}
40
41impl Indicator for TypicalPrice {
42    fn name(&self) -> &str {
43        "TP"
44    }
45
46    fn desc(&self) -> &str {
47        "Typical Price - (High + Low + Close) / 3"
48    }
49
50    fn calculate(&mut self, data: &[Bar]) {
51        self.update(data, 0);
52    }
53
54    fn update(&mut self, data: &[Bar], from: usize) {
55        let from = from.min(self.values.len()).min(data.len());
56        self.values.truncate(from);
57        for bar in &data[from..] {
58            let tp = (bar.high + bar.low + bar.close) / 3.0;
59            self.values.push(IndicatorValue::Single(tp));
60        }
61    }
62
63    fn is_incremental(&self) -> bool {
64        true
65    }
66
67    fn values(&self) -> &IndicatorValues {
68        &self.values
69    }
70
71    fn colors(&self) -> Vec<Color32> {
72        vec![self.color]
73    }
74
75    fn set_colors(&mut self, colors: Vec<Color32>) {
76        if !colors.is_empty() {
77            self.color = colors[0];
78        }
79    }
80
81    fn is_overlay(&self) -> bool {
82        true // Overlay on price chart
83    }
84
85    fn is_visible(&self) -> bool {
86        self.visible
87    }
88
89    fn set_visible(&mut self, visible: bool) {
90        self.visible = visible;
91    }
92
93    fn clone_box(&self) -> Box<dyn Indicator> {
94        Box::new(self.clone())
95    }
96
97    fn line_names(&self) -> Vec<String> {
98        vec!["TP".to_string()]
99    }
100}
101
102/// Weighted Close
103#[derive(Clone)]
104pub struct WeightedClose {
105    values: IndicatorValues,
106    color: Color32,
107    visible: bool,
108}
109
110impl WeightedClose {
111    /// Create with the default plot colors.
112    pub fn new() -> Self {
113        Self {
114            values: IndicatorValues::new(),
115            color: palette::BLUE,
116            visible: true,
117        }
118    }
119
120    /// Set the plot color.
121    pub fn with_color(mut self, color: Color32) -> Self {
122        self.color = color;
123        self
124    }
125}
126
127impl Default for WeightedClose {
128    fn default() -> Self {
129        Self::new()
130    }
131}
132
133impl Indicator for WeightedClose {
134    fn name(&self) -> &str {
135        "WC"
136    }
137
138    fn desc(&self) -> &str {
139        "Weighted Close - (High + Low + 2*Close) / 4"
140    }
141
142    fn calculate(&mut self, data: &[Bar]) {
143        self.update(data, 0);
144    }
145
146    fn update(&mut self, data: &[Bar], from: usize) {
147        let from = from.min(self.values.len()).min(data.len());
148        self.values.truncate(from);
149        for bar in &data[from..] {
150            let wc = (bar.high + bar.low + 2.0 * bar.close) / 4.0;
151            self.values.push(IndicatorValue::Single(wc));
152        }
153    }
154
155    fn is_incremental(&self) -> bool {
156        true
157    }
158
159    fn values(&self) -> &IndicatorValues {
160        &self.values
161    }
162
163    fn colors(&self) -> Vec<Color32> {
164        vec![self.color]
165    }
166
167    fn set_colors(&mut self, colors: Vec<Color32>) {
168        if !colors.is_empty() {
169            self.color = colors[0];
170        }
171    }
172
173    fn is_overlay(&self) -> bool {
174        true
175    }
176
177    fn is_visible(&self) -> bool {
178        self.visible
179    }
180
181    fn set_visible(&mut self, visible: bool) {
182        self.visible = visible;
183    }
184
185    fn clone_box(&self) -> Box<dyn Indicator> {
186        Box::new(self.clone())
187    }
188
189    fn line_names(&self) -> Vec<String> {
190        vec!["WC".to_string()]
191    }
192}
193
194/// Median Price (HL/2)
195/// Note: Same formula as [`HL2`](super::HL2) in average_price; kept for
196/// backwards compatibility under the "MP" indicator name.
197#[derive(Clone)]
198pub struct MedianPrice {
199    values: IndicatorValues,
200    color: Color32,
201    visible: bool,
202}
203
204impl MedianPrice {
205    /// Create with the default plot colors.
206    pub fn new() -> Self {
207        Self {
208            values: IndicatorValues::new(),
209            color: palette::ORANGE,
210            visible: true,
211        }
212    }
213
214    /// Set the plot color.
215    pub fn with_color(mut self, color: Color32) -> Self {
216        self.color = color;
217        self
218    }
219}
220
221impl Default for MedianPrice {
222    fn default() -> Self {
223        Self::new()
224    }
225}
226
227impl Indicator for MedianPrice {
228    fn name(&self) -> &str {
229        "MP"
230    }
231
232    fn desc(&self) -> &str {
233        "Median Price - (High + Low) / 2"
234    }
235
236    fn calculate(&mut self, data: &[Bar]) {
237        self.update(data, 0);
238    }
239
240    fn update(&mut self, data: &[Bar], from: usize) {
241        let from = from.min(self.values.len()).min(data.len());
242        self.values.truncate(from);
243        for bar in &data[from..] {
244            let mp = (bar.high + bar.low) / 2.0;
245            self.values.push(IndicatorValue::Single(mp));
246        }
247    }
248
249    fn is_incremental(&self) -> bool {
250        true
251    }
252
253    fn values(&self) -> &IndicatorValues {
254        &self.values
255    }
256
257    fn colors(&self) -> Vec<Color32> {
258        vec![self.color]
259    }
260
261    fn set_colors(&mut self, colors: Vec<Color32>) {
262        if !colors.is_empty() {
263            self.color = colors[0];
264        }
265    }
266
267    fn is_overlay(&self) -> bool {
268        true
269    }
270
271    fn is_visible(&self) -> bool {
272        self.visible
273    }
274
275    fn set_visible(&mut self, visible: bool) {
276        self.visible = visible;
277    }
278
279    fn clone_box(&self) -> Box<dyn Indicator> {
280        Box::new(self.clone())
281    }
282
283    fn line_names(&self) -> Vec<String> {
284        vec!["MP".to_string()]
285    }
286}