use std::env;
use polars::prelude::*;
#[derive(Clone)]
#[allow(dead_code)]
pub struct PriceChange {
lazyframe: LazyFrame
}
#[derive(Clone)]
#[allow(dead_code)]
pub struct RollingMean {
lazyframe: LazyFrame,
period: i64
}
#[derive(Clone)]
#[allow(dead_code)]
pub struct FinalRS {
lazyframe: LazyFrame
}
#[derive(Clone)]
#[allow(dead_code)]
pub struct FinalRSI {
lazyframe: LazyFrame
}
impl PriceChange {
pub fn new(
lazyframe: LazyFrame
) -> Self {
Self {
lazyframe
}
}
pub fn calculate_price_change(
lazyframe: LazyFrame
) -> Result<LazyFrame, PolarsError>{
let column_close_name: &str = &env::var("CLOSE_COLUMN_NAME").unwrap_or_else(|_| "close".to_string());
let lazyframe_price_change: LazyFrame = lazyframe.clone()
.with_column(
when(
col(column_close_name).neq(lit(0.0))
).then(
col(column_close_name) - col(column_close_name).shift(lit(1))
).otherwise(
lit(0.0)
)
.alias("price_change")
).fill_null(
lit(0.0)
)
.with_columns(
vec![
when(
col("price_change").lt(lit(0.0))
).then(
col("price_change")
).otherwise(
lit(0.0)
)
.alias("loss"),
when(
col("price_change").gt(lit(0.0))
).then(
col("price_change")
).otherwise(
lit(0.0)
)
.alias("gain")
]
)
.with_column(
when(
col("loss").lt(lit(0.0))
).then(
col("loss")
).otherwise(
lit(0.0)
)
.alias("loss_normalized")
);
let df: DataFrame = lazyframe_price_change.collect()?;
let new_df = df.slice(1, df.height() - 1);
let lazyframe_price_change = new_df.lazy();
Ok(lazyframe_price_change)
}
}
impl RollingMean {
pub fn new(
lazyframe: LazyFrame,
period: i64
) -> Self {
Self {
lazyframe,
period
}
}
pub fn period_rolling_mean(
lazyframe: LazyFrame,
period: i64
) -> Result<LazyFrame, PolarsError> {
let dataframe: DataFrame = lazyframe.collect()?;
let series_loss: Series = dataframe.column("loss_normalized")?.clone();
let series_gain: Series = dataframe.column("gain")?.clone();
let loss_average: Series = series_loss.rolling_mean(
RollingOptions::into(
RollingOptions {
window_size: polars::prelude::Duration::new(period),
min_periods: 1,
center: false,
weights: None,
by: None,
closed_window: None,
fn_params: None,
}))?;
let gain_average: Series = series_gain.rolling_mean(
RollingOptions::into(
RollingOptions {
window_size: polars::prelude::Duration::new(period),
min_periods: 1,
center: false,
weights: None,
by: None,
closed_window: None,
fn_params: None,
}))?;
let dataframe: DataFrame = dataframe.clone();
let mut series_change_negative: Series = loss_average;
let mut series_change_positive: Series = gain_average;
series_change_negative.rename("loss_average");
series_change_positive.rename("gain_average");
let dataframe_rolling: DataFrame = dataframe.hstack(
&[
series_change_negative,
series_change_positive
])?;
let lazyframe_rolling: LazyFrame = dataframe_rolling.lazy();
Ok(lazyframe_rolling)
}
}
impl FinalRS {
pub fn new(
lazyframe: LazyFrame,
) -> Self {
Self {
lazyframe
}
}
pub fn calculate_final_rs(
lazyframe: LazyFrame,
) -> Result<LazyFrame, PolarsError> {
let lazyframe_rs: LazyFrame = lazyframe.clone()
.with_column(
when(
col("gain_average").neq(lit(0.0)).and(col("loss_average").neq(lit(0.0)))
).then(
col("gain_average") / col("loss_average")
).otherwise(
lit(0.0)
)
.alias("rs")
);
Ok(lazyframe_rs.clone())
}
}
impl FinalRSI {
pub fn new(
lazyframe: LazyFrame,
) -> Self {
Self {
lazyframe
}
}
pub fn calculate_final_rsi(
lazyframe: LazyFrame,
) -> Result<LazyFrame, PolarsError> {
let lazyframe_rsi: LazyFrame = lazyframe.clone()
.with_column(
when(
col("rs").neq(lit(0.0))
).then(
lit(100.0) - (lit(100.0) / (lit(1.0) + col("rs")))
).otherwise(
lit(0.0)
)
.alias("rsi")
);
Ok(lazyframe_rsi)
}
}