use super::typprice;
use crate::{KandError, TAFloat};
pub const fn lookback() -> Result<usize, KandError> {
Ok(0)
}
pub fn vwap(
input_high: &[TAFloat],
input_low: &[TAFloat],
input_close: &[TAFloat],
input_volume: &[TAFloat],
output_vwap: &mut [TAFloat],
output_cum_pv: &mut [TAFloat],
output_cum_vol: &mut [TAFloat],
) -> Result<(), KandError> {
let len = input_high.len();
#[cfg(feature = "check")]
{
if len == 0 {
return Err(KandError::InvalidData);
}
if input_low.len() != len
|| input_close.len() != len
|| input_volume.len() != len
|| output_vwap.len() != len
|| output_cum_pv.len() != len
|| output_cum_vol.len() != len
{
return Err(KandError::LengthMismatch);
}
}
#[cfg(feature = "deep-check")]
{
for i in 0..len {
if input_high[i].is_nan()
|| input_low[i].is_nan()
|| input_close[i].is_nan()
|| input_volume[i].is_nan()
{
return Err(KandError::NaNDetected);
}
}
}
let mut cum_pv = 0.0;
let mut cum_vol = 0.0;
for i in 0..len {
let (new_cum_pv, new_cum_vol, vwap) = vwap_inc(
input_high[i],
input_low[i],
input_close[i],
input_volume[i],
cum_pv,
cum_vol,
)?;
cum_pv = new_cum_pv;
cum_vol = new_cum_vol;
output_cum_pv[i] = cum_pv;
output_cum_vol[i] = cum_vol;
output_vwap[i] = vwap;
}
Ok(())
}
pub fn vwap_inc(
high: TAFloat,
low: TAFloat,
close: TAFloat,
volume: TAFloat,
prev_cum_pv: TAFloat,
prev_cum_vol: TAFloat,
) -> Result<(TAFloat, TAFloat, TAFloat), KandError> {
let typ_price = typprice::typprice_inc(high, low, close)?;
let cum_pv = typ_price.mul_add(volume, prev_cum_pv);
let cum_vol = prev_cum_vol + volume;
let vwap = if cum_vol == 0.0 {
0.0
} else {
cum_pv / cum_vol
};
Ok((cum_pv, cum_vol, vwap))
}
#[cfg(test)]
mod tests {
use approx::assert_relative_eq;
use super::*;
#[test]
fn test_vwap_calculation() {
let input_high = vec![
96955.7, 96850.0, 96787.8, 97163.0, 97212.0, 96870.7, 96824.2, 97041.9, 96979.8,
97127.0, 97150.0, 97094.5, 96844.7, 96660.0,
];
let input_low = vec![
96490.7, 96309.5, 96407.1, 96492.8, 96707.0, 96505.0, 96556.2, 96765.8, 96743.4,
96782.4, 96916.4, 96750.1, 96436.1, 96507.3,
];
let input_close = vec![
96708.6, 96497.4, 96495.2, 97094.9, 96715.4, 96635.9, 96786.6, 96889.9, 96828.0,
97062.0, 96965.8, 96844.6, 96612.3, 96531.2,
];
let input_volume = vec![
3746.917, 3260.9, 2899.859, 4050.52, 4249.375, 2782.823, 2384.87, 3234.131, 2350.488,
3032.885, 2050.853, 2505.323, 3741.102, 811.82,
];
let mut output_vwap = vec![0.0; 14];
let mut output_cum_pv = vec![0.0; 14];
let mut output_cum_vol = vec![0.0; 14];
vwap(
&input_high,
&input_low,
&input_close,
&input_volume,
&mut output_vwap,
&mut output_cum_pv,
&mut output_cum_vol,
)
.unwrap();
let expected_values = [
96_718.333_333_333_33,
96_641.074_167_366_7,
96_618.330_105_563_28,
96_704.971_912_915_3,
96_745.385_200_930_96,
96_735.461_637_859_99,
96_734.122_217_709_84,
96_754.185_927_279_93,
96_761.995_006_596_99,
96_783.653_909_970_1,
96_797.333_609_807_04,
96_804.124_320_528_47,
96_788.052_086_747_02,
96_783.669_535_800_8,
];
for (i, expected) in expected_values.iter().enumerate() {
assert_relative_eq!(output_vwap[i], *expected, epsilon = 0.0001);
}
let mut prev_cum_pv = 0.0;
let mut prev_cum_vol = 0.0;
for i in 0..input_high.len() {
let (new_cum_pv, new_cum_vol, vwap) = vwap_inc(
input_high[i],
input_low[i],
input_close[i],
input_volume[i],
prev_cum_pv,
prev_cum_vol,
)
.unwrap();
assert_relative_eq!(vwap, expected_values[i], epsilon = 0.0001);
prev_cum_pv = new_cum_pv;
prev_cum_vol = new_cum_vol;
}
}
}