- Introduced a dedicated sub-package for technical indicators under `data/common/indicators/`, improving modularity and maintainability. - Moved `TechnicalIndicators` and `IndicatorResult` classes to their respective files, along with utility functions for configuration management. - Updated import paths throughout the codebase to reflect the new structure, ensuring compatibility. - Added comprehensive safety net tests for the indicators module to verify core functionality and prevent regressions during refactoring. - Enhanced documentation to provide clear usage examples and details on the new package structure. These changes improve the overall architecture of the technical indicators module, making it more scalable and easier to manage.
288 lines
9.7 KiB
Markdown
288 lines
9.7 KiB
Markdown
# Technical Indicators Module
|
|
|
|
The Technical Indicators module provides a suite of common technical analysis tools. It is designed to work efficiently with pandas DataFrames, which is the standard data structure for time-series analysis in the TCP Trading Platform.
|
|
|
|
## Overview
|
|
|
|
The module has been refactored into a dedicated package structure under `data/common/indicators/`. All calculation methods now expect a pandas DataFrame with a `DatetimeIndex` and the required OHLCV columns (`open`, `high`, `low`, `close`, `volume`). This change simplifies the data pipeline, improves performance through vectorization, and ensures consistency across the platform.
|
|
|
|
### Package Structure
|
|
|
|
```
|
|
data/common/indicators/
|
|
├── __init__.py # Package exports
|
|
├── technical.py # TechnicalIndicators class implementation
|
|
├── result.py # IndicatorResult dataclass
|
|
└── utils.py # Utility functions for configuration
|
|
```
|
|
|
|
The module implements five core technical indicators:
|
|
|
|
- **Simple Moving Average (SMA)**
|
|
- **Exponential Moving Average (EMA)**
|
|
- **Relative Strength Index (RSI)**
|
|
- **Moving Average Convergence Divergence (MACD)**
|
|
- **Bollinger Bands**
|
|
|
|
## 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`, `middle_band`, `lower_band`
|
|
|
|
## Data Structures
|
|
|
|
### IndicatorResult
|
|
|
|
The `IndicatorResult` class (from `data.common.indicators.result`) contains technical indicator calculation results:
|
|
|
|
```python
|
|
@dataclass
|
|
class IndicatorResult:
|
|
timestamp: datetime # Right-aligned candle timestamp
|
|
symbol: str # Trading symbol (e.g., 'BTC-USDT')
|
|
timeframe: str # Candle timeframe (e.g., '1m', '5m')
|
|
values: Dict[str, float] # Indicator values
|
|
metadata: Optional[Dict[str, Any]] = None # Calculation metadata
|
|
```
|
|
|
|
### Configuration Management
|
|
|
|
The module provides utilities for managing indicator configurations (from `data.common.indicators.utils`):
|
|
|
|
```python
|
|
# Create default configurations
|
|
config = create_default_indicators_config()
|
|
|
|
# Validate a configuration
|
|
is_valid = validate_indicator_config({
|
|
'type': 'sma',
|
|
'period': 20,
|
|
'price_column': 'close'
|
|
})
|
|
```
|
|
|
|
### Integration with TCP Platform
|
|
|
|
The indicators module is designed to work seamlessly with the platform's components:
|
|
|
|
```python
|
|
from data.common.indicators import TechnicalIndicators
|
|
from data.common.data_types import OHLCVCandle
|
|
from components.charts.utils import prepare_chart_data
|
|
|
|
# Initialize calculator
|
|
indicators = TechnicalIndicators()
|
|
|
|
# Calculate indicators
|
|
results = indicators.calculate_multiple_indicators(df, {
|
|
'sma_20': {'type': 'sma', 'period': 20},
|
|
'rsi_14': {'type': 'rsi', 'period': 14}
|
|
})
|
|
|
|
# Access results
|
|
for indicator_name, indicator_results in results.items():
|
|
for result in indicator_results:
|
|
print(f"{indicator_name}: {result.values}")
|
|
```
|
|
|
|
## Integration with the TCP Platform
|
|
|
|
The refactored `TechnicalIndicators` module is now tightly integrated with the `ChartBuilder`, which handles all data preparation and calculation automatically when indicators are added to a chart. For custom analysis or strategy development, you can use the class directly as shown in the examples above. The key is to always start with a properly prepared DataFrame using `prepare_chart_data`.
|
|
|
|
## Performance Considerations
|
|
|
|
### Memory Usage
|
|
- Process indicators in batches for large datasets
|
|
- Use appropriate period lengths to balance accuracy and performance
|
|
- Consider data retention policies for historical indicator values
|
|
|
|
### Calculation Frequency
|
|
- Calculate indicators only when new complete candles are available
|
|
- Cache recent indicator values to avoid recalculation
|
|
- Use incremental updates for real-time scenarios
|
|
|
|
### Optimization Tips
|
|
- Use `calculate_multiple_indicators()` for efficiency when computing multiple indicators
|
|
- Limit the number of historical candles to what's actually needed
|
|
- Consider using different timeframes for different indicators
|
|
|
|
## Error Handling
|
|
|
|
The module includes comprehensive error handling:
|
|
|
|
- **Insufficient Data**: Returns empty results when not enough data is available
|
|
- **Invalid Configuration**: Validates configuration parameters before calculation
|
|
- **Data Quality Issues**: Handles NaN values and missing data gracefully
|
|
- **Type Errors**: Converts data types safely with fallback values
|
|
|
|
## Testing
|
|
|
|
The module includes comprehensive unit tests covering:
|
|
|
|
- All indicator calculations with known expected values
|
|
- Sparse data handling scenarios
|
|
- Edge cases (insufficient data, invalid parameters)
|
|
- Configuration validation
|
|
- Multiple indicator batch processing
|
|
|
|
Run tests with:
|
|
```bash
|
|
uv run pytest tests/test_indicators.py -v
|
|
```
|
|
|
|
## Future Enhancements
|
|
|
|
Potential future additions to the indicators module:
|
|
|
|
- **Additional Indicators**: Stochastic, Williams %R, Commodity Channel Index
|
|
- **Custom Indicators**: Framework for user-defined indicators
|
|
- **Performance Metrics**: Calculation timing and memory usage statistics
|
|
- **Streaming Updates**: Incremental indicator updates for real-time scenarios
|
|
- **Parallel Processing**: Multi-threaded calculation for large datasets
|
|
|
|
## See Also
|
|
|
|
- [Aggregation Strategy Documentation](aggregation-strategy.md)
|
|
- [Data Types Documentation](data-types.md)
|
|
- [Database Schema Documentation](database-schema.md)
|
|
- [API Reference](api-reference.md)
|
|
|
|
## `TechnicalIndicators` Class
|
|
|
|
The main class for calculating technical indicators.
|
|
|
|
- **RSI**: `rsi(df, period=14, price_column='close')`
|
|
- **MACD**: `macd(df, fast_period=12, slow_period=26, signal_period=9, price_column='close')`
|
|
- **Bollinger Bands**: `bollinger_bands(df, period=20, std_dev=2.0, price_column='close')`
|
|
|
|
### `calculate_multiple_indicators`
|
|
|
|
Calculates multiple indicators in a single pass for efficiency.
|
|
|
|
```python
|
|
# Configuration for multiple indicators
|
|
indicators_config = {
|
|
'sma_20': {'type': 'sma', 'period': 20},
|
|
'ema_50': {'type': 'ema', 'period': 50},
|
|
'rsi_14': {'type': 'rsi', 'period': 14}
|
|
}
|
|
|
|
# Calculate all indicators
|
|
all_results = ti.calculate_multiple_indicators(candles, indicators_config)
|
|
|
|
print(f"SMA results: {len(all_results['sma_20'])}")
|
|
print(f"RSI results: {len(all_results['rsi_14'])}")
|
|
```
|
|
|
|
## Sparse Data Handling
|
|
|
|
The `TechnicalIndicators` class is designed to handle sparse OHLCV data, which is a common scenario in real-time data collection. |