From 4b5c1c5ce0819412d1c6cbfba04b92a24006485a Mon Sep 17 00:00:00 2001 From: cryptooda Date: Tue, 25 Nov 2025 11:03:52 +0700 Subject: [PATCH] Fix graph --- .cursor/commands/build-indicator.md | 9 ++ .../Controllers/DataController.cs | 12 +- .../Scenarios/ScenarioHelpers.cs | 40 +++--- .../Shared/Helpers/TradingBox.cs | 3 +- .../organism/Backtest/backtestRowDetails.tsx | 12 +- .../Trading/TradeChart/TradeChart.tsx | 130 ++++++++++++------ 6 files changed, 140 insertions(+), 66 deletions(-) diff --git a/.cursor/commands/build-indicator.md b/.cursor/commands/build-indicator.md index 326197da..2ea9379d 100644 --- a/.cursor/commands/build-indicator.md +++ b/.cursor/commands/build-indicator.md @@ -208,6 +208,10 @@ public enum IndicatorType **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}` @@ -219,6 +223,10 @@ public enum IndicatorType - 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} }` @@ -502,6 +510,7 @@ public class BollingerBandsVolatilityProtection : BollingerBandsBase { /* Volati - [ ] 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 diff --git a/src/Managing.Api/Controllers/DataController.cs b/src/Managing.Api/Controllers/DataController.cs index 4d66d7e3..73276d05 100644 --- a/src/Managing.Api/Controllers/DataController.cs +++ b/src/Managing.Api/Controllers/DataController.cs @@ -17,7 +17,6 @@ using Managing.Domain.Trades; using MediatR; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; -using Microsoft.Extensions.Configuration; using static Managing.Common.Enums; using DailySnapshot = Managing.Api.Models.Responses.DailySnapshot; @@ -831,9 +830,18 @@ public class DataController : ControllerBase SlowPeriods = indicatorRequest.SlowPeriods, SignalPeriods = indicatorRequest.SignalPeriods, Multiplier = indicatorRequest.Multiplier, + StDev = indicatorRequest.StDev, SmoothPeriods = indicatorRequest.SmoothPeriods, StochPeriods = indicatorRequest.StochPeriods, - CyclePeriods = indicatorRequest.CyclePeriods + CyclePeriods = indicatorRequest.CyclePeriods, + KFactor = indicatorRequest.KFactor, + DFactor = indicatorRequest.DFactor, + TenkanPeriods = indicatorRequest.TenkanPeriods, + KijunPeriods = indicatorRequest.KijunPeriods, + SenkouBPeriods = indicatorRequest.SenkouBPeriods, + OffsetPeriods = indicatorRequest.OffsetPeriods, + SenkouOffset = indicatorRequest.SenkouOffset, + ChikouOffset = indicatorRequest.ChikouOffset }; scenario.AddIndicator(indicator); diff --git a/src/Managing.Domain/Scenarios/ScenarioHelpers.cs b/src/Managing.Domain/Scenarios/ScenarioHelpers.cs index 52ac8975..50aa8fb6 100644 --- a/src/Managing.Domain/Scenarios/ScenarioHelpers.cs +++ b/src/Managing.Domain/Scenarios/ScenarioHelpers.cs @@ -71,40 +71,40 @@ public static class ScenarioHelpers { IIndicator result = indicator.Type switch { - IndicatorType.StDev => new StDevContext(indicator.Name, indicator.Period.Value), + IndicatorType.StDev => new StDevContext(indicator.Name, indicator.Period ?? 14), IndicatorType.RsiDivergence => new RsiDivergenceIndicatorBase(indicator.Name, - indicator.Period.Value), + indicator.Period ?? 14), IndicatorType.RsiDivergenceConfirm => new RsiDivergenceConfirmIndicatorBase(indicator.Name, - indicator.Period.Value), + indicator.Period ?? 14), IndicatorType.MacdCross => new MacdCrossIndicatorBase(indicator.Name, - indicator.FastPeriods.Value, indicator.SlowPeriods.Value, indicator.SignalPeriods.Value), - IndicatorType.EmaCross => new EmaCrossIndicatorBase(indicator.Name, indicator.Period.Value), + indicator.FastPeriods ?? 12, indicator.SlowPeriods ?? 26, indicator.SignalPeriods ?? 9), + IndicatorType.EmaCross => new EmaCrossIndicatorBase(indicator.Name, indicator.Period ?? 14), IndicatorType.DualEmaCross => new DualEmaCrossIndicatorBase(indicator.Name, - indicator.FastPeriods.Value, indicator.SlowPeriods.Value), + indicator.FastPeriods ?? 12, indicator.SlowPeriods ?? 26), IndicatorType.ThreeWhiteSoldiers => new ThreeWhiteSoldiersIndicatorBase(indicator.Name, - indicator.Period.Value), + indicator.Period ?? 14), IndicatorType.SuperTrend => new SuperTrendIndicatorBase(indicator.Name, - indicator.Period.Value, indicator.Multiplier.Value), + indicator.Period ?? 14, indicator.Multiplier ?? 3.0), IndicatorType.ChandelierExit => new ChandelierExitIndicatorBase(indicator.Name, - indicator.Period.Value, indicator.Multiplier.Value), - IndicatorType.EmaTrend => new EmaTrendIndicatorBase(indicator.Name, indicator.Period.Value), + indicator.Period ?? 14, indicator.Multiplier ?? 3.0), + IndicatorType.EmaTrend => new EmaTrendIndicatorBase(indicator.Name, indicator.Period ?? 14), IndicatorType.StochRsiTrend => new StochRsiTrendIndicatorBase(indicator.Name, - indicator.Period.Value, indicator.StochPeriods.Value, indicator.SignalPeriods.Value, - indicator.SmoothPeriods.Value), + indicator.Period ?? 14, indicator.StochPeriods ?? 14, indicator.SignalPeriods ?? 9, + indicator.SmoothPeriods ?? 3), IndicatorType.StochasticCross => new StochasticCrossIndicator(indicator.Name, - indicator.StochPeriods.Value, indicator.SignalPeriods.Value, indicator.SmoothPeriods.Value, + indicator.StochPeriods ?? 14, indicator.SignalPeriods ?? 3, indicator.SmoothPeriods ?? 3, indicator.KFactor ?? 3.0, indicator.DFactor ?? 2.0), - IndicatorType.Stc => new StcIndicatorBase(indicator.Name, indicator.CyclePeriods.Value, - indicator.FastPeriods.Value, indicator.SlowPeriods.Value), - IndicatorType.LaggingStc => new LaggingSTC(indicator.Name, indicator.CyclePeriods.Value, - indicator.FastPeriods.Value, indicator.SlowPeriods.Value), + IndicatorType.Stc => new StcIndicatorBase(indicator.Name, indicator.CyclePeriods ?? 10, + indicator.FastPeriods ?? 12, indicator.SlowPeriods ?? 26), + IndicatorType.LaggingStc => new LaggingSTC(indicator.Name, indicator.CyclePeriods ?? 10, + indicator.FastPeriods ?? 12, indicator.SlowPeriods ?? 26), IndicatorType.SuperTrendCrossEma => new SuperTrendCrossEma(indicator.Name, - indicator.Period.Value, indicator.Multiplier.Value), + indicator.Period ?? 14, indicator.Multiplier ?? 3.0), IndicatorType.BollingerBandsPercentBMomentumBreakout => new BollingerBandsPercentBMomentumBreakout( indicator.Name, - indicator.Period.Value, indicator.StDev.Value), + indicator.Period ?? 20, indicator.StDev ?? 2.0), IndicatorType.BollingerBandsVolatilityProtection => new BollingerBandsVolatilityProtection(indicator.Name, - indicator.Period.Value, indicator.StDev.Value), + indicator.Period ?? 20, indicator.StDev ?? 2.0), IndicatorType.IchimokuKumoTrend => new IchimokuKumoTrend(indicator.Name, indicator.TenkanPeriods ?? 9, indicator.KijunPeriods ?? 26, diff --git a/src/Managing.Domain/Shared/Helpers/TradingBox.cs b/src/Managing.Domain/Shared/Helpers/TradingBox.cs index 247a703a..1fadd278 100644 --- a/src/Managing.Domain/Shared/Helpers/TradingBox.cs +++ b/src/Managing.Domain/Shared/Helpers/TradingBox.cs @@ -937,8 +937,9 @@ public static class TradingBox var buildedIndicator = ScenarioHelpers.BuildIndicator(ScenarioHelpers.BaseToLight(indicator)); indicatorsValues[indicator.Type] = buildedIndicator.GetIndicatorValues(candles); } - catch (Exception) + catch (Exception ex) { + throw; // Removed logging for performance in static method // Consider adding logging back if error handling is needed } diff --git a/src/Managing.WebApp/src/components/organism/Backtest/backtestRowDetails.tsx b/src/Managing.WebApp/src/components/organism/Backtest/backtestRowDetails.tsx index e916290c..63457f5f 100644 --- a/src/Managing.WebApp/src/components/organism/Backtest/backtestRowDetails.tsx +++ b/src/Managing.WebApp/src/components/organism/Backtest/backtestRowDetails.tsx @@ -66,9 +66,18 @@ const BacktestRowDetails: React.FC = ({ slowPeriods: indicator.slowPeriods, signalPeriods: indicator.signalPeriods, multiplier: indicator.multiplier, + stDev: indicator.stDev, smoothPeriods: indicator.smoothPeriods, stochPeriods: indicator.stochPeriods, - cyclePeriods: indicator.cyclePeriods + cyclePeriods: indicator.cyclePeriods, + kFactor: indicator.kFactor, + dFactor: indicator.dFactor, + tenkanPeriods: indicator.tenkanPeriods, + kijunPeriods: indicator.kijunPeriods, + senkouBPeriods: indicator.senkouBPeriods, + offsetPeriods: indicator.offsetPeriods, + senkouOffset: indicator.senkouOffset, + chikouOffset: indicator.chikouOffset })) || [], loopbackPeriod: backtest.config.scenario.loopbackPeriod } : undefined @@ -76,7 +85,6 @@ const BacktestRowDetails: React.FC = ({ return await dataClient.data_GetCandlesWithIndicators(request); }, - enabled: !backtest.candles || backtest.candles.length === 0, // Only run query if no candles exist staleTime: 5 * 60 * 1000, // 5 minutes gcTime: 10 * 60 * 1000, // 10 minutes (formerly cacheTime) }); diff --git a/src/Managing.WebApp/src/components/organism/Trading/TradeChart/TradeChart.tsx b/src/Managing.WebApp/src/components/organism/Trading/TradeChart/TradeChart.tsx index 8bec5c61..50592224 100644 --- a/src/Managing.WebApp/src/components/organism/Trading/TradeChart/TradeChart.tsx +++ b/src/Managing.WebApp/src/components/organism/Trading/TradeChart/TradeChart.tsx @@ -565,47 +565,6 @@ const TradeChart = ({ lowerBandSeries.setData(lowerBandData) } - // Display Bollinger Bands on price chart for Volatility Protection - if (indicatorsValues?.BollingerBandsVolatilityProtection != null) { - const upperBandSeries = chart.current.addLineSeries({ - color: '#FF6B6B', // Lighter red for volatility protection bands - lineWidth: 1, - priceLineVisible: false, - priceLineWidth: 1, - title: 'Volatility Protection Upper Band', - pane: 0, - lineStyle: LineStyle.Dotted, - }) - - const upperBandData = indicatorsValues.BollingerBandsVolatilityProtection.bollingerBands?.map((w) => { - return { - time: moment(w.date).unix(), - value: w.upperBand, - } - }) - // @ts-ignore - upperBandSeries.setData(upperBandData) - - const lowerBandSeries = chart.current.addLineSeries({ - color: '#4ECDC4', // Teal for volatility protection bands - lineWidth: 1, - priceLineVisible: false, - priceLineWidth: 1, - title: 'Volatility Protection Lower Band', - pane: 0, - lineStyle: LineStyle.Dotted, - }) - - const lowerBandData = indicatorsValues.BollingerBandsVolatilityProtection.bollingerBands?.map((w) => { - return { - time: moment(w.date).unix(), - value: w.lowerBand, - } - }) - // @ts-ignore - lowerBandSeries.setData(lowerBandData) - } - if (markers.length > 0) { series1.current.setMarkers(markers) } @@ -674,6 +633,95 @@ const TradeChart = ({ paneCount++ } + // Display Bollinger Bands Volatility Protection Width on separate pane + if (indicatorsValues?.BollingerBandsVolatilityProtection != null) { + const volatilityWidthSeries = chart.current.addLineSeries({ + color: '#8B5CF6', // Purple for volatility width + lineWidth: 2, + priceLineVisible: true, + priceLineWidth: 1, + title: 'Volatility Width (BB %)', + pane: paneCount, + priceFormat: { + minMove: 0.001, + precision: 3, + type: 'price', + }, + }) + + const volatilityWidthData = indicatorsValues.BollingerBandsVolatilityProtection.bollingerBands?.map((w) => { + return { + time: moment(w.date).unix(), + value: w.width, + } + }) + // @ts-ignore + volatilityWidthSeries.setData(volatilityWidthData) + + // Add confidence range lines (0.02 - 0.10) + const confidenceMinLine = chart.current.addLineSeries({ + color: '#16A34A', // Green for confidence range minimum + lineWidth: 1, + priceLineVisible: true, + priceLineWidth: 1, + title: 'Conf Min (2%)', + pane: paneCount, + lineStyle: LineStyle.Dashed, + priceFormat: { + minMove: 0.001, + precision: 3, + type: 'price', + }, + }) + + const confidenceMaxLine = chart.current.addLineSeries({ + color: '#16A34A', // Green for confidence range maximum + lineWidth: 1, + priceLineVisible: true, + priceLineWidth: 1, + title: 'Conf Max (10%)', + pane: paneCount, + lineStyle: LineStyle.Dashed, + priceFormat: { + minMove: 0.001, + precision: 3, + type: 'price', + }, + }) + + // Create horizontal lines for confidence range + const bollingerBands = indicatorsValues.BollingerBandsVolatilityProtection.bollingerBands + if (bollingerBands && bollingerBands.length > 0) { + const confidenceMinData = [ + { + time: moment(bollingerBands[0].date).unix(), + value: 0.02, // Confidence minimum threshold + }, + { + time: moment(bollingerBands[bollingerBands.length - 1].date).unix(), + value: 0.02, // Confidence minimum threshold + } + ] + // @ts-ignore + confidenceMinLine.setData(confidenceMinData) + + const confidenceMaxData = [ + { + time: moment(bollingerBands[0].date).unix(), + value: 0.10, // Confidence maximum threshold + }, + { + time: moment(bollingerBands[bollingerBands.length - 1].date).unix(), + value: 0.10, // Confidence maximum threshold + } + ] + // @ts-ignore + confidenceMaxLine.setData(confidenceMaxData) + } + + paneCount++ + } + if (indicatorsValues?.LaggingStc != null) { const laggingStcSeries = chart.current.addBaselineSeries({ pane: paneCount,