381 lines
11 KiB
Markdown
381 lines
11 KiB
Markdown
# Adding New Indicators Guide
|
|
|
|
## Overview
|
|
|
|
This guide provides comprehensive instructions for adding new technical indicators to the Crypto Trading Bot Dashboard. The system uses a modular approach where each indicator is implemented as a separate class inheriting from `BaseIndicator`.
|
|
|
|
## Table of Contents
|
|
|
|
1. [Prerequisites](#prerequisites)
|
|
2. [Implementation Steps](#implementation-steps)
|
|
3. [Integration with Charts](#integration-with-charts)
|
|
4. [Best Practices](#best-practices)
|
|
5. [Testing Guidelines](#testing-guidelines)
|
|
6. [Common Pitfalls](#common-pitfalls)
|
|
7. [Example Implementation](#example-implementation)
|
|
|
|
## Prerequisites
|
|
|
|
- Python knowledge with pandas/numpy
|
|
- Understanding of technical analysis concepts
|
|
- Familiarity with the project structure
|
|
- Knowledge of the indicator's mathematical formula
|
|
- Understanding of the dashboard's chart system
|
|
|
|
## Implementation Steps
|
|
|
|
### 1. Create Indicator Class
|
|
|
|
Create a new file in `data/common/indicators/implementations/` named after your indicator (e.g., `stochastic.py`):
|
|
|
|
```python
|
|
from typing import Dict, Any, List
|
|
import pandas as pd
|
|
from ..base import BaseIndicator
|
|
from ..result import IndicatorResult
|
|
|
|
class StochasticIndicator(BaseIndicator):
|
|
"""
|
|
Stochastic Oscillator implementation.
|
|
|
|
The Stochastic Oscillator is a momentum indicator comparing a particular closing price
|
|
of a security to a range of its prices over a certain period of time.
|
|
"""
|
|
|
|
def __init__(self, logger=None):
|
|
super().__init__(logger)
|
|
self.name = "stochastic"
|
|
|
|
def calculate(self, df: pd.DataFrame, k_period: int = 14,
|
|
d_period: int = 3, price_column: str = 'close') -> List[IndicatorResult]:
|
|
"""
|
|
Calculate Stochastic Oscillator.
|
|
|
|
Args:
|
|
df: DataFrame with OHLCV data
|
|
k_period: The K period (default: 14)
|
|
d_period: The D period (default: 3)
|
|
price_column: Column to use for calculations (default: 'close')
|
|
|
|
Returns:
|
|
List of IndicatorResult objects containing %K and %D values
|
|
"""
|
|
try:
|
|
# Validate inputs
|
|
self._validate_dataframe(df)
|
|
self._validate_period(k_period, min_value=2)
|
|
self._validate_period(d_period, min_value=2)
|
|
|
|
# Calculate %K
|
|
lowest_low = df['low'].rolling(window=k_period).min()
|
|
highest_high = df['high'].rolling(window=k_period).max()
|
|
k_percent = 100 * ((df[price_column] - lowest_low) /
|
|
(highest_high - lowest_low))
|
|
|
|
# Calculate %D (signal line)
|
|
d_percent = k_percent.rolling(window=d_period).mean()
|
|
|
|
# Create results
|
|
results = []
|
|
for idx, row in df.iterrows():
|
|
if pd.notna(k_percent[idx]) and pd.notna(d_percent[idx]):
|
|
results.append(IndicatorResult(
|
|
timestamp=idx,
|
|
symbol=self._get_symbol(df),
|
|
timeframe=self._get_timeframe(df),
|
|
values={
|
|
'k_percent': float(k_percent[idx]),
|
|
'd_percent': float(d_percent[idx])
|
|
},
|
|
metadata={
|
|
'k_period': k_period,
|
|
'd_period': d_period
|
|
}
|
|
))
|
|
|
|
return results
|
|
|
|
except Exception as e:
|
|
self._handle_error(f"Error calculating Stochastic: {str(e)}")
|
|
return []
|
|
```
|
|
|
|
### 2. Register the Indicator
|
|
|
|
Add your indicator to `data/common/indicators/implementations/__init__.py`:
|
|
|
|
```python
|
|
from .stochastic import StochasticIndicator
|
|
|
|
__all__ = [
|
|
'SMAIndicator',
|
|
'EMAIndicator',
|
|
'RSIIndicator',
|
|
'MACDIndicator',
|
|
'BollingerBandsIndicator',
|
|
'StochasticIndicator'
|
|
]
|
|
```
|
|
|
|
### 3. Add to TechnicalIndicators Class
|
|
|
|
Update `data/common/indicators/technical.py`:
|
|
|
|
```python
|
|
class TechnicalIndicators:
|
|
def __init__(self, logger=None):
|
|
self.logger = logger
|
|
# ... existing indicators ...
|
|
self._stochastic = StochasticIndicator(logger)
|
|
|
|
def stochastic(self, df: pd.DataFrame, k_period: int = 14,
|
|
d_period: int = 3, price_column: str = 'close') -> List[IndicatorResult]:
|
|
"""
|
|
Calculate Stochastic Oscillator.
|
|
|
|
Args:
|
|
df: DataFrame with OHLCV data
|
|
k_period: The K period (default: 14)
|
|
d_period: The D period (default: 3)
|
|
price_column: Column to use (default: 'close')
|
|
|
|
Returns:
|
|
List of indicator results with %K and %D values
|
|
"""
|
|
return self._stochastic.calculate(
|
|
df,
|
|
k_period=k_period,
|
|
d_period=d_period,
|
|
price_column=price_column
|
|
)
|
|
```
|
|
|
|
## Integration with Charts
|
|
|
|
### 1. Create Chart Layer
|
|
|
|
Create a new layer class in `components/charts/layers/indicators.py` (overlay) or `components/charts/layers/subplots.py` (subplot):
|
|
|
|
```python
|
|
class StochasticLayer(IndicatorLayer):
|
|
def __init__(self, config: Dict[str, Any]):
|
|
super().__init__(config)
|
|
self.name = "stochastic"
|
|
self.display_type = "subplot"
|
|
|
|
def create_traces(self, df: pd.DataFrame, values: Dict[str, pd.Series]) -> List[go.Scatter]:
|
|
traces = []
|
|
traces.append(go.Scatter(
|
|
x=df.index,
|
|
y=values['k_percent'],
|
|
mode='lines',
|
|
name=f"%K ({self.config.get('k_period', 14)})",
|
|
line=dict(
|
|
color=self.config.get('color', '#007bff'),
|
|
width=self.config.get('line_width', 2)
|
|
)
|
|
))
|
|
traces.append(go.Scatter(
|
|
x=df.index,
|
|
y=values['d_percent'],
|
|
mode='lines',
|
|
name=f"%D ({self.config.get('d_period', 3)})",
|
|
line=dict(
|
|
color=self.config.get('secondary_color', '#ff6b35'),
|
|
width=self.config.get('line_width', 2)
|
|
)
|
|
))
|
|
return traces
|
|
```
|
|
|
|
### 2. Register in Layer Registry
|
|
|
|
Update `components/charts/layers/__init__.py`:
|
|
|
|
```python
|
|
SUBPLOT_REGISTRY = {
|
|
'rsi': RSILayer,
|
|
'macd': MACDLayer,
|
|
'stochastic': StochasticLayer,
|
|
}
|
|
```
|
|
|
|
### 3. Add UI Components
|
|
|
|
Update `dashboard/components/indicator_modal.py`:
|
|
|
|
```python
|
|
def create_parameter_fields():
|
|
return html.Div([
|
|
# ... existing fields ...
|
|
html.Div([
|
|
dbc.Row([
|
|
dbc.Col([
|
|
dbc.Label("%K Period:"),
|
|
dcc.Input(
|
|
id='stochastic-k-period-input',
|
|
type='number',
|
|
value=14
|
|
)
|
|
], width=6),
|
|
dbc.Col([
|
|
dbc.Label("%D Period:"),
|
|
dcc.Input(
|
|
id='stochastic-d-period-input',
|
|
type='number',
|
|
value=3
|
|
)
|
|
], width=6),
|
|
]),
|
|
dbc.FormText("Stochastic oscillator periods")
|
|
], id='stochastic-parameters', style={'display': 'none'})
|
|
])
|
|
```
|
|
|
|
## Best Practices
|
|
|
|
### Code Quality
|
|
- Follow the project's coding style
|
|
- Add comprehensive docstrings
|
|
- Include type hints
|
|
- Handle edge cases gracefully
|
|
- Use vectorized operations where possible
|
|
|
|
### Error Handling
|
|
- Validate all input parameters
|
|
- Check for sufficient data
|
|
- Handle NaN values appropriately
|
|
- Log errors with meaningful messages
|
|
- Return empty results for invalid inputs
|
|
|
|
### Performance
|
|
- Use vectorized operations
|
|
- Avoid unnecessary loops
|
|
- Clean up temporary calculations
|
|
- Consider memory usage
|
|
- Cache results when appropriate
|
|
|
|
### Documentation
|
|
- Document all public methods
|
|
- Include usage examples
|
|
- Explain parameter ranges
|
|
- Document any assumptions
|
|
- Keep documentation up-to-date
|
|
|
|
## Testing Guidelines
|
|
|
|
### Test File Structure
|
|
Create `tests/indicators/test_stochastic.py`:
|
|
|
|
```python
|
|
import pytest
|
|
import pandas as pd
|
|
import numpy as np
|
|
from data.common.indicators import TechnicalIndicators
|
|
|
|
@pytest.fixture
|
|
def sample_data():
|
|
return pd.DataFrame({
|
|
'open': [10, 11, 12, 13, 14],
|
|
'high': [12, 13, 14, 15, 16],
|
|
'low': [8, 9, 10, 11, 12],
|
|
'close': [11, 12, 13, 14, 15],
|
|
'volume': [100, 110, 120, 130, 140]
|
|
}, index=pd.date_range('2023-01-01', periods=5))
|
|
|
|
def test_stochastic_calculation(sample_data):
|
|
indicators = TechnicalIndicators()
|
|
results = indicators.stochastic(sample_data, k_period=3, d_period=2)
|
|
|
|
assert len(results) > 0
|
|
for result in results:
|
|
assert 0 <= result.values['k_percent'] <= 100
|
|
assert 0 <= result.values['d_percent'] <= 100
|
|
```
|
|
|
|
### Testing Checklist
|
|
- [ ] Basic functionality with ideal data
|
|
- [ ] Edge cases (insufficient data, NaN values)
|
|
- [ ] Performance with large datasets
|
|
- [ ] Error handling
|
|
- [ ] Parameter validation
|
|
- [ ] Integration with TechnicalIndicators class
|
|
- [ ] Chart layer rendering
|
|
- [ ] UI interaction
|
|
|
|
### Running Tests
|
|
```bash
|
|
# Run all indicator tests
|
|
uv run pytest tests/indicators/
|
|
|
|
# Run specific indicator tests
|
|
uv run pytest tests/indicators/test_stochastic.py
|
|
|
|
# Run with coverage
|
|
uv run pytest tests/indicators/ --cov=data.common.indicators
|
|
```
|
|
|
|
## Common Pitfalls
|
|
|
|
1. **Insufficient Data Handling**
|
|
- Always check if enough data points are available
|
|
- Return empty results rather than partial calculations
|
|
- Consider the impact of NaN values
|
|
|
|
2. **NaN Handling**
|
|
- Use appropriate pandas NaN handling methods
|
|
- Don't propagate NaN values unnecessarily
|
|
- Document NaN handling behavior
|
|
|
|
3. **Memory Leaks**
|
|
- Clean up temporary DataFrames
|
|
- Avoid storing large datasets
|
|
- Use efficient data structures
|
|
|
|
4. **Performance Issues**
|
|
- Use vectorized operations instead of loops
|
|
- Profile code with large datasets
|
|
- Consider caching strategies
|
|
|
|
5. **UI Integration**
|
|
- Handle all parameter combinations
|
|
- Provide meaningful validation
|
|
- Give clear user feedback
|
|
|
|
## Example Implementation
|
|
|
|
See the complete Stochastic Oscillator implementation above as a reference. Key points:
|
|
|
|
1. **Modular Structure**
|
|
- Separate indicator class
|
|
- Clear inheritance hierarchy
|
|
- Focused responsibility
|
|
|
|
2. **Error Handling**
|
|
- Input validation
|
|
- Exception handling
|
|
- Meaningful error messages
|
|
|
|
3. **Performance**
|
|
- Vectorized calculations
|
|
- Efficient data structures
|
|
- Memory management
|
|
|
|
4. **Testing**
|
|
- Comprehensive test cases
|
|
- Edge case handling
|
|
- Performance verification
|
|
|
|
## Support
|
|
|
|
For questions or issues:
|
|
1. Check existing documentation
|
|
2. Review test cases
|
|
3. Consult with team members
|
|
4. Create detailed bug reports if needed
|
|
|
|
## Related Documentation
|
|
|
|
- [Technical Indicators Overview](../modules/technical-indicators.md)
|
|
- [Chart System Documentation](../modules/charts/README.md)
|
|
- [Data Types Documentation](../modules/data-types.md) |