Add new strat DualEmaCross

This commit is contained in:
2025-06-02 21:28:56 +07:00
parent de9f77d5ba
commit 7fce1fa59e
22 changed files with 264 additions and 62 deletions

View File

@@ -5,6 +5,8 @@ namespace Managing.Domain.Strategies.Base;
public class StrategiesResultBase
{
public List<EmaResult> Ema { get; set; }
public List<EmaResult> FastEma { get; set; }
public List<EmaResult> SlowEma { get; set; }
public List<MacdResult> Macd { get; set; }
public List<RsiResult> Rsi { get; set; }
public List<StochResult> Stoch { get; set; }

View File

@@ -5,7 +5,7 @@ using Managing.Domain.Strategies.Base;
using Skender.Stock.Indicators;
using static Managing.Common.Enums;
namespace Managing.Domain.Strategies;
namespace Managing.Domain.Strategies.Context;
public class StDevContext : Strategy
{
@@ -39,7 +39,7 @@ public class StDevContext : Strategy
// Lower absolute Z-score = more normal volatility = higher confidence for trading
// Higher absolute Z-score = more extreme volatility = lower confidence for trading
Confidence confidence;
if (Math.Abs(zScore) <= 0.5)
{
// Very low volatility - ideal conditions for trading

View File

@@ -5,7 +5,7 @@ using Managing.Domain.Strategies.Base;
using Skender.Stock.Indicators;
using static Managing.Common.Enums;
namespace Managing.Domain.Strategies;
namespace Managing.Domain.Strategies.Signals;
public class ChandelierExitStrategy : Strategy
{

View File

@@ -0,0 +1,119 @@
using Managing.Core;
using Managing.Domain.Candles;
using Managing.Domain.Shared.Rules;
using Managing.Domain.Strategies.Base;
using Skender.Stock.Indicators;
using static Managing.Common.Enums;
namespace Managing.Domain.Strategies.Signals;
public class DualEmaCrossStrategy : EmaBaseStrategy
{
public List<Signal> Signals { get; set; }
public DualEmaCrossStrategy(string name, int fastPeriod, int slowPeriod) : base(name, StrategyType.DualEmaCross)
{
Signals = new List<Signal>();
FastPeriods = fastPeriod;
SlowPeriods = slowPeriod;
MinimumHistory = Math.Max(fastPeriod, slowPeriod) * 2;
}
public override StrategiesResultBase GetStrategyValues()
{
return new StrategiesResultBase()
{
FastEma = Candles.GetEma(FastPeriods.Value).ToList(),
SlowEma = Candles.GetEma(SlowPeriods.Value).ToList()
};
}
public override List<Signal> Run()
{
if (Candles.Count <= MinimumHistory)
{
return null;
}
try
{
var fastEma = Candles.GetEma(FastPeriods.Value).ToList();
var slowEma = Candles.GetEma(SlowPeriods.Value).ToList();
var dualEmaCandles = MapDualEmaToCandle(fastEma, slowEma, Candles.TakeLast(MinimumHistory));
if (dualEmaCandles.Count < 2)
return null;
var previousCandle = dualEmaCandles[0];
foreach (var currentCandle in dualEmaCandles.Skip(1))
{
// Short signal: Fast EMA crosses below Slow EMA
if (previousCandle.FastEma > previousCandle.SlowEma &&
currentCandle.FastEma < currentCandle.SlowEma)
{
AddSignal(currentCandle, TradeDirection.Short, Confidence.Medium);
}
// Long signal: Fast EMA crosses above Slow EMA
if (previousCandle.FastEma < previousCandle.SlowEma &&
currentCandle.FastEma > currentCandle.SlowEma)
{
AddSignal(currentCandle, TradeDirection.Long, Confidence.Medium);
}
previousCandle = currentCandle;
}
return Signals.Where(s => s.Confidence != Confidence.None).OrderBy(s => s.Date).ToList();
}
catch (RuleException)
{
return null;
}
}
private List<CandleDualEma> MapDualEmaToCandle(List<EmaResult> fastEma, List<EmaResult> slowEma,
IEnumerable<Candle> candles)
{
var dualEmaList = new List<CandleDualEma>();
foreach (var candle in candles)
{
var currentFastEma = fastEma.Find(candle.Date);
var currentSlowEma = slowEma.Find(candle.Date);
if (currentFastEma != null && currentFastEma.Ema.HasValue &&
currentSlowEma != null && currentSlowEma.Ema.HasValue)
{
dualEmaList.Add(new CandleDualEma()
{
Close = candle.Close,
Open = candle.Open,
Date = candle.Date,
Ticker = candle.Ticker,
Exchange = candle.Exchange,
FastEma = currentFastEma.Ema.Value,
SlowEma = currentSlowEma.Ema.Value,
});
}
}
return dualEmaList;
}
private void AddSignal(CandleDualEma candleSignal, TradeDirection direction, Confidence confidence)
{
var signal = new Signal(MiscExtensions.ParseEnum<Ticker>(candleSignal.Ticker), direction, confidence,
candleSignal, candleSignal.Date, candleSignal.Exchange, Type, SignalType);
if (!Signals.Any(s => s.Identifier == signal.Identifier))
{
Signals.AddItem(signal);
}
}
public class CandleDualEma : Candle
{
public double FastEma { get; set; }
public double SlowEma { get; set; }
}
}

View File

@@ -4,7 +4,7 @@ using Managing.Domain.Strategies.Base;
using Skender.Stock.Indicators;
using static Managing.Common.Enums;
namespace Managing.Domain.Strategies;
namespace Managing.Domain.Strategies.Signals;
public class EmaCrossStrategy : EmaBaseStrategy
{

View File

@@ -5,7 +5,7 @@ using Managing.Domain.Strategies.Base;
using Skender.Stock.Indicators;
using static Managing.Common.Enums;
namespace Managing.Domain.Strategies;
namespace Managing.Domain.Strategies.Signals;
///<summary>
/// Lagging STC Strategy: Combines Schaff Trend Cycle with volatility-based confirmation.

View File

@@ -5,7 +5,7 @@ using Managing.Domain.Strategies.Base;
using Skender.Stock.Indicators;
using static Managing.Common.Enums;
namespace Managing.Domain.Strategies;
namespace Managing.Domain.Strategies.Signals;
public class MacdCrossStrategy : Strategy
{

View File

@@ -5,13 +5,13 @@ using Skender.Stock.Indicators;
using static Managing.Common.Enums;
using Candle = Managing.Domain.Candles.Candle;
namespace Managing.Domain.Strategies;
namespace Managing.Domain.Strategies.Signals;
public class RSIDivergenceConfirmStrategy : Strategy
public class RsiDivergenceConfirmStrategy : Strategy
{
public List<Signal> Signals { get; set; }
public RSIDivergenceConfirmStrategy(string name, int period) : base(name, StrategyType.RsiDivergenceConfirm)
public RsiDivergenceConfirmStrategy(string name, int period) : base(name, StrategyType.RsiDivergenceConfirm)
{
Period = period;
Signals = new List<Signal>();

View File

@@ -5,16 +5,16 @@ using Skender.Stock.Indicators;
using static Managing.Common.Enums;
using Candle = Managing.Domain.Candles.Candle;
namespace Managing.Domain.Strategies;
namespace Managing.Domain.Strategies.Signals;
public class RSIDivergenceStrategy : Strategy
public class RsiDivergenceStrategy : Strategy
{
public List<Signal> Signals { get; set; }
public TradeDirection Direction { get; set; }
private const int UpperBand = 70;
private const int LowerBand = 30;
public RSIDivergenceStrategy(string name, int period) : base(name, StrategyType.RsiDivergence)
public RsiDivergenceStrategy(string name, int period) : base(name, StrategyType.RsiDivergence)
{
Period = period;
Signals = new List<Signal>();

View File

@@ -5,13 +5,13 @@ using Managing.Domain.Strategies.Base;
using Skender.Stock.Indicators;
using static Managing.Common.Enums;
namespace Managing.Domain.Strategies;
namespace Managing.Domain.Strategies.Signals;
public class STCStrategy : Strategy
public class StcStrategy : Strategy
{
public List<Signal> Signals { get; set; }
public STCStrategy(string name, int cyclePeriods, int fastPeriods, int slowPeriods) : base(name, StrategyType.Stc)
public StcStrategy(string name, int cyclePeriods, int fastPeriods, int slowPeriods) : base(name, StrategyType.Stc)
{
Signals = new List<Signal>();
FastPeriods = fastPeriods;
@@ -28,26 +28,32 @@ public class STCStrategy : Strategy
try
{
var stc = Candles.GetStc(FastPeriods.Value, FastPeriods.Value, SlowPeriods.Value).ToList();
var stcCandles = MapStcToCandle(stc, Candles.TakeLast(CyclePeriods.Value));
if (stc.Count == 0)
return null;
var previousCandle = stcCandles[0];
foreach (var currentCandle in stcCandles.Skip(1))
if (FastPeriods != null)
{
if (previousCandle.Stc > 75 && currentCandle.Stc <= 75)
var stc = Candles.GetStc(FastPeriods.Value, FastPeriods.Value, SlowPeriods.Value).ToList();
if (CyclePeriods != null)
{
AddSignal(currentCandle, TradeDirection.Short, Confidence.Medium);
}
var stcCandles = MapStcToCandle(stc, Candles.TakeLast(CyclePeriods.Value));
if (previousCandle.Stc < 25 && currentCandle.Stc >= 25)
{
AddSignal(currentCandle, TradeDirection.Long, Confidence.Medium);
}
if (stc.Count == 0)
return null;
previousCandle = currentCandle;
var previousCandle = stcCandles[0];
foreach (var currentCandle in stcCandles.Skip(1))
{
if (previousCandle.Stc > 75 && currentCandle.Stc <= 75)
{
AddSignal(currentCandle, TradeDirection.Short, Confidence.Medium);
}
if (previousCandle.Stc < 25 && currentCandle.Stc >= 25)
{
AddSignal(currentCandle, TradeDirection.Long, Confidence.Medium);
}
previousCandle = currentCandle;
}
}
}
return Signals.Where(s => s.Confidence != Confidence.None).OrderBy(s => s.Date).ToList();
@@ -60,11 +66,16 @@ public class STCStrategy : Strategy
public override StrategiesResultBase GetStrategyValues()
{
var stc = Candles.GetStc(FastPeriods.Value, FastPeriods.Value, SlowPeriods.Value).ToList();
return new StrategiesResultBase
if (FastPeriods != null && SlowPeriods != null)
{
Stc = stc
};
var stc = Candles.GetStc(FastPeriods.Value, FastPeriods.Value, SlowPeriods.Value).ToList();
return new StrategiesResultBase
{
Stc = stc
};
}
return null;
}
private List<CandleSct> MapStcToCandle(List<StcResult> stc, IEnumerable<Candle> candles)

View File

@@ -5,7 +5,7 @@ using Managing.Domain.Strategies.Base;
using Skender.Stock.Indicators;
using static Managing.Common.Enums;
namespace Managing.Domain.Strategies;
namespace Managing.Domain.Strategies.Signals;
public class SuperTrendCrossEma : Strategy
{

View File

@@ -5,7 +5,7 @@ using Managing.Domain.Strategies.Base;
using Skender.Stock.Indicators;
using static Managing.Common.Enums;
namespace Managing.Domain.Strategies;
namespace Managing.Domain.Strategies.Signals;
public class SuperTrendStrategy : Strategy
{

View File

@@ -4,7 +4,7 @@ using Managing.Domain.Strategies.Base;
using Managing.Domain.Strategies.Rules;
using static Managing.Common.Enums;
namespace Managing.Domain.Strategies
namespace Managing.Domain.Strategies.Signals
{
public class ThreeWhiteSoldiersStrategy : Strategy
{

View File

@@ -4,7 +4,7 @@ using Managing.Domain.Strategies.Base;
using Skender.Stock.Indicators;
using static Managing.Common.Enums;
namespace Managing.Domain.Strategies;
namespace Managing.Domain.Strategies.Trends;
public class EmaTrendStrategy : EmaBaseStrategy
{

View File

@@ -5,7 +5,7 @@ using Managing.Domain.Strategies.Base;
using Skender.Stock.Indicators;
using static Managing.Common.Enums;
namespace Managing.Domain.Strategies;
namespace Managing.Domain.Strategies.Trends;
public class StochRsiTrendStrategy : Strategy
{