Skip to main content

egui_charts/studies/builtin/
net_volume.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/// Volume signed by the close against the previous close: positive, negative or zero.
8/// The first bar has no value.
9#[derive(Clone)]
10pub struct NetVolume {
11    values: IndicatorValues,
12    stepper: Stepper<Option<f64>>,
13    colors: Vec<Color32>,
14    visible: bool,
15}
16
17impl NetVolume {
18    /// Create with the default plot colors.
19    pub fn new() -> Self {
20        Self {
21            values: IndicatorValues::new(),
22            stepper: Stepper::default(),
23            colors: vec![palette::BLUE], // Teal
24            visible: true,
25        }
26    }
27}
28
29impl Default for NetVolume {
30    fn default() -> Self {
31        Self::new()
32    }
33}
34
35impl Indicator for NetVolume {
36    fn source(&self) -> Option<crate::studies::StudySource> {
37        Some(crate::studies::StudySource::Price(
38            crate::model::PriceSource::Close,
39        ))
40    }
41
42    fn plot_style(&self, _line: usize) -> crate::studies::PlotStyle {
43        crate::studies::PlotStyle {
44            color: self.colors[0],
45            width: 1.0,
46            pattern: crate::model::LineStyle::Solid,
47            plot_type: crate::studies::PlotType::Line,
48            visible: true,
49        }
50    }
51
52    fn value_format(&self) -> crate::scales::StudyFormat {
53        crate::scales::StudyFormat::Volume
54    }
55
56    fn name(&self) -> &str {
57        "Net Volume"
58    }
59
60    fn desc(&self) -> &str {
61        "Net Volume - Volume signed by the change from the previous close"
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, |previous, bar| {
71                if !bar.close.is_finite() || !bar.volume.is_finite() {
72                    return IndicatorValue::None;
73                }
74                let value = match *previous {
75                    None => IndicatorValue::None,
76                    Some(close) => IndicatorValue::Single(if bar.close > close {
77                        bar.volume
78                    } else if bar.close < close {
79                        -bar.volume
80                    } else {
81                        0.0
82                    }),
83                };
84                *previous = Some(bar.close);
85                value
86            });
87    }
88
89    fn is_incremental(&self) -> bool {
90        true
91    }
92
93    fn values(&self) -> &IndicatorValues {
94        &self.values
95    }
96
97    fn colors(&self) -> Vec<Color32> {
98        self.colors.clone()
99    }
100
101    fn set_colors(&mut self, colors: Vec<Color32>) {
102        if !colors.is_empty() {
103            self.colors = colors;
104        }
105    }
106
107    fn is_overlay(&self) -> bool {
108        false
109    }
110
111    fn is_visible(&self) -> bool {
112        self.visible
113    }
114
115    fn set_visible(&mut self, visible: bool) {
116        self.visible = visible;
117    }
118
119    fn clone_box(&self) -> Box<dyn Indicator> {
120        Box::new(self.clone())
121    }
122
123    fn line_names(&self) -> Vec<String> {
124        vec!["Net Volume".to_string()]
125    }
126}