# 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 ***(No longer needed - UI is dynamically generated from JSON templates)*** ## 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)