# 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
```

**Bollinger Bands Example:**
```
Type: Context
Label: Bollinger Bands Volatility Protection
Core Logic: Uses the Bandwidth (distance between Upper and Lower bands) to measure market volatility and apply veto filters during extreme conditions.
Context Confidence Levels: Block signals when bandwidth is extremely high (>0.15) or low (<0.02), validate when normal (0.02-0.15).
Parameters:
Period (default: 20)
StDev (default: 2.0)
```

### 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<LightSignal> Signals { get; set; }

    public {IndicatorName}(string name, {parameters}) :
        base(name, IndicatorType.{EnumName})
    {
        Signals = new List<LightSignal>();
        // Initialize parameters (e.g., Period, Multiplier, StDev)
    }

    // Implementation methods...
}
```

**For Bollinger Bands (use shared base):**
```csharp
public class {IndicatorName} : BollingerBandsBase
{
    public {IndicatorName}(string name, int period, double stdev) :
        base(name, IndicatorType.{EnumName}, period, stdev)
    {
    }

    // Only implement ProcessBollingerBandsSignals method
}
```

**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<Candle> candles)
    {
        // Shared mapping implementation
    }
}

public class {IndicatorName} : {SharedBaseName}Base
{
    // Indicator-specific logic only
}
```

**Key Methods to Implement:**
1. `Run(HashSet<Candle> candles)` - Main calculation logic
2. `Run(HashSet<Candle> candles, IndicatorsResultBase preCalculatedValues)` - Optimized version
3. `GetIndicatorValues(HashSet<Candle> candles)` - Return calculated values
4. Private processing methods for signal generation

**Signal Generation Pattern:**
```csharp
private void ProcessSignals(List<{Indicator}Result> results, HashSet<Candle> 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 IndicatorBase.cs:**
- Add any new parameter properties needed (e.g., `StDev` for Bollinger Bands)

**Update LightIndicator.cs:**
- Add any new parameter properties with proper Id attributes for Orleans serialization
- Update `LightToBase()` method to copy new properties

**Update IndicatorRequest.cs:**
- Add any new parameter properties to match LightIndicator

**Update DataController.cs:**
- Add any new parameter properties to the `MapScenarioRequestToScenario()` method's `IndicatorBase` initialization
- This ensures API requests with indicator parameters are properly mapped to domain objects

**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 parameter validation in `BuildIndicator()` method switch statement
- Add new parameters to `BuildIndicator()` method signature if needed
- Update `BaseToLight()` method to copy all LightIndicator properties

**Update BacktestJobService.cs:**
- Update LightIndicator creation in bundle job creation to include all new properties
- Ensure all indicator parameters are properly mapped from requests

**Update DataController.cs:**
- Update `MapScenarioRequestToScenario()` method to include all new parameters in the `IndicatorBase` initialization
- Ensure all properties from `IndicatorRequest` are properly mapped to `IndicatorBase` (Period, StDev, KFactor, DFactor, TenkanPeriods, etc.)

**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}]`
- Update `TradingBotChromosome.GetSelectedIndicators()` to handle new parameters

**Update Frontend Files:**

*CustomScenario.tsx:*
- Add new parameters to indicator type definitions
- Update parameter input handling (float vs int parsing)
- Add default values for new parameters

*TradeChart.tsx (if applicable):*
- Add visualization logic for new indicator bands/lines
- Use appropriate colors and styles for differentiation

### Step 5: Test and Validate

**Compile Check:**
```bash
# Backend compilation
dotnet build

# Frontend compilation
cd src/Managing.WebApp && npm run build
```

**Basic Validation:**
- Verify indicator appears in GeneticService configurations
- Check that BuildIndicator methods work correctly
- Ensure proper SignalType assignment
- Verify LightIndicator serialization works (Orleans Id attributes)
- Check parameter validation in ScenarioHelpers.BuildIndicator
- Confirm frontend parameter handling works correctly

**Integration Test:**
- Create a simple backtest using the new indicator
- Verify signals are generated correctly
- Check parameter handling and validation
- Test frontend scenario creation with new parameters
- Verify chart visualization displays correctly (if applicable)

## 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 (StDev) 1.0-3.0 (Bollinger Bands)
- **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
- `GetBollingerBands(period, stdev)` → `BollingerBandsResult` - Used in Bollinger Bands indicators
- `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<CandleStoch> MapStochToCandle(List<StochResult> stochResults, IEnumerable<Candle> candles)
    {
        // Shared mapping logic for all Stochastic-based indicators
    }
}

public class StochasticFiltered : StochasticBase { /* Specific logic */ }
public class AnotherStochasticIndicator : StochasticBase { /* Specific logic */ }
```

**Bollinger Bands Example (Implemented):**
```csharp
public abstract class BollingerBandsBase : IndicatorBase
{
    protected double Stdev { get; set; }

    protected BollingerBandsBase(string name, IndicatorType type, int period, double stdev)
        : base(name, type)
    {
        Stdev = stdev;
        Period = period;
    }

    protected virtual IEnumerable<CandleBollingerBands> MapBollingerBandsToCandle(
        IEnumerable<BollingerBandsResult> bbResults, IEnumerable<Candle> candles)
    {
        // Shared Bollinger Bands mapping logic with all properties
        // (Sma, UpperBand, LowerBand, PercentB, ZScore, Width)
    }
}

public class BollingerBandsPercentBMomentumBreakout : BollingerBandsBase { /* %B momentum logic */ }
public class BollingerBandsVolatilityProtection : BollingerBandsBase { /* Volatility protection 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
- [ ] IndicatorBase.cs properties added if needed
- [ ] LightIndicator.cs properties added with proper Id attributes
- [ ] IndicatorRequest.cs properties added
- [ ] ScenarioHelpers.cs BuildIndicator and BaseToLight methods updated
- [ ] BacktestJobService.cs LightIndicator mapping updated
- [ ] DataController.cs MapScenarioRequestToScenario method updated
- [ ] GeneticService.cs configurations updated (defaults, ranges, mappings)
- [ ] Frontend CustomScenario.tsx updated for new parameters
- [ ] Frontend TradeChart.tsx updated for visualization if needed
- [ ] Compiles without errors (backend and frontend)
- [ ] TypeScript types properly aligned
