egui_charts/studies/builtin/
special_k.rs1use super::over_finite_bars;
34use crate::model::Bar;
35use crate::studies::palette;
36use crate::studies::stepper::{rolling_mean, update_window, usable_behind};
37use crate::studies::{Indicator, IndicatorValue, IndicatorValues};
38use egui::Color32;
39
40const COMPONENTS: [(usize, usize, f64); 12] = [
42 (10, 10, 1.0),
43 (15, 10, 2.0),
44 (20, 10, 3.0),
45 (30, 15, 4.0),
46 (40, 50, 1.0),
47 (65, 65, 2.0),
48 (75, 75, 3.0),
49 (100, 100, 4.0),
50 (195, 130, 1.0),
51 (265, 130, 2.0),
52 (390, 130, 3.0),
53 (530, 195, 4.0),
54];
55
56#[derive(Clone)]
58pub struct PringsSpecialK {
59 signal_lengths: [usize; 2],
60 values: IndicatorValues,
61 colors: Vec<Color32>,
63 visible: bool,
64}
65
66impl PringsSpecialK {
67 pub fn new(signal_length_1: usize, signal_length_2: usize) -> Self {
69 Self {
70 signal_lengths: [signal_length_1.max(1), signal_length_2.max(1)],
71 values: IndicatorValues::new(),
72 colors: vec![palette::BLUE, palette::ORANGE],
73 visible: true,
74 }
75 }
76
77 fn compute(&self, data: &[Bar]) -> IndicatorValues {
79 let closes: Vec<f64> = data.iter().map(|b| b.close).collect();
80 let mut special_k = vec![0.0; closes.len()];
81 for (roc_length, sma_length, weight) in COMPONENTS {
82 let roc: Vec<f64> = (0..closes.len())
83 .map(|i| match i.checked_sub(roc_length) {
84 Some(back) if closes[back] != 0.0 => (closes[i] / closes[back] - 1.0) * 100.0,
85 _ => f64::NAN,
86 })
87 .collect();
88 for (sum, average) in special_k.iter_mut().zip(rolling_mean(&roc, sma_length)) {
89 *sum += weight * average;
90 }
91 }
92 let signal = rolling_mean(
93 &rolling_mean(&special_k, self.signal_lengths[0]),
94 self.signal_lengths[1],
95 );
96 let mut values = IndicatorValues::new();
97 for (value, signal) in special_k.into_iter().zip(signal) {
98 if value.is_finite() {
99 values.push_lines(&[value, signal]);
100 } else {
101 values.push(IndicatorValue::None);
102 }
103 }
104 values
105 }
106}
107
108impl Default for PringsSpecialK {
109 fn default() -> Self {
110 Self::new(100, 100)
111 }
112}
113
114impl Indicator for PringsSpecialK {
115 fn source(&self) -> Option<crate::studies::StudySource> {
116 Some(crate::studies::StudySource::Price(
117 crate::model::PriceSource::Close,
118 ))
119 }
120
121 crate::studies::inputs::study_inputs!(self;
122 signal_lengths[0]: length("Signal length 1", 1, usize::MAX),
123 signal_lengths[1]: length("Signal length 2", 1, usize::MAX)
124 ; {});
125
126 fn name(&self) -> &str {
127 "Pring's Special K"
128 }
129
130 fn desc(&self) -> &str {
131 "Pring's Special K - Weighted sum of smoothed rates of change across cycles"
132 }
133
134 fn calculate(&mut self, data: &[Bar]) {
135 self.update(data, 0);
136 }
137
138 fn update(&mut self, data: &[Bar], from: usize) {
139 let mut values = std::mem::take(&mut self.values);
140 update_window(
141 &mut values,
142 data,
143 from,
144 usable_behind(
145 COMPONENTS
146 .iter()
147 .map(|(roc, sma, _)| roc + sma - 1)
148 .max()
149 .unwrap()
150 .saturating_add(self.signal_lengths[0] - 1)
151 .saturating_add(self.signal_lengths[1] - 1),
152 |b| b.close.is_finite(),
153 ),
154 |data| over_finite_bars(data, |b| b.close.is_finite(), |data| self.compute(data)),
155 );
156 self.values = values;
157 }
158
159 fn is_incremental(&self) -> bool {
160 true
161 }
162
163 fn values(&self) -> &IndicatorValues {
164 &self.values
165 }
166
167 fn colors(&self) -> Vec<Color32> {
168 self.colors.clone()
169 }
170
171 fn set_colors(&mut self, colors: Vec<Color32>) {
172 if colors.len() >= 2 {
173 self.colors = colors;
174 }
175 }
176
177 fn is_overlay(&self) -> bool {
178 false
179 }
180
181 fn is_visible(&self) -> bool {
182 self.visible
183 }
184
185 fn set_visible(&mut self, visible: bool) {
186 self.visible = visible;
187 }
188
189 fn clone_box(&self) -> Box<dyn Indicator> {
190 Box::new(self.clone())
191 }
192
193 fn line_count(&self) -> usize {
194 2
195 }
196
197 fn line_names(&self) -> Vec<String> {
198 vec![
199 "Special K".to_string(),
200 format!(
201 "Signal({},{})",
202 self.signal_lengths[0], self.signal_lengths[1]
203 ),
204 ]
205 }
206}