egui_charts/studies/builtin/
price_volume_trend_study.rs1use crate::model::Bar;
2use crate::studies::palette;
3use crate::studies::stepper::Stepper;
4use crate::studies::{Indicator, IndicatorValue, IndicatorValues};
5use egui::Color32;
6
7#[derive(Clone)]
11pub struct PriceVolumeTrendStudy {
12 signal_period: usize,
13 values: IndicatorValues,
14 stepper: Stepper<(Option<f64>, f64, f64)>,
15 colors: Vec<Color32>,
16 visible: bool,
17}
18
19impl PriceVolumeTrendStudy {
20 pub fn new(signal_period: usize) -> Self {
22 Self {
23 signal_period: signal_period.max(1),
24 values: IndicatorValues::new(),
25 stepper: Stepper::default(),
26 colors: vec![
27 palette::BLUE, palette::ORANGE, ],
30 visible: true,
31 }
32 }
33}
34
35impl Default for PriceVolumeTrendStudy {
36 fn default() -> Self {
37 Self::new(9)
38 }
39}
40
41impl Indicator for PriceVolumeTrendStudy {
42 fn source(&self) -> Option<crate::studies::StudySource> {
43 Some(crate::studies::StudySource::Price(
44 crate::model::PriceSource::Close,
45 ))
46 }
47
48 crate::studies::inputs::study_inputs!(self;
49 signal_period: length("Signal period", 1, usize::MAX)
50 ; {});
51
52 fn value_format(&self) -> crate::scales::StudyFormat {
53 crate::scales::StudyFormat::Volume
54 }
55
56 fn name(&self) -> &str {
57 "PVT Enhanced"
58 }
59
60 fn desc(&self) -> &str {
61 "Price Volume Trend Enhanced - PVT with EMA signal line"
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 if !bar.close.is_finite() || !bar.volume.is_finite() {
72 return IndicatorValue::None;
73 }
74 if let Some(previous) = state.0 {
75 if previous != 0.0 {
76 state.1 += bar.volume * (bar.close - previous) / previous;
77 }
78 state.2 =
79 (state.1 - state.2) * (2.0 / (self.signal_period as f64 + 1.0)) + state.2;
80 }
81 state.0 = Some(bar.close);
82 IndicatorValue::Multiple(vec![state.1, state.2])
83 });
84 }
85
86 fn is_incremental(&self) -> bool {
87 true
88 }
89
90 fn values(&self) -> &IndicatorValues {
91 &self.values
92 }
93
94 fn colors(&self) -> Vec<Color32> {
95 self.colors.clone()
96 }
97
98 fn set_colors(&mut self, colors: Vec<Color32>) {
99 if colors.len() >= 2 {
100 self.colors = colors;
101 } else if !colors.is_empty() {
102 self.colors = vec![colors[0], colors[0]];
103 }
104 }
105
106 fn is_overlay(&self) -> bool {
107 false
108 }
109
110 fn line_count(&self) -> usize {
111 2
112 }
113
114 fn is_visible(&self) -> bool {
115 self.visible
116 }
117
118 fn set_visible(&mut self, visible: bool) {
119 self.visible = visible;
120 }
121
122 fn clone_box(&self) -> Box<dyn Indicator> {
123 Box::new(self.clone())
124 }
125
126 fn line_names(&self) -> Vec<String> {
127 vec![format!("PVT({})", self.signal_period), "Signal".to_string()]
128 }
129}