# Technical Indicators Module ## Overview The Technical Indicators module provides a modular, extensible system for calculating technical analysis indicators. It is designed to handle sparse OHLCV data efficiently, making it ideal for real-time trading applications. ## Architecture ### Package Structure ``` data/common/indicators/ ├── __init__.py # Package exports ├── technical.py # Main facade class ├── base.py # Base indicator class ├── result.py # Result container class ├── utils.py # Utility functions └── implementations/ # Individual indicator implementations ├── __init__.py ├── sma.py # Simple Moving Average ├── ema.py # Exponential Moving Average ├── rsi.py # Relative Strength Index ├── macd.py # MACD └── bollinger.py # Bollinger Bands ``` ### Key Components #### 1. Base Classes - **BaseIndicator**: Abstract base class providing common functionality - Data preparation - Validation - Error handling - Logging #### 2. Individual Indicators Each indicator is implemented as a separate class inheriting from `BaseIndicator`: - Focused responsibility - Independent testing - Easy maintenance - Clear documentation #### 3. TechnicalIndicators Facade Main entry point providing: - Unified interface - Batch calculations - Consistent error handling - Data preparation ## Supported Indicators ### Simple Moving Average (SMA) ```python from data.common.indicators import TechnicalIndicators indicators = TechnicalIndicators() results = indicators.sma(df, period=20, price_column='close') ``` - **Parameters**: - `period`: Number of periods (default: 20) - `price_column`: Column to average (default: 'close') ### Exponential Moving Average (EMA) ```python results = indicators.ema(df, period=12, price_column='close') ``` - **Parameters**: - `period`: Number of periods (default: 20) - `price_column`: Column to average (default: 'close') ### Relative Strength Index (RSI) ```python results = indicators.rsi(df, period=14, price_column='close') ``` - **Parameters**: - `period`: Number of periods (default: 14) - `price_column`: Column to analyze (default: 'close') ### Moving Average Convergence Divergence (MACD) ```python results = indicators.macd( df, fast_period=12, slow_period=26, signal_period=9, price_column='close' ) ``` - **Parameters**: - `fast_period`: Fast EMA period (default: 12) - `slow_period`: Slow EMA period (default: 26) - `signal_period`: Signal line period (default: 9) - `price_column`: Column to analyze (default: 'close') ### Bollinger Bands ```python results = indicators.bollinger_bands( df, period=20, std_dev=2.0, price_column='close' ) ``` - **Parameters**: - `period`: SMA period (default: 20) - `std_dev`: Standard deviation multiplier (default: 2.0) - `price_column`: Column to analyze (default: 'close') ## Usage Examples ### Basic Usage ```python from data.common.indicators import TechnicalIndicators # Initialize calculator indicators = TechnicalIndicators(logger=my_logger) # Calculate single indicator sma_results = indicators.sma(df, period=20) # Access results for result in sma_results: print(f"Time: {result.timestamp}, SMA: {result.values['sma']}") ``` ### Batch Calculations ```python # Configure multiple indicators config = { 'sma_20': {'type': 'sma', 'period': 20}, 'ema_12': {'type': 'ema', 'period': 12}, 'rsi_14': {'type': 'rsi', 'period': 14}, 'macd': { 'type': 'macd', 'fast_period': 12, 'slow_period': 26, 'signal_period': 9 } } # Calculate all at once results = indicators.calculate_multiple_indicators(df, config) ``` ### Dynamic Indicator Selection ```python # Calculate any indicator by name result = indicators.calculate( 'macd', df, fast_period=12, slow_period=26, signal_period=9 ) ``` ## Data Structures ### IndicatorResult ```python @dataclass class IndicatorResult: timestamp: datetime # Right-aligned timestamp symbol: str # Trading symbol timeframe: str # Candle timeframe values: Dict[str, float] # Indicator values metadata: Optional[Dict[str, Any]] = None # Calculation metadata ``` ## Error Handling The module provides comprehensive error handling: - Input validation - Data sufficiency checks - Calculation error handling - Detailed error logging Example: ```python try: results = indicators.rsi(df, period=14) except Exception as e: logger.error(f"RSI calculation failed: {e}") results = [] ``` ## Performance Considerations 1. **Data Preparation** - Uses pandas for vectorized calculations - Handles sparse data efficiently - Maintains timestamp alignment 2. **Memory Usage** - Avoids unnecessary data copies - Cleans up temporary calculations - Uses efficient data structures 3. **Calculation Optimization** - Vectorized operations where possible - Minimal data transformations - Efficient algorithm implementations ## Testing The module includes comprehensive tests: - Unit tests for each indicator - Integration tests for the facade - Edge case handling - Performance benchmarks Run tests with: ```bash uv run pytest tests/test_indicators.py ``` ## Contributing When adding new indicators: 1. Create a new class in `implementations/` 2. Inherit from `BaseIndicator` 3. Implement the `calculate` method 4. Add tests 5. Update documentation See [Adding New Indicators](./adding-new-indicators.md) for detailed instructions. ## Key Features - **DataFrame-Centric Design**: Operates directly on pandas DataFrames for performance and simplicity. - **Vectorized Calculations**: Leverages pandas and numpy for high-speed computation. - **Flexible `calculate` Method**: A single entry point for calculating any supported indicator by name. - **Standardized Output**: All methods return a DataFrame containing the calculated indicator values, indexed by timestamp. - **Modular Architecture**: Clear separation between calculation logic, result types, and utilities. ## Usage Examples ### Importing the Required Components ```python from data.common.indicators import ( TechnicalIndicators, IndicatorResult, create_default_indicators_config, validate_indicator_config ) from data.common.data_types import OHLCVCandle ``` ### Preparing the DataFrame Before you can calculate indicators, you need a properly formatted pandas DataFrame. The `prepare_chart_data` utility is the recommended way to create one from a list of candle dictionaries. ```python from components.charts.utils import prepare_chart_data from data.common.indicators import TechnicalIndicators # Assume 'candles' is a list of OHLCV dictionaries from the database # candles = fetch_market_data(...) # Prepare the DataFrame df = prepare_chart_data(candles) # df is now ready for indicator calculations # It has a DatetimeIndex and the necessary OHLCV columns. ``` ### Basic Indicator Calculation Once you have a prepared DataFrame, you can calculate indicators directly. ```python # Initialize the calculator indicators = TechnicalIndicators() # Calculate a Simple Moving Average sma_df = indicators.sma(df, period=20) # Calculate an Exponential Moving Average ema_df = indicators.ema(df, period=12) # sma_df and ema_df are pandas DataFrames containing the results. ``` ### Using the `calculate` Method The most flexible way to compute an indicator is with the `calculate` method, which accepts the indicator type as a string. ```python # Calculate RSI using the generic method rsi_pkg = indicators.calculate('rsi', df, period=14) if rsi_pkg: rsi_df = rsi_pkg['data'] # Calculate MACD with custom parameters macd_pkg = indicators.calculate('macd', df, fast_period=10, slow_period=30, signal_period=8) if macd_pkg: macd_df = macd_pkg['data'] ``` ### Using Different Price Columns You can specify which price column (`open`, `high`, `low`, or `close`) to use for the calculation. ```python # Calculate SMA on the 'high' price sma_high_df = indicators.sma(df, period=20, price_column='high') # Calculate RSI on the 'open' price rsi_open_pkg = indicators.calculate('rsi', df, period=14, price_column='open') ``` ## Indicator Details The following details the parameters and the columns returned in the result DataFrame for each indicator. ### Simple Moving Average (SMA) - **Parameters**: `period` (int), `price_column` (str, default: 'close') - **Returned Columns**: `sma` ### Exponential Moving Average (EMA) - **Parameters**: `period` (int), `price_column` (str, default: 'close') - **Returned Columns**: `ema` ### Relative Strength Index (RSI) - **Parameters**: `period` (int), `price_column` (str, default: 'close') - **Returned Columns**: `rsi` ### MACD (Moving Average Convergence Divergence) - **Parameters**: `fast_period` (int), `slow_period` (int), `signal_period` (int), `price_column` (str, default: 'close') - **Returned Columns**: `macd`, `signal`, `histogram` ### Bollinger Bands - **Parameters**: `period` (int), `std_dev` (float), `price_column` (str, default: 'close') - **Returned Columns**: `upper_band`, `