# build-indicator ## When to Use Use this command when you need to: - Create new technical indicators based on pattern descriptions - Add signal, trend, or context indicators to the trading system - Update all related files and configurations automatically - Follow the established indicator architecture and conventions ## Prerequisites - Clear indicator specification with Type, Label, Core Logic, Triggers, and Parameters - Understanding of indicator categories (Signal/Trend/Context) - Access to existing indicator implementations for reference - Knowledge of the indicator's mathematical calculations ## Execution Steps ### Step 1: Parse Indicator Specification Analyze the indicator description and extract: **Required Information:** - **Type**: Signal/Trend/Context (determines folder location) - **Label**: Indicator name (e.g., "Stochastic Filtered") - **Core Logic**: Technical description of what the indicator does - **Trigger Conditions**: When to generate signals (for Signal indicators) - **Parameters**: Configuration values with defaults - **Signal Type**: Long/Short for Signal indicators, Confidence levels for Context **Example Format:** ``` Type: Signal Label: Stochastic Filtered Core Logic: Generates signals by filtering %K / %D crossovers to occur only within extreme overbought (above 80) or oversold (below 20) zones. Trigger a Long when → The %K line crosses above the %D line (bullish momentum shift). The crossover occurs in the oversold zone (both %K and %D lines are below 20). Trigger a Short when → The %K line crosses below the %D line (bearish momentum shift). The crossover occurs in the overbought zone (both %K and %D lines are above 80). Parameters: %K Period (default: 14) %K Slowing (default: 3) %D Period (default: 3) Oversold Threshold: 20 Overbought Threshold: 80 ``` ### Step 2: Determine Implementation Details **Check Existing Indicators:** - Search codebase: `grep -r "Get{IndicatorType}" src/Managing.Domain/Indicators/` - Look for similar Skender.Stock.Indicators usage patterns - Check if candle mapping logic can be shared with existing indicators **Class Name Convention:** - Signal indicators: `{IndicatorName}.cs` (e.g., `StochasticFiltered.cs`) - Trend indicators: `{IndicatorName}.cs` (e.g., `EmaTrend.cs`) - Context indicators: `{IndicatorName}.cs` (e.g., `StDev.cs`) **Inheritance Strategy:** - Default: Extend `IndicatorBase` directly - Shared Mapping: Extend from existing shared base class if mappings overlap - New Shared Base: Create base class only if multiple indicators will share the same mapping **Class Name Pattern:** - For signal/trend indicators: Class name = `{IndicatorName}` (inherits from `IndicatorBase` or shared base) - For context indicators: Class name = `{IndicatorName}` (inherits from `IndicatorBase` or shared base) **Location:** - Signal → `src/Managing.Domain/Indicators/Signals/` - Trend → `src/Managing.Domain/Indicators/Trends/` - Context → `src/Managing.Domain/Indicators/Context/` **Enum Name:** - Convert label to PascalCase: `StochasticFiltered` - Add to `IndicatorType` enum in `src/Managing.Common/Enums.cs` ### Step 3: Implement Indicator Class Create the indicator class following the established pattern. Check if other indicators use similar candle mappings - if so, consider creating or extending a base class. **Check for Existing Candle Mappings:** - Search for similar indicator types that might share candle mappings - If another indicator uses the same Skender.Stock.Indicators result type, consider extending an existing base class or creating a shared base class - Only create a new base class if no other indicator shares the same candle mapping pattern **Base Structure:** ```csharp using Managing.Core; using Managing.Domain.Candles; using Managing.Domain.Indicators; using Managing.Domain.Shared.Rules; using Managing.Domain.Strategies.Base; using Skender.Stock.Indicators; using static Managing.Common.Enums; namespace Managing.Domain.Strategies.{TypeFolder}; public class {IndicatorName} : IndicatorBase { public List Signals { get; set; } public {IndicatorName}(string name, {parameters}) : base(name, IndicatorType.{EnumName}) { Signals = new List(); // Initialize parameters } // Implementation methods... } ``` **Shared Base Class Pattern (use only if mapping is shared):** If another indicator uses the same candle result mapping, extend from a shared base class: ```csharp public class {SharedBaseName}Base : IndicatorBase { // Shared candle mapping logic here protected List<{CandleResultType}> Map{Indicator}ToCandle(List<{SkenderResult}> results, IEnumerable candles) { // Shared mapping implementation } } public class {IndicatorName} : {SharedBaseName}Base { // Indicator-specific logic only } ``` **Key Methods to Implement:** 1. `Run(HashSet candles)` - Main calculation logic 2. `Run(HashSet candles, IndicatorsResultBase preCalculatedValues)` - Optimized version 3. `GetIndicatorValues(HashSet candles)` - Return calculated values 4. Private processing methods for signal generation **Signal Generation Pattern:** ```csharp private void ProcessSignals(List<{Indicator}Result> results, HashSet candles) { var mappedData = Map{Indicator}ToCandle(results, candles); if (mappedData.Count == 0) return; var previousCandle = mappedData[0]; foreach (var currentCandle in mappedData.Skip(1)) { // Check trigger conditions if (/* Long condition */) { AddSignal(currentCandle, TradeDirection.Long, Confidence.Medium); } if (/* Short condition */) { AddSignal(currentCandle, TradeDirection.Short, Confidence.Medium); } previousCandle = currentCandle; } } ``` ### Step 4: Update Configuration Files **Update Enums.cs:** ```csharp public enum IndicatorType { // ... existing indicators StochasticFiltered, // ... continue } ``` **Update ScenarioHelpers.cs:** - Add case to `BuildIndicator()` method: `IndicatorType.{EnumName} => new {IndicatorName}(indicator.Name, {parameters})` - Add case to `GetSignalType()` method: `IndicatorType.{EnumName} => SignalType.{Type}` - Add parameters to `BuildIndicator()` overload if needed **Update GeneticService.cs:** - Add default values to `DefaultIndicatorValues`: `[IndicatorType.{EnumName}] = new() { {param_mappings} }` - Add parameter ranges to `IndicatorParameterRanges`: `[IndicatorType.{EnumName}] = new() { {param_ranges} }` - Add parameter mapping to `IndicatorParamMapping`: `[IndicatorType.{EnumName}] = [{param_names}]` ### Step 5: Test and Validate **Compile Check:** ```bash dotnet build ``` **Basic Validation:** - Verify indicator appears in GeneticService configurations - Check that BuildIndicator methods work correctly - Ensure proper SignalType assignment **Integration Test:** - Create a simple backtest using the new indicator - Verify signals are generated correctly - Check parameter handling and validation ## Available Skender.Stock.Indicators The following indicators are available from the [Skender.Stock.Indicators](https://dotnet.stockindicators.dev/) library and can be used as the basis for custom trading indicators: ### Trend Indicators - **EMA (Exponential Moving Average)**: `GetEma(period)` - Smooths price data with exponential weighting - **SMA (Simple Moving Average)**: `GetSma(period)` - Arithmetic mean of prices over period - **WMA (Weighted Moving Average)**: `GetWma(period)` - Weighted average favoring recent prices - **HMA (Hull Moving Average)**: `GetHma(period)` - Responsive moving average using WMA - **DEMA (Double Exponential Moving Average)**: `GetDema(period)` - Two EMAs for reduced lag - **TEMA (Triple Exponential Moving Average)**: `GetTema(period)` - Three EMAs for further lag reduction - **VWMA (Volume Weighted Moving Average)**: `GetVwma(period)` - Volume-weighted price average ### Momentum Oscillators - **RSI (Relative Strength Index)**: `GetRsi(period)` - Momentum oscillator (0-100) - **Stochastic Oscillator**: `GetStoch(kPeriod, kSlowing, dPeriod)` - %K and %D lines - **Stochastic RSI**: `GetStochRsi(rsiPeriod, stochPeriod, signalPeriod, smoothPeriod)` - Stochastic of RSI - **Williams %R**: `GetWilliamsR(period)` - Momentum oscillator (-100 to 0) - **CCI (Commodity Channel Index)**: `GetCci(period)` - Mean deviation from average price - **MFI (Money Flow Index)**: `GetMfi(period)` - Volume-weighted RSI - **AO (Awesome Oscillator)**: `GetAo()` - MACD of median price - **KVO (Klinger Volume Oscillator)**: `GetKvo(fastPeriod, slowPeriod, signalPeriod)` - Volume oscillator ### Trend Following - **MACD (Moving Average Convergence Divergence)**: `GetMacd(fastPeriod, slowPeriod, signalPeriod)` - Trend momentum indicator - **SuperTrend**: `GetSuperTrend(period, multiplier)` - ATR-based trailing stop - **Chandelier Exit**: `GetChandelier(period, multiplier, type)` - ATR-based exit levels - **Parabolic SAR**: `GetParabolicSar(accelerationStep, maxAcceleration)` - Trailing stop and reversal - **ADX (Average Directional Index)**: `GetAdx(period)` - Trend strength indicator - **DMI (Directional Movement Index)**: `GetDmi(period)` - Trend direction and strength - **PSAR (Parabolic SAR)**: `GetPsar(accelerationStep, maxAcceleration)` - Dynamic support/resistance ### Volatility Indicators - **ATR (Average True Range)**: `GetAtr(period)` - Volatility measurement - **Bollinger Bands**: `GetBollingerBands(period, standardDeviations)` - Price volatility bands - **Standard Deviation**: `GetStdDev(period)` - Statistical volatility measure - **TR (True Range)**: `GetTr()` - Maximum price movement range ### Volume Indicators - **OBV (On Balance Volume)**: `GetObv()` - Cumulative volume based on price direction - **CMF (Chaikin Money Flow)**: `GetCmf(period)` - Volume-weighted price trend - **ADL (Accumulation/Distribution Line)**: `GetAdl()` - Volume-based price accumulation - **EMV (Ease of Movement)**: `GetEmv(period)` - Price movement relative to volume - **NVI (Negative Volume Index)**: `GetNvi()` - Volume-based trend indicator ### Cycle Indicators - **STC (Schaff Trend Cycle)**: `GetStc(cyclePeriod, fastPeriod, slowPeriod)` - Cycle oscillator (0-100) - **DPO (Detrended Price Oscillator)**: `GetDpo(period)` - Removes trend from price - **EPMA (Endpoint Moving Average)**: `GetEpma(period)` - End-point moving average ### Support/Resistance - **Pivot Points**: `GetPivotPoints(period)` - Traditional pivot levels - **Fibonacci Retracements**: `GetFibonacciRetracements()` - Fibonacci ratio levels ### Candlestick Patterns - **Doji**: `GetDoji()` - Doji candlestick patterns - **Hammer**: `GetHammer()` - Hammer patterns - **Engulfing**: `GetEngulfing()` - Bullish/bearish engulfing - **Marubozu**: `GetMarubozu()` - Marubozu patterns - **And many more...** ### Usage Examples ```csharp // Basic usage var ema = candles.GetEma(20).ToList(); var macd = candles.GetMacd(12, 26, 9).ToList(); var rsi = candles.GetRsi(14).ToList(); var stoch = candles.GetStoch(14, 3, 3).ToList(); var superTrend = candles.GetSuperTrend(10, 3.0).ToList(); // Chain indicators (indicator of indicators) var rsiOfObv = candles.GetObv().GetRsi(14).ToList(); var smaOfRsi = candles.GetRsi(14).GetSma(9).ToList(); ``` For complete documentation and examples, visit: [Skender.Stock.Indicators Guide](https://dotnet.stockindicators.dev/guide/) ### Finding the Right Method When implementing a new indicator, search the [Skender documentation](https://dotnet.stockindicators.dev/indicators/) for your indicator concept: 1. **Identify the core calculation**: What mathematical formula does your indicator use? 2. **Find the Skender equivalent**: Search for methods like `Get{IndicatorName}()` 3. **Check parameters**: Most indicators follow common patterns: - `period`: Lookback period (typically 5-300) - `fastPeriod`/`slowPeriod`: For dual moving averages - `signalPeriod`: For signal line calculations - `multiplier`: ATR multipliers (typically 1.0-5.0) 4. **Verify result structure**: Check what properties the result object contains ### Parameter Guidelines **Common Ranges by Indicator Type:** - **Moving Averages**: Period 5-300 (shorter = responsive, longer = smooth) - **Oscillators**: Period 5-50 (RSI: 14, Stoch: 14, CCI: 20) - **Trend Following**: Period 10-50, Multiplier 1.0-5.0 - **Volatility**: Period 5-50, Standard Deviations 1.0-3.0 - **Volume**: Period 5-50 (OBV uses no period) **Testing Parameters:** - Start with industry standard defaults - Test multiple parameter combinations - Consider timeframe: Shorter timeframes may need smaller periods ### Result Object Patterns Different indicators return different result objects. Common patterns: **Single Value Results:** - `EmaResult`: `{ Date, Ema }` - `RsiResult`: `{ Date, Rsi }` - `AtrResult`: `{ Date, Atr }` - `ObvResult`: `{ Date, Obv }` **Dual Value Results:** - `StochResult`: `{ Date, PercentK, PercentD, Oscillator }` - `MacdResult`: `{ Date, Macd, Signal, Histogram }` - `StochRsiResult`: `{ Date, Rsi, StochRsi, Signal }` **Triple+ Value Results:** - `BollingerBandsResult`: `{ Date, Sma, UpperBand, LowerBand }` - `SuperTrendResult`: `{ Date, SuperTrend, UpperBand, LowerBand }` - `ChandelierResult`: `{ Date, ChandelierExit }` **Candlestick Results:** - `CandleResult`: `{ Date, Price, Match, Candle }` (for pattern recognition) When creating your `Candle{Indicator}` mapping class, include all relevant result properties plus the base Candle properties (Close, Open, Date, Ticker, Exchange). ### Quick Reference - Currently Used Indicators **In This Codebase:** - `GetEma(period)` → `EmaResult` - Used in EMA Trend, EMA Cross, Dual EMA Cross - `GetMacd(fast, slow, signal)` → `MacdResult` - Used in MACD Cross - `GetRsi(period)` → `RsiResult` - Used in RSI Divergence variants - `GetStoch(kPeriod, kSlowing, dPeriod)` → `StochResult` - Used in Stochastic Filtered - `GetStochRsi(rsiPeriod, stochPeriod, signalPeriod, smoothPeriod)` → `StochRsiResult` - Used in Stoch RSI Trend - `GetSuperTrend(period, multiplier)` → `SuperTrendResult` - Used in SuperTrend, SuperTrend Cross EMA - `GetStc(cyclePeriod, fastPeriod, slowPeriod)` → `StcResult` - Used in STC, Lagging STC - `GetStdDev(period)` → `StdDevResult` - Used in StDev Context - `GetChandelier(period, multiplier, type)` → `ChandelierResult` - Used in Chandelier Exit - `GetAdx(period)` → `AdxResult` - Used in SuperTrend Cross EMA **Available But Unused:** - `GetBollingerBands(period, stdDev)` → `BollingerBandsResult` - `GetAtr(period)` → `AtrResult` - `GetObv()` → `ObvResult` - `GetCci(period)` → `CciResult` - `GetMfi(period)` → `MfiResult` - And many more... (see full list above) ## Common Patterns ### Signal Indicator Pattern - Uses `TradeDirection.Long`/`Short` with `Confidence` levels - Implements crossover or threshold-based logic - Returns filtered signals only when conditions are met ### Trend Indicator Pattern - Uses `TradeDirection.Long`/`Short` for trend direction - Continuous assessment rather than discrete signals - Lower confidence levels for trend indicators ### Context Indicator Pattern - Uses `Confidence.None`/`Low`/`Medium`/`High` for veto power - Acts as filter for other indicators - No directional signals, only context assessment ### Shared Base Class Pattern **When to Use:** - Multiple indicators use the same Skender.Stock.Indicators result type - Indicators share identical candle mapping logic - Common signal processing patterns exist **Example:** ```csharp public abstract class StochasticBase : IndicatorBase { protected List MapStochToCandle(List stochResults, IEnumerable candles) { // Shared mapping logic for all Stochastic-based indicators } } public class StochasticFiltered : StochasticBase { /* Specific logic */ } public class AnotherStochasticIndicator : StochasticBase { /* Specific logic */ } ``` **When NOT to Use:** - Indicators have different result types (Stoch vs StochRsi) - Mapping logic differs significantly - Only one indicator uses a particular pattern ## Error Handling **Common Issues:** - Missing parameters in constructor - Incorrect SignalType assignment - Wrong folder location (Signals/Trends/Context) - Missing enum updates - Parameter range mismatches **Validation Checklist:** - [ ] Checked for existing indicators with similar candle mappings - [ ] Used appropriate base class (IndicatorBase or shared base if mappings overlap) - [ ] Constructor parameters match IIndicator interface - [ ] SignalType correctly assigned - [ ] Enum added to IndicatorType - [ ] BuildIndicator methods updated - [ ] GeneticService configurations updated - [ ] Compiles without errors