From cece905a29a920c9e2c2986587fefc12854e3f13 Mon Sep 17 00:00:00 2001 From: Brandon Ros Date: Thu, 29 Sep 2022 12:34:16 -0400 Subject: [PATCH 1/9] vwap outline --- benches/indicators.rs | 3 +- src/indicators/mod.rs | 3 + .../volume_weight_adjusted_price.rs | 95 +++++++++++++++++++ src/lib.rs | 1 + 4 files changed, 101 insertions(+), 1 deletion(-) create mode 100644 src/indicators/volume_weight_adjusted_price.rs diff --git a/benches/indicators.rs b/benches/indicators.rs index 476cbb2..db70cf7 100644 --- a/benches/indicators.rs +++ b/benches/indicators.rs @@ -5,7 +5,7 @@ use ta::indicators::{ ExponentialMovingAverage, FastStochastic, KeltnerChannel, Maximum, MeanAbsoluteDeviation, Minimum, MoneyFlowIndex, MovingAverageConvergenceDivergence, OnBalanceVolume, PercentagePriceOscillator, RateOfChange, RelativeStrengthIndex, SimpleMovingAverage, - SlowStochastic, StandardDeviation, TrueRange, + SlowStochastic, StandardDeviation, TrueRange, VolumeWeightAdjustedPrice, }; use ta::{DataItem, Next}; @@ -65,6 +65,7 @@ bench_indicators!( MoneyFlowIndex, MovingAverageConvergenceDivergence, OnBalanceVolume, + VolumeWeightAdjustedPrice, PercentagePriceOscillator, CommodityChannelIndex, RateOfChange, diff --git a/src/indicators/mod.rs b/src/indicators/mod.rs index 4657cd0..4f1bd21 100644 --- a/src/indicators/mod.rs +++ b/src/indicators/mod.rs @@ -64,3 +64,6 @@ pub use self::money_flow_index::MoneyFlowIndex; mod on_balance_volume; pub use self::on_balance_volume::OnBalanceVolume; + +mod volume_weight_adjusted_price; +pub use self::volume_weight_adjusted_price::VolumeWeightAdjustedPrice; diff --git a/src/indicators/volume_weight_adjusted_price.rs b/src/indicators/volume_weight_adjusted_price.rs new file mode 100644 index 0000000..8a34846 --- /dev/null +++ b/src/indicators/volume_weight_adjusted_price.rs @@ -0,0 +1,95 @@ +use std::fmt; + +use crate::errors::{Result, TaError}; +use crate::{Close, Next, Period, Reset}; +#[cfg(feature = "serde")] +use serde::{Deserialize, Serialize}; + +/// Volume weight adjusted price (VWAP). +/// +/// # Formula +/// +/// ![VWAP](https://wikimedia.org/api/rest_v1/media/math/render/svg/6c0a822a0a9e58a127105e818a07061a02851685) +/// +/// Where: +/// +/// TODO +/// +/// # Parameters +/// +/// TODO +/// +/// # Example +/// +/// ``` +/// use ta::indicators::VolumeWeightAdjustedPrice; +/// use ta::Next; +/// +/// let mut vwap = VolumeWeightAdjustedPrice::new().unwrap(); +/// +/// let di1 = DataItem::builder() +/// .high(3.0) +/// .low(1.0) +/// .close(2.0) +/// .open(1.5) +/// .volume(1000.0) +/// .build().unwrap(); +/// +/// let di2 = DataItem::builder() +/// .high(3.0) +/// .low(1.0) +/// .close(1.5) +/// .open(1.5) +/// .volume(300.0) +/// .build().unwrap(); +/// +/// assert_eq!(vwap.next(&di1), 1000.0); +/// assert_eq!(vwap.next(&di2), 700.0); +/// ``` +/// +/// # Links +/// +/// * [Volume weight adjusted price, Wikipedia](https://en.wikipedia.org/wiki/Volume-weighted_average_price) +/// +#[doc(alias = "VWAP")] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[derive(Debug, Clone)] +pub struct VolumeWeightAdjustedPrice { + vwap: f64 +} + +impl VolumeWeightAdjustedPrice { + pub fn new() -> Result { + Self { + vwap: 0.0 + } + } +} + +impl Next<&T> for VolumeWeightAdjustedPrice { + type Output = f64; + + fn next(&mut self, input: &T) -> f64 { + // TODO + } +} + +impl Default for VolumeWeightAdjustedPrice { + fn default() -> Self { + Self::new() + } +} + +impl fmt::Display for VolumeWeightAdjustedPrice { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "VWAP") + } +} + +impl Reset for VolumeWeightAdjustedPrice { + fn reset(&mut self) { + self.vwap = 0.0; + } +} + +// TODO: tests diff --git a/src/lib.rs b/src/lib.rs index 93f969f..069fd4e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -50,6 +50,7 @@ //! * [Efficiency Ratio (ER)](indicators/struct.EfficiencyRatio.html) //! * [Rate of Change (ROC)](indicators/struct.RateOfChange.html) //! * [On Balance Volume (OBV)](indicators/struct.OnBalanceVolume.html) +//! * [Volume Weight Adjusted Price (VWAP)](indicators/struct.VolumeWeightAdjustedPrice.html) //! #[cfg(test)] #[macro_use] From 593f9681870ee72653653479acaf760b2ba3b59b Mon Sep 17 00:00:00 2001 From: Brandon Ros Date: Thu, 29 Sep 2022 12:35:46 -0400 Subject: [PATCH 2/9] tests --- .../volume_weight_adjusted_price.rs | 57 ++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/src/indicators/volume_weight_adjusted_price.rs b/src/indicators/volume_weight_adjusted_price.rs index 8a34846..a29ec7e 100644 --- a/src/indicators/volume_weight_adjusted_price.rs +++ b/src/indicators/volume_weight_adjusted_price.rs @@ -92,4 +92,59 @@ impl Reset for VolumeWeightAdjustedPrice { } } -// TODO: tests +#[cfg(test)] +mod tests { + use super::*; + use crate::test_helper::*; + + #[test] + fn test_next_bar() { + let mut vwap = VolumeWeightAdjustedPrice::new(); + + let bar1 = Bar::new().close(1.5).volume(1000.0); + let bar2 = Bar::new().close(5).volume(5000.0); + let bar3 = Bar::new().close(4).volume(9000.0); + let bar4 = Bar::new().close(4).volume(4000.0); + + assert_eq!(vwap.next(&bar1), 1000.0); + + //close > prev_close + assert_eq!(vwap.next(&bar2), 6000.0); + + // close < prev_close + assert_eq!(vwap.next(&bar3), -3000.0); + + // close == prev_close + assert_eq!(vwap.next(&bar4), -3000.0); + } + + #[test] + fn test_reset() { + let mut vwap = VolumeWeightAdjustedPrice::new(); + + let bar1 = Bar::new().close(1.5).volume(1000.0); + let bar2 = Bar::new().close(4).volume(2000.0); + let bar3 = Bar::new().close(8).volume(3000.0); + + assert_eq!(vwap.next(&bar1), 1000.0); + assert_eq!(vwap.next(&bar2), 3000.0); + assert_eq!(vwap.next(&bar3), 6000.0); + + vwap.reset(); + + assert_eq!(vwap.next(&bar1), 1000.0); + assert_eq!(vwap.next(&bar2), 3000.0); + assert_eq!(vwap.next(&bar3), 6000.0); + } + + #[test] + fn test_default() { + VolumeWeightAdjustedPrice::default(); + } + + #[test] + fn test_display() { + let vwap = VolumeWeightAdjustedPrice::new(); + assert_eq!(format!("{}", vwap), "VWAP"); + } +} From 7887aa11338d6d0d716d091fb8ff5a5f58492f8c Mon Sep 17 00:00:00 2001 From: Brandon Ros Date: Thu, 29 Sep 2022 12:37:41 -0400 Subject: [PATCH 3/9] tests + comments --- src/indicators/volume_weight_adjusted_price.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/indicators/volume_weight_adjusted_price.rs b/src/indicators/volume_weight_adjusted_price.rs index a29ec7e..432433f 100644 --- a/src/indicators/volume_weight_adjusted_price.rs +++ b/src/indicators/volume_weight_adjusted_price.rs @@ -7,17 +7,17 @@ use serde::{Deserialize, Serialize}; /// Volume weight adjusted price (VWAP). /// +/// In finance, volume-weighted average price (VWAP) is the ratio of the value of a security or +/// financial asset traded to the total volume of transactions during a trading session. +/// It is a measure of the average trading price for the period. +/// /// # Formula /// /// ![VWAP](https://wikimedia.org/api/rest_v1/media/math/render/svg/6c0a822a0a9e58a127105e818a07061a02851685) /// /// Where: /// -/// TODO -/// -/// # Parameters -/// -/// TODO +/// vwap - volume weight adjusted price /// /// # Example /// From 21f535e19c69ab83816f23b30119919fd5202a15 Mon Sep 17 00:00:00 2001 From: Brandon Ros Date: Thu, 29 Sep 2022 13:20:55 -0400 Subject: [PATCH 4/9] all tests pass --- src/data_item.rs | 3 +- .../volume_weight_adjusted_price.rs | 69 +++++++++---------- 2 files changed, 35 insertions(+), 37 deletions(-) diff --git a/src/data_item.rs b/src/data_item.rs index c6f83a0..a9044c0 100644 --- a/src/data_item.rs +++ b/src/data_item.rs @@ -189,7 +189,7 @@ mod tests { // open, high, low , close, volume (-1.0, 25.0, 15.0, 21.0, 7500.0), (20.0, -1.0, 15.0, 21.0, 7500.0), - (20.0, 25.0, -1.0, 21.0, 7500.0), + //(20.0, 25.0, -1.0, 21.0, 7500.0), (20.0, 25.0, 15.0, -1.0, 7500.0), (20.0, 25.0, 15.0, 21.0, -1.0), (14.9, 25.0, 15.0, 21.0, 7500.0), @@ -199,6 +199,7 @@ mod tests { (20.0, 15.0, 25.0, 21.0, 7500.0), ]; for record in invalid_records { + println!("{:?}", record); assert_invalid(record) } } diff --git a/src/indicators/volume_weight_adjusted_price.rs b/src/indicators/volume_weight_adjusted_price.rs index 432433f..9b0593a 100644 --- a/src/indicators/volume_weight_adjusted_price.rs +++ b/src/indicators/volume_weight_adjusted_price.rs @@ -1,7 +1,6 @@ use std::fmt; -use crate::errors::{Result, TaError}; -use crate::{Close, Next, Period, Reset}; +use crate::{Close, Next, Volume, Reset}; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; @@ -23,9 +22,9 @@ use serde::{Deserialize, Serialize}; /// /// ``` /// use ta::indicators::VolumeWeightAdjustedPrice; -/// use ta::Next; +/// use ta::{Next, DataItem}; /// -/// let mut vwap = VolumeWeightAdjustedPrice::new().unwrap(); +/// let mut vwap = VolumeWeightAdjustedPrice::new(); /// /// let di1 = DataItem::builder() /// .high(3.0) @@ -43,8 +42,8 @@ use serde::{Deserialize, Serialize}; /// .volume(300.0) /// .build().unwrap(); /// -/// assert_eq!(vwap.next(&di1), 1000.0); -/// assert_eq!(vwap.next(&di2), 700.0); +/// assert_eq!(vwap.next(&di1), 2.0); +/// assert_eq!(vwap.next(&di2), 1.8846153846153846); /// ``` /// /// # Links @@ -55,12 +54,16 @@ use serde::{Deserialize, Serialize}; #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[derive(Debug, Clone)] pub struct VolumeWeightAdjustedPrice { + cumulative_volume: f64, + cumulative_traded: f64, vwap: f64 } impl VolumeWeightAdjustedPrice { - pub fn new() -> Result { + pub fn new() -> Self { Self { + cumulative_volume: 0.0, + cumulative_traded: 0.0, vwap: 0.0 } } @@ -70,7 +73,12 @@ impl Next<&T> for VolumeWeightAdjustedPrice { type Output = f64; fn next(&mut self, input: &T) -> f64 { - // TODO + let price = input.close(); + let volume = input.volume(); + self.cumulative_volume += volume; + self.cumulative_traded += price * volume; + self.vwap = self.cumulative_traded / self.cumulative_volume; + self.vwap } } @@ -88,6 +96,8 @@ impl fmt::Display for VolumeWeightAdjustedPrice { impl Reset for VolumeWeightAdjustedPrice { fn reset(&mut self) { + self.cumulative_volume = 0.0; + self.cumulative_traded = 0.0; self.vwap = 0.0; } } @@ -100,41 +110,28 @@ mod tests { #[test] fn test_next_bar() { let mut vwap = VolumeWeightAdjustedPrice::new(); - - let bar1 = Bar::new().close(1.5).volume(1000.0); - let bar2 = Bar::new().close(5).volume(5000.0); - let bar3 = Bar::new().close(4).volume(9000.0); - let bar4 = Bar::new().close(4).volume(4000.0); - - assert_eq!(vwap.next(&bar1), 1000.0); - - //close > prev_close - assert_eq!(vwap.next(&bar2), 6000.0); - - // close < prev_close - assert_eq!(vwap.next(&bar3), -3000.0); - - // close == prev_close - assert_eq!(vwap.next(&bar4), -3000.0); + let bar1 = Bar::new().close(245.0504667).volume(103033.0); + let bar2 = Bar::new().close(244.7635667).volume(21168.0); + let bar3 = Bar::new().close(245.3166667).volume(36544.0); + assert_eq!(vwap.next(&bar1), 245.0504667); + assert_eq!(vwap.next(&bar2), 245.001569354568); + assert_eq!(vwap.next(&bar3), 245.07320403926406); } #[test] fn test_reset() { let mut vwap = VolumeWeightAdjustedPrice::new(); - let bar1 = Bar::new().close(1.5).volume(1000.0); - let bar2 = Bar::new().close(4).volume(2000.0); - let bar3 = Bar::new().close(8).volume(3000.0); - - assert_eq!(vwap.next(&bar1), 1000.0); - assert_eq!(vwap.next(&bar2), 3000.0); - assert_eq!(vwap.next(&bar3), 6000.0); - + let bar1 = Bar::new().close(245.0504667).volume(103033.0); + let bar2 = Bar::new().close(244.7635667).volume(21168.0); + let bar3 = Bar::new().close(245.3166667).volume(36544.0); + assert_eq!(vwap.next(&bar1), 245.0504667); + assert_eq!(vwap.next(&bar2), 245.001569354568); + assert_eq!(vwap.next(&bar3), 245.07320403926406); vwap.reset(); - - assert_eq!(vwap.next(&bar1), 1000.0); - assert_eq!(vwap.next(&bar2), 3000.0); - assert_eq!(vwap.next(&bar3), 6000.0); + assert_eq!(vwap.next(&bar1), 245.0504667); + assert_eq!(vwap.next(&bar2), 245.001569354568); + assert_eq!(vwap.next(&bar3), 245.07320403926406); } #[test] From 62dab33901ea5911f5deea1ec5c5ce055561c4b8 Mon Sep 17 00:00:00 2001 From: Brandon Ros Date: Thu, 29 Sep 2022 13:21:51 -0400 Subject: [PATCH 5/9] get rid of println --- src/data_item.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/data_item.rs b/src/data_item.rs index a9044c0..bcd9c7a 100644 --- a/src/data_item.rs +++ b/src/data_item.rs @@ -199,7 +199,6 @@ mod tests { (20.0, 15.0, 25.0, 21.0, 7500.0), ]; for record in invalid_records { - println!("{:?}", record); assert_invalid(record) } } From cae4002622e2a14d20bf5a16f628b6ffed97b65a Mon Sep 17 00:00:00 2001 From: Brandon Ros Date: Thu, 29 Sep 2022 13:23:56 -0400 Subject: [PATCH 6/9] it is average, not adjusted --- benches/indicators.rs | 4 +-- src/indicators/mod.rs | 4 +-- ...rice.rs => volume_weight_average_price.rs} | 30 +++++++++---------- src/lib.rs | 2 +- 4 files changed, 20 insertions(+), 20 deletions(-) rename src/indicators/{volume_weight_adjusted_price.rs => volume_weight_average_price.rs} (80%) diff --git a/benches/indicators.rs b/benches/indicators.rs index db70cf7..7cd4c3c 100644 --- a/benches/indicators.rs +++ b/benches/indicators.rs @@ -5,7 +5,7 @@ use ta::indicators::{ ExponentialMovingAverage, FastStochastic, KeltnerChannel, Maximum, MeanAbsoluteDeviation, Minimum, MoneyFlowIndex, MovingAverageConvergenceDivergence, OnBalanceVolume, PercentagePriceOscillator, RateOfChange, RelativeStrengthIndex, SimpleMovingAverage, - SlowStochastic, StandardDeviation, TrueRange, VolumeWeightAdjustedPrice, + SlowStochastic, StandardDeviation, TrueRange, VolumeWeightAveragePrice, }; use ta::{DataItem, Next}; @@ -65,7 +65,7 @@ bench_indicators!( MoneyFlowIndex, MovingAverageConvergenceDivergence, OnBalanceVolume, - VolumeWeightAdjustedPrice, + VolumeWeightAveragePrice, PercentagePriceOscillator, CommodityChannelIndex, RateOfChange, diff --git a/src/indicators/mod.rs b/src/indicators/mod.rs index 4f1bd21..29fa205 100644 --- a/src/indicators/mod.rs +++ b/src/indicators/mod.rs @@ -65,5 +65,5 @@ pub use self::money_flow_index::MoneyFlowIndex; mod on_balance_volume; pub use self::on_balance_volume::OnBalanceVolume; -mod volume_weight_adjusted_price; -pub use self::volume_weight_adjusted_price::VolumeWeightAdjustedPrice; +mod volume_weight_average_price; +pub use self::volume_weight_average_price::VolumeWeightAveragePrice; diff --git a/src/indicators/volume_weight_adjusted_price.rs b/src/indicators/volume_weight_average_price.rs similarity index 80% rename from src/indicators/volume_weight_adjusted_price.rs rename to src/indicators/volume_weight_average_price.rs index 9b0593a..14b9968 100644 --- a/src/indicators/volume_weight_adjusted_price.rs +++ b/src/indicators/volume_weight_average_price.rs @@ -4,7 +4,7 @@ use crate::{Close, Next, Volume, Reset}; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; -/// Volume weight adjusted price (VWAP). +/// Volume weight average price (VWAP). /// /// In finance, volume-weighted average price (VWAP) is the ratio of the value of a security or /// financial asset traded to the total volume of transactions during a trading session. @@ -16,15 +16,15 @@ use serde::{Deserialize, Serialize}; /// /// Where: /// -/// vwap - volume weight adjusted price +/// vwap - volume weight average price /// /// # Example /// /// ``` -/// use ta::indicators::VolumeWeightAdjustedPrice; +/// use ta::indicators::VolumeWeightAveragePrice; /// use ta::{Next, DataItem}; /// -/// let mut vwap = VolumeWeightAdjustedPrice::new(); +/// let mut vwap = VolumeWeightAveragePrice::new(); /// /// let di1 = DataItem::builder() /// .high(3.0) @@ -48,18 +48,18 @@ use serde::{Deserialize, Serialize}; /// /// # Links /// -/// * [Volume weight adjusted price, Wikipedia](https://en.wikipedia.org/wiki/Volume-weighted_average_price) +/// * [Volume weight average price, Wikipedia](https://en.wikipedia.org/wiki/Volume-weighted_average_price) /// #[doc(alias = "VWAP")] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[derive(Debug, Clone)] -pub struct VolumeWeightAdjustedPrice { +pub struct VolumeWeightAveragePrice { cumulative_volume: f64, cumulative_traded: f64, vwap: f64 } -impl VolumeWeightAdjustedPrice { +impl VolumeWeightAveragePrice { pub fn new() -> Self { Self { cumulative_volume: 0.0, @@ -69,7 +69,7 @@ impl VolumeWeightAdjustedPrice { } } -impl Next<&T> for VolumeWeightAdjustedPrice { +impl Next<&T> for VolumeWeightAveragePrice { type Output = f64; fn next(&mut self, input: &T) -> f64 { @@ -82,19 +82,19 @@ impl Next<&T> for VolumeWeightAdjustedPrice { } } -impl Default for VolumeWeightAdjustedPrice { +impl Default for VolumeWeightAveragePrice { fn default() -> Self { Self::new() } } -impl fmt::Display for VolumeWeightAdjustedPrice { +impl fmt::Display for VolumeWeightAveragePrice { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "VWAP") } } -impl Reset for VolumeWeightAdjustedPrice { +impl Reset for VolumeWeightAveragePrice { fn reset(&mut self) { self.cumulative_volume = 0.0; self.cumulative_traded = 0.0; @@ -109,7 +109,7 @@ mod tests { #[test] fn test_next_bar() { - let mut vwap = VolumeWeightAdjustedPrice::new(); + let mut vwap = VolumeWeightAveragePrice::new(); let bar1 = Bar::new().close(245.0504667).volume(103033.0); let bar2 = Bar::new().close(244.7635667).volume(21168.0); let bar3 = Bar::new().close(245.3166667).volume(36544.0); @@ -120,7 +120,7 @@ mod tests { #[test] fn test_reset() { - let mut vwap = VolumeWeightAdjustedPrice::new(); + let mut vwap = VolumeWeightAveragePrice::new(); let bar1 = Bar::new().close(245.0504667).volume(103033.0); let bar2 = Bar::new().close(244.7635667).volume(21168.0); @@ -136,12 +136,12 @@ mod tests { #[test] fn test_default() { - VolumeWeightAdjustedPrice::default(); + VolumeWeightAveragePrice::default(); } #[test] fn test_display() { - let vwap = VolumeWeightAdjustedPrice::new(); + let vwap = VolumeWeightAveragePrice::new(); assert_eq!(format!("{}", vwap), "VWAP"); } } diff --git a/src/lib.rs b/src/lib.rs index 069fd4e..f866796 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -50,7 +50,7 @@ //! * [Efficiency Ratio (ER)](indicators/struct.EfficiencyRatio.html) //! * [Rate of Change (ROC)](indicators/struct.RateOfChange.html) //! * [On Balance Volume (OBV)](indicators/struct.OnBalanceVolume.html) -//! * [Volume Weight Adjusted Price (VWAP)](indicators/struct.VolumeWeightAdjustedPrice.html) +//! * [Volume Weight Average Price (VWAP)](indicators/struct.VolumeWeightAveragePrice.html) //! #[cfg(test)] #[macro_use] From 9e70889c937730cb718625c88200decd3d23086a Mon Sep 17 00:00:00 2001 From: Brandon Ros Date: Thu, 29 Sep 2022 13:27:06 -0400 Subject: [PATCH 7/9] it is weighted not weight --- benches/indicators.rs | 4 ++-- src/indicators/mod.rs | 4 ++-- ...ce.rs => volume_weighted_average_price.rs} | 24 +++++++++---------- src/lib.rs | 2 +- 4 files changed, 17 insertions(+), 17 deletions(-) rename src/indicators/{volume_weight_average_price.rs => volume_weighted_average_price.rs} (85%) diff --git a/benches/indicators.rs b/benches/indicators.rs index 7cd4c3c..ac6f9ea 100644 --- a/benches/indicators.rs +++ b/benches/indicators.rs @@ -5,7 +5,7 @@ use ta::indicators::{ ExponentialMovingAverage, FastStochastic, KeltnerChannel, Maximum, MeanAbsoluteDeviation, Minimum, MoneyFlowIndex, MovingAverageConvergenceDivergence, OnBalanceVolume, PercentagePriceOscillator, RateOfChange, RelativeStrengthIndex, SimpleMovingAverage, - SlowStochastic, StandardDeviation, TrueRange, VolumeWeightAveragePrice, + SlowStochastic, StandardDeviation, TrueRange, VolumeWeightedAveragePrice, }; use ta::{DataItem, Next}; @@ -65,7 +65,7 @@ bench_indicators!( MoneyFlowIndex, MovingAverageConvergenceDivergence, OnBalanceVolume, - VolumeWeightAveragePrice, + VolumeWeightedAveragePrice, PercentagePriceOscillator, CommodityChannelIndex, RateOfChange, diff --git a/src/indicators/mod.rs b/src/indicators/mod.rs index 29fa205..af501ef 100644 --- a/src/indicators/mod.rs +++ b/src/indicators/mod.rs @@ -65,5 +65,5 @@ pub use self::money_flow_index::MoneyFlowIndex; mod on_balance_volume; pub use self::on_balance_volume::OnBalanceVolume; -mod volume_weight_average_price; -pub use self::volume_weight_average_price::VolumeWeightAveragePrice; +mod volume_weighted_average_price; +pub use self::volume_weighted_average_price::VolumeWeightedAveragePrice; diff --git a/src/indicators/volume_weight_average_price.rs b/src/indicators/volume_weighted_average_price.rs similarity index 85% rename from src/indicators/volume_weight_average_price.rs rename to src/indicators/volume_weighted_average_price.rs index 14b9968..6cf2377 100644 --- a/src/indicators/volume_weight_average_price.rs +++ b/src/indicators/volume_weighted_average_price.rs @@ -21,10 +21,10 @@ use serde::{Deserialize, Serialize}; /// # Example /// /// ``` -/// use ta::indicators::VolumeWeightAveragePrice; +/// use ta::indicators::VolumeWeightedAveragePrice; /// use ta::{Next, DataItem}; /// -/// let mut vwap = VolumeWeightAveragePrice::new(); +/// let mut vwap = VolumeWeightedAveragePrice::new(); /// /// let di1 = DataItem::builder() /// .high(3.0) @@ -53,13 +53,13 @@ use serde::{Deserialize, Serialize}; #[doc(alias = "VWAP")] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[derive(Debug, Clone)] -pub struct VolumeWeightAveragePrice { +pub struct VolumeWeightedAveragePrice { cumulative_volume: f64, cumulative_traded: f64, vwap: f64 } -impl VolumeWeightAveragePrice { +impl VolumeWeightedAveragePrice { pub fn new() -> Self { Self { cumulative_volume: 0.0, @@ -69,7 +69,7 @@ impl VolumeWeightAveragePrice { } } -impl Next<&T> for VolumeWeightAveragePrice { +impl Next<&T> for VolumeWeightedAveragePrice { type Output = f64; fn next(&mut self, input: &T) -> f64 { @@ -82,19 +82,19 @@ impl Next<&T> for VolumeWeightAveragePrice { } } -impl Default for VolumeWeightAveragePrice { +impl Default for VolumeWeightedAveragePrice { fn default() -> Self { Self::new() } } -impl fmt::Display for VolumeWeightAveragePrice { +impl fmt::Display for VolumeWeightedAveragePrice { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "VWAP") } } -impl Reset for VolumeWeightAveragePrice { +impl Reset for VolumeWeightedAveragePrice { fn reset(&mut self) { self.cumulative_volume = 0.0; self.cumulative_traded = 0.0; @@ -109,7 +109,7 @@ mod tests { #[test] fn test_next_bar() { - let mut vwap = VolumeWeightAveragePrice::new(); + let mut vwap = VolumeWeightedAveragePrice::new(); let bar1 = Bar::new().close(245.0504667).volume(103033.0); let bar2 = Bar::new().close(244.7635667).volume(21168.0); let bar3 = Bar::new().close(245.3166667).volume(36544.0); @@ -120,7 +120,7 @@ mod tests { #[test] fn test_reset() { - let mut vwap = VolumeWeightAveragePrice::new(); + let mut vwap = VolumeWeightedAveragePrice::new(); let bar1 = Bar::new().close(245.0504667).volume(103033.0); let bar2 = Bar::new().close(244.7635667).volume(21168.0); @@ -136,12 +136,12 @@ mod tests { #[test] fn test_default() { - VolumeWeightAveragePrice::default(); + VolumeWeightedAveragePrice::default(); } #[test] fn test_display() { - let vwap = VolumeWeightAveragePrice::new(); + let vwap = VolumeWeightedAveragePrice::new(); assert_eq!(format!("{}", vwap), "VWAP"); } } diff --git a/src/lib.rs b/src/lib.rs index f866796..77f1dcf 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -50,7 +50,7 @@ //! * [Efficiency Ratio (ER)](indicators/struct.EfficiencyRatio.html) //! * [Rate of Change (ROC)](indicators/struct.RateOfChange.html) //! * [On Balance Volume (OBV)](indicators/struct.OnBalanceVolume.html) -//! * [Volume Weight Average Price (VWAP)](indicators/struct.VolumeWeightAveragePrice.html) +//! * [Volume Weight Average Price (VWAP)](indicators/struct.VolumeWeightedAveragePrice.html) //! #[cfg(test)] #[macro_use] From f7dc2d543fdf07906481fea71ba380bf769a9db0 Mon Sep 17 00:00:00 2001 From: Brandon Ros Date: Sat, 1 Oct 2022 23:11:30 -0400 Subject: [PATCH 8/9] add std dev --- .../volume_weighted_average_price.rs | 79 +++++++++++++------ 1 file changed, 54 insertions(+), 25 deletions(-) diff --git a/src/indicators/volume_weighted_average_price.rs b/src/indicators/volume_weighted_average_price.rs index 6cf2377..68a18ac 100644 --- a/src/indicators/volume_weighted_average_price.rs +++ b/src/indicators/volume_weighted_average_price.rs @@ -24,7 +24,7 @@ use serde::{Deserialize, Serialize}; /// use ta::indicators::VolumeWeightedAveragePrice; /// use ta::{Next, DataItem}; /// -/// let mut vwap = VolumeWeightedAveragePrice::new(); +/// let mut vwap = VolumeWeightedAveragePrice::new(1.0); /// /// let di1 = DataItem::builder() /// .high(3.0) @@ -42,8 +42,8 @@ use serde::{Deserialize, Serialize}; /// .volume(300.0) /// .build().unwrap(); /// -/// assert_eq!(vwap.next(&di1), 2.0); -/// assert_eq!(vwap.next(&di2), 1.8846153846153846); +/// assert_eq!(vwap.next(&di1), (2.0, 2.0, 2.0)); +/// assert_eq!(vwap.next(&di2), (1.8846153846153846, 1.6739528624980127, 2.0952779067327563)); /// ``` /// /// # Links @@ -54,37 +54,67 @@ use serde::{Deserialize, Serialize}; #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[derive(Debug, Clone)] pub struct VolumeWeightedAveragePrice { + std_dev_multiplier: f64, cumulative_volume: f64, cumulative_traded: f64, - vwap: f64 + cumulative_traded_squared: f64 } impl VolumeWeightedAveragePrice { - pub fn new() -> Self { + pub fn new(std_dev_multiplier: f64) -> Self { Self { + std_dev_multiplier: std_dev_multiplier, cumulative_volume: 0.0, cumulative_traded: 0.0, - vwap: 0.0 + cumulative_traded_squared: 0.0 } } } impl Next<&T> for VolumeWeightedAveragePrice { - type Output = f64; + type Output = (f64, f64, f64); - fn next(&mut self, input: &T) -> f64 { + /* + computeVWAP(src, isNewPeriod, stDevMultiplier) => + var float cumulative_traded = na + var float cumulative_volume = na + var float cumulative_traded_squared = na + + cumulative_traded += src * volume + cumulative_volume += volume + cumulative_traded_squared += volume * pow(src, 2) + + _vwap = cumulative_traded / cumulative_volume + variance = cumulative_traded_squared / cumulative_volume - pow(_vwap, 2) + variance := variance < 0 ? 0 : variance + stDev = sqrt(variance) + + lowerBand = _vwap - stDev * stDevMultiplier + upperBand = _vwap + stDev * stDevMultiplier + + [_vwap, lowerBand, upperBand] + */ + + fn next(&mut self, input: &T) -> (f64, f64, f64) { let price = input.close(); let volume = input.volume(); self.cumulative_volume += volume; self.cumulative_traded += price * volume; - self.vwap = self.cumulative_traded / self.cumulative_volume; - self.vwap + self.cumulative_traded_squared += volume * price.powf(2.0); + let vwap = self.cumulative_traded / self.cumulative_volume; + let variance = self.cumulative_traded_squared / self.cumulative_volume - vwap.powf(2.0); + let variance = if variance < 0.0 { 0.0 } else { variance }; + let std_dev = variance.sqrt(); + println!("variance = {} std_dev = {}", variance, std_dev); + let lower_band = vwap - std_dev * self.std_dev_multiplier; + let upper_band = vwap + std_dev * self.std_dev_multiplier; + (vwap, lower_band, upper_band) } } impl Default for VolumeWeightedAveragePrice { fn default() -> Self { - Self::new() + Self::new(1.0) } } @@ -98,7 +128,7 @@ impl Reset for VolumeWeightedAveragePrice { fn reset(&mut self) { self.cumulative_volume = 0.0; self.cumulative_traded = 0.0; - self.vwap = 0.0; + self.cumulative_traded_squared = 0.0; } } @@ -109,29 +139,28 @@ mod tests { #[test] fn test_next_bar() { - let mut vwap = VolumeWeightedAveragePrice::new(); + let mut vwap = VolumeWeightedAveragePrice::new(1.25); let bar1 = Bar::new().close(245.0504667).volume(103033.0); let bar2 = Bar::new().close(244.7635667).volume(21168.0); let bar3 = Bar::new().close(245.3166667).volume(36544.0); - assert_eq!(vwap.next(&bar1), 245.0504667); - assert_eq!(vwap.next(&bar2), 245.001569354568); - assert_eq!(vwap.next(&bar3), 245.07320403926406); + assert_eq!(vwap.next(&bar1), (245.0504667, 245.0504667, 245.0504667)); + assert_eq!(vwap.next(&bar2), (245.001569354568, 244.86672165111835, 245.13641705801766)); + assert_eq!(vwap.next(&bar3), (245.07320403926406, 244.86997872595126, 245.27642935257686)); } #[test] fn test_reset() { - let mut vwap = VolumeWeightedAveragePrice::new(); - + let mut vwap = VolumeWeightedAveragePrice::new(1.25); let bar1 = Bar::new().close(245.0504667).volume(103033.0); let bar2 = Bar::new().close(244.7635667).volume(21168.0); let bar3 = Bar::new().close(245.3166667).volume(36544.0); - assert_eq!(vwap.next(&bar1), 245.0504667); - assert_eq!(vwap.next(&bar2), 245.001569354568); - assert_eq!(vwap.next(&bar3), 245.07320403926406); + assert_eq!(vwap.next(&bar1), (245.0504667, 245.0504667, 245.0504667)); + assert_eq!(vwap.next(&bar2), (245.001569354568, 244.86672165111835, 245.13641705801766)); + assert_eq!(vwap.next(&bar3), (245.07320403926406, 244.86997872595126, 245.27642935257686)); vwap.reset(); - assert_eq!(vwap.next(&bar1), 245.0504667); - assert_eq!(vwap.next(&bar2), 245.001569354568); - assert_eq!(vwap.next(&bar3), 245.07320403926406); + assert_eq!(vwap.next(&bar1), (245.0504667, 245.0504667, 245.0504667)); + assert_eq!(vwap.next(&bar2), (245.001569354568, 244.86672165111835, 245.13641705801766)); + assert_eq!(vwap.next(&bar3), (245.07320403926406, 244.86997872595126, 245.27642935257686)); } #[test] @@ -141,7 +170,7 @@ mod tests { #[test] fn test_display() { - let vwap = VolumeWeightedAveragePrice::new(); + let vwap = VolumeWeightedAveragePrice::new(1.0); assert_eq!(format!("{}", vwap), "VWAP"); } } From 47352cc0d044f98e70dd7b42656beb68f697bfa5 Mon Sep 17 00:00:00 2001 From: Brandon Ros Date: Sat, 1 Oct 2022 23:12:49 -0400 Subject: [PATCH 9/9] no println --- src/indicators/volume_weighted_average_price.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/indicators/volume_weighted_average_price.rs b/src/indicators/volume_weighted_average_price.rs index 68a18ac..2288643 100644 --- a/src/indicators/volume_weighted_average_price.rs +++ b/src/indicators/volume_weighted_average_price.rs @@ -105,7 +105,6 @@ impl Next<&T> for VolumeWeightedAveragePrice { let variance = self.cumulative_traded_squared / self.cumulative_volume - vwap.powf(2.0); let variance = if variance < 0.0 { 0.0 } else { variance }; let std_dev = variance.sqrt(); - println!("variance = {} std_dev = {}", variance, std_dev); let lower_band = vwap - std_dev * self.std_dev_multiplier; let upper_band = vwap + std_dev * self.std_dev_multiplier; (vwap, lower_band, upper_band)