Skip to main content

egui_charts/studies/builtin/
acc_dist.rs

1//! Accumulation/Distribution Line (A/D Line) Indicator
2//!
3//! The A/D Line measures the cumulative flow of money into and out of a security
4//! based on the close's position within the bar's high-low range.
5//!
6//! # Formula
7//! Money Flow Multiplier = ((Close - Low) - (High - Close)) / (High - Low)
8//! Money Flow Volume = Money Flow Multiplier * Volume
9//! A/D Line = Previous A/D + Money Flow Volume
10//!
11//! # Interpretation
12//! - Rising A/D Line: Accumulation (buying pressure)
13//! - Falling A/D Line: Distribution (selling pressure)
14//! - Divergence with price: Potential reversal signal
15//!
16//! # Example
17//! ```
18//! # let bars: Vec<egui_charts::model::Bar> = (0..60).map(|i| { let p = 100.0 + (i as f64 * 0.3).sin() * 5.0; egui_charts::model::Bar::new(chrono::Utc::now(), p, p + 1.0, p - 1.0, p + 0.5, 1_000.0) }).collect();
19//! use egui_charts::studies::{AccumulationDistribution, Indicator};
20//!
21//! let mut ad = AccumulationDistribution::new();
22//! ad.calculate(&bars);
23//! ```
24
25use crate::model::Bar;
26use crate::studies::stepper::Stepper;
27use crate::studies::{Indicator, IndicatorValue, IndicatorValues};
28use egui::Color32;
29
30/// Accumulation/Distribution Line indicator
31#[derive(Clone)]
32pub struct AccumulationDistribution {
33    values: IndicatorValues,
34    stepper: Stepper<f64>,
35    color: Color32,
36    visible: bool,
37}
38
39impl AccumulationDistribution {
40    /// Create a new A/D Line indicator
41    pub fn new() -> Self {
42        Self {
43            values: IndicatorValues::new(),
44            stepper: Stepper::default(),
45            color: Color32::from_rgb(153, 153, 21), // Blue
46            visible: true,
47        }
48    }
49
50    /// Set the line color
51    pub fn with_color(mut self, color: Color32) -> Self {
52        self.color = color;
53        self
54    }
55}
56
57impl Default for AccumulationDistribution {
58    fn default() -> Self {
59        Self::new()
60    }
61}
62
63impl Indicator for AccumulationDistribution {
64    fn value_format(&self) -> crate::scales::StudyFormat {
65        crate::scales::StudyFormat::Volume
66    }
67
68    fn name(&self) -> &str {
69        "A/D"
70    }
71
72    fn desc(&self) -> &str {
73        "Accumulation/Distribution Line - Measures buying/selling pressure"
74    }
75
76    fn calculate(&mut self, data: &[Bar]) {
77        self.update(data, 0);
78    }
79
80    fn update(&mut self, data: &[Bar], from: usize) {
81        self.stepper
82            .run(data, from, &mut self.values, |state, bar| {
83                if ![bar.high, bar.low, bar.close, bar.volume]
84                    .iter()
85                    .all(|x| x.is_finite())
86                {
87                    return IndicatorValue::None;
88                }
89                let range = bar.high - bar.low;
90                if range > 0.0 {
91                    let multiplier = (2.0 * bar.close - bar.high - bar.low) / range;
92                    *state += multiplier * bar.volume;
93                }
94                IndicatorValue::Single(*state)
95            });
96    }
97
98    fn is_incremental(&self) -> bool {
99        true
100    }
101
102    fn values(&self) -> &IndicatorValues {
103        &self.values
104    }
105
106    fn colors(&self) -> Vec<Color32> {
107        vec![self.color]
108    }
109
110    fn set_colors(&mut self, colors: Vec<Color32>) {
111        if !colors.is_empty() {
112            self.color = colors[0];
113        }
114    }
115
116    fn is_overlay(&self) -> bool {
117        false // A/D is a separate pane
118    }
119
120    fn line_count(&self) -> usize {
121        1
122    }
123
124    fn is_visible(&self) -> bool {
125        self.visible
126    }
127
128    fn set_visible(&mut self, visible: bool) {
129        self.visible = visible;
130    }
131
132    fn clone_box(&self) -> Box<dyn Indicator> {
133        Box::new(self.clone())
134    }
135
136    fn line_names(&self) -> Vec<String> {
137        vec!["A/D Line".to_string()]
138    }
139}