9.1 KiB
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)
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)
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)
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)
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
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
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
# 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
# Calculate any indicator by name
result = indicators.calculate(
'macd',
df,
fast_period=12,
slow_period=26,
signal_period=9
)
Data Structures
IndicatorResult
@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:
try:
results = indicators.rsi(df, period=14)
except Exception as e:
logger.error(f"RSI calculation failed: {e}")
results = []
Performance Considerations
-
Data Preparation
- Uses pandas for vectorized calculations
- Handles sparse data efficiently
- Maintains timestamp alignment
-
Memory Usage
- Avoids unnecessary data copies
- Cleans up temporary calculations
- Uses efficient data structures
-
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:
uv run pytest tests/test_indicators.py
Contributing
When adding new indicators:
- Create a new class in
implementations/ - Inherit from
BaseIndicator - Implement the
calculatemethod - Add tests
- Update documentation
See Adding New Indicators 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
calculateMethod: 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
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.
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.
# 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.
# 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.
# 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, `