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#[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 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 (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 (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}