egui_charts/studies/builtin/
aroon_oscillator.rs1use super::Aroon;
26use crate::model::Bar;
27use crate::studies::palette;
28use crate::studies::stepper::{update_window, usable_behind};
29use crate::studies::{Indicator, IndicatorValue, IndicatorValues};
30use egui::Color32;
31
32#[derive(Clone)]
34pub struct AroonOscillator {
35 period: usize,
36 values: IndicatorValues,
37 colors: [Color32; 2],
38 visible: bool,
39}
40
41impl AroonOscillator {
42 pub fn new(period: usize) -> Self {
44 Self {
45 period: period.max(1),
46 values: IndicatorValues::new(),
47 colors: [palette::GREEN, palette::HISTOGRAM_RED],
48 visible: true,
49 }
50 }
51}
52
53impl Default for AroonOscillator {
54 fn default() -> Self {
55 Self::new(14)
56 }
57}
58
59impl AroonOscillator {
60 fn compute(&self, data: &[Bar]) -> IndicatorValues {
61 let mut aroon = Aroon::new(self.period);
62 aroon.calculate(data);
63 let lines = aroon.values();
64 (0..data.len())
65 .map(|bar| match (lines.value(0, bar), lines.value(1, bar)) {
66 (Some(up), Some(down)) => IndicatorValue::Single(up - down),
67 _ => IndicatorValue::None,
68 })
69 .collect()
70 }
71}
72
73impl Indicator for AroonOscillator {
74 fn plot_color(&self, _line: usize, bar: usize) -> Option<Color32> {
75 self.values
76 .value(0, bar)
77 .map(|value| self.colors[usize::from(value < 0.0)])
78 }
79 fn line_count(&self) -> usize {
80 1
81 }
82 fn set_color(&mut self, line: usize, color: Color32) {
83 if line == 0 {
84 self.colors.fill(color);
85 }
86 }
87
88 crate::studies::inputs::study_inputs!(self;
89 period: length("Length", 1, usize::MAX)
90 ; {});
91
92 fn name(&self) -> &str {
93 "Aroon Oscillator"
94 }
95
96 fn desc(&self) -> &str {
97 "Aroon Oscillator - Aroon Up minus Aroon Down"
98 }
99
100 fn calculate(&mut self, data: &[Bar]) {
101 self.update(data, 0);
102 }
103
104 fn update(&mut self, data: &[Bar], from: usize) {
105 let mut values = std::mem::take(&mut self.values);
106 update_window(
107 &mut values,
108 data,
109 from,
110 usable_behind(self.period, |bar| {
111 bar.high.is_finite() && bar.low.is_finite()
112 }),
113 |data| self.compute(data),
114 );
115 self.values = values;
116 }
117
118 fn is_incremental(&self) -> bool {
119 true
120 }
121
122 fn values(&self) -> &IndicatorValues {
123 &self.values
124 }
125
126 fn colors(&self) -> Vec<Color32> {
127 self.colors.to_vec()
128 }
129
130 fn set_colors(&mut self, colors: Vec<Color32>) {
131 if let Some(&color) = colors.first() {
132 self.colors = [color, colors.get(1).copied().unwrap_or(color)];
133 }
134 }
135
136 fn pane(&self) -> crate::studies::StudyPane {
137 crate::studies::StudyPane {
138 range: Some((-100.0, 100.0)),
139 levels: vec![(0.0, palette::GRAY, "Zero")],
140 ..Default::default()
141 }
142 }
143
144 fn is_overlay(&self) -> bool {
145 false
146 }
147
148 fn is_visible(&self) -> bool {
149 self.visible
150 }
151
152 fn set_visible(&mut self, visible: bool) {
153 self.visible = visible;
154 }
155
156 fn clone_box(&self) -> Box<dyn Indicator> {
157 Box::new(self.clone())
158 }
159
160 fn line_names(&self) -> Vec<String> {
161 vec![format!("Aroon Osc({})", self.period)]
162 }
163}