use crate::core::{check_eq_len, rolling_mean};
use crate::error::{TaError, check_period};
use crate::indicator::indicator;
indicator! {
fn avgprice(high: &[f64], low: &[f64], close: &[f64], open: &[f64]) -> Vec<f64> with avgprice_with_output init zero;
}
pub fn avgprice_with_output(
high: &[f64],
low: &[f64],
close: &[f64],
open: &[f64],
out: &mut [f64],
) -> Result<(), TaError> {
check_eq_len(&[high, low, close, open], "avgprice")?;
if out.len() != high.len() {
return Err(TaError::BadParam(
"avgprice_with_output: out length must equal high length".into(),
));
}
let n = high.len();
for i in 0..n {
out[i] = (high[i] + low[i] + close[i] + open[i]) / 4.0;
}
Ok(())
}
indicator! {
fn medprice(high: &[f64], low: &[f64]) -> Vec<f64> with medprice_with_output init zero;
}
pub fn medprice_with_output(high: &[f64], low: &[f64], out: &mut [f64]) -> Result<(), TaError> {
check_eq_len(&[high, low], "medprice")?;
if out.len() != high.len() {
return Err(TaError::BadParam(
"medprice_with_output: out length must equal high length".into(),
));
}
let n = high.len();
for i in 0..n {
out[i] = (high[i] + low[i]) / 2.0;
}
Ok(())
}
indicator! {
fn typprice(high: &[f64], low: &[f64], close: &[f64]) -> Vec<f64> with typprice_with_output init zero;
}
pub fn typprice_with_output(
high: &[f64],
low: &[f64],
close: &[f64],
out: &mut [f64],
) -> Result<(), TaError> {
check_eq_len(&[high, low, close], "typprice")?;
if out.len() != high.len() {
return Err(TaError::BadParam(
"typprice_with_output: out length must equal high length".into(),
));
}
let n = high.len();
for i in 0..n {
out[i] = (high[i] + low[i] + close[i]) / 3.0;
}
Ok(())
}
indicator! {
fn wclprice(high: &[f64], low: &[f64], close: &[f64]) -> Vec<f64> with wclprice_with_output init zero;
}
pub fn wclprice_with_output(
high: &[f64],
low: &[f64],
close: &[f64],
out: &mut [f64],
) -> Result<(), TaError> {
check_eq_len(&[high, low, close], "wclprice")?;
if out.len() != high.len() {
return Err(TaError::BadParam(
"wclprice_with_output: out length must equal high length".into(),
));
}
let n = high.len();
for i in 0..n {
out[i] = (high[i] + low[i] + 2.0 * close[i]) / 4.0;
}
Ok(())
}
indicator! {
fn avgdev(values: &[f64], time_period: usize) -> Vec<f64> with avgdev_with_output
default avgdev_default(values: &[f64]) => (14)
;
}
pub fn avgdev_with_output(
values: &[f64],
time_period: usize,
out: &mut [f64],
) -> Result<(), TaError> {
check_period(time_period)?;
if out.len() != values.len() {
return Err(TaError::BadParam(
"avgdev_with_output: out length must equal values length".into(),
));
}
let n = values.len();
if n < time_period {
return Ok(());
}
let mean = rolling_mean(values, time_period);
let p = time_period as f64;
for i in (time_period - 1)..n {
let m = mean[i];
let mut s = 0.0_f64;
for j in 0..time_period {
s += (values[i - j] - m).abs();
}
out[i] = s / p;
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn avgprice_basic() {
let o = [1.0, 2.0];
let h = [2.0, 3.0];
let l = [0.5, 1.0];
let c = [1.5, 2.5];
let out = avgprice(&h, &l, &c, &o).unwrap();
assert!((out[0] - (2.0 + 0.5 + 1.5 + 1.0) / 4.0).abs() < 1e-12);
assert!((out[1] - (3.0 + 1.0 + 2.5 + 2.0) / 4.0).abs() < 1e-12);
}
#[test]
fn medprice_basic() {
let h = [2.0, 4.0];
let l = [1.0, 3.0];
let out = medprice(&h, &l).unwrap();
assert!((out[0] - 1.5).abs() < 1e-12);
assert!((out[1] - 3.5).abs() < 1e-12);
}
#[test]
fn typprice_basic() {
let h = [2.0, 4.0];
let l = [1.0, 3.0];
let c = [1.5, 3.5];
let out = typprice(&h, &l, &c).unwrap();
assert!((out[0] - (2.0 + 1.0 + 1.5) / 3.0).abs() < 1e-12);
}
#[test]
fn wclprice_basic() {
let h = [2.0, 4.0];
let l = [1.0, 3.0];
let c = [1.5, 3.5];
let out = wclprice(&h, &l, &c).unwrap();
assert!((out[0] - (2.0 + 1.0 + 3.0) / 4.0).abs() < 1e-12);
}
}