Files
managing-apps/src/Managing.Domain/Scenarios/ScenarioHelpers.cs
cryptooda 4268626897 Add IchimokuKumoTrend indicator support across application
- Introduced IchimokuKumoTrend indicator in GeneticService with configuration settings for tenkanPeriods, kijunPeriods, senkouBPeriods, offsetPeriods, senkouOffset, and chikouOffset.
- Updated ScenarioHelpers to handle creation and validation of the new indicator type.
- Enhanced CustomScenario, backtest, and scenario pages to include IchimokuKumoTrend in indicator lists and parameter mappings.
- Modified API and types to reflect the addition of the new indicator in relevant enums and mappings.
2025-11-24 19:43:18 +07:00

306 lines
13 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using Managing.Domain.Strategies;
using Managing.Domain.Strategies.Context;
using Managing.Domain.Strategies.Signals;
using Managing.Domain.Strategies.Trends;
using Newtonsoft.Json;
using static Managing.Common.Enums;
namespace Managing.Domain.Scenarios;
public static class ScenarioHelpers
{
/// <summary>
/// Compares two lists of indicators and returns a list of changes (added, removed, modified).
/// </summary>
/// <param name="oldIndicators">The previous list of indicators</param>
/// <param name="newIndicators">The new list of indicators</param>
/// <returns>A list of change descriptions</returns>
public static List<string> CompareIndicators(List<LightIndicator> oldIndicators, List<LightIndicator> newIndicators)
{
var changes = new List<string>();
// Create dictionaries for easier comparison using Type as key
var oldIndicatorDict = oldIndicators.ToDictionary(i => i.Type, i => i);
var newIndicatorDict = newIndicators.ToDictionary(i => i.Type, i => i);
// Find removed indicators
var removedTypes = oldIndicatorDict.Keys.Except(newIndicatorDict.Keys);
foreach (var removedType in removedTypes)
{
var indicator = oldIndicatorDict[removedType];
changes.Add($" **Removed Indicator:** {removedType} ({indicator.GetType().Name})");
}
// Find added indicators
var addedTypes = newIndicatorDict.Keys.Except(oldIndicatorDict.Keys);
foreach (var addedType in addedTypes)
{
var indicator = newIndicatorDict[addedType];
changes.Add($" **Added Indicator:** {addedType} ({indicator.GetType().Name})");
}
// Find modified indicators (same type but potentially different configuration)
var commonTypes = oldIndicatorDict.Keys.Intersect(newIndicatorDict.Keys);
foreach (var commonType in commonTypes)
{
var oldIndicator = oldIndicatorDict[commonType];
var newIndicator = newIndicatorDict[commonType];
// Compare indicators by serializing them (simple way to detect configuration changes)
var oldSerialized = JsonConvert.SerializeObject(oldIndicator, Formatting.None);
var newSerialized = JsonConvert.SerializeObject(newIndicator, Formatting.None);
if (oldSerialized != newSerialized)
{
changes.Add($"🔄 **Modified Indicator:** {commonType} ({newIndicator.GetType().Name})");
}
}
// Add summary if there are changes
if (changes.Any())
{
var summary =
$"📊 **Indicator Changes:** {addedTypes.Count()} added, {removedTypes.Count()} removed, {commonTypes.Count(c => JsonConvert.SerializeObject(oldIndicatorDict[c]) != JsonConvert.SerializeObject(newIndicatorDict[c]))} modified";
changes.Insert(0, summary);
}
return changes;
}
public static IIndicator BuildIndicator(LightIndicator indicator)
{
IIndicator result = indicator.Type switch
{
IndicatorType.StDev => new StDevContext(indicator.Name, indicator.Period.Value),
IndicatorType.RsiDivergence => new RsiDivergenceIndicatorBase(indicator.Name,
indicator.Period.Value),
IndicatorType.RsiDivergenceConfirm => new RsiDivergenceConfirmIndicatorBase(indicator.Name,
indicator.Period.Value),
IndicatorType.MacdCross => new MacdCrossIndicatorBase(indicator.Name,
indicator.FastPeriods.Value, indicator.SlowPeriods.Value, indicator.SignalPeriods.Value),
IndicatorType.EmaCross => new EmaCrossIndicatorBase(indicator.Name, indicator.Period.Value),
IndicatorType.DualEmaCross => new DualEmaCrossIndicatorBase(indicator.Name,
indicator.FastPeriods.Value, indicator.SlowPeriods.Value),
IndicatorType.ThreeWhiteSoldiers => new ThreeWhiteSoldiersIndicatorBase(indicator.Name,
indicator.Period.Value),
IndicatorType.SuperTrend => new SuperTrendIndicatorBase(indicator.Name,
indicator.Period.Value, indicator.Multiplier.Value),
IndicatorType.ChandelierExit => new ChandelierExitIndicatorBase(indicator.Name,
indicator.Period.Value, indicator.Multiplier.Value),
IndicatorType.EmaTrend => new EmaTrendIndicatorBase(indicator.Name, indicator.Period.Value),
IndicatorType.StochRsiTrend => new StochRsiTrendIndicatorBase(indicator.Name,
indicator.Period.Value, indicator.StochPeriods.Value, indicator.SignalPeriods.Value,
indicator.SmoothPeriods.Value),
IndicatorType.StochasticCross => new StochasticCrossIndicator(indicator.Name,
indicator.StochPeriods.Value, indicator.SignalPeriods.Value, indicator.SmoothPeriods.Value,
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.SuperTrendCrossEma => new SuperTrendCrossEma(indicator.Name,
indicator.Period.Value, indicator.Multiplier.Value),
IndicatorType.BollingerBandsPercentBMomentumBreakout => new BollingerBandsPercentBMomentumBreakout(indicator.Name,
indicator.Period.Value, indicator.Multiplier.Value),
IndicatorType.IchimokuKumoTrend => new IchimokuKumoTrend(indicator.Name,
indicator.TenkanPeriods ?? 9,
indicator.KijunPeriods ?? 26,
indicator.SenkouBPeriods ?? 52,
indicator.OffsetPeriods ?? 26,
indicator.SenkouOffset,
indicator.ChikouOffset),
_ => throw new NotImplementedException(),
};
return result;
}
/// <summary>
/// Converts a full Indicator to a LightIndicator
/// </summary>
public static LightIndicator BaseToLight(IndicatorBase indicatorBase)
{
return new LightIndicator(indicatorBase.Name, indicatorBase.Type)
{
SignalType = indicatorBase.SignalType,
MinimumHistory = indicatorBase.MinimumHistory,
Period = indicatorBase.Period,
FastPeriods = indicatorBase.FastPeriods,
SlowPeriods = indicatorBase.SlowPeriods,
SignalPeriods = indicatorBase.SignalPeriods,
Multiplier = indicatorBase.Multiplier,
SmoothPeriods = indicatorBase.SmoothPeriods,
StochPeriods = indicatorBase.StochPeriods,
CyclePeriods = indicatorBase.CyclePeriods
};
}
public static IIndicator BuildIndicator(
IndicatorType type,
string name,
int? period = null,
int? fastPeriods = null,
int? slowPeriods = null,
int? signalPeriods = null,
double? multiplier = null,
int? stochPeriods = null,
int? smoothPeriods = null,
int? cyclePeriods = null,
double? kFactor = null,
double? dFactor = null)
{
IIndicator indicator = new IndicatorBase(name, type);
switch (type)
{
case IndicatorType.RsiDivergence:
case IndicatorType.RsiDivergenceConfirm:
case IndicatorType.EmaTrend:
case IndicatorType.EmaCross:
case IndicatorType.StDev:
if (!period.HasValue)
{
throw new Exception($"Missing period for {indicator.Type} strategy type");
}
else
{
indicator.Period = period.Value;
}
break;
case IndicatorType.MacdCross:
if (!fastPeriods.HasValue || !slowPeriods.HasValue || !signalPeriods.HasValue)
{
throw new Exception(
$"Missing fastPeriods or slowPeriods or signalPeriods, for {indicator.Type} strategy type");
}
else
{
indicator.FastPeriods = fastPeriods;
indicator.SlowPeriods = slowPeriods;
indicator.SignalPeriods = signalPeriods;
}
break;
case IndicatorType.DualEmaCross:
if (!fastPeriods.HasValue || !slowPeriods.HasValue)
{
throw new Exception(
$"Missing fastPeriods or slowPeriods for {indicator.Type} strategy type");
}
else
{
indicator.FastPeriods = fastPeriods;
indicator.SlowPeriods = slowPeriods;
}
break;
case IndicatorType.ThreeWhiteSoldiers:
break;
case IndicatorType.SuperTrend:
case IndicatorType.SuperTrendCrossEma:
case IndicatorType.ChandelierExit:
if (!period.HasValue || !multiplier.HasValue)
{
throw new Exception($"Missing period or multiplier, for {indicator.Type} strategy type");
}
else
{
indicator.Period = period;
indicator.Multiplier = multiplier;
}
break;
case IndicatorType.StochRsiTrend:
if (!period.HasValue
|| !stochPeriods.HasValue
|| !signalPeriods.HasValue
|| !smoothPeriods.HasValue)
{
throw new Exception(
$"Missing period, stochPeriods, signalPeriods, smoothPeriods for {indicator.Type} strategy type");
}
else
{
indicator.Period = period;
indicator.StochPeriods = stochPeriods;
indicator.SignalPeriods = signalPeriods;
indicator.SmoothPeriods = smoothPeriods;
}
break;
case IndicatorType.StochasticCross:
if (!stochPeriods.HasValue || !signalPeriods.HasValue || !smoothPeriods.HasValue)
{
throw new Exception(
$"Missing stochPeriods, signalPeriods, smoothPeriods for {indicator.Type} strategy type");
}
else
{
indicator.StochPeriods = stochPeriods;
indicator.SignalPeriods = signalPeriods;
indicator.SmoothPeriods = smoothPeriods;
// Set default values for optional parameters
indicator.KFactor = kFactor ?? 3.0;
indicator.DFactor = dFactor ?? 2.0;
// Validate kFactor and dFactor are greater than 0
if (indicator.KFactor <= 0)
{
throw new Exception($"kFactor must be greater than 0 for {indicator.Type} strategy type");
}
if (indicator.DFactor <= 0)
{
throw new Exception($"dFactor must be greater than 0 for {indicator.Type} strategy type");
}
}
break;
case IndicatorType.Stc:
case IndicatorType.LaggingStc:
if (!fastPeriods.HasValue || !slowPeriods.HasValue || !cyclePeriods.HasValue)
{
throw new Exception(
$"Missing fastPeriods or slowPeriods or cyclePeriods, for {indicator.Type} strategy type");
}
else
{
indicator.FastPeriods = fastPeriods;
indicator.SlowPeriods = slowPeriods;
indicator.CyclePeriods = cyclePeriods;
}
break;
default:
break;
}
return indicator;
}
public static SignalType GetSignalType(IndicatorType type)
{
return type switch
{
IndicatorType.RsiDivergence => SignalType.Signal,
IndicatorType.RsiDivergenceConfirm => SignalType.Signal,
IndicatorType.MacdCross => SignalType.Signal,
IndicatorType.EmaCross => SignalType.Signal,
IndicatorType.DualEmaCross => SignalType.Signal,
IndicatorType.ThreeWhiteSoldiers => SignalType.Signal,
IndicatorType.SuperTrend => SignalType.Trend,
IndicatorType.ChandelierExit => SignalType.Signal,
IndicatorType.EmaTrend => SignalType.Trend,
IndicatorType.Composite => SignalType.Signal,
IndicatorType.StochRsiTrend => SignalType.Trend,
IndicatorType.StochasticCross => SignalType.Signal,
IndicatorType.Stc => SignalType.Signal,
IndicatorType.StDev => SignalType.Context,
IndicatorType.LaggingStc => SignalType.Signal,
IndicatorType.SuperTrendCrossEma => SignalType.Signal,
IndicatorType.BollingerBandsPercentBMomentumBreakout => SignalType.Signal,
IndicatorType.IchimokuKumoTrend => SignalType.Trend,
_ => throw new NotImplementedException(),
};
}
}