Skip to main content

egui_charts/studies/builtin/
williams_ad.rs

1use crate::model::Bar;
2use crate::studies::palette;
3use crate::studies::stepper::Stepper;
4use crate::studies::{Indicator, IndicatorValue, IndicatorValues};
5use egui::Color32;
6
7/// Williams Accumulation/Distribution
8/// Developed by Larry Williams
9/// Measures buying and selling pressure
10#[derive(Clone)]
11pub struct WilliamsAD {
12    values: IndicatorValues,
13    stepper: Stepper<State>,
14    color: Color32,
15    visible: bool,
16}
17
18#[derive(Clone, Default)]
19struct State {
20    bars: usize,
21    count: usize,
22    first: Option<usize>,
23    previous: Option<Bar>,
24    total: f64,
25}
26
27impl WilliamsAD {
28    /// Create with the default plot colors.
29    pub fn new() -> Self {
30        Self {
31            values: IndicatorValues::new(),
32            stepper: Stepper::default(),
33            color: palette::UP, // Teal
34            visible: true,
35        }
36    }
37
38    /// Set the plot color.
39    pub fn with_color(mut self, color: Color32) -> Self {
40        self.color = color;
41        self
42    }
43}
44
45impl Default for WilliamsAD {
46    fn default() -> Self {
47        Self::new()
48    }
49}
50
51impl Indicator for WilliamsAD {
52    fn value_format(&self) -> crate::scales::StudyFormat {
53        crate::scales::StudyFormat::Price
54    }
55
56    fn name(&self) -> &str {
57        "WAD"
58    }
59
60    fn desc(&self) -> &str {
61        "Williams Accumulation/Distribution - Buying/selling pressure"
62    }
63
64    fn calculate(&mut self, data: &[Bar]) {
65        self.update(data, 0);
66    }
67
68    fn update(&mut self, data: &[Bar], from: usize) {
69        self.stepper
70            .run(data, from, &mut self.values, |state, bar| {
71                let index = state.bars;
72                state.bars += 1;
73                if !([bar.high, bar.low, bar.close].iter().all(|x| x.is_finite())) {
74                    return IndicatorValue::None;
75                }
76                state.count += 1;
77                if let Some(previous) = &state.previous {
78                    state.total += if bar.close > previous.close {
79                        bar.close - bar.low.min(previous.close)
80                    } else if bar.close < previous.close {
81                        bar.close - bar.high.max(previous.close)
82                    } else {
83                        0.0
84                    };
85                }
86                state.first.get_or_insert(index);
87                state.previous = Some(bar.clone());
88                IndicatorValue::Single(state.total)
89            });
90        // The batch definition reveals the initial zero only once a second usable bar exists.
91        if let Some(first) = self.stepper.state().first {
92            self.values.set(
93                first,
94                if self.stepper.state().count < 2 {
95                    IndicatorValue::None
96                } else {
97                    IndicatorValue::Single(0.0)
98                },
99            );
100        }
101    }
102
103    fn is_incremental(&self) -> bool {
104        true
105    }
106
107    fn values(&self) -> &IndicatorValues {
108        &self.values
109    }
110
111    fn colors(&self) -> Vec<Color32> {
112        vec![self.color]
113    }
114
115    fn set_colors(&mut self, colors: Vec<Color32>) {
116        if !colors.is_empty() {
117            self.color = colors[0];
118        }
119    }
120
121    fn is_overlay(&self) -> bool {
122        false
123    }
124
125    fn is_visible(&self) -> bool {
126        self.visible
127    }
128
129    fn set_visible(&mut self, visible: bool) {
130        self.visible = visible;
131    }
132
133    fn clone_box(&self) -> Box<dyn Indicator> {
134        Box::new(self.clone())
135    }
136
137    fn line_names(&self) -> Vec<String> {
138        vec!["WAD".to_string()]
139    }
140}