finlib_ta/indicators/
volume_weighted_average_price.rs

1use crate::{Close, High, Low, Next, Reset, Volume};
2use alloc::vec;
3use core::fmt;
4#[cfg(not(feature = "std"))]
5use libm::sqrt;
6#[cfg(feature = "serde")]
7use serde::{Deserialize, Serialize};
8#[cfg(feature = "std")]
9use std::f64;
10
11/// # Example
12///
13/// ```
14/// extern crate finlib_ta;
15/// #[macro_use] extern crate assert_approx_eq;
16///
17/// use finlib_ta::{Next, DataItem};
18/// use finlib_ta::indicators::VolumeWeightedAveragePrice;
19///
20///
21/// fn main() {
22///     let data = vec![
23///         // open, high, low, close, volume, vwap
24///         (150.39, 150.39, 150.22, 150.31, 380.0,  150.31),
25///         (150.47, 150.47, 150.38, 150.41, 5270.0, 150.41),
26///         (150.49, 150.49, 150.33, 150.46, 990.0,  150.41),
27///         (150.63, 150.63, 150.44, 150.61, 1031.0, 150.43),
28///         (151.10, 151.10, 150.67, 151.01, 2675.0, 150.56),
29///         (151.30, 151.30, 150.77, 150.80, 3334.0, 150.66),
30///         (150.95, 150.95, 150.78, 150.93, 430.0,  150.66),
31///         (151.12, 151.12, 150.80, 151.10, 220.0,  150.67),
32///         (151.27, 151.27, 151.01, 151.25, 900.0,  150.70),
33///         (151.35, 151.35, 151.26, 151.33, 4088.0, 150.83),
34///         (151.52, 151.52, 151.32, 151.51, 650.0,  150.85),
35///         (151.69, 151.69, 151.49, 151.67, 1582.0, 150.91),
36///         (152.03, 152.03, 151.66, 151.80, 1892.0, 150.98),
37///         (151.90, 151.90, 151.75, 151.88, 2200.0, 151.05),
38///         (152.15, 152.15, 151.86, 152.10, 3043.0, 151.16),
39///         (152.43, 152.43, 152.03, 152.33, 675.0,  151.18),
40///         (152.57, 152.57, 152.25, 152.50, 1243.0, 151.24)
41///     ];
42///     let mut indicator = VolumeWeightedAveragePrice::new();
43///
44///     for (open, high, low, close, volume, vwap) in data {
45///         let di = DataItem::builder()
46///             .high(high)
47///             .low(low)
48///             .close(close)
49///             .open(open)
50///             .volume(volume)
51///             .build().unwrap();
52///         assert_approx_eq!(indicator.next(&di), vwap, 0.01);
53///     }
54/// }
55/// ```
56///
57/// # Example StdDev
58///
59/// ```
60/// extern crate finlib_ta;
61/// #[macro_use] extern crate assert_approx_eq;
62///
63/// use finlib_ta::{Next, DataItem};
64/// use finlib_ta::indicators::VolumeWeightedAveragePrice;
65/// use finlib_ta::indicators::VolumeWeightedAveragePriceBands;
66///
67///
68/// fn main() {
69///     let data = vec![
70///         //open  ,high   ,low     ,close  ,volume,vwap              ,(upper, lower)                         ,(upper, lower)
71///         (76.529, 76.529, 76.529, 76.529, 1.0    ,76.529            ,(76.529, 76.529)                       ,(76.529, 76.529)),
72///         (76.073, 76.073, 76.043, 76.073, 121.0  ,76.06681967213113 ,(76.15085245902783, 75.98278688523443) ,(76.19286885247618, 75.94077049178608)),
73///         (76.323, 76.323, 76.053, 76.193, 181.0  ,76.14020352035202 ,(76.27197010203601, 76.00843693866803) ,(76.33785339287802, 75.94255364782602)),
74///         (76.208, 76.208, 75.918, 75.988, 146.0  ,76.1069703043801  ,(76.25148729829992, 75.96245331046028) ,(76.32374579525984, 75.89019481350036)),
75///         (76.088, 76.088, 75.883, 76.058, 149.0  ,76.08272575250835 ,(76.23361138086482, 75.93184012415189) ,(76.30905419504305, 75.85639730997366)),
76///         (76.183, 76.183, 76.063, 76.153, 93.0   ,76.08949204052098 ,(76.23399096258677, 75.94499311845519) ,(76.30624042361966, 75.8727436574223)),
77///         (76.178, 76.178, 76.098, 76.158, 75.0   ,76.09489425587466 ,(76.23600089361555, 75.95378761813377) ,(76.30655421248599, 75.88323429926334)),
78///         (76.153, 76.153, 75.984, 76.034, 141.0  ,76.0890033076075  ,(76.22155470994076, 75.95645190527424) ,(76.28783041110741, 75.89017620410759)),
79///         (76.092, 76.092, 75.903, 75.929, 205.0  ,76.06792505995203 ,(76.21690062084983, 75.91894949905424) ,(76.29138840129872, 75.84446171860534)),
80///         (76.017, 76.017, 75.812, 75.958, 204.0  ,76.04638956433638 ,(76.21628813403485, 75.8764909946379)  ,(76.30123741888409, 75.79154170978867)),
81///         (76.012, 76.012, 75.922, 75.937, 107.0  ,76.03966807214805 ,(76.20971995401032, 75.86961619028577) ,(76.29474589494147, 75.78459024935462)),
82///         (76.049, 76.049, 75.943, 75.977, 122.0  ,76.03571974110032 ,(76.20113288848688, 75.87030659371376) ,(76.28383946218017, 75.78760002002048)),
83///         (76.069, 76.069, 75.938, 76.048, 82.0   ,76.03484347469781 ,(76.19621376886145, 75.87347318053416) ,(76.27689891594328, 75.79278803345234)),
84///         (76.117, 76.117, 75.997, 76.068, 148.0  ,76.03699661971831 ,(76.19215131179875, 75.88184192763786) ,(76.26972865783898, 75.80426458159764)),
85///         (76.167, 76.167, 76.027, 76.093, 200.0  ,76.04293789029535 ,(76.19422672735257, 75.89164905323813) ,(76.2698711458812, 75.8160046347095)),
86///         (76.109, 76.109, 76.048, 76.104, 123.0  ,76.0455211312361  ,(76.19376091244948, 75.89728135002272) ,(76.26788080305617, 75.82316145941603)),
87///     ];
88///     let mut indicator = VolumeWeightedAveragePrice::new();
89///
90///     for (open, high, low, close, volume, vwap, (vwap_std_2_up, vwap_std_2_down), (vwap_std_3_up,vwap_std_3_down)) in data {
91///         let di = DataItem::builder()
92///             .high(high)
93///             .low(low)
94///             .close(close)
95///             .open(open)
96///             .volume(volume)
97///             .build().unwrap();
98///
99///         assert_approx_eq!(indicator.next(&di), vwap, 0.01);
100///         assert_approx_eq!(indicator.std_dev(2.0, VolumeWeightedAveragePriceBands::Up), vwap_std_2_up, 0.01);
101///         assert_approx_eq!(indicator.std_dev(2.0, VolumeWeightedAveragePriceBands::Down), vwap_std_2_down, 0.01);
102///         assert_approx_eq!(indicator.std_dev(3.0, VolumeWeightedAveragePriceBands::Up), vwap_std_3_up, 0.01);
103///         assert_approx_eq!(indicator.std_dev(3.0, VolumeWeightedAveragePriceBands::Down), vwap_std_3_down, 0.01);
104///     }
105///     
106/// }
107/// ```
108
109#[derive(Debug)]
110pub enum VolumeWeightedAveragePriceBands {
111    Up,
112    Down,
113}
114
115#[doc(alias = "VWAP")]
116#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
117#[derive(Debug, Clone)]
118pub struct VolumeWeightedAveragePrice {
119    cumulative_total: f64,
120    cumulative_volume: f64,
121    cumulative_v2: f64,
122    vwap: f64,
123    std_dev: f64,
124}
125
126impl VolumeWeightedAveragePrice {
127    pub fn new() -> Self {
128        Self {
129            cumulative_total: 0.0,
130            cumulative_volume: 0.0,
131            cumulative_v2: 0.0,
132            vwap: 0.0,
133            std_dev: 0.0,
134        }
135    }
136
137    pub fn std_dev(&self, offset: f64, band_direction: VolumeWeightedAveragePriceBands) -> f64 {
138        match band_direction {
139            VolumeWeightedAveragePriceBands::Up => self.vwap + offset * self.std_dev,
140            VolumeWeightedAveragePriceBands::Down => self.vwap - offset * self.std_dev,
141        }
142    }
143}
144
145impl<T: High + Low + Close + Volume> Next<&T> for VolumeWeightedAveragePrice {
146    type Output = f64;
147
148    fn next(&mut self, d: &T) -> Self::Output {
149        let typical_price = (d.high() + d.low() + d.close()) / 3.0;
150
151        self.cumulative_volume = d.volume() + self.cumulative_volume;
152
153        self.cumulative_total = (typical_price * d.volume()) + self.cumulative_total;
154        self.vwap = self.cumulative_total / self.cumulative_volume;
155
156        self.cumulative_v2 = (d.volume() * typical_price * typical_price) + self.cumulative_v2;
157
158        let val = (self.cumulative_v2 / self.cumulative_volume) - self.vwap * self.vwap;
159
160        #[cfg(feature = "std")]
161        {
162            self.std_dev = val.max(0.0).sqrt();
163        }
164        #[cfg(not(feature = "std"))]
165        {
166            self.std_dev = sqrt(val.max(0.0));
167        }
168
169        self.vwap
170    }
171}
172
173impl Reset for VolumeWeightedAveragePrice {
174    fn reset(&mut self) {
175        self.cumulative_total = 0.0;
176        self.cumulative_volume = 0.0;
177        self.cumulative_v2 = 0.0;
178        self.vwap = 0.0;
179        self.std_dev = 0.0;
180    }
181}
182
183impl Default for VolumeWeightedAveragePrice {
184    fn default() -> Self {
185        Self::new()
186    }
187}
188
189impl fmt::Display for VolumeWeightedAveragePrice {
190    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
191        write!(f, "VWAP()")
192    }
193}
194
195#[cfg(test)]
196mod tests {
197    use super::*;
198    use crate::DataItem;
199    use alloc::format;
200    use assert_approx_eq::assert_approx_eq;
201    use VolumeWeightedAveragePriceBands::*;
202
203    fn generate_bar(record: (f64, f64, f64, f64, f64)) -> DataItem {
204        let (open, high, low, close, volume): (f64, f64, f64, f64, f64) = record;
205        // open doesn't matter in our context
206        DataItem::builder()
207            .open(open)
208            .high(high)
209            .low(low)
210            .close(close)
211            .volume(volume)
212            .build()
213            .unwrap()
214    }
215
216    #[test]
217    fn test_next() {
218        let data = vec![
219            // open, high, low, close, volume, vwap
220            (150.39, 150.39, 150.22, 150.31, 380.0, 150.31),
221            (150.47, 150.47, 150.38, 150.41, 5270.0, 150.41),
222            (150.49, 150.49, 150.33, 150.46, 990.0, 150.41),
223            (150.63, 150.63, 150.44, 150.61, 1031.0, 150.43),
224            (151.10, 151.10, 150.67, 151.01, 2675.0, 150.56),
225            (151.30, 151.30, 150.77, 150.80, 3334.0, 150.66),
226            (150.95, 150.95, 150.78, 150.93, 430.0, 150.66),
227            (151.12, 151.12, 150.80, 151.10, 220.0, 150.67),
228            (151.27, 151.27, 151.01, 151.25, 900.0, 150.70),
229            (151.35, 151.35, 151.26, 151.33, 4088.0, 150.83),
230            (151.52, 151.52, 151.32, 151.51, 650.0, 150.85),
231            (151.69, 151.69, 151.49, 151.67, 1582.0, 150.91),
232            (152.03, 152.03, 151.66, 151.80, 1892.0, 150.98),
233            (151.90, 151.90, 151.75, 151.88, 2200.0, 151.05),
234            (152.15, 152.15, 151.86, 152.10, 3043.0, 151.16),
235            (152.43, 152.43, 152.03, 152.33, 675.0, 151.18),
236            (152.57, 152.57, 152.25, 152.50, 1243.0, 151.24)
237        ];
238        let mut indicator = VolumeWeightedAveragePrice::new();
239        for (open, high, low, close, volume, vwap) in data {
240            let di = generate_bar((open, high, low, close, volume));
241            assert_approx_eq!(indicator.next(&di), vwap, 0.01);
242        }
243    }
244
245    #[test]
246    fn test_next_std_dev() {
247        let mut indicator = VolumeWeightedAveragePrice::new();
248
249        let data = vec![
250            //open  ,high   ,low     ,close  ,volume,vwap              ,(upper, lower)                         ,(upper, lower)
251            (76.529, 76.529, 76.529, 76.529, 1.0, 76.529, (76.529, 76.529), (76.529, 76.529)),
252            (76.073, 76.073, 76.043, 76.073, 121.0, 76.06681967213113, (76.15085245902783, 75.98278688523443), (76.19286885247618, 75.94077049178608)),
253            (76.323, 76.323, 76.053, 76.193, 181.0, 76.14020352035202, (76.27197010203601, 76.00843693866803), (76.33785339287802, 75.94255364782602)),
254            (76.208, 76.208, 75.918, 75.988, 146.0, 76.1069703043801, (76.25148729829992, 75.96245331046028), (76.32374579525984, 75.89019481350036)),
255            (76.088, 76.088, 75.883, 76.058, 149.0, 76.08272575250835, (76.23361138086482, 75.93184012415189), (76.30905419504305, 75.85639730997366)),
256            (76.183, 76.183, 76.063, 76.153, 93.0, 76.08949204052098, (76.23399096258677, 75.94499311845519), (76.30624042361966, 75.8727436574223)),
257            (76.178, 76.178, 76.098, 76.158, 75.0, 76.09489425587466, (76.23600089361555, 75.95378761813377), (76.30655421248599, 75.88323429926334)),
258            (76.153, 76.153, 75.984, 76.034, 141.0, 76.0890033076075, (76.22155470994076, 75.95645190527424), (76.28783041110741, 75.89017620410759)),
259            (76.092, 76.092, 75.903, 75.929, 205.0, 76.06792505995203, (76.21690062084983, 75.91894949905424), (76.29138840129872, 75.84446171860534)),
260            (76.017, 76.017, 75.812, 75.958, 204.0, 76.04638956433638, (76.21628813403485, 75.8764909946379), (76.30123741888409, 75.79154170978867)),
261            (76.012, 76.012, 75.922, 75.937, 107.0, 76.03966807214805, (76.20971995401032, 75.86961619028577), (76.29474589494147, 75.78459024935462)),
262            (76.049, 76.049, 75.943, 75.977, 122.0, 76.03571974110032, (76.20113288848688, 75.87030659371376), (76.28383946218017, 75.78760002002048)),
263            (76.069, 76.069, 75.938, 76.048, 82.0, 76.03484347469781, (76.19621376886145, 75.87347318053416), (76.27689891594328, 75.79278803345234)),
264            (76.117, 76.117, 75.997, 76.068, 148.0, 76.03699661971831, (76.19215131179875, 75.88184192763786), (76.26972865783898, 75.80426458159764)),
265            (76.167, 76.167, 76.027, 76.093, 200.0, 76.04293789029535, (76.19422672735257, 75.89164905323813), (76.2698711458812, 75.8160046347095)),
266            (76.109, 76.109, 76.048, 76.104, 123.0, 76.0455211312361, (76.19376091244948, 75.89728135002272), (76.26788080305617, 75.82316145941603)),
267        ];
268
269        for (open, high, low, close, volume, vwap, (vwap_std_2_up, vwap_std_2_down), (vwap_std_3_up, vwap_std_3_down)) in data {
270            let di = generate_bar((open, high, low, close, volume));
271
272            assert_approx_eq!(indicator.next(&di), vwap, 0.01);
273            assert_approx_eq!(indicator.std_dev(2.0, Up), vwap_std_2_up, 0.01);
274            assert_approx_eq!(indicator.std_dev(2.0, Down), vwap_std_2_down, 0.01);
275            assert_approx_eq!(indicator.std_dev(3.0, Up), vwap_std_3_up, 0.01);
276            assert_approx_eq!(indicator.std_dev(3.0, Down), vwap_std_3_down, 0.01);
277        }
278    }
279
280    #[test]
281    fn test_reset() {
282        let mut vwap = VolumeWeightedAveragePrice::new();
283
284        assert_approx_eq!(
285            vwap.next(&generate_bar((150.39, 150.39, 150.22, 150.31, 380.0))),
286            150.31,
287            0.01
288        );
289        vwap.next(&generate_bar((150.47, 150.47, 150.38, 150.41, 5270.0)));
290        assert_ne!(
291            vwap.next(&generate_bar((150.49, 150.49, 150.33, 150.46, 990.0))),
292            150.31
293        );
294
295        vwap.reset();
296        assert_approx_eq!(
297            vwap.next(&generate_bar((150.39, 150.39, 150.22, 150.31, 380.0))),
298            150.31,
299            0.01
300        );
301    }
302
303    #[test]
304    fn test_default() {
305        VolumeWeightedAveragePrice::default();
306    }
307
308    #[test]
309    fn test_display() {
310        let vwap = VolumeWeightedAveragePrice::new();
311        assert_eq!(format!("{}", vwap), "VWAP()");
312    }
313}