quantwave_core/indicators/
vwap.rs1use crate::indicators::metadata::IndicatorMetadata;
2use crate::traits::Next;
3
4#[derive(Debug, Clone)]
5pub struct AnchoredVWAP {
6 cumulative_tp_v: f64,
7 cumulative_v: f64,
8}
9
10impl AnchoredVWAP {
11 pub fn new() -> Self {
12 Self {
13 cumulative_tp_v: 0.0,
14 cumulative_v: 0.0,
15 }
16 }
17}
18
19impl Next<(f64, f64, bool)> for AnchoredVWAP {
20 type Output = f64;
21
22 fn next(&mut self, (price, volume, anchor): (f64, f64, bool)) -> Self::Output {
23 if anchor {
24 self.cumulative_tp_v = price * volume;
25 self.cumulative_v = volume;
26 } else {
27 self.cumulative_tp_v += price * volume;
28 self.cumulative_v += volume;
29 }
30
31 if self.cumulative_v == 0.0 {
32 0.0
33 } else {
34 self.cumulative_tp_v / self.cumulative_v
35 }
36 }
37}
38
39#[cfg(test)]
40mod tests {
41 use super::*;
42
43 #[test]
44 fn test_basic_vwap_no_reset() {
45 let mut vwap = AnchoredVWAP::new();
46 let result1 = vwap.next((10.0, 100.0, false));
50 approx::assert_relative_eq!(result1, 10.0);
51
52 let result2 = vwap.next((12.0, 200.0, false));
53 approx::assert_relative_eq!(result2, 11.3333333333, epsilon = 1e-6);
54 }
55
56 #[test]
57 fn test_anchored_vwap_reset() {
58 let mut vwap = AnchoredVWAP::new();
59
60 vwap.next((10.0, 100.0, false));
61 vwap.next((12.0, 200.0, false));
62
63 let result3 = vwap.next((15.0, 100.0, true));
65 approx::assert_relative_eq!(result3, 15.0);
66
67 let result4 = vwap.next((16.0, 100.0, false));
69 approx::assert_relative_eq!(result4, 15.5);
70 }
71}
72
73pub const VWAP_METADATA: IndicatorMetadata = IndicatorMetadata {
74 name: "Anchored VWAP",
75 description: "Volume Weighted Average Price anchored to a specific starting point.",
76 params: &[],
77 formula_source: "https://www.investopedia.com/terms/v/vwap.asp",
78 formula_latex: r#"
79\[
80VWAP = \frac{\sum (Price \times Volume)}{\sum Volume}
81\]
82"#,
83 gold_standard_file: "vwap.json",
84 category: "Classic",
85};