use polars::prelude::*;
use pyo3_polars::derive::polars_expr;
use serde::Deserialize;
use quantwave_core::*;
use quantwave_core::traits::Next;
#[derive(Deserialize)]
struct AutoTuneFilterKwargs {
window: usize,
bandwidth: f64,
}
#[polars_expr(output_type=Float64)]
fn autotune_filter(inputs: &[Series], kwargs: AutoTuneFilterKwargs) -> PolarsResult<Series> {
let s = inputs[0].f64()?;
let mut indicator = AutoTuneFilter::new(kwargs.window, kwargs.bandwidth);
let mut values = Vec::with_capacity(s.len());
for i in 0..s.len() {
let val = s.get(i).unwrap_or(f64::NAN);
values.push(indicator.next(val));
}
Ok(Series::new("autotune".into(), values))
}
#[derive(Deserialize)]
struct TRAdjEMAKwargs {
period: usize,
pds: usize,
mltp: f64,
}
#[polars_expr(output_type=Float64)]
fn tradj_ema(inputs: &[Series], kwargs: TRAdjEMAKwargs) -> PolarsResult<Series> {
let high = inputs[0].f64()?;
let low = inputs[1].f64()?;
let close = inputs[2].f64()?;
let mut indicator = TRAdjEMA::new(kwargs.period, kwargs.pds, kwargs.mltp);
let mut values = Vec::with_capacity(high.len());
for i in 0..high.len() {
let h = high.get(i).unwrap_or(f64::NAN);
let l = low.get(i).unwrap_or(f64::NAN);
let c = close.get(i).unwrap_or(f64::NAN);
values.push(indicator.next((h, l, c)));
}
Ok(Series::new("tradj_ema".into(), values))
}
#[derive(Deserialize)]
struct TEMAKwargs {
period: usize,
}
#[polars_expr(output_type=Float64)]
fn tema(inputs: &[Series], kwargs: TEMAKwargs) -> PolarsResult<Series> {
let s = inputs[0].f64()?;
let mut indicator = TEMA::new(kwargs.period);
let mut values = Vec::with_capacity(s.len());
for i in 0..s.len() {
let val = s.get(i).unwrap_or(0.0);
values.push(indicator.next(val));
}
Ok(Series::new("tema".into(), values))
}
#[derive(Deserialize)]
struct RSMKKwargs {
length: usize,
ema_length: usize,
}
#[polars_expr(output_type=Float64)]
fn rsmk(inputs: &[Series], kwargs: RSMKKwargs) -> PolarsResult<Series> {
let price = inputs[0].f64()?;
let benchmark = inputs[1].f64()?;
let mut indicator = RSMK::new(kwargs.length, kwargs.ema_length);
let mut values = Vec::with_capacity(price.len());
for i in 0..price.len() {
let p = price.get(i).unwrap_or(f64::NAN);
let b = benchmark.get(i).unwrap_or(f64::NAN);
values.push(indicator.next((p, b)));
}
Ok(Series::new("rsmk".into(), values))
}
#[derive(Deserialize)]
struct ExpDevBandsKwargs {
period: usize,
multiplier: f64,
use_sma: bool,
}
pub fn exp_dev_bands_output(_: &[Field]) -> PolarsResult<Field> {
Ok(Field::new(
"exp_dev_bands".into(),
DataType::Struct(vec![
Field::new("upper".into(), DataType::Float64),
Field::new("middle".into(), DataType::Float64),
Field::new("lower".into(), DataType::Float64),
]),
))
}
#[polars_expr(output_type_func=exp_dev_bands_output)]
fn exp_dev_bands(inputs: &[Series], kwargs: ExpDevBandsKwargs) -> PolarsResult<Series> {
let s = inputs[0].f64()?;
let mut indicator = ExpDevBands::new(kwargs.period, kwargs.multiplier, kwargs.use_sma);
let mut upper_vals = Vec::with_capacity(s.len());
let mut mid_vals = Vec::with_capacity(s.len());
let mut lower_vals = Vec::with_capacity(s.len());
for i in 0..s.len() {
let val = s.get(i).unwrap_or(f64::NAN);
let (upper, mid, lower) = indicator.next(val);
upper_vals.push(upper);
mid_vals.push(mid);
lower_vals.push(lower);
}
let s_upper = Series::new("upper".into(), upper_vals);
let s_mid = Series::new("middle".into(), mid_vals);
let s_lower = Series::new("lower".into(), lower_vals);
let out = StructChunked::from_series(
"exp_dev_bands".into(),
s.len(),
[s_upper, s_mid, s_lower].iter(),
)?;
Ok(out.into_series())
}