rustalib 1.0.9

A library of technical indicators for financial analysis, similar to TA-Lib
Documentation
//! # Stock Price Action Indicators
//!
//! This module provides indicators based on stock-specific price action patterns.

use polars::prelude::*;

/// Stock price patterns detection and analysis
pub struct StockPricePatterns {
    /// Minimum volume increase required for a valid breakout
    pub min_volume_increase: f64,

    /// Minimum price range for a valid pattern
    pub min_price_range: f64,

    /// Number of days to look back for pattern formation
    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,
        }
    }
}

/// Detect potential price breakouts based on stock-specific criteria
///
/// This function identifies potential breakout candidates by analyzing price and volume patterns
/// specific to stock markets, including pre-market gap analysis.
///
/// # Arguments
///
/// * `df` - DataFrame with OHLCV data
/// * `min_volume_ratio` - Minimum volume ratio compared to average to consider a breakout
/// * `min_price_change` - Minimum price percentage change to qualify
///
/// # Returns
///
/// * `Result<Series, PolarsError>` - Boolean series indicating potential breakouts
pub fn detect_stock_breakouts(
    df: &DataFrame,
    min_volume_ratio: f64,
    min_price_change: f64,
) -> Result<Series, PolarsError> {
    // Extract required columns
    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());

    // Calculate rolling volume average (20-day)
    let vol_window_size = 20.min(df.height());

    // Skip initial rows where we don't have enough data
    for _i in 0..vol_window_size {
        breakout_signals.push(false);
    }

    // Process each data point
    for i in vol_window_size..df.height() {
        let current_volume = volume.get(i).unwrap_or(f64::NAN);

        // Calculate average volume for the previous N days
        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;

        // Calculate price change
        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
        };

        // Check for breakout conditions specific to stocks
        let volume_condition = current_volume >= min_volume_ratio * avg_volume;
        let price_condition = price_change.abs() >= min_price_change;

        // Additional stock-specific condition: check for gap up or down
        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;

        // Determine if this is a breakout
        let is_breakout = volume_condition && price_condition && gap_condition;
        breakout_signals.push(is_breakout);
    }

    // Create and return a Series with the breakout signals
    Ok(Series::new("stock_breakouts".into(), breakout_signals))
}

/// Detect institutional activity in a stock based on volume analysis
///
/// This function identifies potential institutional buying or selling
/// by analyzing volume patterns and block trades.
///
/// # Arguments
///
/// * `df` - DataFrame with OHLCV data
/// * `block_threshold` - Volume threshold to consider as a block trade
///
/// # Returns
///
/// * `Result<(Series, Series), PolarsError>` - Tuple of buying and selling pressure series
pub fn detect_institutional_activity(
    df: &DataFrame,
    _block_threshold: f64,
) -> Result<(Series, Series), PolarsError> {
    // Implementation to be completed
    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))
}

/// Detect supply and demand blocks in a stock based on volume analysis
///
/// This function identifies potential supply and demand blocks in a stock
/// by analyzing volume patterns and block trades.
///
/// # Arguments
///
/// * `df` - DataFrame with OHLCV data
/// * `window_size` - Size of the window to analyze
/// * `vol_threshold` - Volume threshold to consider as a block trade
/// * `block_threshold` - Volume threshold to consider as a block trade
///
/// # Returns
///
/// * `Result<(Series, Series), PolarsError>` - Tuple of buying and selling pressure series
pub fn detect_supply_demand_blocks(
    df: &DataFrame,
    _window_size: usize,
    _vol_threshold: f64,
    _block_threshold: f64,
) -> Result<(Series, Series), PolarsError> {
    // Implementation to be completed
    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))
}