use polars::prelude::*;
pub fn calculate_eom(
df: &DataFrame,
high_col: &str,
low_col: &str,
volume_col: &str,
period: usize,
) -> PolarsResult<Series> {
let high = df.column(high_col)?.f64()?;
let low = df.column(low_col)?.f64()?;
let volume = df.column(volume_col)?.f64()?;
let len = df.height();
let mut eom = vec![f64::NAN; len];
for (i, value) in eom.iter_mut().enumerate().take(len).skip(1) {
let distance = ((high.get(i).unwrap_or(f64::NAN) + low.get(i).unwrap_or(f64::NAN)) / 2.0)
- ((high.get(i - 1).unwrap_or(f64::NAN) + low.get(i - 1).unwrap_or(f64::NAN)) / 2.0);
let box_ratio = if (volume.get(i).unwrap_or(f64::NAN) != 0.0)
&& ((high.get(i).unwrap_or(f64::NAN) - low.get(i).unwrap_or(f64::NAN)) != 0.0)
{
volume.get(i).unwrap_or(f64::NAN)
/ (high.get(i).unwrap_or(f64::NAN) - low.get(i).unwrap_or(f64::NAN))
} else {
f64::NAN
};
*value = if !box_ratio.is_nan() && box_ratio != 0.0 {
distance / box_ratio
} else {
f64::NAN
};
}
let mut eom_sma = vec![f64::NAN; len];
for i in 0..len {
if i + 1 >= period {
let sum: f64 = eom[(i + 1 - period)..=i]
.iter()
.filter(|x| !x.is_nan())
.sum();
let count = eom[(i + 1 - period)..=i]
.iter()
.filter(|x| !x.is_nan())
.count();
if count > 0 {
eom_sma[i] = sum / count as f64;
}
}
}
Ok(Series::new("eom".into(), eom_sma))
}