use polars::prelude::*;
use quantwave_core::traits::Next;
use quantwave_core::*;
pub mod prelude {
pub use crate::{QuantWaveExt, QuantWaveNamespace};
}
pub trait QuantWaveExt {
fn ta(&self) -> QuantWaveNamespace<'_>;
}
pub struct QuantWaveNamespace<'a>(&'a LazyFrame);
impl<'a> QuantWaveNamespace<'a> {
pub fn acos(self, name: &str) -> LazyFrame {
self.math_transform_1_in_1_out::<ACOS>(name, "acos")
}
pub fn asin(self, name: &str) -> LazyFrame {
self.math_transform_1_in_1_out::<ASIN>(name, "asin")
}
pub fn atan(self, name: &str) -> LazyFrame {
self.math_transform_1_in_1_out::<ATAN>(name, "atan")
}
pub fn ceil(self, name: &str) -> LazyFrame {
self.math_transform_1_in_1_out::<CEIL>(name, "ceil")
}
pub fn cos(self, name: &str) -> LazyFrame {
self.math_transform_1_in_1_out::<COS>(name, "cos")
}
pub fn cosh(self, name: &str) -> LazyFrame {
self.math_transform_1_in_1_out::<COSH>(name, "cosh")
}
pub fn exp(self, name: &str) -> LazyFrame {
self.math_transform_1_in_1_out::<EXP>(name, "exp")
}
pub fn floor(self, name: &str) -> LazyFrame {
self.math_transform_1_in_1_out::<FLOOR>(name, "floor")
}
pub fn ln(self, name: &str) -> LazyFrame {
self.math_transform_1_in_1_out::<LN>(name, "ln")
}
pub fn log10(self, name: &str) -> LazyFrame {
self.math_transform_1_in_1_out::<LOG10>(name, "log10")
}
pub fn sin(self, name: &str) -> LazyFrame {
self.math_transform_1_in_1_out::<SIN>(name, "sin")
}
pub fn sinh(self, name: &str) -> LazyFrame {
self.math_transform_1_in_1_out::<SINH>(name, "sinh")
}
pub fn sqrt(self, name: &str) -> LazyFrame {
self.math_transform_1_in_1_out::<SQRT>(name, "sqrt")
}
pub fn tan(self, name: &str) -> LazyFrame {
self.math_transform_1_in_1_out::<TAN>(name, "tan")
}
pub fn tanh(self, name: &str) -> LazyFrame {
self.math_transform_1_in_1_out::<TANH>(name, "tanh")
}
pub fn add(self, in1: &str, in2: &str) -> LazyFrame {
self.math_operator_2_in_1_out::<ADD>(in1, in2, "add")
}
pub fn sub(self, in1: &str, in2: &str) -> LazyFrame {
self.math_operator_2_in_1_out::<SUB>(in1, in2, "sub")
}
pub fn mult(self, in1: &str, in2: &str) -> LazyFrame {
self.math_operator_2_in_1_out::<MULT>(in1, in2, "mult")
}
pub fn div(self, in1: &str, in2: &str) -> LazyFrame {
self.math_operator_2_in_1_out::<DIV>(in1, in2, "div")
}
pub fn max(self, name: &str, period: usize) -> LazyFrame {
self.math_operator_1_in_1_out_period::<MAX>(name, period, "max")
}
pub fn maxindex(self, name: &str, period: usize) -> LazyFrame {
self.math_operator_1_in_1_out_period::<MAXINDEX>(name, period, "maxindex")
}
pub fn min(self, name: &str, period: usize) -> LazyFrame {
self.math_operator_1_in_1_out_period::<MIN>(name, period, "min")
}
pub fn minindex(self, name: &str, period: usize) -> LazyFrame {
self.math_operator_1_in_1_out_period::<MININDEX>(name, period, "minindex")
}
pub fn sum(self, name: &str, period: usize) -> LazyFrame {
self.math_operator_1_in_1_out_period::<SUM>(name, period, "sum")
}
pub fn sma(self, name: &str, period: usize) -> LazyFrame {
self.math_operator_1_in_1_out_period::<SMA>(name, period, "sma")
}
pub fn ema(self, name: &str, period: usize) -> LazyFrame {
self.math_operator_1_in_1_out_period::<EMA>(name, period, "ema")
}
pub fn wma(self, name: &str, period: usize) -> LazyFrame {
self.math_operator_1_in_1_out_period::<WMA>(name, period, "wma")
}
pub fn dema(self, name: &str, period: usize) -> LazyFrame {
self.math_operator_1_in_1_out_period::<DEMA>(name, period, "dema")
}
pub fn trima(self, name: &str, period: usize) -> LazyFrame {
self.math_operator_1_in_1_out_period::<TRIMA>(name, period, "trima")
}
pub fn kama(self, name: &str, period: usize) -> LazyFrame {
self.math_operator_1_in_1_out_period::<KAMA>(name, period, "kama")
}
pub fn midpoint(self, name: &str, period: usize) -> LazyFrame {
self.math_operator_1_in_1_out_period::<MIDPOINT>(name, period, "midpoint")
}
pub fn ht_trendline(self, name: &str) -> LazyFrame {
self.math_transform_1_in_1_out::<HT_TRENDLINE>(name, "ht_trendline")
}
pub fn midprice(self, high: &str, low: &str, period: usize) -> LazyFrame {
self.math_operator_2_in_1_out_period::<MIDPRICE>(high, low, period, "midprice")
}
pub fn rsi(self, name: &str, period: usize) -> LazyFrame {
self.math_operator_1_in_1_out_period::<RSI>(name, period, "rsi")
}
pub fn mom(self, name: &str, period: usize) -> LazyFrame {
self.math_operator_1_in_1_out_period::<MOM>(name, period, "mom")
}
pub fn roc(self, name: &str, period: usize) -> LazyFrame {
self.math_operator_1_in_1_out_period::<ROC>(name, period, "roc")
}
pub fn rocp(self, name: &str, period: usize) -> LazyFrame {
self.math_operator_1_in_1_out_period::<ROCP>(name, period, "rocp")
}
pub fn rocr(self, name: &str, period: usize) -> LazyFrame {
self.math_operator_1_in_1_out_period::<ROCR>(name, period, "rocr")
}
pub fn rocr100(self, name: &str, period: usize) -> LazyFrame {
self.math_operator_1_in_1_out_period::<ROCR100>(name, period, "rocr100")
}
pub fn trix(self, name: &str, period: usize) -> LazyFrame {
self.math_operator_1_in_1_out_period::<TRIX>(name, period, "trix")
}
pub fn cmo(self, name: &str, period: usize) -> LazyFrame {
self.math_operator_1_in_1_out_period::<CMO>(name, period, "cmo")
}
pub fn adx(self, high: &str, low: &str, close: &str, period: usize) -> LazyFrame {
self.ta_3_in_1_out_period::<ADX>(high, low, close, period, "adx")
}
pub fn adxr(self, high: &str, low: &str, close: &str, period: usize) -> LazyFrame {
self.ta_3_in_1_out_period::<ADXR>(high, low, close, period, "adxr")
}
pub fn cci(self, high: &str, low: &str, close: &str, period: usize) -> LazyFrame {
self.ta_3_in_1_out_period::<CCI>(high, low, close, period, "cci")
}
pub fn willr(self, high: &str, low: &str, close: &str, period: usize) -> LazyFrame {
self.ta_3_in_1_out_period::<WILLR>(high, low, close, period, "willr")
}
pub fn dx(self, high: &str, low: &str, close: &str, period: usize) -> LazyFrame {
self.ta_3_in_1_out_period::<DX>(high, low, close, period, "dx")
}
pub fn plus_di(self, high: &str, low: &str, close: &str, period: usize) -> LazyFrame {
self.ta_3_in_1_out_period::<PLUS_DI>(high, low, close, period, "plus_di")
}
pub fn minus_di(self, high: &str, low: &str, close: &str, period: usize) -> LazyFrame {
self.ta_3_in_1_out_period::<MINUS_DI>(high, low, close, period, "minus_di")
}
pub fn ta_atr(self, high: &str, low: &str, close: &str, period: usize) -> LazyFrame {
self.ta_3_in_1_out_period::<TaATR>(high, low, close, period, "ta_atr")
}
pub fn ta_natr(self, high: &str, low: &str, close: &str, period: usize) -> LazyFrame {
self.ta_3_in_1_out_period::<TaNATR>(high, low, close, period, "ta_natr")
}
pub fn ta_trange(self, high: &str, low: &str, close: &str) -> LazyFrame {
self.ta_3_in_1_out_default::<TaTRANGE>(high, low, close, "ta_trange")
}
pub fn obv(self, close: &str, volume: &str) -> LazyFrame {
self.math_operator_2_in_1_out::<OBV>(close, volume, "obv")
}
pub fn ad(self, high: &str, low: &str, close: &str, volume: &str) -> LazyFrame {
self.ta_4_in_1_out_default::<AD>(high, low, close, volume, "ad")
}
pub fn adosc(
self,
high: &str,
low: &str,
close: &str,
volume: &str,
fast: usize,
slow: usize,
) -> LazyFrame {
let high_str = high.to_string();
let low_str = low.to_string();
let close_str = close.to_string();
let volume_str = volume.to_string();
self.0.clone().with_columns([as_struct(vec![
col(&high_str),
col(&low_str),
col(&close_str),
col(&volume_str),
])
.map(
move |s| {
let ca = s.struct_()?;
let s_h = ca.field_by_name(&high_str)?;
let s_l = ca.field_by_name(&low_str)?;
let s_c = ca.field_by_name(&close_str)?;
let s_v = ca.field_by_name(&volume_str)?;
let high = s_h.f64()?;
let low = s_l.f64()?;
let close = s_c.f64()?;
let volume = s_v.f64()?;
let mut indicator = ADOSC::new(fast, slow);
let mut values = Vec::with_capacity(s.len());
for i in 0..s.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);
let v = volume.get(i).unwrap_or(f64::NAN);
values.push(indicator.next((h, l, c, v)));
}
Ok(Some(Column::from(Series::new("adosc".into(), values))))
},
GetOutput::from_type(DataType::Float64),
)
.alias("adosc")])
}
pub fn aroon(self, high: &str, low: &str, period: usize) -> LazyFrame {
let high_str = high.to_string();
let low_str = low.to_string();
self.0
.clone()
.with_columns([as_struct(vec![col(&high_str), col(&low_str)])
.map(
move |s| {
let ca = s.struct_()?;
let s_h = ca.field_by_name(&high_str)?;
let s_l = ca.field_by_name(&low_str)?;
let high = s_h.f64()?;
let low = s_l.f64()?;
let mut indicator = AROON::new(period);
let mut up_vals = Vec::with_capacity(s.len());
let mut down_vals = Vec::with_capacity(s.len());
for i in 0..s.len() {
let h = high.get(i).unwrap_or(f64::NAN);
let l = low.get(i).unwrap_or(f64::NAN);
let (up, down) = indicator.next((h, l));
up_vals.push(up);
down_vals.push(down);
}
let s_up = Series::new("aroon_up".into(), up_vals);
let s_down = Series::new("aroon_down".into(), down_vals);
let struct_series = StructChunked::from_series(
"aroon_result".into(),
s.len(),
[s_up, s_down].iter(),
)?;
Ok(Some(Column::from(struct_series.into_series())))
},
GetOutput::from_type(DataType::Struct(vec![
Field::new("aroon_up".into(), DataType::Float64),
Field::new("aroon_down".into(), DataType::Float64),
])),
)
.alias("aroon")])
}
pub fn stoch(
self,
high: &str,
low: &str,
close: &str,
fastk: usize,
slowk: usize,
slowk_matype: talib::MaType,
slowd: usize,
slowd_matype: talib::MaType,
) -> LazyFrame {
let high_str = high.to_string();
let low_str = low.to_string();
let close_str = close.to_string();
self.0.clone().with_columns([as_struct(vec![
col(&high_str),
col(&low_str),
col(&close_str),
])
.map(
move |s| {
let ca = s.struct_()?;
let s_h = ca.field_by_name(&high_str)?;
let s_l = ca.field_by_name(&low_str)?;
let s_c = ca.field_by_name(&close_str)?;
let high = s_h.f64()?;
let low = s_l.f64()?;
let close = s_c.f64()?;
let mut indicator = STOCH::new(fastk, slowk, slowk_matype, slowd, slowd_matype);
let mut k_vals = Vec::with_capacity(s.len());
let mut d_vals = Vec::with_capacity(s.len());
for i in 0..s.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);
let (k, d) = indicator.next((h, l, c));
k_vals.push(k);
d_vals.push(d);
}
let s_k = Series::new("slowk".into(), k_vals);
let s_d = Series::new("slowd".into(), d_vals);
let struct_series =
StructChunked::from_series("stoch_result".into(), s.len(), [s_k, s_d].iter())?;
Ok(Some(Column::from(struct_series.into_series())))
},
GetOutput::from_type(DataType::Struct(vec![
Field::new("slowk".into(), DataType::Float64),
Field::new("slowd".into(), DataType::Float64),
])),
)
.alias("stoch")])
}
pub fn avgprice(self, open: &str, high: &str, low: &str, close: &str) -> LazyFrame {
self.ta_4_in_1_out_default::<AVGPRICE>(open, high, low, close, "avgprice")
}
pub fn medprice(self, high: &str, low: &str) -> LazyFrame {
self.math_operator_2_in_1_out::<MEDPRICE>(high, low, "medprice")
}
pub fn typprice(self, high: &str, low: &str, close: &str) -> LazyFrame {
self.ta_3_in_1_out_default::<TYPPRICE>(high, low, close, "typprice")
}
pub fn wclprice(self, high: &str, low: &str, close: &str) -> LazyFrame {
self.ta_3_in_1_out_default::<WCLPRICE>(high, low, close, "wclprice")
}
pub fn ht_dcperiod(self, name: &str) -> LazyFrame {
self.math_transform_1_in_1_out::<HT_DCPERIOD>(name, "ht_dcperiod")
}
pub fn ht_dcphase(self, name: &str) -> LazyFrame {
self.math_transform_1_in_1_out::<HT_DCPHASE>(name, "ht_dcphase")
}
pub fn ht_trendmode(self, name: &str) -> LazyFrame {
self.math_transform_1_in_1_out::<HT_TRENDMODE>(name, "ht_trendmode")
}
pub fn ta_stddev(self, name: &str, period: usize, nbdev: f64) -> LazyFrame {
let name_str = name.to_string();
self.0.clone().with_columns([col(&name_str)
.map(
move |s| {
let ca = s.f64()?;
let mut indicator = TaSTDDEV::new(period, nbdev);
let mut values = Vec::with_capacity(s.len());
for i in 0..s.len() {
let val = ca.get(i).unwrap_or(f64::NAN);
values.push(indicator.next(val));
}
Ok(Some(Column::from(Series::new("ta_stddev".into(), values))))
},
GetOutput::from_type(DataType::Float64),
)
.alias("ta_stddev")])
}
pub fn ta_var(self, name: &str, period: usize, nbdev: f64) -> LazyFrame {
let name_str = name.to_string();
self.0.clone().with_columns([col(&name_str)
.map(
move |s| {
let ca = s.f64()?;
let mut indicator = TaVAR::new(period, nbdev);
let mut values = Vec::with_capacity(s.len());
for i in 0..s.len() {
let val = ca.get(i).unwrap_or(f64::NAN);
values.push(indicator.next(val));
}
Ok(Some(Column::from(Series::new("ta_var".into(), values))))
},
GetOutput::from_type(DataType::Float64),
)
.alias("ta_var")])
}
pub fn ta_beta(self, in1: &str, in2: &str, period: usize) -> LazyFrame {
self.math_operator_2_in_1_out_period::<TaBETA>(in1, in2, period, "ta_beta")
}
pub fn ta_correl(self, in1: &str, in2: &str, period: usize) -> LazyFrame {
self.math_operator_2_in_1_out_period::<TaCORREL>(in1, in2, period, "ta_correl")
}
pub fn ta_linearreg(self, name: &str, period: usize) -> LazyFrame {
self.math_operator_1_in_1_out_period::<TaLINEARREG>(name, period, "ta_linearreg")
}
pub fn ta_linearreg_slope(self, name: &str, period: usize) -> LazyFrame {
self.math_operator_1_in_1_out_period::<TaLINEARREG_SLOPE>(
name,
period,
"ta_linearreg_slope",
)
}
pub fn ta_linearreg_intercept(self, name: &str, period: usize) -> LazyFrame {
self.math_operator_1_in_1_out_period::<TaLINEARREG_INTERCEPT>(
name,
period,
"ta_linearreg_intercept",
)
}
pub fn ta_linearreg_angle(self, name: &str, period: usize) -> LazyFrame {
self.math_operator_1_in_1_out_period::<TaLINEARREG_ANGLE>(
name,
period,
"ta_linearreg_angle",
)
}
pub fn ta_tsf(self, name: &str, period: usize) -> LazyFrame {
self.math_operator_1_in_1_out_period::<TaTSF>(name, period, "ta_tsf")
}
pub fn cdl_2crows(self, open: &str, high: &str, low: &str, close: &str) -> LazyFrame {
self.ta_4_in_1_out_default::<CDL2CROWS>(open, high, low, close, "cdl_2crows")
}
pub fn cdl_3blackcrows(self, open: &str, high: &str, low: &str, close: &str) -> LazyFrame {
self.ta_4_in_1_out_default::<CDL3BLACKCROWS>(open, high, low, close, "cdl_3blackcrows")
}
pub fn cdl_3inside(self, open: &str, high: &str, low: &str, close: &str) -> LazyFrame {
self.ta_4_in_1_out_default::<CDL3INSIDE>(open, high, low, close, "cdl_3inside")
}
pub fn cdl_3linestrike(self, open: &str, high: &str, low: &str, close: &str) -> LazyFrame {
self.ta_4_in_1_out_default::<CDL3LINESTRIKE>(open, high, low, close, "cdl_3linestrike")
}
pub fn cdl_3outside(self, open: &str, high: &str, low: &str, close: &str) -> LazyFrame {
self.ta_4_in_1_out_default::<CDL3OUTSIDE>(open, high, low, close, "cdl_3outside")
}
pub fn cdl_3starsinsouth(self, open: &str, high: &str, low: &str, close: &str) -> LazyFrame {
self.ta_4_in_1_out_default::<CDL3STARSINSOUTH>(open, high, low, close, "cdl_3starsinsouth")
}
pub fn cdl_3whitesoldiers(self, open: &str, high: &str, low: &str, close: &str) -> LazyFrame {
self.ta_4_in_1_out_default::<CDL3WHITESOLDIERS>(
open,
high,
low,
close,
"cdl_3whitesoldiers",
)
}
pub fn cdl_abandonedbaby(self, open: &str, high: &str, low: &str, close: &str) -> LazyFrame {
self.ta_4_in_1_out_default::<CDLABANDONEDBABY>(open, high, low, close, "cdl_abandonedbaby")
}
pub fn cdl_advanceblock(self, open: &str, high: &str, low: &str, close: &str) -> LazyFrame {
self.ta_4_in_1_out_default::<CDLADVANCEBLOCK>(open, high, low, close, "cdl_advanceblock")
}
pub fn cdl_belthold(self, open: &str, high: &str, low: &str, close: &str) -> LazyFrame {
self.ta_4_in_1_out_default::<CDLBELTHOLD>(open, high, low, close, "cdl_belthold")
}
pub fn cdl_breakaway(self, open: &str, high: &str, low: &str, close: &str) -> LazyFrame {
self.ta_4_in_1_out_default::<CDLBREAKAWAY>(open, high, low, close, "cdl_breakaway")
}
pub fn cdl_closingmarubozu(self, open: &str, high: &str, low: &str, close: &str) -> LazyFrame {
self.ta_4_in_1_out_default::<CDLCLOSINGMARUBOZU>(
open,
high,
low,
close,
"cdl_closingmarubozu",
)
}
pub fn cdl_concealbabyswall(self, open: &str, high: &str, low: &str, close: &str) -> LazyFrame {
self.ta_4_in_1_out_default::<CDLCONCEALBABYSWALL>(
open,
high,
low,
close,
"cdl_concealbabyswall",
)
}
pub fn cdl_counterattack(self, open: &str, high: &str, low: &str, close: &str) -> LazyFrame {
self.ta_4_in_1_out_default::<CDLCOUNTERATTACK>(open, high, low, close, "cdl_counterattack")
}
pub fn cdl_darkcloudcover(self, open: &str, high: &str, low: &str, close: &str) -> LazyFrame {
self.ta_4_in_1_out_default::<CDLDARKCLOUDCOVER>(
open,
high,
low,
close,
"cdl_darkcloudcover",
)
}
pub fn cdl_doji(self, open: &str, high: &str, low: &str, close: &str) -> LazyFrame {
self.ta_4_in_1_out_default::<CDLDOJI>(open, high, low, close, "cdl_doji")
}
pub fn cdl_dojistar(self, open: &str, high: &str, low: &str, close: &str) -> LazyFrame {
self.ta_4_in_1_out_default::<CDLDOJISTAR>(open, high, low, close, "cdl_dojistar")
}
pub fn cdl_dragonflydoji(self, open: &str, high: &str, low: &str, close: &str) -> LazyFrame {
self.ta_4_in_1_out_default::<CDLDRAGONFLYDOJI>(open, high, low, close, "cdl_dragonflydoji")
}
pub fn cdl_engulfing(self, open: &str, high: &str, low: &str, close: &str) -> LazyFrame {
self.ta_4_in_1_out_default::<CDLENGULFING>(open, high, low, close, "cdl_engulfing")
}
pub fn cdl_eveningdojistar(self, open: &str, high: &str, low: &str, close: &str) -> LazyFrame {
self.ta_4_in_1_out_default::<CDLEVENINGDOJISTAR>(
open,
high,
low,
close,
"cdl_eveningdojistar",
)
}
pub fn cdl_eveningstar(self, open: &str, high: &str, low: &str, close: &str) -> LazyFrame {
self.ta_4_in_1_out_default::<CDLEVENINGSTAR>(open, high, low, close, "cdl_eveningstar")
}
pub fn cdl_gapsidesidewhite(self, open: &str, high: &str, low: &str, close: &str) -> LazyFrame {
self.ta_4_in_1_out_default::<CDLGAPSIDESIDEWHITE>(
open,
high,
low,
close,
"cdl_gapsidesidewhite",
)
}
pub fn cdl_gravestonedoji(self, open: &str, high: &str, low: &str, close: &str) -> LazyFrame {
self.ta_4_in_1_out_default::<CDLGRAVESTONEDOJI>(
open,
high,
low,
close,
"cdl_gravestonedoji",
)
}
pub fn cdl_hammer(self, open: &str, high: &str, low: &str, close: &str) -> LazyFrame {
self.ta_4_in_1_out_default::<CDLHAMMER>(open, high, low, close, "cdl_hammer")
}
pub fn cdl_hangingman(self, open: &str, high: &str, low: &str, close: &str) -> LazyFrame {
self.ta_4_in_1_out_default::<CDLHANGINGMAN>(open, high, low, close, "cdl_hangingman")
}
pub fn cdl_harami(self, open: &str, high: &str, low: &str, close: &str) -> LazyFrame {
self.ta_4_in_1_out_default::<CDLHARAMI>(open, high, low, close, "cdl_harami")
}
pub fn cdl_haramicross(self, open: &str, high: &str, low: &str, close: &str) -> LazyFrame {
self.ta_4_in_1_out_default::<CDLHARAMICROSS>(open, high, low, close, "cdl_haramicross")
}
pub fn cdl_highwave(self, open: &str, high: &str, low: &str, close: &str) -> LazyFrame {
self.ta_4_in_1_out_default::<CDLHIGHWAVE>(open, high, low, close, "cdl_highwave")
}
pub fn cdl_hikkake(self, open: &str, high: &str, low: &str, close: &str) -> LazyFrame {
self.ta_4_in_1_out_default::<CDLHIKKAKE>(open, high, low, close, "cdl_hikkake")
}
pub fn cdl_hikkakemod(self, open: &str, high: &str, low: &str, close: &str) -> LazyFrame {
self.ta_4_in_1_out_default::<CDLHIKKAKEMOD>(open, high, low, close, "cdl_hikkakemod")
}
pub fn cdl_homingpigeon(self, open: &str, high: &str, low: &str, close: &str) -> LazyFrame {
self.ta_4_in_1_out_default::<CDLHOMINGPIGEON>(open, high, low, close, "cdl_homingpigeon")
}
pub fn cdl_identical3crows(self, open: &str, high: &str, low: &str, close: &str) -> LazyFrame {
self.ta_4_in_1_out_default::<CDLIDENTICAL3CROWS>(
open,
high,
low,
close,
"cdl_identical3crows",
)
}
pub fn cdl_inneck(self, open: &str, high: &str, low: &str, close: &str) -> LazyFrame {
self.ta_4_in_1_out_default::<CDLINNECK>(open, high, low, close, "cdl_inneck")
}
pub fn cdl_invertedhammer(self, open: &str, high: &str, low: &str, close: &str) -> LazyFrame {
self.ta_4_in_1_out_default::<CDLINVERTEDHAMMER>(
open,
high,
low,
close,
"cdl_invertedhammer",
)
}
pub fn cdl_kicking(self, open: &str, high: &str, low: &str, close: &str) -> LazyFrame {
self.ta_4_in_1_out_default::<CDLKICKING>(open, high, low, close, "cdl_kicking")
}
pub fn cdl_kickingbylength(self, open: &str, high: &str, low: &str, close: &str) -> LazyFrame {
self.ta_4_in_1_out_default::<CDLKICKINGBYLENGTH>(
open,
high,
low,
close,
"cdl_kickingbylength",
)
}
pub fn cdl_ladderbottom(self, open: &str, high: &str, low: &str, close: &str) -> LazyFrame {
self.ta_4_in_1_out_default::<CDLLADDERBOTTOM>(open, high, low, close, "cdl_ladderbottom")
}
pub fn cdl_longleggeddoji(self, open: &str, high: &str, low: &str, close: &str) -> LazyFrame {
self.ta_4_in_1_out_default::<CDLLONGLEGGEDDOJI>(
open,
high,
low,
close,
"cdl_longleggeddoji",
)
}
pub fn cdl_longline(self, open: &str, high: &str, low: &str, close: &str) -> LazyFrame {
self.ta_4_in_1_out_default::<CDLLONGLINE>(open, high, low, close, "cdl_longline")
}
pub fn cdl_marubozu(self, open: &str, high: &str, low: &str, close: &str) -> LazyFrame {
self.ta_4_in_1_out_default::<CDLMARUBOZU>(open, high, low, close, "cdl_marubozu")
}
pub fn cdl_matchinglow(self, open: &str, high: &str, low: &str, close: &str) -> LazyFrame {
self.ta_4_in_1_out_default::<CDLMATCHINGLOW>(open, high, low, close, "cdl_matchinglow")
}
pub fn cdl_mathold(self, open: &str, high: &str, low: &str, close: &str) -> LazyFrame {
self.ta_4_in_1_out_default::<CDLMATHOLD>(open, high, low, close, "cdl_mathold")
}
pub fn cdl_morningdojistar(self, open: &str, high: &str, low: &str, close: &str) -> LazyFrame {
self.ta_4_in_1_out_default::<CDLMORNINGDOJISTAR>(
open,
high,
low,
close,
"cdl_morningdojistar",
)
}
pub fn cdl_morningstar(self, open: &str, high: &str, low: &str, close: &str) -> LazyFrame {
self.ta_4_in_1_out_default::<CDLMORNINGSTAR>(open, high, low, close, "cdl_morningstar")
}
pub fn cdl_onneck(self, open: &str, high: &str, low: &str, close: &str) -> LazyFrame {
self.ta_4_in_1_out_default::<CDLONNECK>(open, high, low, close, "cdl_onneck")
}
pub fn cdl_piercing(self, open: &str, high: &str, low: &str, close: &str) -> LazyFrame {
self.ta_4_in_1_out_default::<CDLPIERCING>(open, high, low, close, "cdl_piercing")
}
pub fn cdl_rickshawman(self, open: &str, high: &str, low: &str, close: &str) -> LazyFrame {
self.ta_4_in_1_out_default::<CDLRICKSHAWMAN>(open, high, low, close, "cdl_rickshawman")
}
pub fn cdl_risefall3methods(self, open: &str, high: &str, low: &str, close: &str) -> LazyFrame {
self.ta_4_in_1_out_default::<CDLRISEFALL3METHODS>(
open,
high,
low,
close,
"cdl_risefall3methods",
)
}
pub fn cdl_separatinglines(self, open: &str, high: &str, low: &str, close: &str) -> LazyFrame {
self.ta_4_in_1_out_default::<CDLSEPARATINGLINES>(
open,
high,
low,
close,
"cdl_separatinglines",
)
}
pub fn cdl_shootingstar(self, open: &str, high: &str, low: &str, close: &str) -> LazyFrame {
self.ta_4_in_1_out_default::<CDLSHOOTINGSTAR>(open, high, low, close, "cdl_shootingstar")
}
pub fn cdl_shortline(self, open: &str, high: &str, low: &str, close: &str) -> LazyFrame {
self.ta_4_in_1_out_default::<CDLSHORTLINE>(open, high, low, close, "cdl_shortline")
}
pub fn cdl_spinningtop(self, open: &str, high: &str, low: &str, close: &str) -> LazyFrame {
self.ta_4_in_1_out_default::<CDLSPINNINGTOP>(open, high, low, close, "cdl_spinningtop")
}
pub fn cdl_stalledpattern(self, open: &str, high: &str, low: &str, close: &str) -> LazyFrame {
self.ta_4_in_1_out_default::<CDLSTALLEDPATTERN>(
open,
high,
low,
close,
"cdl_stalledpattern",
)
}
pub fn cdl_sticksandwich(self, open: &str, high: &str, low: &str, close: &str) -> LazyFrame {
self.ta_4_in_1_out_default::<CDLSTICKSANDWICH>(open, high, low, close, "cdl_sticksandwich")
}
pub fn cdl_takuri(self, open: &str, high: &str, low: &str, close: &str) -> LazyFrame {
self.ta_4_in_1_out_default::<CDLTAKURI>(open, high, low, close, "cdl_takuri")
}
pub fn cdl_tasukigap(self, open: &str, high: &str, low: &str, close: &str) -> LazyFrame {
self.ta_4_in_1_out_default::<CDLTASUKIGAP>(open, high, low, close, "cdl_tasukigap")
}
pub fn cdl_thrusting(self, open: &str, high: &str, low: &str, close: &str) -> LazyFrame {
self.ta_4_in_1_out_default::<CDLTHRUSTING>(open, high, low, close, "cdl_thrusting")
}
pub fn cdl_tristar(self, open: &str, high: &str, low: &str, close: &str) -> LazyFrame {
self.ta_4_in_1_out_default::<CDLTRISTAR>(open, high, low, close, "cdl_tristar")
}
pub fn cdl_unique3river(self, open: &str, high: &str, low: &str, close: &str) -> LazyFrame {
self.ta_4_in_1_out_default::<CDLUNIQUE3RIVER>(open, high, low, close, "cdl_unique3river")
}
pub fn cdl_upsidegap2crows(self, open: &str, high: &str, low: &str, close: &str) -> LazyFrame {
self.ta_4_in_1_out_default::<CDLUPSIDEGAP2CROWS>(
open,
high,
low,
close,
"cdl_upsidegap2crows",
)
}
pub fn cdl_xsidegap3methods(self, open: &str, high: &str, low: &str, close: &str) -> LazyFrame {
self.ta_4_in_1_out_default::<CDLXSIDEGAP3METHODS>(
open,
high,
low,
close,
"cdl_xsidegap3methods",
)
}
pub fn macd(self, name: &str, fast: usize, slow: usize, signal: usize) -> LazyFrame {
let name_str = name.to_string();
self.0.clone().with_columns([col(&name_str)
.map(
move |s| {
let ca = s.f64()?;
let mut indicator = MACD::new(fast, slow, signal);
let mut macd_vals = Vec::with_capacity(s.len());
let mut signal_vals = Vec::with_capacity(s.len());
let mut hist_vals = Vec::with_capacity(s.len());
for i in 0..s.len() {
let val = ca.get(i).unwrap_or(f64::NAN);
let (m, s_val, h) = indicator.next(val);
macd_vals.push(m);
signal_vals.push(s_val);
hist_vals.push(h);
}
let s_macd = Series::new("macd".into(), macd_vals);
let s_signal = Series::new("macd_signal".into(), signal_vals);
let s_hist = Series::new("macd_hist".into(), hist_vals);
let struct_series = StructChunked::from_series(
"macd_result".into(),
s.len(),
[s_macd, s_signal, s_hist].iter(),
)?;
Ok(Some(Column::from(struct_series.into_series())))
},
GetOutput::from_type(DataType::Struct(vec![
Field::new("macd".into(), DataType::Float64),
Field::new("macd_signal".into(), DataType::Float64),
Field::new("macd_hist".into(), DataType::Float64),
])),
)
.alias("macd")])
}
pub fn bbands(
self,
name: &str,
period: usize,
nbdevup: f64,
nbdevdn: f64,
matype: talib::MaType,
) -> LazyFrame {
let name_str = name.to_string();
self.0.clone().with_columns([col(&name_str)
.map(
move |s| {
let ca = s.f64()?;
let mut indicator = BBANDS::new(period, nbdevup, nbdevdn, matype);
let mut upper_vals = Vec::with_capacity(s.len());
let mut middle_vals = Vec::with_capacity(s.len());
let mut lower_vals = Vec::with_capacity(s.len());
for i in 0..s.len() {
let val = ca.get(i).unwrap_or(f64::NAN);
let (u, m, l) = indicator.next(val);
upper_vals.push(u);
middle_vals.push(m);
lower_vals.push(l);
}
let s_upper = Series::new("upper".into(), upper_vals);
let s_middle = Series::new("middle".into(), middle_vals);
let s_lower = Series::new("lower".into(), lower_vals);
let struct_series = StructChunked::from_series(
"bbands_result".into(),
s.len(),
[s_upper, s_middle, s_lower].iter(),
)?;
Ok(Some(Column::from(struct_series.into_series())))
},
GetOutput::from_type(DataType::Struct(vec![
Field::new("upper".into(), DataType::Float64),
Field::new("middle".into(), DataType::Float64),
Field::new("lower".into(), DataType::Float64),
])),
)
.alias("bbands")])
}
fn ta_3_in_1_out_period<I>(
self,
in1: &str,
in2: &str,
in3: &str,
period: usize,
output_name: &str,
) -> LazyFrame
where
I: Next<(f64, f64, f64), Output = f64> + Send + Sync + 'static,
I: From<usize>,
{
let in1_str = in1.to_string();
let in2_str = in2.to_string();
let in3_str = in3.to_string();
let output_name_str = output_name.to_string();
let output_name_for_closure = output_name_str.clone();
self.0.clone().with_columns(
[as_struct(vec![col(&in1_str), col(&in2_str), col(&in3_str)])
.map(
move |s| {
let ca = s.struct_()?;
let s1 = ca.field_by_name(&in1_str)?;
let s2 = ca.field_by_name(&in2_str)?;
let s3 = ca.field_by_name(&in3_str)?;
let ca1 = s1.f64()?;
let ca2 = s2.f64()?;
let ca3 = s3.f64()?;
let mut indicator = I::from(period);
let mut values = Vec::with_capacity(s.len());
for i in 0..s.len() {
let v1 = ca1.get(i).unwrap_or(f64::NAN);
let v2 = ca2.get(i).unwrap_or(f64::NAN);
let v3 = ca3.get(i).unwrap_or(f64::NAN);
values.push(indicator.next((v1, v2, v3)));
}
Ok(Some(Column::from(Series::new(
output_name_for_closure.clone().into(),
values,
))))
},
GetOutput::from_type(DataType::Float64),
)
.alias(&output_name_str)],
)
}
fn ta_3_in_1_out_default<I>(
self,
in1: &str,
in2: &str,
in3: &str,
output_name: &str,
) -> LazyFrame
where
I: Next<(f64, f64, f64), Output = f64> + Default + Send + Sync + 'static,
{
let in1_str = in1.to_string();
let in2_str = in2.to_string();
let in3_str = in3.to_string();
let output_name_str = output_name.to_string();
let output_name_for_closure = output_name_str.clone();
self.0.clone().with_columns(
[as_struct(vec![col(&in1_str), col(&in2_str), col(&in3_str)])
.map(
move |s| {
let ca = s.struct_()?;
let s1 = ca.field_by_name(&in1_str)?;
let s2 = ca.field_by_name(&in2_str)?;
let s3 = ca.field_by_name(&in3_str)?;
let ca1 = s1.f64()?;
let ca2 = s2.f64()?;
let ca3 = s3.f64()?;
let mut indicator = I::default();
let mut values = Vec::with_capacity(s.len());
for i in 0..s.len() {
let v1 = ca1.get(i).unwrap_or(f64::NAN);
let v2 = ca2.get(i).unwrap_or(f64::NAN);
let v3 = ca3.get(i).unwrap_or(f64::NAN);
values.push(indicator.next((v1, v2, v3)));
}
Ok(Some(Column::from(Series::new(
output_name_for_closure.clone().into(),
values,
))))
},
GetOutput::from_type(DataType::Float64),
)
.alias(&output_name_str)],
)
}
fn ta_4_in_1_out_default<I>(
self,
in1: &str,
in2: &str,
in3: &str,
in4: &str,
output_name: &str,
) -> LazyFrame
where
I: Next<(f64, f64, f64, f64), Output = f64> + Default + Send + Sync + 'static,
{
let in1_str = in1.to_string();
let in2_str = in2.to_string();
let in3_str = in3.to_string();
let in4_str = in4.to_string();
let output_name_str = output_name.to_string();
let output_name_for_closure = output_name_str.clone();
self.0.clone().with_columns([as_struct(vec![
col(&in1_str),
col(&in2_str),
col(&in3_str),
col(&in4_str),
])
.map(
move |s| {
let ca = s.struct_()?;
let s1 = ca.field_by_name(&in1_str)?;
let s2 = ca.field_by_name(&in2_str)?;
let s3 = ca.field_by_name(&in3_str)?;
let s4 = ca.field_by_name(&in4_str)?;
let ca1 = s1.f64()?;
let ca2 = s2.f64()?;
let ca3 = s3.f64()?;
let ca4 = s4.f64()?;
let mut indicator = I::default();
let mut values = Vec::with_capacity(s.len());
for i in 0..s.len() {
let v1 = ca1.get(i).unwrap_or(f64::NAN);
let v2 = ca2.get(i).unwrap_or(f64::NAN);
let v3 = ca3.get(i).unwrap_or(f64::NAN);
let v4 = ca4.get(i).unwrap_or(f64::NAN);
values.push(indicator.next((v1, v2, v3, v4)));
}
Ok(Some(Column::from(Series::new(
output_name_for_closure.clone().into(),
values,
))))
},
GetOutput::from_type(DataType::Float64),
)
.alias(&output_name_str)])
}
fn math_transform_1_in_1_out<I>(self, name: &str, output_name: &str) -> LazyFrame
where
I: Next<f64, Output = f64> + Default + Send + Sync + 'static,
{
let name = name.to_string();
let output_name_str = output_name.to_string();
let output_name_for_closure = output_name_str.clone();
self.0.clone().with_columns([col(&name)
.map(
move |s| {
let ca = s.f64()?;
let mut indicator = I::default();
let mut values = Vec::with_capacity(s.len());
for i in 0..s.len() {
let val = ca.get(i).unwrap_or(f64::NAN);
values.push(indicator.next(val));
}
Ok(Some(Column::from(Series::new(
output_name_for_closure.clone().into(),
values,
))))
},
GetOutput::from_type(DataType::Float64),
)
.alias(&output_name_str)])
}
fn math_operator_2_in_1_out<I>(self, in1: &str, in2: &str, output_name: &str) -> LazyFrame
where
I: Next<(f64, f64), Output = f64> + Default + Send + Sync + 'static,
{
let in1_str = in1.to_string();
let in2_str = in2.to_string();
let output_name_str = output_name.to_string();
let output_name_for_closure = output_name_str.clone();
self.0
.clone()
.with_columns([as_struct(vec![col(&in1_str), col(&in2_str)])
.map(
move |s| {
let ca = s.struct_()?;
let s1 = ca.field_by_name(&in1_str)?;
let s2 = ca.field_by_name(&in2_str)?;
let ca1 = s1.f64()?;
let ca2 = s2.f64()?;
let mut indicator = I::default();
let mut values = Vec::with_capacity(s.len());
for i in 0..s.len() {
let v1 = ca1.get(i).unwrap_or(f64::NAN);
let v2 = ca2.get(i).unwrap_or(f64::NAN);
values.push(indicator.next((v1, v2)));
}
Ok(Some(Column::from(Series::new(
output_name_for_closure.clone().into(),
values,
))))
},
GetOutput::from_type(DataType::Float64),
)
.alias(&output_name_str)])
}
fn math_operator_1_in_1_out_period<I>(
self,
name: &str,
period: usize,
output_name: &str,
) -> LazyFrame
where
I: Next<f64, Output = f64> + Send + Sync + 'static,
I: From<usize>,
{
let name = name.to_string();
let output_name_str = output_name.to_string();
let output_name_for_closure = output_name_str.clone();
self.0.clone().with_columns([col(&name)
.map(
move |s| {
let ca = s.f64()?;
let mut indicator = I::from(period);
let mut values = Vec::with_capacity(s.len());
for i in 0..s.len() {
let val = ca.get(i).unwrap_or(f64::NAN);
values.push(indicator.next(val));
}
Ok(Some(Column::from(Series::new(
output_name_for_closure.clone().into(),
values,
))))
},
GetOutput::from_type(DataType::Float64),
)
.alias(&output_name_str)])
}
fn math_operator_2_in_1_out_period<I>(
self,
in1: &str,
in2: &str,
period: usize,
output_name: &str,
) -> LazyFrame
where
I: Next<(f64, f64), Output = f64> + Send + Sync + 'static,
I: From<usize>,
{
let in1_str = in1.to_string();
let in2_str = in2.to_string();
let output_name_str = output_name.to_string();
let output_name_for_closure = output_name_str.clone();
self.0
.clone()
.with_columns([as_struct(vec![col(&in1_str), col(&in2_str)])
.map(
move |s| {
let ca = s.struct_()?;
let s1 = ca.field_by_name(&in1_str)?;
let s2 = ca.field_by_name(&in2_str)?;
let ca1 = s1.f64()?;
let ca2 = s2.f64()?;
let mut indicator = I::from(period);
let mut values = Vec::with_capacity(s.len());
for i in 0..s.len() {
let v1 = ca1.get(i).unwrap_or(f64::NAN);
let v2 = ca2.get(i).unwrap_or(f64::NAN);
values.push(indicator.next((v1, v2)));
}
Ok(Some(Column::from(Series::new(
output_name_for_closure.clone().into(),
values,
))))
},
GetOutput::from_type(DataType::Float64),
)
.alias(&output_name_str)])
}
pub fn supertrend(self, period: usize, multiplier: f64) -> LazyFrame {
self.0
.clone()
.with_columns([as_struct(vec![col("high"), col("low"), col("close")])
.map(
move |s| {
let ca = s.struct_()?;
let s_high = ca.field_by_name("high")?;
let s_low = ca.field_by_name("low")?;
let s_close = ca.field_by_name("close")?;
let high = s_high.f64()?;
let low = s_low.f64()?;
let close = s_close.f64()?;
let mut st = SuperTrend::new(period, multiplier);
let mut values = Vec::with_capacity(s.len());
let mut directions = Vec::with_capacity(s.len());
for i in 0..s.len() {
let h = high.get(i).unwrap_or(0.0);
let l = low.get(i).unwrap_or(0.0);
let c = close.get(i).unwrap_or(0.0);
let (val, dir) = st.next((h, l, c));
values.push(val);
directions.push(dir as f64);
}
let st_series = Series::new("supertrend".into(), values);
let dir_series = Series::new("supertrend_direction".into(), directions);
let out = StructChunked::from_series(
"supertrend_output".into(),
s.len(),
[st_series, dir_series].iter(),
)?;
Ok(Some(Column::from(out.into_series())))
},
GetOutput::from_type(DataType::Struct(vec![
Field::new("supertrend".into(), DataType::Float64),
Field::new("supertrend_direction".into(), DataType::Float64),
])),
)
.alias("supertrend_data")])
}
pub fn anchored_vwap(self, price: &str, volume: &str, anchor: &str) -> LazyFrame {
let price = price.to_string();
let volume = volume.to_string();
let anchor = anchor.to_string();
self.0
.clone()
.with_columns([as_struct(vec![col(&price), col(&volume), col(&anchor)])
.map(
move |s| {
let ca = s.struct_()?;
let s_price = ca.field_by_name(&price)?;
let s_volume = ca.field_by_name(&volume)?;
let s_anchor = ca.field_by_name(&anchor)?;
let price = s_price.f64()?;
let volume = s_volume.f64()?;
let anchor = s_anchor.bool()?;
let mut avwap = quantwave_core::AnchoredVWAP::new();
let mut values = Vec::with_capacity(s.len());
for i in 0..s.len() {
let p = price.get(i).unwrap_or(0.0);
let v = volume.get(i).unwrap_or(0.0);
let a = anchor.get(i).unwrap_or(false);
values.push(avwap.next((p, v, a)));
}
Ok(Some(Column::from(Series::new(
"anchored_vwap".into(),
values,
))))
},
GetOutput::from_type(DataType::Float64),
)
.alias("avwap")])
}
pub fn hma(self, name: &str, period: usize) -> LazyFrame {
let name = name.to_string();
self.0.clone().with_columns([col(&name)
.map(
move |s| {
let ca = s.f64()?;
let mut hma = quantwave_core::HMA::new(period);
let mut values = Vec::with_capacity(s.len());
for i in 0..s.len() {
let val = ca.get(i).unwrap_or(0.0);
values.push(hma.next(val));
}
Ok(Some(Column::from(Series::new("hma".into(), values))))
},
GetOutput::from_type(DataType::Float64),
)
.alias("hma")])
}
pub fn keltner_channels(
self,
high: &str,
low: &str,
close: &str,
ema_period: usize,
atr_period: usize,
multiplier: f64,
) -> LazyFrame {
let high = high.to_string();
let low = low.to_string();
let close = close.to_string();
self.0
.clone()
.with_columns([as_struct(vec![col(&high), col(&low), col(&close)])
.map(
move |s| {
let ca = s.struct_()?;
let s_high = ca.field_by_name(&high)?;
let s_low = ca.field_by_name(&low)?;
let s_close = ca.field_by_name(&close)?;
let high = s_high.f64()?;
let low = s_low.f64()?;
let close = s_close.f64()?;
let mut kc = quantwave_core::KeltnerChannels::new(
ema_period, atr_period, multiplier,
);
let mut uppers = Vec::with_capacity(s.len());
let mut middles = Vec::with_capacity(s.len());
let mut lowers = Vec::with_capacity(s.len());
for i in 0..s.len() {
let h = high.get(i).unwrap_or(0.0);
let l = low.get(i).unwrap_or(0.0);
let c = close.get(i).unwrap_or(0.0);
let (upper, middle, lower) = kc.next((h, l, c));
uppers.push(upper);
middles.push(middle);
lowers.push(lower);
}
let upper_series = Series::new("upper".into(), uppers);
let middle_series = Series::new("middle".into(), middles);
let lower_series = Series::new("lower".into(), lowers);
let out = StructChunked::from_series(
"keltner_output".into(),
s.len(),
[upper_series, middle_series, lower_series].iter(),
)?;
Ok(Some(Column::from(out.into_series())))
},
GetOutput::from_type(DataType::Struct(vec![
Field::new("upper".into(), DataType::Float64),
Field::new("middle".into(), DataType::Float64),
Field::new("lower".into(), DataType::Float64),
])),
)
.alias("keltner_data")])
}
pub fn alma(self, name: &str, period: usize, offset: f64, sigma: f64) -> LazyFrame {
let name = name.to_string();
self.0.clone().with_columns([col(&name)
.map(
move |s| {
let ca = s.f64()?;
let mut alma = quantwave_core::ALMA::new(period, offset, sigma);
let mut values = Vec::with_capacity(s.len());
for i in 0..s.len() {
let val = ca.get(i).unwrap_or(0.0);
values.push(alma.next(val));
}
Ok(Some(Column::from(Series::new("alma".into(), values))))
},
GetOutput::from_type(DataType::Float64),
)
.alias("alma")])
}
pub fn donchian_channels(self, high: &str, low: &str, period: usize) -> LazyFrame {
let high = high.to_string();
let low = low.to_string();
self.0
.clone()
.with_columns([as_struct(vec![col(&high), col(&low)])
.map(
move |s| {
let ca = s.struct_()?;
let s_high = ca.field_by_name(&high)?;
let s_low = ca.field_by_name(&low)?;
let high = s_high.f64()?;
let low = s_low.f64()?;
let mut dc = quantwave_core::DonchianChannels::new(period);
let mut uppers = Vec::with_capacity(s.len());
let mut middles = Vec::with_capacity(s.len());
let mut lowers = Vec::with_capacity(s.len());
for i in 0..s.len() {
let h = high.get(i).unwrap_or(0.0);
let l = low.get(i).unwrap_or(0.0);
let (upper, middle, lower) = dc.next((h, l));
uppers.push(upper);
middles.push(middle);
lowers.push(lower);
}
let upper_series = Series::new("upper".into(), uppers);
let middle_series = Series::new("middle".into(), middles);
let lower_series = Series::new("lower".into(), lowers);
let out = StructChunked::from_series(
"donchian_output".into(),
s.len(),
[upper_series, middle_series, lower_series].iter(),
)?;
Ok(Some(Column::from(out.into_series())))
},
GetOutput::from_type(DataType::Struct(vec![
Field::new("upper".into(), DataType::Float64),
Field::new("middle".into(), DataType::Float64),
Field::new("lower".into(), DataType::Float64),
])),
)
.alias("donchian_data")])
}
pub fn ttm_squeeze(
self,
high: &str,
low: &str,
close: &str,
period: usize,
multiplier_bb: f64,
multiplier_kc: f64,
) -> LazyFrame {
let high = high.to_string();
let low = low.to_string();
let close = close.to_string();
self.0
.clone()
.with_columns([as_struct(vec![col(&high), col(&low), col(&close)])
.map(
move |s| {
let ca = s.struct_()?;
let s_high = ca.field_by_name(&high)?;
let s_low = ca.field_by_name(&low)?;
let s_close = ca.field_by_name(&close)?;
let high = s_high.f64()?;
let low = s_low.f64()?;
let close = s_close.f64()?;
let mut ttm =
quantwave_core::TTMSqueeze::new(period, multiplier_bb, multiplier_kc);
let mut histograms = Vec::with_capacity(s.len());
let mut squeezed = Vec::with_capacity(s.len());
for i in 0..s.len() {
let h = high.get(i).unwrap_or(0.0);
let l = low.get(i).unwrap_or(0.0);
let c = close.get(i).unwrap_or(0.0);
let (hist, is_sq) = ttm.next((h, l, c));
histograms.push(hist);
squeezed.push(is_sq);
}
let hist_series = Series::new("histogram".into(), histograms);
let squeezed_series = Series::new("is_squeezed".into(), squeezed);
let out = StructChunked::from_series(
"ttm_squeeze_output".into(),
s.len(),
[hist_series, squeezed_series].iter(),
)?;
Ok(Some(Column::from(out.into_series())))
},
GetOutput::from_type(DataType::Struct(vec![
Field::new("histogram".into(), DataType::Float64),
Field::new("is_squeezed".into(), DataType::Boolean),
])),
)
.alias("ttm_squeeze_data")])
}
pub fn vortex_indicator(self, high: &str, low: &str, close: &str, period: usize) -> LazyFrame {
let high = high.to_string();
let low = low.to_string();
let close = close.to_string();
self.0
.clone()
.with_columns([as_struct(vec![col(&high), col(&low), col(&close)])
.map(
move |s| {
let ca = s.struct_()?;
let s_high = ca.field_by_name(&high)?;
let s_low = ca.field_by_name(&low)?;
let s_close = ca.field_by_name(&close)?;
let high = s_high.f64()?;
let low = s_low.f64()?;
let close = s_close.f64()?;
let mut vi = quantwave_core::VortexIndicator::new(period);
let mut plus_vals = Vec::with_capacity(s.len());
let mut minus_vals = Vec::with_capacity(s.len());
for i in 0..s.len() {
let h = high.get(i).unwrap_or(0.0);
let l = low.get(i).unwrap_or(0.0);
let c = close.get(i).unwrap_or(0.0);
let (plus, minus) = vi.next((h, l, c));
plus_vals.push(plus);
minus_vals.push(minus);
}
let plus_series = Series::new("vi_plus".into(), plus_vals);
let minus_series = Series::new("vi_minus".into(), minus_vals);
let out = StructChunked::from_series(
"vortex_output".into(),
s.len(),
[plus_series, minus_series].iter(),
)?;
Ok(Some(Column::from(out.into_series())))
},
GetOutput::from_type(DataType::Struct(vec![
Field::new("vi_plus".into(), DataType::Float64),
Field::new("vi_minus".into(), DataType::Float64),
])),
)
.alias("vortex_data")])
}
pub fn heikin_ashi(self, open: &str, high: &str, low: &str, close: &str) -> LazyFrame {
let open = open.to_string();
let high = high.to_string();
let low = low.to_string();
let close = close.to_string();
self.0.clone().with_columns([as_struct(vec![
col(&open),
col(&high),
col(&low),
col(&close),
])
.map(
move |s| {
let ca = s.struct_()?;
let s_open = ca.field_by_name(&open)?;
let s_high = ca.field_by_name(&high)?;
let s_low = ca.field_by_name(&low)?;
let s_close = ca.field_by_name(&close)?;
let open = s_open.f64()?;
let high = s_high.f64()?;
let low = s_low.f64()?;
let close = s_close.f64()?;
let mut ha = quantwave_core::HeikinAshi::new();
let mut ha_opens = Vec::with_capacity(s.len());
let mut ha_highs = Vec::with_capacity(s.len());
let mut ha_lows = Vec::with_capacity(s.len());
let mut ha_closes = Vec::with_capacity(s.len());
for i in 0..s.len() {
let o = open.get(i).unwrap_or(0.0);
let h = high.get(i).unwrap_or(0.0);
let l = low.get(i).unwrap_or(0.0);
let c = close.get(i).unwrap_or(0.0);
let (ha_o, ha_h, ha_l, ha_c) = ha.next((o, h, l, c));
ha_opens.push(ha_o);
ha_highs.push(ha_h);
ha_lows.push(ha_l);
ha_closes.push(ha_c);
}
let o_series = Series::new("ha_open".into(), ha_opens);
let h_series = Series::new("ha_high".into(), ha_highs);
let l_series = Series::new("ha_low".into(), ha_lows);
let c_series = Series::new("ha_close".into(), ha_closes);
let out = StructChunked::from_series(
"heikin_ashi_output".into(),
s.len(),
[o_series, h_series, l_series, c_series].iter(),
)?;
Ok(Some(Column::from(out.into_series())))
},
GetOutput::from_type(DataType::Struct(vec![
Field::new("ha_open".into(), DataType::Float64),
Field::new("ha_high".into(), DataType::Float64),
Field::new("ha_low".into(), DataType::Float64),
Field::new("ha_close".into(), DataType::Float64),
])),
)
.alias("heikin_ashi_data")])
}
pub fn wavetrend(
self,
high: &str,
low: &str,
close: &str,
n1: usize,
n2: usize,
n3: usize,
) -> LazyFrame {
let high = high.to_string();
let low = low.to_string();
let close = close.to_string();
self.0
.clone()
.with_columns([as_struct(vec![col(&high), col(&low), col(&close)])
.map(
move |s| {
let ca = s.struct_()?;
let s_high = ca.field_by_name(&high)?;
let s_low = ca.field_by_name(&low)?;
let s_close = ca.field_by_name(&close)?;
let high = s_high.f64()?;
let low = s_low.f64()?;
let close = s_close.f64()?;
let mut wt = quantwave_core::WaveTrend::new(n1, n2, n3);
let mut wt1_vals = Vec::with_capacity(s.len());
let mut wt2_vals = Vec::with_capacity(s.len());
for i in 0..s.len() {
let h = high.get(i).unwrap_or(0.0);
let l = low.get(i).unwrap_or(0.0);
let c = close.get(i).unwrap_or(0.0);
let (wt1, wt2) = wt.next((h, l, c));
wt1_vals.push(wt1);
wt2_vals.push(wt2);
}
let wt1_series = Series::new("wt1".into(), wt1_vals);
let wt2_series = Series::new("wt2".into(), wt2_vals);
let out = StructChunked::from_series(
"wavetrend_output".into(),
s.len(),
[wt1_series, wt2_series].iter(),
)?;
Ok(Some(Column::from(out.into_series())))
},
GetOutput::from_type(DataType::Struct(vec![
Field::new("wt1".into(), DataType::Float64),
Field::new("wt2".into(), DataType::Float64),
])),
)
.alias("wavetrend_data")])
}
pub fn tema(self, name: &str, period: usize) -> LazyFrame {
let name = name.to_string();
self.0.clone().with_columns([col(&name)
.map(
move |s| {
let ca = s.f64()?;
let mut tema = quantwave_core::TEMA::new(period);
let mut values = Vec::with_capacity(s.len());
for i in 0..s.len() {
let val = ca.get(i).unwrap_or(0.0);
values.push(tema.next(val));
}
Ok(Some(Column::from(Series::new("tema".into(), values))))
},
GetOutput::from_type(DataType::Float64),
)
.alias("tema")])
}
pub fn zlema(self, name: &str, period: usize) -> LazyFrame {
let name = name.to_string();
self.0.clone().with_columns([col(&name)
.map(
move |s| {
let ca = s.f64()?;
let mut zlema = quantwave_core::ZLEMA::new(period);
let mut values = Vec::with_capacity(s.len());
for i in 0..s.len() {
let val = ca.get(i).unwrap_or(0.0);
values.push(zlema.next(val));
}
Ok(Some(Column::from(Series::new("zlema".into(), values))))
},
GetOutput::from_type(DataType::Float64),
)
.alias("zlema")])
}
pub fn atr_trailing_stop(
self,
high: &str,
low: &str,
close: &str,
period: usize,
multiplier: f64,
) -> LazyFrame {
let high = high.to_string();
let low = low.to_string();
let close = close.to_string();
self.0
.clone()
.with_columns([as_struct(vec![col(&high), col(&low), col(&close)])
.map(
move |s| {
let ca = s.struct_()?;
let s_high = ca.field_by_name(&high)?;
let s_low = ca.field_by_name(&low)?;
let s_close = ca.field_by_name(&close)?;
let high = s_high.f64()?;
let low = s_low.f64()?;
let close = s_close.f64()?;
let mut atr_ts = quantwave_core::ATRTrailingStop::new(period, multiplier);
let mut stops = Vec::with_capacity(s.len());
let mut directions = Vec::with_capacity(s.len());
for i in 0..s.len() {
let h = high.get(i).unwrap_or(0.0);
let l = low.get(i).unwrap_or(0.0);
let c = close.get(i).unwrap_or(0.0);
let (stop, dir) = atr_ts.next((h, l, c));
stops.push(stop);
directions.push(dir as f64);
}
let stop_series = Series::new("stop".into(), stops);
let dir_series = Series::new("direction".into(), directions);
let out = StructChunked::from_series(
"atr_ts_output".into(),
s.len(),
[stop_series, dir_series].iter(),
)?;
Ok(Some(Column::from(out.into_series())))
},
GetOutput::from_type(DataType::Struct(vec![
Field::new("stop".into(), DataType::Float64),
Field::new("direction".into(), DataType::Float64),
])),
)
.alias("atr_ts_data")])
}
pub fn pivot_points(self, high: &str, low: &str, close: &str) -> LazyFrame {
let high = high.to_string();
let low = low.to_string();
let close = close.to_string();
self.0
.clone()
.with_columns([as_struct(vec![col(&high), col(&low), col(&close)])
.map(
move |s| {
let ca = s.struct_()?;
let s_high = ca.field_by_name(&high)?;
let s_low = ca.field_by_name(&low)?;
let s_close = ca.field_by_name(&close)?;
let high = s_high.f64()?;
let low = s_low.f64()?;
let close = s_close.f64()?;
let mut pivot = quantwave_core::PivotPoints::new();
let mut p_vals = Vec::with_capacity(s.len());
let mut r1_vals = Vec::with_capacity(s.len());
let mut s1_vals = Vec::with_capacity(s.len());
let mut r2_vals = Vec::with_capacity(s.len());
let mut s2_vals = Vec::with_capacity(s.len());
for i in 0..s.len() {
let h = high.get(i).unwrap_or(0.0);
let l = low.get(i).unwrap_or(0.0);
let c = close.get(i).unwrap_or(0.0);
let (p, r1, s1, r2, s2) = pivot.next((h, l, c));
p_vals.push(p);
r1_vals.push(r1);
s1_vals.push(s1);
r2_vals.push(r2);
s2_vals.push(s2);
}
let p_series = Series::new("p".into(), p_vals);
let r1_series = Series::new("r1".into(), r1_vals);
let s1_series = Series::new("s1".into(), s1_vals);
let r2_series = Series::new("r2".into(), r2_vals);
let s2_series = Series::new("s2".into(), s2_vals);
let out = StructChunked::from_series(
"pivot_output".into(),
s.len(),
[p_series, r1_series, s1_series, r2_series, s2_series].iter(),
)?;
Ok(Some(Column::from(out.into_series())))
},
GetOutput::from_type(DataType::Struct(vec![
Field::new("p".into(), DataType::Float64),
Field::new("r1".into(), DataType::Float64),
Field::new("s1".into(), DataType::Float64),
Field::new("r2".into(), DataType::Float64),
Field::new("s2".into(), DataType::Float64),
])),
)
.alias("pivot_points_data")])
}
pub fn bill_williams_fractals(self, high: &str, low: &str) -> LazyFrame {
let high = high.to_string();
let low = low.to_string();
self.0
.clone()
.with_columns([as_struct(vec![col(&high), col(&low)])
.map(
move |s| {
let ca = s.struct_()?;
let s_high = ca.field_by_name(&high)?;
let s_low = ca.field_by_name(&low)?;
let high = s_high.f64()?;
let low = s_low.f64()?;
let mut fractals = quantwave_core::BillWilliamsFractals::new();
let mut bearish_vals = Vec::with_capacity(s.len());
let mut bullish_vals = Vec::with_capacity(s.len());
for i in 0..s.len() {
let h = high.get(i).unwrap_or(0.0);
let l = low.get(i).unwrap_or(0.0);
let (bear, bull) = fractals.next((h, l));
bearish_vals.push(bear);
bullish_vals.push(bull);
}
let bearish_series = Series::new("bearish".into(), bearish_vals);
let bullish_series = Series::new("bullish".into(), bullish_vals);
let out = StructChunked::from_series(
"fractals_output".into(),
s.len(),
[bearish_series, bullish_series].iter(),
)?;
Ok(Some(Column::from(out.into_series())))
},
GetOutput::from_type(DataType::Struct(vec![
Field::new("bearish".into(), DataType::Boolean),
Field::new("bullish".into(), DataType::Boolean),
])),
)
.alias("fractals_data")])
}
pub fn ichimoku_cloud(
self,
high: &str,
low: &str,
p1: usize,
p2: usize,
p3: usize,
) -> LazyFrame {
let high = high.to_string();
let low = low.to_string();
self.0
.clone()
.with_columns([as_struct(vec![col(&high), col(&low)])
.map(
move |s| {
let ca = s.struct_()?;
let s_high = ca.field_by_name(&high)?;
let s_low = ca.field_by_name(&low)?;
let high = s_high.f64()?;
let low = s_low.f64()?;
let mut ic = quantwave_core::IchimokuCloud::new(p1, p2, p3);
let mut t_vals = Vec::with_capacity(s.len());
let mut k_vals = Vec::with_capacity(s.len());
let mut sa_vals = Vec::with_capacity(s.len());
let mut sb_vals = Vec::with_capacity(s.len());
for i in 0..s.len() {
let h = high.get(i).unwrap_or(0.0);
let l = low.get(i).unwrap_or(0.0);
let (t, k, sa, sb) = ic.next((h, l));
t_vals.push(t);
k_vals.push(k);
sa_vals.push(sa);
sb_vals.push(sb);
}
let t_series = Series::new("tenkan".into(), t_vals);
let k_series = Series::new("kijun".into(), k_vals);
let sa_series = Series::new("senkou_a".into(), sa_vals);
let sb_series = Series::new("senkou_b".into(), sb_vals);
let out = StructChunked::from_series(
"ichimoku_output".into(),
s.len(),
[t_series, k_series, sa_series, sb_series].iter(),
)?;
Ok(Some(Column::from(out.into_series())))
},
GetOutput::from_type(DataType::Struct(vec![
Field::new("tenkan".into(), DataType::Float64),
Field::new("kijun".into(), DataType::Float64),
Field::new("senkou_a".into(), DataType::Float64),
Field::new("senkou_b".into(), DataType::Float64),
])),
)
.alias("ichimoku_data")])
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_polars_heikin_ashi() -> PolarsResult<()> {
let df = df![
"open" => [10.0, 11.0],
"high" => [12.0, 13.0],
"low" => [8.0, 10.0],
"close" => [11.0, 12.0]
]?;
let out = df
.lazy()
.ta()
.heikin_ashi("open", "high", "low", "close")
.collect()?;
let ha = out.column("heikin_ashi_data")?.struct_()?;
assert_eq!(
ha.field_by_name("ha_open".into())?.f64()?.get(0),
Some(10.5)
);
assert_eq!(
ha.field_by_name("ha_close".into())?.f64()?.get(0),
Some(10.25)
);
Ok(())
}
#[test]
fn test_polars_tema_zlema() -> PolarsResult<()> {
let df = df![
"price" => [1.0, 2.0, 3.0, 4.0, 5.0]
]?;
let out = df.clone().lazy().ta().tema("price", 3).collect()?;
let tema = out.column("tema")?.f64()?;
assert!(tema.get(4).is_some());
let out2 = df.lazy().ta().zlema("price", 3).collect()?;
let zlema = out2.column("zlema")?.f64()?;
assert!(zlema.get(4).is_some());
Ok(())
}
#[test]
fn test_polars_atr_ts() -> PolarsResult<()> {
let df = df![
"high" => [10.0, 12.0, 11.0],
"low" => [8.0, 10.0, 9.0],
"close" => [9.0, 11.0, 10.0]
]?;
let out = df
.lazy()
.ta()
.atr_trailing_stop("high", "low", "close", 14, 2.5)
.collect()?;
let atr_ts = out.column("atr_ts_data")?.struct_()?;
assert!(atr_ts.field_by_name("stop".into())?.f64()?.get(0).is_some());
assert!(
atr_ts
.field_by_name("direction".into())?
.f64()?
.get(0)
.is_some()
);
Ok(())
}
#[test]
fn test_polars_pivot_points() -> PolarsResult<()> {
let df = df![
"high" => [10.0, 12.0, 11.0],
"low" => [8.0, 10.0, 9.0],
"close" => [9.0, 11.0, 10.0]
]?;
let out = df
.lazy()
.ta()
.pivot_points("high", "low", "close")
.collect()?;
let pivot = out.column("pivot_points_data")?.struct_()?;
assert!(pivot.field_by_name("p".into())?.f64()?.get(0).is_some());
assert!(pivot.field_by_name("r1".into())?.f64()?.get(0).is_some());
Ok(())
}
#[test]
fn test_polars_fractals() -> PolarsResult<()> {
let df = df![
"high" => [10.0, 11.0, 15.0, 12.0, 10.0],
"low" => [5.0, 6.0, 2.0, 6.0, 7.0]
]?;
let out = df
.lazy()
.ta()
.bill_williams_fractals("high", "low")
.collect()?;
let fractals = out.column("fractals_data")?.struct_()?;
assert!(
fractals
.field_by_name("bearish".into())?
.bool()?
.get(4)
.unwrap()
);
assert!(
fractals
.field_by_name("bullish".into())?
.bool()?
.get(4)
.unwrap()
);
Ok(())
}
#[test]
fn test_polars_ichimoku() -> PolarsResult<()> {
let df = df![
"high" => [10.0, 11.0, 15.0, 12.0, 10.0],
"low" => [5.0, 6.0, 2.0, 6.0, 7.0]
]?;
let out = df
.lazy()
.ta()
.ichimoku_cloud("high", "low", 9, 26, 52)
.collect()?;
let ichimoku = out.column("ichimoku_data")?.struct_()?;
assert!(
ichimoku
.field_by_name("tenkan".into())?
.f64()?
.get(4)
.is_some()
);
assert!(
ichimoku
.field_by_name("kijun".into())?
.f64()?
.get(4)
.is_some()
);
Ok(())
}
#[test]
fn test_polars_wavetrend() -> PolarsResult<()> {
let df = df![
"high" => [10.0, 12.0, 11.0],
"low" => [8.0, 10.0, 9.0],
"close" => [9.0, 11.0, 10.0]
]?;
let out = df
.lazy()
.ta()
.wavetrend("high", "low", "close", 10, 21, 4)
.collect()?;
let wt = out.column("wavetrend_data")?.struct_()?;
assert!(wt.field_by_name("wt1".into())?.f64()?.get(0).is_some());
assert!(wt.field_by_name("wt2".into())?.f64()?.get(0).is_some());
Ok(())
}
#[test]
fn test_polars_vortex() -> PolarsResult<()> {
let df = df![
"high" => [10.0, 12.0, 11.0],
"low" => [8.0, 10.0, 9.0],
"close" => [9.0, 11.0, 10.0]
]?;
let out = df
.lazy()
.ta()
.vortex_indicator("high", "low", "close", 14)
.collect()?;
let vortex = out.column("vortex_data")?.struct_()?;
assert!(
vortex
.field_by_name("vi_plus".into())?
.f64()?
.get(0)
.is_some()
);
assert!(
vortex
.field_by_name("vi_minus".into())?
.f64()?
.get(0)
.is_some()
);
Ok(())
}
#[test]
fn test_polars_ttm_squeeze() -> PolarsResult<()> {
let df = df![
"high" => [11.0, 12.0, 13.0, 14.0],
"low" => [9.0, 10.0, 11.0, 12.0],
"close" => [10.0, 11.0, 12.0, 13.0]
]?;
let out = df
.lazy()
.ta()
.ttm_squeeze("high", "low", "close", 20, 2.0, 1.5)
.collect()?;
let ttm = out.column("ttm_squeeze_data")?.struct_()?;
assert!(
ttm.field_by_name("histogram".into())?
.f64()?
.get(0)
.is_some()
);
assert!(
ttm.field_by_name("is_squeezed".into())?
.bool()?
.get(0)
.is_some()
);
Ok(())
}
#[test]
fn test_polars_donchian() -> PolarsResult<()> {
let df = df![
"high" => [10.0, 12.0, 11.0, 13.0, 15.0],
"low" => [8.0, 7.0, 9.0, 10.0, 12.0]
]?;
let out = df
.lazy()
.ta()
.donchian_channels("high", "low", 3)
.collect()?;
let donchian = out.column("donchian_data")?.struct_()?;
assert_eq!(
donchian.field_by_name("upper".into())?.f64()?.get(3),
Some(13.0)
);
assert_eq!(
donchian.field_by_name("middle".into())?.f64()?.get(3),
Some(10.0)
);
assert_eq!(
donchian.field_by_name("lower".into())?.f64()?.get(3),
Some(7.0)
);
Ok(())
}
#[test]
fn test_polars_alma() -> PolarsResult<()> {
let df = df![
"price" => [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0]
]?;
let out = df.lazy().ta().alma("price", 9, 0.85, 6.0).collect()?;
let alma = out.column("alma")?.f64()?;
assert!(alma.get(9).is_some());
Ok(())
}
#[test]
fn test_polars_keltner() -> PolarsResult<()> {
let df = df![
"high" => [12.0],
"low" => [8.0],
"close" => [10.0]
]?;
let out = df
.lazy()
.ta()
.keltner_channels("high", "low", "close", 3, 3, 2.0)
.collect()?;
let keltner = out.column("keltner_data")?.struct_()?;
assert_eq!(
keltner.field_by_name("middle".into())?.f64()?.get(0),
Some(10.0)
);
assert_eq!(
keltner.field_by_name("upper".into())?.f64()?.get(0),
Some(18.0)
);
assert_eq!(
keltner.field_by_name("lower".into())?.f64()?.get(0),
Some(2.0)
);
Ok(())
}
#[test]
fn test_polars_hma() -> PolarsResult<()> {
let df = df![
"price" => [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0]
]?;
let out = df.lazy().ta().hma("price", 4).collect()?;
let hma = out.column("hma")?.f64()?;
assert!(hma.get(9).is_some());
Ok(())
}
#[test]
fn test_polars_anchored_vwap() -> PolarsResult<()> {
let df = df![
"price" => [10.0, 12.0, 15.0, 16.0],
"volume" => [100.0, 200.0, 100.0, 100.0],
"anchor" => [false, false, true, false]
]?;
let out = df
.lazy()
.ta()
.anchored_vwap("price", "volume", "anchor")
.collect()?;
let avwap = out.column("avwap")?.f64()?;
assert_eq!(avwap.get(0), Some(10.0));
assert_eq!(avwap.get(1), Some(11.333333333333334));
assert_eq!(avwap.get(2), Some(15.0));
assert_eq!(avwap.get(3), Some(15.5));
Ok(())
}
#[test]
fn test_polars_math_transforms() -> PolarsResult<()> {
let df = df![
"val" => [0.0, 1.5707963267948966] ]?;
let out = df.lazy().ta().sin("val").collect()?;
let sin = out.column("sin")?.f64()?;
assert!((sin.get(0).unwrap() - 0.0).abs() < 1e-10);
assert!((sin.get(1).unwrap() - 1.0).abs() < 1e-10);
Ok(())
}
#[test]
fn test_polars_math_operators() -> PolarsResult<()> {
let df = df![
"v1" => [10.0, 20.0],
"v2" => [5.0, 30.0]
]?;
let out = df.lazy().ta().add("v1", "v2").ta().max("v1", 2).collect()?;
let add = out.column("add")?.f64()?;
assert_eq!(add.get(0), Some(15.0));
assert_eq!(add.get(1), Some(50.0));
let max = out.column("max")?.f64()?;
assert_eq!(max.get(1), Some(20.0));
Ok(())
}
}
impl QuantWaveExt for LazyFrame {
fn ta(&self) -> QuantWaveNamespace<'_> {
QuantWaveNamespace(self)
}
}