From ad3b3f2fa537ddfa17aa4d33062ceb326faf0170 Mon Sep 17 00:00:00 2001 From: cryptooda Date: Mon, 24 Nov 2025 10:05:16 +0700 Subject: [PATCH] Add command for adding indicators --- .cursor/commands/build-indicator.md | 415 ++++++++++++++++++++++++++++ 1 file changed, 415 insertions(+) create mode 100644 .cursor/commands/build-indicator.md diff --git a/.cursor/commands/build-indicator.md b/.cursor/commands/build-indicator.md new file mode 100644 index 00000000..676fb5f4 --- /dev/null +++ b/.cursor/commands/build-indicator.md @@ -0,0 +1,415 @@ +# 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