use polars::prelude::*;
pub struct StockPricePatterns {
pub min_volume_increase: f64,
pub min_price_range: f64,
pub lookback_period: usize,
}
impl Default for StockPricePatterns {
fn default() -> Self {
Self {
min_volume_increase: 2.0,
min_price_range: 0.03,
lookback_period: 20,
}
}
}
pub fn detect_stock_breakouts(
df: &DataFrame,
min_volume_ratio: f64,
min_price_change: f64,
) -> Result<Series, PolarsError> {
let close = df.column("close")?.f64()?;
let volume = df.column("volume")?.f64()?;
let high = df.column("high")?.f64()?;
let low = df.column("low")?.f64()?;
let mut breakout_signals = Vec::with_capacity(df.height());
let vol_window_size = 20.min(df.height());
for _i in 0..vol_window_size {
breakout_signals.push(false);
}
for i in vol_window_size..df.height() {
let current_volume = volume.get(i).unwrap_or(f64::NAN);
let mut sum_volume = 0.0;
for j in (i - vol_window_size)..i {
sum_volume += volume.get(j).unwrap_or(0.0);
}
let avg_volume = sum_volume / vol_window_size as f64;
let current_close = close.get(i).unwrap_or(f64::NAN);
let prev_close = close.get(i - 1).unwrap_or(f64::NAN);
let price_change = if !prev_close.is_nan() && prev_close > 0.0 {
(current_close - prev_close) / prev_close
} else {
0.0
};
let volume_condition = current_volume >= min_volume_ratio * avg_volume;
let price_condition = price_change.abs() >= min_price_change;
let prev_high = high.get(i - 1).unwrap_or(f64::NAN);
let current_low = low.get(i).unwrap_or(f64::NAN);
let prev_low = low.get(i - 1).unwrap_or(f64::NAN);
let current_high = high.get(i).unwrap_or(f64::NAN);
let gap_up = current_low > prev_high;
let gap_down = current_high < prev_low;
let gap_condition = gap_up || gap_down;
let is_breakout = volume_condition && price_condition && gap_condition;
breakout_signals.push(is_breakout);
}
Ok(Series::new("stock_breakouts".into(), breakout_signals))
}
pub fn detect_institutional_activity(
df: &DataFrame,
_block_threshold: f64,
) -> Result<(Series, Series), PolarsError> {
let buying_pressure = Series::new("institutional_buying".into(), vec![0.0; df.height()]);
let selling_pressure = Series::new("institutional_selling".into(), vec![0.0; df.height()]);
Ok((buying_pressure, selling_pressure))
}
pub fn detect_supply_demand_blocks(
df: &DataFrame,
_window_size: usize,
_vol_threshold: f64,
_block_threshold: f64,
) -> Result<(Series, Series), PolarsError> {
let buying_pressure = Series::new("institutional_buying".into(), vec![0.0; df.height()]);
let selling_pressure = Series::new("institutional_selling".into(), vec![0.0; df.height()]);
Ok((buying_pressure, selling_pressure))
}