Technical Indicators

Comprehensive technical analysis library with 58+ TA-Lib compatible indicators built specifically for Polars DataFrames, including advanced pattern recognition indicators.

Overview

The indicators module provides both class-based and function-based interfaces for technical analysis, similar to TA-Lib but optimized for Polars DataFrames.

ProjectX Indicators - Technical Analysis Library

Author: @TexasCoding Date: 2025-08-02

Overview:

ProjectX Indicators provides a comprehensive, extensible technical analysis library similar to TA-Lib, built on Polars DataFrames for high-performance financial analysis. It offers both class-based and function-based interfaces for over 60 technical indicators, with seamless integration for vectorized backtesting and strategy development in ProjectX and beyond.

Key Features:
  • Wide range of indicators: trend/overlap, momentum, volatility, volume, and patterns

  • Class-based and TA-Lib-style function interface for flexible usage

  • All indicators operate on Polars DataFrames for speed and modern analytics

  • Utilities for indicator discovery, grouping, and docstring access

  • Clean API and naming convention for easy scripting and research

  • Built-in caching and validation for optimal performance

  • Support for custom indicators through base classes

Indicator Categories:
  • Overlap Studies: SMA, EMA, BBANDS, DEMA, TEMA, WMA, SAR, etc.

  • Momentum Indicators: RSI, MACD, STOCH, CCI, ADX, AROON, etc.

  • Volatility Indicators: ATR, NATR, TRANGE, STDDEV

  • Volume Indicators: OBV, VWAP, AD, ADOSC

  • Pattern Indicators: FVG (Fair Value Gap), ORDERBLOCK, WAE (Waddah Attar Explosion)

Example Usage:

```python # Class-based interface from project_x_py.indicators import RSI, SMA

rsi = RSI() data_with_rsi = rsi.calculate(ohlcv_data, period=14)

# Function-based interface (TA-Lib style) from project_x_py.indicators import calculate_rsi, calculate_sma

data_with_rsi = calculate_rsi(ohlcv_data, period=14) data_with_sma = calculate_sma(ohlcv_data, period=20)

# Pattern detection from project_x_py.indicators import FVG, ORDERBLOCK

fvg_data = FVG().calculate(ohlcv_data, min_gap_size=0.001) order_blocks = ORDERBLOCK().calculate(ohlcv_data, min_volume_percentile=75) ```

Performance Notes:
  • All indicators use vectorized operations for optimal speed

  • Built-in caching prevents redundant calculations

  • Memory-efficient Polars DataFrame operations

  • Supports large datasets with minimal memory overhead

See also

  • project_x_py.indicators.base (abstract base classes/utilities)

  • project_x_py.indicators.momentum

  • project_x_py.indicators.overlap

  • project_x_py.indicators.volume

  • project_x_py.indicators.volatility

  • project_x_py.indicators.order_block

  • project_x_py.indicators.fvg

  • project_x_py.indicators.waddah_attar

AD(data, high_column='high', low_column='low', close_column='close', volume_column='volume')[source]

Accumulation/Distribution Line (TA-Lib style).

Return type:

DataFrame

ADOSC(data, high_column='high', low_column='low', close_column='close', volume_column='volume', fast_period=3, slow_period=10)[source]

Accumulation/Distribution Oscillator (TA-Lib style).

Return type:

DataFrame

ADX(data, high_column='high', low_column='low', close_column='close', period=14)[source]

Average Directional Movement Index (TA-Lib style).

Return type:

DataFrame

ATR(data, high_column='high', low_column='low', close_column='close', period=14)[source]

Average True Range (TA-Lib style).

Return type:

DataFrame

BBANDS(data, column='close', period=20, std_dev=2.0)[source]

Bollinger Bands (TA-Lib style).

Return type:

DataFrame

BULLISHENGULFING(data, **kwargs)[source]

Bullish Engulfing pattern (TA-Lib style).

Return type:

DataFrame

CCI(data, high_column='high', low_column='low', close_column='close', period=20, constant=0.015)[source]

Commodity Channel Index (TA-Lib style).

Return type:

DataFrame

DEMA(data, column='close', period=20)[source]

Double Exponential Moving Average (TA-Lib style).

Return type:

DataFrame

DOJI(data, **kwargs)[source]

Doji candlestick pattern (TA-Lib style).

Return type:

DataFrame

EMA(data, column='close', period=20)[source]

Exponential Moving Average (TA-Lib style).

Return type:

DataFrame

FVG(data, high_column='high', low_column='low', close_column='close', min_gap_size=0.0, check_mitigation=False, mitigation_threshold=0.5)[source]

Fair Value Gap (TA-Lib style).

Return type:

DataFrame

HAMMER(data, **kwargs)[source]

Hammer candlestick pattern (TA-Lib style).

Return type:

DataFrame

HT_TRENDLINE(data, column='close')[source]

Hilbert Transform - Instantaneous Trendline (TA-Lib style).

Return type:

DataFrame

KAMA(data, column='close', period=30, fast_sc=2.0, slow_sc=30.0)[source]

Kaufman Adaptive Moving Average (TA-Lib style).

Return type:

DataFrame

MA(data, column='close', period=30, ma_type='sma')[source]

Moving Average (TA-Lib style).

Return type:

DataFrame

MACD(data, column='close', fast_period=12, slow_period=26, signal_period=9)[source]

Moving Average Convergence Divergence (TA-Lib style).

Return type:

DataFrame

MAMA(data, column='close', fast_limit=0.5, slow_limit=0.05)[source]

MESA Adaptive Moving Average (TA-Lib style).

Return type:

DataFrame

MAVP(data, column='close', periods_column='periods', min_period=2, max_period=30, ma_type='sma')[source]

Moving Average with Variable Period (TA-Lib style).

Return type:

DataFrame

MIDPOINT(data, column='close', period=14)[source]

Midpoint over period (TA-Lib style).

Return type:

DataFrame

MIDPRICE(data, high_column='high', low_column='low', period=14)[source]

Midpoint Price over period (TA-Lib style).

Return type:

DataFrame

MOM(data, column='close', period=10)[source]

Momentum (TA-Lib style).

Return type:

DataFrame

NATR(data, high_column='high', low_column='low', close_column='close', period=14)[source]

Normalized Average True Range (TA-Lib style).

Return type:

DataFrame

OBV(data, close_column='close', volume_column='volume')[source]

On-Balance Volume (TA-Lib style).

Return type:

DataFrame

ORDERBLOCK(data, open_column='open', high_column='high', low_column='low', close_column='close', volume_column='volume', min_volume_percentile=50, check_mitigation=False, mitigation_threshold=0.5, lookback_periods=3, use_wicks=True)[source]

Order Block (TA-Lib style).

Return type:

DataFrame

ROC(data, column='close', period=10)[source]

Rate of Change (TA-Lib style).

Return type:

DataFrame

RSI(data, column='close', period=14)[source]

Relative Strength Index (TA-Lib style).

Return type:

DataFrame

SAR(data, high_column='high', low_column='low', acceleration=0.02, maximum=0.2)[source]

Parabolic SAR (TA-Lib style).

Return type:

DataFrame

SAREXT(data, high_column='high', low_column='low', start_value=0.0, offset_on_reverse=0.0, acceleration_init_long=0.02, acceleration_long=0.02, acceleration_max_long=0.2, acceleration_init_short=0.02, acceleration_short=0.02, acceleration_max_short=0.2)[source]

Parabolic SAR - Extended (TA-Lib style).

Return type:

DataFrame

SHOOTINGSTAR(data, **kwargs)[source]

Shooting Star candlestick pattern (TA-Lib style).

Return type:

DataFrame

SMA(data, column='close', period=20)[source]

Simple Moving Average (TA-Lib style).

Return type:

DataFrame

STDDEV(data, column='close', period=5, ddof=1)[source]

Standard Deviation (TA-Lib style).

Return type:

DataFrame

STOCH(data, high_column='high', low_column='low', close_column='close', k_period=14, d_period=3)[source]

Stochastic Oscillator (TA-Lib style).

Return type:

DataFrame

STOCHRSI(data, column='close', rsi_period=14, stoch_period=14, k_period=3, d_period=3)[source]

Stochastic RSI (TA-Lib style).

Return type:

DataFrame

T3(data, column='close', period=5, v_factor=0.7)[source]

Triple Exponential Moving Average (T3) (TA-Lib style).

Return type:

DataFrame

TEMA(data, column='close', period=20)[source]

Triple Exponential Moving Average (TA-Lib style).

Return type:

DataFrame

TRANGE(data, high_column='high', low_column='low', close_column='close')[source]

True Range (TA-Lib style).

Return type:

DataFrame

TRIMA(data, column='close', period=20)[source]

Triangular Moving Average (TA-Lib style).

Return type:

DataFrame

ULTOSC(data, high_column='high', low_column='low', close_column='close', period1=7, period2=14, period3=28)[source]

Ultimate Oscillator (TA-Lib style).

Return type:

DataFrame

VWAP(data, high_column='high', low_column='low', close_column='close', volume_column='volume', period=None)[source]

Volume Weighted Average Price (TA-Lib style).

Return type:

DataFrame

WAE(data, close_column='close', high_column='high', low_column='low', fast_period=20, slow_period=40, bb_period=20, bb_mult=2.0, sensitivity=150, dead_zone_period=100, dead_zone_mult=3.6)[source]

Waddah Attar Explosion (TA-Lib style).

Return type:

DataFrame

WILLR(data, high_column='high', low_column='low', close_column='close', period=14)[source]

Williams %R (TA-Lib style).

Return type:

DataFrame

WMA(data, column='close', period=20)[source]

Weighted Moving Average (TA-Lib style).

Return type:

DataFrame

class BaseIndicator(name, description='')[source]

Bases: ABC

Base class for all technical indicators.

Provides common validation, error handling, caching, and utility methods that all indicators can inherit from. This abstract base class ensures consistent behavior across all indicators while providing performance optimizations through intelligent caching.

Key Features:
  • Automatic parameter validation and data checking

  • Built-in caching system to avoid redundant calculations

  • Standardized error handling with IndicatorError exceptions

  • Support for both class-based and function-based usage

  • Memory-efficient operations with Polars DataFrames

All custom indicators should inherit from this class or one of its specialized subclasses (OverlapIndicator, MomentumIndicator, etc.) for consistent behavior and optimal performance.

__call__(data, **kwargs)[source]

Allow indicator to be called directly with caching.

Parameters:
  • data (DataFrame) – Input DataFrame

  • **kwargs (Any) – Additional parameters

Return type:

DataFrame

Returns:

DataFrame with indicator values

__init__(name, description='')[source]

Initialize base indicator.

Parameters:
  • name (str) – Indicator name

  • description (str) – Optional description

abstractmethod calculate(data, **kwargs)[source]

Calculate the indicator values.

This method must be implemented by all indicator subclasses. It should perform the core calculation logic for the specific indicator, including parameter validation, data processing, and result generation.

The method should: 1. Validate input data and parameters using inherited validation methods 2. Perform the indicator-specific calculations 3. Return a DataFrame with the original data plus new indicator columns 4. Handle edge cases (insufficient data, invalid parameters, etc.)

Parameters:
  • data (DataFrame) – Input DataFrame with OHLCV data (must contain required columns)

  • **kwargs (Any) – Additional parameters specific to each indicator (period, thresholds, column names, etc.)

Returns:

DataFrame with original data plus new indicator columns.

The indicator values should be added as new columns with descriptive names (e.g., “rsi”, “macd”, “bb_upper”).

Return type:

pl.DataFrame

Raises:

IndicatorError – If data validation fails or calculation cannot proceed

validate_data(data, required_columns)[source]

Validate input DataFrame and required columns.

Parameters:
  • data (DataFrame) – Input DataFrame

  • required_columns (list[str]) – List of required column names

Raises:

IndicatorError – If validation fails

Return type:

None

validate_data_length(data, min_length)[source]

Validate that data has sufficient length for calculation.

Parameters:
  • data (DataFrame) – Input DataFrame

  • min_length (int) – Minimum required data length

Raises:

IndicatorError – If data is too short

Return type:

None

validate_period(period, min_period=1)[source]

Validate period parameter.

Parameters:
  • period (int) – Period value to validate

  • min_period (int) – Minimum allowed period

Raises:

IndicatorError – If period is invalid

Return type:

None

exception IndicatorError[source]

Bases: Exception

Custom exception for indicator calculation errors.

class MomentumIndicator(name, description='')[source]

Bases: BaseIndicator

Base class for momentum indicators.

__init__(name, description='')[source]

Initialize base indicator.

Parameters:
  • name (str) – Indicator name

  • description (str) – Optional description

class OverlapIndicator(name, description='')[source]

Bases: BaseIndicator

Base class for overlap study indicators (trend-following).

__init__(name, description='')[source]

Initialize base indicator.

Parameters:
  • name (str) – Indicator name

  • description (str) – Optional description

class VolatilityIndicator(name, description='')[source]

Bases: BaseIndicator

Base class for volatility indicators.

__init__(name, description='')[source]

Initialize base indicator.

Parameters:
  • name (str) – Indicator name

  • description (str) – Optional description

class VolumeIndicator(name, description='')[source]

Bases: BaseIndicator

Base class for volume indicators.

__init__(name, description='')[source]

Initialize base indicator.

Parameters:
  • name (str) – Indicator name

  • description (str) – Optional description

calculate_adx(data, high_column='high', low_column='low', close_column='close', period=14)[source]

Calculate ADX (convenience function).

Return type:

DataFrame

calculate_aroon(data, high_column='high', low_column='low', period=14)[source]

Calculate Aroon (convenience function).

Return type:

DataFrame

calculate_atr(data, high_column='high', low_column='low', close_column='close', period=14)[source]

Calculate ATR (convenience function).

Return type:

DataFrame

calculate_bollinger_bands(data, column='close', period=20, std_dev=2.0)[source]

Calculate Bollinger Bands (convenience function).

Return type:

DataFrame

calculate_bullishengulfing(data, **kwargs)[source]
Return type:

DataFrame

calculate_commodity_channel_index(data, high_column='high', low_column='low', close_column='close', period=20, constant=0.015)[source]

Calculate CCI (convenience function).

Return type:

DataFrame

calculate_dema(data, column='close', period=20)[source]

Calculate Double Exponential Moving Average (convenience function).

Return type:

DataFrame

calculate_doji(data, **kwargs)[source]
Return type:

DataFrame

calculate_ema(data, column='close', period=20)[source]

Calculate Exponential Moving Average (convenience function).

Return type:

DataFrame

calculate_fvg(data, high_column='high', low_column='low', close_column='close', min_gap_size=0.0, check_mitigation=False, mitigation_threshold=0.5)[source]

Calculate Fair Value Gaps (convenience function).

See FVG.calculate() for detailed documentation.

Parameters:
  • data (DataFrame) – DataFrame with OHLC data

  • high_column (str) – High price column

  • low_column (str) – Low price column

  • close_column (str) – Close price column

  • min_gap_size (float) – Minimum gap size to consider valid

  • check_mitigation (bool) – Whether to check if gaps have been mitigated

  • mitigation_threshold (float) – Percentage of gap that needs to be filled to consider it mitigated

Return type:

DataFrame

Returns:

DataFrame with FVG columns added

calculate_hammer(data, **kwargs)[source]
Return type:

DataFrame

calculate_ht_trendline(data, column='close')[source]

Calculate Hilbert Transform Trendline (convenience function).

Return type:

DataFrame

calculate_kama(data, column='close', period=30, fast_sc=2.0, slow_sc=30.0)[source]

Calculate Kaufman Adaptive Moving Average (convenience function).

Return type:

DataFrame

calculate_ma(data, column='close', period=30, ma_type='sma')[source]

Calculate generic Moving Average (convenience function).

Return type:

DataFrame

calculate_macd(data, column='close', fast_period=12, slow_period=26, signal_period=9)[source]

Calculate MACD (convenience function).

Return type:

DataFrame

calculate_mama(data, column='close', fast_limit=0.5, slow_limit=0.05)[source]

Calculate MESA Adaptive Moving Average (convenience function).

Return type:

DataFrame

calculate_midpoint(data, column='close', period=14)[source]

Calculate Midpoint (convenience function).

Return type:

DataFrame

calculate_midprice(data, high_column='high', low_column='low', period=14)[source]

Calculate Midpoint Price (convenience function).

Return type:

DataFrame

calculate_money_flow_index(data, high_column='high', low_column='low', close_column='close', volume_column='volume', period=14)[source]

Calculate MFI (convenience function).

Return type:

DataFrame

calculate_obv(data, close_column='close', volume_column='volume')[source]

Calculate OBV (convenience function).

Return type:

DataFrame

calculate_order_block(data, open_column='open', high_column='high', low_column='low', close_column='close', volume_column='volume', min_volume_percentile=50, check_mitigation=False, mitigation_threshold=0.5, lookback_periods=3, use_wicks=True)[source]

Calculate Order Blocks (convenience function).

See OrderBlock.calculate() for detailed documentation.

Parameters:
  • data (DataFrame) – DataFrame with OHLC data

  • open_column (str) – Open price column

  • high_column (str) – High price column

  • low_column (str) – Low price column

  • close_column (str) – Close price column

  • volume_column (str) – Volume column

  • min_volume_percentile (float) – Minimum volume percentile for valid OB

  • check_mitigation (bool) – Whether to check if blocks have been mitigated

  • mitigation_threshold (float) – Percentage of block that needs to be filled

  • lookback_periods (int) – Number of periods to look back for break

  • use_wicks (bool) – Whether to use wicks or bodies for OB zones

Return type:

DataFrame

Returns:

DataFrame with Order Block columns added

calculate_ppo(data, column='close', fast_period=12, slow_period=26, signal_period=9)[source]

Calculate PPO (convenience function).

Return type:

DataFrame

calculate_rsi(data, column='close', period=14)[source]

Calculate RSI (convenience function).

Return type:

DataFrame

calculate_sar(data, high_column='high', low_column='low', acceleration=0.02, maximum=0.2)[source]

Calculate Parabolic SAR (convenience function).

Return type:

DataFrame

calculate_shootingstar(data, **kwargs)[source]
Return type:

DataFrame

calculate_sma(data, column='close', period=20)[source]

Calculate Simple Moving Average (convenience function).

Return type:

DataFrame

calculate_stddev(data, column='close', period=5, ddof=1)[source]

Calculate STDDEV (convenience function).

Return type:

DataFrame

calculate_stochastic(data, high_column='high', low_column='low', close_column='close', k_period=14, d_period=3)[source]

Calculate Stochastic (convenience function).

Return type:

DataFrame

calculate_t3(data, column='close', period=5, v_factor=0.7)[source]

Calculate T3 Moving Average (convenience function).

Return type:

DataFrame

calculate_tema(data, column='close', period=20)[source]

Calculate Triple Exponential Moving Average (convenience function).

Return type:

DataFrame

calculate_trima(data, column='close', period=20)[source]

Calculate Triangular Moving Average (convenience function).

Return type:

DataFrame

calculate_ultimate_oscillator(data, high_column='high', low_column='low', close_column='close', period1=7, period2=14, period3=28)[source]

Calculate Ultimate Oscillator (convenience function).

Return type:

DataFrame

calculate_vwap(data, high_column='high', low_column='low', close_column='close', volume_column='volume', period=None)[source]

Calculate VWAP (convenience function).

Return type:

DataFrame

calculate_wae(data, close_column='close', high_column='high', low_column='low', fast_period=20, slow_period=40, bb_period=20, bb_mult=2.0, sensitivity=150, dead_zone_period=100, dead_zone_mult=3.6)[source]

Calculate Waddah Attar Explosion (convenience function).

See WAE.calculate() for detailed documentation.

Parameters:
  • data (DataFrame) – DataFrame with OHLC data

  • close_column (str) – Close price column

  • high_column (str) – High price column

  • low_column (str) – Low price column

  • fast_period (int) – Fast EMA period for MACD

  • slow_period (int) – Slow EMA period for MACD

  • bb_period (int) – Bollinger Bands period

  • bb_mult (float) – Bollinger Bands multiplier

  • sensitivity (float) – Sensitivity multiplier for explosion

  • dead_zone_period (int) – ATR period for dead zone

  • dead_zone_mult (float) – Multiplier for dead zone ATR

Return type:

DataFrame

Returns:

DataFrame with WAE columns added

calculate_williams_r(data, high_column='high', low_column='low', close_column='close', period=14)[source]

Calculate Williams %R (convenience function).

Return type:

DataFrame

calculate_wma(data, column='close', period=20)[source]

Calculate Weighted Moving Average (convenience function).

Return type:

DataFrame

ema_alpha(period)[source]

Calculate EMA alpha (smoothing factor) from period.

This utility function calculates the smoothing factor (alpha) used in Exponential Moving Average calculations. The alpha determines how much weight is given to recent prices versus older prices.

Formula: alpha = 2 / (period + 1)

Parameters:

period (int) – EMA period (number of periods for the moving average)

Returns:

Alpha value (smoothing factor) between 0 and 1

Return type:

float

Example

>>> alpha = ema_alpha(14)  # Returns 0.1333...
>>> # Higher alpha = more weight to recent prices
>>> alpha_short = ema_alpha(5)  # 0.3333...
>>> alpha_long = ema_alpha(50)  # 0.0392...
get_all_indicators()[source]

Get list of all available indicators.

Return type:

list[str]

get_indicator_groups()[source]

Get available indicator groups.

Return type:

dict[str, list[str]]

get_indicator_info(indicator_name)[source]

Get information about a specific indicator.

Return type:

str

safe_division(numerator, denominator, default=0.0)[source]

Safe division that handles division by zero.

This utility function creates a Polars expression that performs division while safely handling cases where the denominator is zero. It’s commonly used in technical indicator calculations where division operations might encounter zero values.

Parameters:
  • numerator (Expr) – Numerator expression (pl.Expr)

  • denominator (Expr) – Denominator expression (pl.Expr)

  • default (float) – Default value to return when denominator is zero (default: 0.0)

Returns:

Polars expression that performs safe division, returning the

default value when denominator is zero

Return type:

pl.Expr

Example

>>> # Safe division in RSI calculation
>>> gain = pl.col("close").diff().filter(pl.col("close").diff() > 0)
>>> loss = -pl.col("close").diff().filter(pl.col("close").diff() < 0)
>>> rs = safe_division(gain.rolling_mean(14), loss.rolling_mean(14))

Quick Start

import asyncio
from project_x_py.indicators import RSI, SMA, MACD, BBANDS
from project_x_py import ProjectX

async def analyze_market():
    # Get market data
    async with ProjectX.from_env() as client:
        await client.authenticate()
        data = await client.get_bars('MNQ', days=30, interval=60)  # V3: actual symbol

    # Class-based interface
    rsi = RSI()
    data_with_rsi = rsi.calculate(data, period=14)

    # TA-Lib style functions (direct usage)
    data = RSI(data, period=14)        # Add RSI
    data = SMA(data, period=20)        # Add 20-period SMA
    data = BBANDS(data, period=20)     # Add Bollinger Bands

    return data

# Run the analysis
data = asyncio.run(analyze_market())

Base Classes

class BaseIndicator(name, description='')[source]

Bases: ABC

Base class for all technical indicators.

Provides common validation, error handling, caching, and utility methods that all indicators can inherit from. This abstract base class ensures consistent behavior across all indicators while providing performance optimizations through intelligent caching.

Key Features:
  • Automatic parameter validation and data checking

  • Built-in caching system to avoid redundant calculations

  • Standardized error handling with IndicatorError exceptions

  • Support for both class-based and function-based usage

  • Memory-efficient operations with Polars DataFrames

All custom indicators should inherit from this class or one of its specialized subclasses (OverlapIndicator, MomentumIndicator, etc.) for consistent behavior and optimal performance.

__init__(name, description='')[source]

Initialize base indicator.

Parameters:
  • name (str) – Indicator name

  • description (str) – Optional description

validate_data(data, required_columns)[source]

Validate input DataFrame and required columns.

Parameters:
  • data (DataFrame) – Input DataFrame

  • required_columns (list[str]) – List of required column names

Raises:

IndicatorError – If validation fails

Return type:

None

validate_period(period, min_period=1)[source]

Validate period parameter.

Parameters:
  • period (int) – Period value to validate

  • min_period (int) – Minimum allowed period

Raises:

IndicatorError – If period is invalid

Return type:

None

validate_data_length(data, min_length)[source]

Validate that data has sufficient length for calculation.

Parameters:
  • data (DataFrame) – Input DataFrame

  • min_length (int) – Minimum required data length

Raises:

IndicatorError – If data is too short

Return type:

None

abstractmethod calculate(data, **kwargs)[source]

Calculate the indicator values.

This method must be implemented by all indicator subclasses. It should perform the core calculation logic for the specific indicator, including parameter validation, data processing, and result generation.

The method should: 1. Validate input data and parameters using inherited validation methods 2. Perform the indicator-specific calculations 3. Return a DataFrame with the original data plus new indicator columns 4. Handle edge cases (insufficient data, invalid parameters, etc.)

Parameters:
  • data (DataFrame) – Input DataFrame with OHLCV data (must contain required columns)

  • **kwargs (Any) – Additional parameters specific to each indicator (period, thresholds, column names, etc.)

Returns:

DataFrame with original data plus new indicator columns.

The indicator values should be added as new columns with descriptive names (e.g., “rsi”, “macd”, “bb_upper”).

Return type:

pl.DataFrame

Raises:

IndicatorError – If data validation fails or calculation cannot proceed

__call__(data, **kwargs)[source]

Allow indicator to be called directly with caching.

Parameters:
  • data (DataFrame) – Input DataFrame

  • **kwargs (Any) – Additional parameters

Return type:

DataFrame

Returns:

DataFrame with indicator values

class OverlapIndicator(name, description='')[source]

Bases: BaseIndicator

Base class for overlap study indicators (trend-following).

__init__(name, description='')[source]

Initialize base indicator.

Parameters:
  • name (str) – Indicator name

  • description (str) – Optional description

class MomentumIndicator(name, description='')[source]

Bases: BaseIndicator

Base class for momentum indicators.

__init__(name, description='')[source]

Initialize base indicator.

Parameters:
  • name (str) – Indicator name

  • description (str) – Optional description

class VolatilityIndicator(name, description='')[source]

Bases: BaseIndicator

Base class for volatility indicators.

__init__(name, description='')[source]

Initialize base indicator.

Parameters:
  • name (str) – Indicator name

  • description (str) – Optional description

class VolumeIndicator(name, description='')[source]

Bases: BaseIndicator

Base class for volume indicators.

__init__(name, description='')[source]

Initialize base indicator.

Parameters:
  • name (str) – Indicator name

  • description (str) – Optional description

Overlap Studies (Trend Indicators)

class SMA(data, column='close', period=20)[source]

Bases:

Simple Moving Average (TA-Lib style).

Return type:

DataFrame

class EMA(data, column='close', period=20)[source]

Bases:

Exponential Moving Average (TA-Lib style).

Return type:

DataFrame

class BBANDS(data, column='close', period=20, std_dev=2.0)[source]

Bases:

Bollinger Bands (TA-Lib style).

Return type:

DataFrame

class DEMA(data, column='close', period=20)[source]

Bases:

Double Exponential Moving Average (TA-Lib style).

Return type:

DataFrame

class TEMA(data, column='close', period=20)[source]

Bases:

Triple Exponential Moving Average (TA-Lib style).

Return type:

DataFrame

class WMA(data, column='close', period=20)[source]

Bases:

Weighted Moving Average (TA-Lib style).

Return type:

DataFrame

class MIDPOINT(data, column='close', period=14)[source]

Bases:

Midpoint over period (TA-Lib style).

Return type:

DataFrame

Momentum Indicators

class RSI(data, column='close', period=14)[source]

Bases:

Relative Strength Index (TA-Lib style).

Return type:

DataFrame

class MACD(data, column='close', fast_period=12, slow_period=26, signal_period=9)[source]

Bases:

Moving Average Convergence Divergence (TA-Lib style).

Return type:

DataFrame

class STOCH(data, high_column='high', low_column='low', close_column='close', k_period=14, d_period=3)[source]

Bases:

Stochastic Oscillator (TA-Lib style).

Return type:

DataFrame

class WILLR(data, high_column='high', low_column='low', close_column='close', period=14)[source]

Bases:

Williams %R (TA-Lib style).

Return type:

DataFrame

class CCI(data, high_column='high', low_column='low', close_column='close', period=20, constant=0.015)[source]

Bases:

Commodity Channel Index (TA-Lib style).

Return type:

DataFrame

class ROC(data, column='close', period=10)[source]

Bases:

Rate of Change (TA-Lib style).

Return type:

DataFrame

class MOM(data, column='close', period=10)[source]

Bases:

Momentum (TA-Lib style).

Return type:

DataFrame

class STOCHRSI(data, column='close', rsi_period=14, stoch_period=14, k_period=3, d_period=3)[source]

Bases:

Stochastic RSI (TA-Lib style).

Return type:

DataFrame

Volatility Indicators

class ATR(data, high_column='high', low_column='low', close_column='close', period=14)[source]

Bases:

Average True Range (TA-Lib style).

Return type:

DataFrame

class ADX(data, high_column='high', low_column='low', close_column='close', period=14)[source]

Bases:

Average Directional Movement Index (TA-Lib style).

Return type:

DataFrame

class NATR(data, high_column='high', low_column='low', close_column='close', period=14)[source]

Bases:

Normalized Average True Range (TA-Lib style).

Return type:

DataFrame

class TRANGE(data, high_column='high', low_column='low', close_column='close')[source]

Bases:

True Range (TA-Lib style).

Return type:

DataFrame

class ULTOSC(data, high_column='high', low_column='low', close_column='close', period1=7, period2=14, period3=28)[source]

Bases:

Ultimate Oscillator (TA-Lib style).

Return type:

DataFrame

Volume Indicators

class OBV(data, close_column='close', volume_column='volume')[source]

Bases:

On-Balance Volume (TA-Lib style).

Return type:

DataFrame

class VWAP(data, high_column='high', low_column='low', close_column='close', volume_column='volume', period=None)[source]

Bases:

Volume Weighted Average Price (TA-Lib style).

Return type:

DataFrame

class AD(data, high_column='high', low_column='low', close_column='close', volume_column='volume')[source]

Bases:

Accumulation/Distribution Line (TA-Lib style).

Return type:

DataFrame

class ADOSC(data, high_column='high', low_column='low', close_column='close', volume_column='volume', fast_period=3, slow_period=10)[source]

Bases:

Accumulation/Distribution Oscillator (TA-Lib style).

Return type:

DataFrame

Pattern Recognition Indicators

class FVG(data, high_column='high', low_column='low', close_column='close', min_gap_size=0.0, check_mitigation=False, mitigation_threshold=0.5)[source]

Bases:

Fair Value Gap (TA-Lib style).

Return type:

DataFrame

class WAE(data, close_column='close', high_column='high', low_column='low', fast_period=20, slow_period=40, bb_period=20, bb_mult=2.0, sensitivity=150, dead_zone_period=100, dead_zone_mult=3.6)[source]

Bases:

Waddah Attar Explosion (TA-Lib style).

Return type:

DataFrame

Convenience Functions

Overlap Studies

calculate_sma(data, column='close', period=20)[source]

Calculate Simple Moving Average (convenience function).

Return type:

DataFrame

calculate_ema(data, column='close', period=20)[source]

Calculate Exponential Moving Average (convenience function).

Return type:

DataFrame

calculate_bollinger_bands(data, column='close', period=20, std_dev=2.0)[source]

Calculate Bollinger Bands (convenience function).

Return type:

DataFrame

Momentum Indicators

calculate_rsi(data, column='close', period=14)[source]

Calculate RSI (convenience function).

Return type:

DataFrame

calculate_macd(data, column='close', fast_period=12, slow_period=26, signal_period=9)[source]

Calculate MACD (convenience function).

Return type:

DataFrame

calculate_stochastic(data, high_column='high', low_column='low', close_column='close', k_period=14, d_period=3)[source]

Calculate Stochastic (convenience function).

Return type:

DataFrame

calculate_williams_r(data, high_column='high', low_column='low', close_column='close', period=14)[source]

Calculate Williams %R (convenience function).

Return type:

DataFrame

calculate_commodity_channel_index(data, high_column='high', low_column='low', close_column='close', period=20, constant=0.015)[source]

Calculate CCI (convenience function).

Return type:

DataFrame

Volatility Indicators

calculate_atr(data, high_column='high', low_column='low', close_column='close', period=14)[source]

Calculate ATR (convenience function).

Return type:

DataFrame

calculate_adx(data, high_column='high', low_column='low', close_column='close', period=14)[source]

Calculate ADX (convenience function).

Return type:

DataFrame

Volume Indicators

calculate_obv(data, close_column='close', volume_column='volume')[source]

Calculate OBV (convenience function).

Return type:

DataFrame

calculate_vwap(data, high_column='high', low_column='low', close_column='close', volume_column='volume', period=None)[source]

Calculate VWAP (convenience function).

Return type:

DataFrame

Pattern Recognition

calculate_fvg(data, high_column='high', low_column='low', close_column='close', min_gap_size=0.0, check_mitigation=False, mitigation_threshold=0.5)[source]

Calculate Fair Value Gaps (convenience function).

See FVG.calculate() for detailed documentation.

Parameters:
  • data (DataFrame) – DataFrame with OHLC data

  • high_column (str) – High price column

  • low_column (str) – Low price column

  • close_column (str) – Close price column

  • min_gap_size (float) – Minimum gap size to consider valid

  • check_mitigation (bool) – Whether to check if gaps have been mitigated

  • mitigation_threshold (float) – Percentage of gap that needs to be filled to consider it mitigated

Return type:

DataFrame

Returns:

DataFrame with FVG columns added

calculate_order_block(data, open_column='open', high_column='high', low_column='low', close_column='close', volume_column='volume', min_volume_percentile=50, check_mitigation=False, mitigation_threshold=0.5, lookback_periods=3, use_wicks=True)[source]

Calculate Order Blocks (convenience function).

See OrderBlock.calculate() for detailed documentation.

Parameters:
  • data (DataFrame) – DataFrame with OHLC data

  • open_column (str) – Open price column

  • high_column (str) – High price column

  • low_column (str) – Low price column

  • close_column (str) – Close price column

  • volume_column (str) – Volume column

  • min_volume_percentile (float) – Minimum volume percentile for valid OB

  • check_mitigation (bool) – Whether to check if blocks have been mitigated

  • mitigation_threshold (float) – Percentage of block that needs to be filled

  • lookback_periods (int) – Number of periods to look back for break

  • use_wicks (bool) – Whether to use wicks or bodies for OB zones

Return type:

DataFrame

Returns:

DataFrame with Order Block columns added

calculate_wae(data, close_column='close', high_column='high', low_column='low', fast_period=20, slow_period=40, bb_period=20, bb_mult=2.0, sensitivity=150, dead_zone_period=100, dead_zone_mult=3.6)[source]

Calculate Waddah Attar Explosion (convenience function).

See WAE.calculate() for detailed documentation.

Parameters:
  • data (DataFrame) – DataFrame with OHLC data

  • close_column (str) – Close price column

  • high_column (str) – High price column

  • low_column (str) – Low price column

  • fast_period (int) – Fast EMA period for MACD

  • slow_period (int) – Slow EMA period for MACD

  • bb_period (int) – Bollinger Bands period

  • bb_mult (float) – Bollinger Bands multiplier

  • sensitivity (float) – Sensitivity multiplier for explosion

  • dead_zone_period (int) – ATR period for dead zone

  • dead_zone_mult (float) – Multiplier for dead zone ATR

Return type:

DataFrame

Returns:

DataFrame with WAE columns added

Discovery Functions

get_all_indicators()[source]

Get list of all available indicators.

Return type:

list[str]

get_indicator_groups()[source]

Get available indicator groups.

Return type:

dict[str, list[str]]

get_indicator_info(indicator_name)[source]

Get information about a specific indicator.

Return type:

str

Utility Functions

ema_alpha(period)[source]

Calculate EMA alpha (smoothing factor) from period.

This utility function calculates the smoothing factor (alpha) used in Exponential Moving Average calculations. The alpha determines how much weight is given to recent prices versus older prices.

Formula: alpha = 2 / (period + 1)

Parameters:

period (int) – EMA period (number of periods for the moving average)

Returns:

Alpha value (smoothing factor) between 0 and 1

Return type:

float

Example

>>> alpha = ema_alpha(14)  # Returns 0.1333...
>>> # Higher alpha = more weight to recent prices
>>> alpha_short = ema_alpha(5)  # 0.3333...
>>> alpha_long = ema_alpha(50)  # 0.0392...
safe_division(numerator, denominator, default=0.0)[source]

Safe division that handles division by zero.

This utility function creates a Polars expression that performs division while safely handling cases where the denominator is zero. It’s commonly used in technical indicator calculations where division operations might encounter zero values.

Parameters:
  • numerator (Expr) – Numerator expression (pl.Expr)

  • denominator (Expr) – Denominator expression (pl.Expr)

  • default (float) – Default value to return when denominator is zero (default: 0.0)

Returns:

Polars expression that performs safe division, returning the

default value when denominator is zero

Return type:

pl.Expr

Example

>>> # Safe division in RSI calculation
>>> gain = pl.col("close").diff().filter(pl.col("close").diff() > 0)
>>> loss = -pl.col("close").diff().filter(pl.col("close").diff() < 0)
>>> rs = safe_division(gain.rolling_mean(14), loss.rolling_mean(14))

Usage Examples

Basic Usage

import asyncio
from project_x_py.indicators import RSI, SMA, MACD
from project_x_py import ProjectX

async def basic_analysis():
    # Load your data (Polars DataFrame with OHLCV columns)
    async with ProjectX.from_env() as client:
        await client.authenticate()
        data = await client.get_bars('MNQ', days=30, interval=60)  # V3: actual symbol

    # Add indicators using TA-Lib style functions
    data = RSI(data, period=14)
    data = SMA(data, period=20)
    data = SMA(data, period=50)
    data = MACD(data, fast_period=12, slow_period=26, signal_period=9)

    # Check latest values
    latest = data.tail(1)
    print(f"RSI: {latest['rsi_14'].item():.2f}")
    print(f"SMA(20): ${latest['sma_20'].item():.2f}")

asyncio.run(basic_analysis())

Class-Based Interface

from project_x_py.indicators import RSI, SMA, BBANDS

# Create indicator instances
rsi = RSI()
sma = SMA()
bb = BBANDS()

# Calculate indicators
data_with_rsi = rsi.calculate(data, period=14)
data_with_sma = sma.calculate(data_with_rsi, period=20)
data_with_bb = bb.calculate(data_with_sma, period=20, std_dev=2.0)

Multi-Indicator Strategy

import asyncio
import polars as pl
from project_x_py.indicators import *
from project_x_py import ProjectX

async def multi_indicator_analysis():
    # Get data
    async with ProjectX.from_env() as client:
        await client.authenticate()
        data = await client.get_bars('MNQ', days=60, interval=60)  # V3: actual symbol

    # Comprehensive technical analysis
    analysis = (
        data
        # Trend indicators
        .pipe(SMA, period=20)
        .pipe(SMA, period=50)
        .pipe(EMA, period=21)
        .pipe(BBANDS, period=20, std_dev=2.0)

        # Momentum indicators
        .pipe(RSI, period=14)
        .pipe(MACD, fast_period=12, slow_period=26, signal_period=9)
        .pipe(STOCH, k_period=14, d_period=3)

        # Volatility indicators
        .pipe(ATR, period=14)
        .pipe(ADX, period=14)

        # Volume indicators
        .pipe(OBV)
        .pipe(VWAP, period=20)

        # Pattern recognition
        .pipe(FVG, min_gap_size=0.001, check_mitigation=True)
        .pipe(ORDERBLOCK, min_volume_percentile=70)
        .pipe(WAE, sensitivity=150)
    )

    return analysis

# Run the strategy
result = asyncio.run(multi_indicator_analysis())

Pattern Recognition Examples

from project_x_py.indicators import FVG, OrderBlock, WAE

# Fair Value Gap Detection
fvg = FVG()
data_with_fvg = fvg.calculate(
    data,
    min_gap_size=0.001,  # 0.1% minimum gap
    check_mitigation=True,  # Track if gaps get filled
    mitigation_threshold=0.5  # 50% fill threshold
)

# Order Block Identification
ob = OrderBlock()
data_with_ob = ob.calculate(
    data,
    min_volume_percentile=70,  # Top 30% volume
    lookback_periods=3,  # Look for 3-candle patterns
    use_wicks=True  # Consider wicks in patterns
)

# Waddah Attar Explosion
wae = WAE()
data_with_wae = wae.calculate(
    data,
    sensitivity=150,  # Trend sensitivity
    dead_zone_period=100,  # ATR period for filtering
    dead_zone_mult=3.6  # Dead zone multiplier
)

# Confluence Trading: Combine all three
confluence_data = (
    data
    .pipe(FVG, check_mitigation=True)
    .pipe(ORDERBLOCK, min_volume_percentile=80)
    .pipe(WAE, sensitivity=150)
)

# Find strong signals where patterns align
strong_bullish = confluence_data.filter(
    (pl.col("fvg_bullish") == True) &
    (pl.col("ob_bullish") == True) &
    (pl.col("wae_explosion_up") > 0)
)

Indicator Discovery

from project_x_py.indicators import get_all_indicators, get_indicator_groups

# List all available indicators
all_indicators = get_all_indicators()
print(f"Total indicators: {len(all_indicators)}")

# Get indicators by category
groups = get_indicator_groups()
for category, indicators in groups.items():
    print(f"{category}: {indicators}")

# Get information about specific indicator
rsi_info = get_indicator_info('RSI')
print(f"RSI: {rsi_info}")

Error Handling

from project_x_py.indicators import IndicatorError

try:
    # This will raise an error if the column doesn't exist
    data_with_rsi = RSI(data, column='nonexistent_column', period=14)
except IndicatorError as e:
    print(f"Indicator error: {e}")

try:
    # This will raise an error if period is too large
    data_with_sma = SMA(data, period=1000)  # More than available data
except IndicatorError as e:
    print(f"Invalid period: {e}")

Performance Tips

  1. Use Polars methods: Indicators are optimized for Polars DataFrames

  2. Chain operations: Use .pipe() for efficient chaining

  3. Reuse instances: Create indicator instances once and reuse them

  4. Batch calculations: Calculate multiple indicators in one pass when possible

  5. Async data fetching: Fetch data once and apply all indicators

async def efficient_analysis():
    # Fetch data once
    async with ProjectX.from_env() as client:
        await client.authenticate()
        data = await client.get_bars('MNQ', days=30)  # V3: actual symbol

    # Efficient: Chain multiple indicators
    data = (
        data
        .pipe(RSI, period=14)
        .pipe(SMA, period=20)
        .pipe(MACD)
    )

    # Less efficient: Separate calculations
    # data = RSI(data, period=14)
    # data = SMA(data, period=20)
    # data = MACD(data)

    return data

TA-Lib Compatibility

The indicators are designed to be compatible with TA-Lib naming and parameter conventions:

TA-Lib Compatibility

TA-Lib Function

project-x-py Equivalent

Notes

talib.SMA(close, timeperiod=20)

SMA(data, period=20)

Uses ‘close’ column by default

talib.RSI(close, timeperiod=14)

RSI(data, period=14)

Identical calculation method

talib.BBANDS(close, timeperiod=20)

BBANDS(data, period=20, std_dev=2.0)

Returns upper, middle, lower bands

talib.MACD(close)

MACD(data)

Returns MACD line, signal, histogram

Exception Classes

class IndicatorError[source]

Bases: Exception

Custom exception for indicator calculation errors.