Add new strat DualEmaCross
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
using Managing.Application.Abstractions.Services;
|
||||
using Managing.Domain.Accounts;
|
||||
using Managing.Domain.Strategies;
|
||||
using Managing.Domain.Strategies.Signals;
|
||||
using Managing.Domain.Strategies.Trends;
|
||||
using Xunit;
|
||||
using static Managing.Common.Enums;
|
||||
|
||||
@@ -22,7 +24,7 @@ namespace Managing.Application.Tests
|
||||
{
|
||||
var account = GetAccount(exchange);
|
||||
// Arrange
|
||||
var rsiStrategy = new RSIDivergenceStrategy("unittest", 5);
|
||||
var rsiStrategy = new RsiDivergenceStrategy("unittest", 5);
|
||||
var candles = _exchangeService.GetCandles(account, ticker, DateTime.Now.AddDays(-50), timeframe).Result;
|
||||
var resultSignal = new List<Signal>();
|
||||
|
||||
@@ -56,7 +58,7 @@ namespace Managing.Application.Tests
|
||||
{
|
||||
// Arrange
|
||||
var account = GetAccount(exchange);
|
||||
var rsiStrategy = new RSIDivergenceStrategy("unittest", 5);
|
||||
var rsiStrategy = new RsiDivergenceStrategy("unittest", 5);
|
||||
var candles = _exchangeService.GetCandles(account, ticker, DateTime.Now.AddDays(-50), timeframe).Result;
|
||||
var resultSignal = new List<Signal>();
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
using Managing.Domain.Candles;
|
||||
using Managing.Domain.Strategies;
|
||||
using Managing.Domain.Strategies.Signals;
|
||||
using Managing.Domain.Workflows;
|
||||
using Newtonsoft.Json;
|
||||
using static Managing.Common.Enums;
|
||||
@@ -30,7 +30,7 @@ public class RsiDiv : FlowBase
|
||||
MapParameters();
|
||||
var candles = JsonConvert.DeserializeObject<HashSet<Candle>>(input);
|
||||
|
||||
var strategy = new RSIDivergenceStrategy(Name, RsiDivParameters.Period);
|
||||
var strategy = new RsiDivergenceStrategy(Name, RsiDivParameters.Period);
|
||||
strategy.UpdateCandles(candles);
|
||||
strategy.Run();
|
||||
|
||||
|
||||
@@ -63,7 +63,8 @@ public static class Enums
|
||||
Stc,
|
||||
StDev,
|
||||
LaggingStc,
|
||||
SuperTrendCrossEma
|
||||
SuperTrendCrossEma,
|
||||
DualEmaCross
|
||||
}
|
||||
|
||||
public enum SignalType
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
using Managing.Core.FixedSizedQueue;
|
||||
using Managing.Domain.Candles;
|
||||
using Managing.Domain.Strategies;
|
||||
using Managing.Domain.Strategies.Context;
|
||||
using Managing.Domain.Strategies.Signals;
|
||||
using Managing.Domain.Strategies.Trends;
|
||||
using static Managing.Common.Enums;
|
||||
|
||||
namespace Managing.Domain.Scenarios;
|
||||
@@ -24,13 +27,15 @@ public static class ScenarioHelpers
|
||||
IStrategy result = strategy.Type switch
|
||||
{
|
||||
StrategyType.StDev => new StDevContext(strategy.Name, strategy.Period.Value),
|
||||
StrategyType.RsiDivergence => new RSIDivergenceStrategy(strategy.Name,
|
||||
StrategyType.RsiDivergence => new RsiDivergenceStrategy(strategy.Name,
|
||||
strategy.Period.Value),
|
||||
StrategyType.RsiDivergenceConfirm => new RSIDivergenceConfirmStrategy(strategy.Name,
|
||||
StrategyType.RsiDivergenceConfirm => new RsiDivergenceConfirmStrategy(strategy.Name,
|
||||
strategy.Period.Value),
|
||||
StrategyType.MacdCross => new MacdCrossStrategy(strategy.Name,
|
||||
strategy.FastPeriods.Value, strategy.SlowPeriods.Value, strategy.SignalPeriods.Value),
|
||||
StrategyType.EmaCross => new EmaCrossStrategy(strategy.Name, strategy.Period.Value),
|
||||
StrategyType.DualEmaCross => new DualEmaCrossStrategy(strategy.Name,
|
||||
strategy.FastPeriods.Value, strategy.SlowPeriods.Value),
|
||||
StrategyType.ThreeWhiteSoldiers => new ThreeWhiteSoldiersStrategy(strategy.Name,
|
||||
strategy.Period.Value),
|
||||
StrategyType.SuperTrend => new SuperTrendStrategy(strategy.Name,
|
||||
@@ -41,7 +46,7 @@ public static class ScenarioHelpers
|
||||
StrategyType.StochRsiTrend => new StochRsiTrendStrategy(strategy.Name,
|
||||
strategy.Period.Value, strategy.StochPeriods.Value, strategy.SignalPeriods.Value,
|
||||
strategy.SmoothPeriods.Value),
|
||||
StrategyType.Stc => new STCStrategy(strategy.Name, strategy.CyclePeriods.Value,
|
||||
StrategyType.Stc => new StcStrategy(strategy.Name, strategy.CyclePeriods.Value,
|
||||
strategy.FastPeriods.Value, strategy.SlowPeriods.Value),
|
||||
StrategyType.LaggingStc => new LaggingSTC(strategy.Name, strategy.CyclePeriods.Value,
|
||||
strategy.FastPeriods.Value, strategy.SlowPeriods.Value),
|
||||
@@ -99,6 +104,18 @@ public static class ScenarioHelpers
|
||||
}
|
||||
|
||||
break;
|
||||
case StrategyType.DualEmaCross:
|
||||
if (!fastPeriods.HasValue || !slowPeriods.HasValue)
|
||||
{
|
||||
throw new Exception(
|
||||
$"Missing fastPeriods or slowPeriods for {strategy.Type} strategy type");
|
||||
}
|
||||
else
|
||||
{
|
||||
strategy.FastPeriods = fastPeriods;
|
||||
strategy.SlowPeriods = slowPeriods;
|
||||
}
|
||||
|
||||
break;
|
||||
case StrategyType.ThreeWhiteSoldiers:
|
||||
break;
|
||||
@@ -164,6 +181,7 @@ public static class ScenarioHelpers
|
||||
StrategyType.RsiDivergenceConfirm => SignalType.Signal,
|
||||
StrategyType.MacdCross => SignalType.Signal,
|
||||
StrategyType.EmaCross => SignalType.Signal,
|
||||
StrategyType.DualEmaCross => SignalType.Signal,
|
||||
StrategyType.ThreeWhiteSoldiers => SignalType.Signal,
|
||||
StrategyType.SuperTrend => SignalType.Signal,
|
||||
StrategyType.ChandelierExit => SignalType.Signal,
|
||||
|
||||
@@ -60,13 +60,13 @@ public static class TradingBox
|
||||
{
|
||||
var signalOnCandles = new HashSet<Signal>();
|
||||
var limitedCandles = newCandles.ToList().TakeLast(600).ToList();
|
||||
|
||||
|
||||
foreach (var strategy in strategies)
|
||||
{
|
||||
strategy.UpdateCandles(limitedCandles.ToHashSet());
|
||||
var signals = strategy.Run();
|
||||
|
||||
if (signals == null || signals.Count == 0)
|
||||
if (signals == null || signals.Count == 0)
|
||||
{
|
||||
// For trend and context strategies, lack of signal might be meaningful
|
||||
// Signal strategies are expected to be sparse, so we continue
|
||||
@@ -74,7 +74,7 @@ public static class TradingBox
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
// For trend strategies, no signal might mean neutral trend
|
||||
// For context strategies, no signal might mean no restrictions
|
||||
// We'll let the ComputeSignals method handle these cases
|
||||
@@ -82,6 +82,7 @@ public static class TradingBox
|
||||
}
|
||||
|
||||
// Ensure limitedCandles is ordered chronologically
|
||||
loopbackPeriod = 20;
|
||||
var orderedCandles = limitedCandles.OrderBy(c => c.Date).ToList();
|
||||
var loopback = loopbackPeriod.HasValue && loopbackPeriod > 1 ? loopbackPeriod.Value : 1;
|
||||
var candleLoopback = orderedCandles.TakeLast(loopback).ToList();
|
||||
@@ -135,6 +136,13 @@ public static class TradingBox
|
||||
return signalOnCandles.Single();
|
||||
}
|
||||
|
||||
// Check if all strategies produced signals - this is required for composite signals
|
||||
if (signalOnCandles.Count != strategies.Count)
|
||||
{
|
||||
// Not all strategies produced signals - composite signal requires all strategies to contribute
|
||||
return null;
|
||||
}
|
||||
|
||||
// Group signals by type for analysis
|
||||
var signalStrategies = signalOnCandles.Where(s => s.SignalType == SignalType.Signal).ToList();
|
||||
var trendStrategies = signalOnCandles.Where(s => s.SignalType == SignalType.Trend).ToList();
|
||||
@@ -153,7 +161,8 @@ public static class TradingBox
|
||||
var signalDirection = EvaluateSignalDirection(signalStrategies, config);
|
||||
|
||||
// Determine final direction and confidence
|
||||
var (finalDirection, confidence) = DetermineFinalSignal(signalDirection, trendDirection, signalStrategies, trendStrategies, config);
|
||||
var (finalDirection, confidence) =
|
||||
DetermineFinalSignal(signalDirection, trendDirection, signalStrategies, trendStrategies, config);
|
||||
|
||||
if (finalDirection == TradeDirection.None || confidence < config.MinimumConfidence)
|
||||
{
|
||||
@@ -161,8 +170,9 @@ public static class TradingBox
|
||||
}
|
||||
|
||||
// Create composite signal
|
||||
var lastSignal = signalStrategies.LastOrDefault() ?? trendStrategies.LastOrDefault() ?? contextStrategies.LastOrDefault();
|
||||
|
||||
var lastSignal = signalStrategies.LastOrDefault() ??
|
||||
trendStrategies.LastOrDefault() ?? contextStrategies.LastOrDefault();
|
||||
|
||||
return new Signal(
|
||||
ticker,
|
||||
finalDirection,
|
||||
@@ -170,17 +180,18 @@ public static class TradingBox
|
||||
lastSignal?.Candle,
|
||||
lastSignal?.Date ?? DateTime.UtcNow,
|
||||
lastSignal?.Exchange ?? config.DefaultExchange,
|
||||
StrategyType.Composite,
|
||||
StrategyType.Composite,
|
||||
SignalType.Signal);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validates context strategies based on confidence levels indicating market condition quality
|
||||
/// </summary>
|
||||
private static bool ValidateContextStrategies(HashSet<IStrategy> allStrategies, List<Signal> contextSignals, StrategyComboConfig config)
|
||||
private static bool ValidateContextStrategies(HashSet<IStrategy> allStrategies, List<Signal> contextSignals,
|
||||
StrategyComboConfig config)
|
||||
{
|
||||
var contextStrategiesCount = allStrategies.Count(s => s.SignalType == SignalType.Context);
|
||||
|
||||
|
||||
if (contextStrategiesCount == 0)
|
||||
{
|
||||
return true; // No context strategies, no restrictions
|
||||
@@ -256,9 +267,9 @@ public static class TradingBox
|
||||
/// Determines final signal direction and confidence based on signal and trend analysis
|
||||
/// </summary>
|
||||
private static (TradeDirection Direction, Confidence Confidence) DetermineFinalSignal(
|
||||
TradeDirection signalDirection,
|
||||
TradeDirection trendDirection,
|
||||
List<Signal> signalStrategies,
|
||||
TradeDirection signalDirection,
|
||||
TradeDirection trendDirection,
|
||||
List<Signal> signalStrategies,
|
||||
List<Signal> trendStrategies,
|
||||
StrategyComboConfig config)
|
||||
{
|
||||
@@ -294,12 +305,12 @@ public static class TradingBox
|
||||
{
|
||||
// Calculate confidence based on trend strength
|
||||
var totalTrend = trendStrategies.Count;
|
||||
var majorityDirection = trendDirection == TradeDirection.Long
|
||||
var majorityDirection = trendDirection == TradeDirection.Long
|
||||
? trendStrategies.Count(s => s.Direction == TradeDirection.Long)
|
||||
: trendStrategies.Count(s => s.Direction == TradeDirection.Short);
|
||||
|
||||
var agreementPercentage = (decimal)majorityDirection / totalTrend;
|
||||
|
||||
|
||||
if (agreementPercentage >= 0.8m)
|
||||
return (trendDirection, Confidence.High);
|
||||
else if (agreementPercentage >= config.TrendStrongAgreementThreshold)
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
{
|
||||
119
src/Managing.Domain/Strategies/Signals/DualEmaCrossStrategy.cs
Normal file
119
src/Managing.Domain/Strategies/Signals/DualEmaCrossStrategy.cs
Normal 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; }
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
{
|
||||
@@ -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.
|
||||
@@ -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
|
||||
{
|
||||
@@ -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>();
|
||||
@@ -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>();
|
||||
@@ -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)
|
||||
@@ -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
|
||||
{
|
||||
@@ -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
|
||||
{
|
||||
@@ -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
|
||||
{
|
||||
@@ -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
|
||||
{
|
||||
@@ -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
|
||||
{
|
||||
@@ -2991,6 +2991,7 @@ export enum StrategyType {
|
||||
StDev = "StDev",
|
||||
LaggingStc = "LaggingStc",
|
||||
SuperTrendCrossEma = "SuperTrendCrossEma",
|
||||
DualEmaCross = "DualEmaCross",
|
||||
}
|
||||
|
||||
export enum SignalType {
|
||||
@@ -3017,6 +3018,8 @@ export interface KeyValuePairOfDateTimeAndDecimal {
|
||||
|
||||
export interface StrategiesResultBase {
|
||||
ema?: EmaResult[] | null;
|
||||
fastEma?: EmaResult[] | null;
|
||||
slowEma?: EmaResult[] | null;
|
||||
macd?: MacdResult[] | null;
|
||||
rsi?: RsiResult[] | null;
|
||||
stoch?: StochResult[] | null;
|
||||
|
||||
@@ -227,6 +227,41 @@ const StrategyList: React.FC = () => {
|
||||
</>
|
||||
) : null}
|
||||
|
||||
{strategyType == StrategyType.DualEmaCross ? (
|
||||
<>
|
||||
<div className="form-control">
|
||||
<div className="input-group">
|
||||
<label htmlFor="period" className="label mr-6">
|
||||
Fast Periods
|
||||
</label>
|
||||
<label className="input-group">
|
||||
<input
|
||||
type="number"
|
||||
placeholder="9"
|
||||
className="input"
|
||||
{...register('fastPeriods')}
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div className="form-control">
|
||||
<div className="input-group">
|
||||
<label htmlFor="period" className="label mr-6">
|
||||
Slow Periods
|
||||
</label>
|
||||
<label className="input-group">
|
||||
<input
|
||||
type="number"
|
||||
placeholder="21"
|
||||
className="input"
|
||||
{...register('slowPeriods')}
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
) : null}
|
||||
|
||||
{strategyType == StrategyType.Stc || strategyType == StrategyType.LaggingStc ? (
|
||||
<>
|
||||
<div className="form-control">
|
||||
|
||||
Reference in New Issue
Block a user