298 lines
10 KiB
Markdown
298 lines
10 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 to be **DataFrame-centric**. 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.
|
|
|
|
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.
|
|
|
|
## Usage Examples
|
|
|
|
### 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`
|
|
|
|
## 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`.
|
|
|
|
## Data Structures
|
|
|
|
### IndicatorResult
|
|
|
|
Container for 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 Format
|
|
|
|
Indicator configurations use a standardized JSON format:
|
|
|
|
```json
|
|
{
|
|
"indicator_name": {
|
|
"type": "sma|ema|rsi|macd|bollinger_bands",
|
|
"period": 20,
|
|
"price_column": "close",
|
|
// Additional parameters specific to indicator type
|
|
}
|
|
}
|
|
```
|
|
|
|
## Integration with TCP Platform
|
|
|
|
### Aggregation Strategy Compatibility
|
|
|
|
The indicators module is designed to work seamlessly with the TCP platform's aggregation strategy:
|
|
|
|
- **Right-Aligned Timestamps**: Uses `end_time` from OHLCV candles
|
|
- **Sparse Data Support**: Handles missing candles without interpolation
|
|
- **No Future Leakage**: Only processes completed candles
|
|
- **Time Boundary Respect**: Maintains proper temporal ordering
|
|
|
|
### Real-Time Processing
|
|
|
|
```python
|
|
from data.common.aggregation import RealTimeCandleProcessor
|
|
from data.common.indicators import TechnicalIndicators
|
|
|
|
# Set up real-time processing
|
|
candle_processor = RealTimeCandleProcessor(symbol='BTC-USDT', exchange='okx')
|
|
indicators = TechnicalIndicators()
|
|
|
|
# Process incoming trades and calculate indicators
|
|
def on_new_candle(candle):
|
|
# Get recent candles for indicator calculation
|
|
recent_candles = get_recent_candles(symbol='BTC-USDT', count=50)
|
|
|
|
# Calculate indicators
|
|
sma_results = indicators.sma(recent_candles, period=20)
|
|
rsi_results = indicators.rsi(recent_candles, period=14)
|
|
|
|
# Use indicator values for trading decisions
|
|
if sma_results and rsi_results:
|
|
latest_sma = sma_results[-1].values['sma']
|
|
latest_rsi = rsi_results[-1].values['rsi']
|
|
|
|
# Trading logic here...
|
|
```
|
|
|
|
### Database Integration
|
|
|
|
```python
|
|
from database.models import IndicatorData
|
|
|
|
# Store indicator results in database
|
|
def store_indicators(indicator_results, indicator_type):
|
|
for result in indicator_results:
|
|
indicator_data = IndicatorData(
|
|
symbol=result.symbol,
|
|
timeframe=result.timeframe,
|
|
timestamp=result.timestamp,
|
|
indicator_type=indicator_type,
|
|
values=result.values,
|
|
metadata=result.metadata
|
|
)
|
|
session.add(indicator_data)
|
|
session.commit()
|
|
```
|
|
|
|
## 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. |