Add indicators to backtest and bot (#14)
* Add indicators to backtest and bot * Remove
This commit is contained in:
@@ -4,6 +4,7 @@ using Managing.Domain.MoneyManagements;
|
||||
using Managing.Domain.Strategies;
|
||||
using Managing.Domain.Trades;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Managing.Domain.Strategies.Base;
|
||||
using static Managing.Common.Enums;
|
||||
|
||||
namespace Managing.Domain.Backtests;
|
||||
@@ -30,45 +31,30 @@ public class Backtest
|
||||
AccountName = accountName;
|
||||
}
|
||||
|
||||
[Required]
|
||||
public string Id { get; set; }
|
||||
[Required]
|
||||
public decimal FinalPnl { get; set; }
|
||||
[Required]
|
||||
public int WinRate { get; set; }
|
||||
[Required]
|
||||
public decimal GrowthPercentage { get; set; }
|
||||
[Required]
|
||||
public decimal HodlPercentage { get; set; }
|
||||
[Required]
|
||||
public Ticker Ticker { get; }
|
||||
[Required]
|
||||
public string Scenario { get; set; }
|
||||
[Required]
|
||||
public List<Position> Positions { get; }
|
||||
[Required]
|
||||
public List<Signal> Signals { get; }
|
||||
[Required]
|
||||
public Timeframe Timeframe { get; }
|
||||
[Required]
|
||||
public BotType BotType { get; }
|
||||
[Required]
|
||||
public string AccountName { get; }
|
||||
[Required]
|
||||
public List<Candle> Candles { get; }
|
||||
[Required]
|
||||
public PerformanceMetrics Statistics { get; set; }
|
||||
[Required]
|
||||
public decimal Fees { get; set; }
|
||||
[Required]
|
||||
public List<KeyValuePair<DateTime, decimal>> WalletBalances { get; set; }
|
||||
[Required]
|
||||
public MoneyManagement OptimizedMoneyManagement { get; set; }
|
||||
[Required]
|
||||
public MoneyManagement MoneyManagement { get; set; }
|
||||
[Required] public string Id { get; set; }
|
||||
[Required] public decimal FinalPnl { get; set; }
|
||||
[Required] public int WinRate { get; set; }
|
||||
[Required] public decimal GrowthPercentage { get; set; }
|
||||
[Required] public decimal HodlPercentage { get; set; }
|
||||
[Required] public Ticker Ticker { get; }
|
||||
[Required] public string Scenario { get; set; }
|
||||
[Required] public List<Position> Positions { get; }
|
||||
[Required] public List<Signal> Signals { get; }
|
||||
[Required] public Timeframe Timeframe { get; }
|
||||
[Required] public BotType BotType { get; }
|
||||
[Required] public string AccountName { get; }
|
||||
[Required] public List<Candle> Candles { get; }
|
||||
[Required] public PerformanceMetrics Statistics { get; set; }
|
||||
[Required] public decimal Fees { get; set; }
|
||||
[Required] public List<KeyValuePair<DateTime, decimal>> WalletBalances { get; set; }
|
||||
[Required] public MoneyManagement OptimizedMoneyManagement { get; set; }
|
||||
[Required] public MoneyManagement MoneyManagement { get; set; }
|
||||
|
||||
public Dictionary<StrategyType, StrategiesResultBase> StrategiesValues { get; set; }
|
||||
|
||||
public string GetStringReport()
|
||||
{
|
||||
return $"{Ticker} | {Timeframe} | Positions: {Positions.Count} | Winrate: {WinRate}% | Pnl: {FinalPnl:#.##}$ | %Pnl: {GrowthPercentage:#.##}% | %Hodl: {HodlPercentage:#.##}%";
|
||||
return
|
||||
$"{Ticker} | {Timeframe} | Positions: {Positions.Count} | Winrate: {WinRate}% | Pnl: {FinalPnl:#.##}$ | %Pnl: {GrowthPercentage:#.##}% | %Hodl: {HodlPercentage:#.##}%";
|
||||
}
|
||||
}
|
||||
@@ -7,43 +7,51 @@ namespace Managing.Domain.Scenarios;
|
||||
|
||||
public static class ScenarioHelpers
|
||||
{
|
||||
|
||||
|
||||
public static IEnumerable<IStrategy> GetStrategiesFromScenario(Scenario scenario)
|
||||
{
|
||||
var strategies = new List<IStrategy>();
|
||||
foreach (var strategy in scenario.Strategies)
|
||||
{
|
||||
IStrategy result = strategy.Type switch
|
||||
{
|
||||
StrategyType.StDev => new StDevContext(strategy.Name, strategy.Period.Value),
|
||||
StrategyType.RsiDivergence => new RSIDivergenceStrategy(strategy.Name,
|
||||
strategy.Period.Value),
|
||||
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.ThreeWhiteSoldiers => new ThreeWhiteSoldiersStrategy(strategy.Name,
|
||||
strategy.Period.Value),
|
||||
StrategyType.SuperTrend => new SuperTrendStrategy(strategy.Name,
|
||||
strategy.Period.Value, strategy.Multiplier.Value),
|
||||
StrategyType.ChandelierExit => new ChandelierExitStrategy(strategy.Name,
|
||||
strategy.Period.Value, strategy.Multiplier.Value),
|
||||
StrategyType.EmaTrend => new EmaTrendStrategy(strategy.Name, strategy.Period.Value),
|
||||
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,
|
||||
strategy.FastPeriods.Value, strategy.SlowPeriods.Value),
|
||||
_ => throw new NotImplementedException(),
|
||||
};
|
||||
|
||||
result.Candles = new FixedSizeQueue<Candle>(600);
|
||||
var result = BuildStrategy(strategy);
|
||||
strategies.Add(result);
|
||||
}
|
||||
|
||||
return strategies;
|
||||
}
|
||||
|
||||
public static IStrategy BuildStrategy(Strategy strategy, int size = 600)
|
||||
{
|
||||
IStrategy result = strategy.Type switch
|
||||
{
|
||||
StrategyType.StDev => new StDevContext(strategy.Name, strategy.Period.Value),
|
||||
StrategyType.RsiDivergence => new RSIDivergenceStrategy(strategy.Name,
|
||||
strategy.Period.Value),
|
||||
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.ThreeWhiteSoldiers => new ThreeWhiteSoldiersStrategy(strategy.Name,
|
||||
strategy.Period.Value),
|
||||
StrategyType.SuperTrend => new SuperTrendStrategy(strategy.Name,
|
||||
strategy.Period.Value, strategy.Multiplier.Value),
|
||||
StrategyType.ChandelierExit => new ChandelierExitStrategy(strategy.Name,
|
||||
strategy.Period.Value, strategy.Multiplier.Value),
|
||||
StrategyType.EmaTrend => new EmaTrendStrategy(strategy.Name, strategy.Period.Value),
|
||||
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,
|
||||
strategy.FastPeriods.Value, strategy.SlowPeriods.Value),
|
||||
_ => throw new NotImplementedException(),
|
||||
};
|
||||
|
||||
result.Candles = new FixedSizeQueue<Candle>(size);
|
||||
return result;
|
||||
}
|
||||
|
||||
public static Strategy BuildStrategy(
|
||||
StrategyType type,
|
||||
string name,
|
||||
|
||||
18
src/Managing.Domain/Strategies/Base/StrategiesResultBase.cs
Normal file
18
src/Managing.Domain/Strategies/Base/StrategiesResultBase.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using Skender.Stock.Indicators;
|
||||
|
||||
namespace Managing.Domain.Strategies.Base;
|
||||
|
||||
public class StrategiesResultBase
|
||||
{
|
||||
public List<EmaResult> Ema { get; set; }
|
||||
public List<MacdResult> Macd { get; set; }
|
||||
public List<RsiResult> Rsi { get; set; }
|
||||
public List<StochResult> Stoch { get; set; }
|
||||
public List<StochRsiResult> StochRsi { get; set; }
|
||||
public List<BollingerBandsResult> BollingerBands { get; set; }
|
||||
public List<ChandelierResult> ChandelierShort { get; set; }
|
||||
public List<StcResult> Stc { get; set; }
|
||||
public List<StdDevResult> StdDev { get; set; }
|
||||
public List<SuperTrendResult> SuperTrend { get; set; }
|
||||
public List<ChandelierResult> ChandelierLong { get; set; }
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
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;
|
||||
|
||||
@@ -38,6 +39,15 @@ public class ChandelierExitStrategy : Strategy
|
||||
}
|
||||
}
|
||||
|
||||
public override StrategiesResultBase GetStrategyValues()
|
||||
{
|
||||
return new StrategiesResultBase()
|
||||
{
|
||||
ChandelierLong = Candles.GetChandelier(Period.Value, Multiplier.Value, ChandelierType.Long).ToList(),
|
||||
ChandelierShort = Candles.GetChandelier(Period.Value, Multiplier.Value, ChandelierType.Short).ToList()
|
||||
};
|
||||
}
|
||||
|
||||
private void GetSignals(ChandelierType chandelierType)
|
||||
{
|
||||
var chandelier = Candles.GetChandelier(Period.Value, Multiplier.Value, chandelierType)
|
||||
|
||||
@@ -16,6 +16,14 @@ public class EmaCrossStrategy : EmaBaseStrategy
|
||||
Period = period;
|
||||
}
|
||||
|
||||
public override StrategiesResultBase GetStrategyValues()
|
||||
{
|
||||
return new StrategiesResultBase()
|
||||
{
|
||||
Ema = Candles.GetEma(Period.Value).ToList()
|
||||
};
|
||||
}
|
||||
|
||||
public override List<Signal> Run()
|
||||
{
|
||||
if (Candles.Count <= Period)
|
||||
|
||||
@@ -54,6 +54,14 @@ public class EmaTrendStrategy : EmaBaseStrategy
|
||||
}
|
||||
}
|
||||
|
||||
public override StrategiesResultBase GetStrategyValues()
|
||||
{
|
||||
return new StrategiesResultBase()
|
||||
{
|
||||
Ema = Candles.GetEma(Period.Value).ToList()
|
||||
};
|
||||
}
|
||||
|
||||
public void AddSignal(CandleEma candleSignal, TradeDirection direction, Confidence confidence)
|
||||
{
|
||||
var signal = new Signal(MiscExtensions.ParseEnum<Ticker>(candleSignal.Ticker), direction, confidence,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Managing.Core.FixedSizedQueue;
|
||||
using Managing.Domain.Candles;
|
||||
using Managing.Domain.Strategies.Base;
|
||||
using static Managing.Common.Enums;
|
||||
|
||||
namespace Managing.Domain.Strategies
|
||||
@@ -16,6 +17,7 @@ namespace Managing.Domain.Strategies
|
||||
FixedSizeQueue<Candle> Candles { get; set; }
|
||||
|
||||
List<Signal> Run();
|
||||
StrategiesResultBase GetStrategyValues();
|
||||
void UpdateCandles(HashSet<Candle> newCandles);
|
||||
string GetName();
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
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;
|
||||
|
||||
@@ -58,6 +59,15 @@ public class MacdCrossStrategy : Strategy
|
||||
}
|
||||
}
|
||||
|
||||
public override StrategiesResultBase GetStrategyValues()
|
||||
{
|
||||
return new StrategiesResultBase()
|
||||
{
|
||||
Macd = Candles.GetMacd(FastPeriods.Value, SlowPeriods.Value, SignalPeriods.Value).ToList()
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
private List<CandleMacd> MapMacdToCandle(List<MacdResult> macd, IEnumerable<Candle> candles)
|
||||
{
|
||||
var macdList = new List<CandleMacd>();
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Managing.Core;
|
||||
using Managing.Domain.Shared.Rules;
|
||||
using Managing.Domain.Strategies.Base;
|
||||
using Skender.Stock.Indicators;
|
||||
using static Managing.Common.Enums;
|
||||
using Candle = Managing.Domain.Candles.Candle;
|
||||
@@ -48,6 +49,14 @@ public class RSIDivergenceConfirmStrategy : Strategy
|
||||
}
|
||||
}
|
||||
|
||||
public override StrategiesResultBase GetStrategyValues()
|
||||
{
|
||||
return new StrategiesResultBase()
|
||||
{
|
||||
Rsi = Candles.GetRsi(Period.Value).ToList()
|
||||
};
|
||||
}
|
||||
|
||||
private void GetLongSignals(List<CandleRsi> candlesRsi)
|
||||
{
|
||||
// Set the low and high for first candle
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Managing.Core;
|
||||
using Managing.Domain.Shared.Rules;
|
||||
using Managing.Domain.Strategies.Base;
|
||||
using Skender.Stock.Indicators;
|
||||
using static Managing.Common.Enums;
|
||||
using Candle = Managing.Domain.Candles.Candle;
|
||||
@@ -51,6 +52,14 @@ public class RSIDivergenceStrategy : Strategy
|
||||
}
|
||||
}
|
||||
|
||||
public override StrategiesResultBase GetStrategyValues()
|
||||
{
|
||||
return new StrategiesResultBase()
|
||||
{
|
||||
Rsi = Candles.GetRsi(Period.Value).ToList()
|
||||
};
|
||||
}
|
||||
|
||||
private void GetLongSignals(List<CandleRsi> candlesRsi)
|
||||
{
|
||||
// Set the low and high for first candle
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
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;
|
||||
|
||||
@@ -57,6 +58,15 @@ public class STCStrategy : Strategy
|
||||
}
|
||||
}
|
||||
|
||||
public override StrategiesResultBase GetStrategyValues()
|
||||
{
|
||||
var stc = Candles.GetStc(FastPeriods.Value, FastPeriods.Value, SlowPeriods.Value).ToList();
|
||||
return new StrategiesResultBase
|
||||
{
|
||||
Stc = stc
|
||||
};
|
||||
}
|
||||
|
||||
private List<CandleSct> MapStcToCandle(List<StcResult> stc, IEnumerable<Candle> candles)
|
||||
{
|
||||
var sctList = new List<CandleSct>();
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
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;
|
||||
|
||||
@@ -50,6 +51,16 @@ public class StDevContext : Strategy
|
||||
}
|
||||
}
|
||||
|
||||
public override StrategiesResultBase GetStrategyValues()
|
||||
{
|
||||
var test = new StrategiesResultBase()
|
||||
{
|
||||
StdDev = Candles.GetStdDev(Period.Value).ToList()
|
||||
};
|
||||
|
||||
return test;
|
||||
}
|
||||
|
||||
private List<CandleStDev> MapStDev(List<StdDevResult> stDev, IEnumerable<Candle> candles)
|
||||
{
|
||||
var sctList = new List<CandleStDev>();
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
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;
|
||||
|
||||
@@ -64,6 +65,15 @@ public class StochRsiTrendStrategy : Strategy
|
||||
}
|
||||
}
|
||||
|
||||
public override StrategiesResultBase GetStrategyValues()
|
||||
{
|
||||
return new StrategiesResultBase()
|
||||
{
|
||||
StochRsi = Candles.GetStochRsi(Period.Value, StochPeriods.Value, SignalPeriods.Value, SmoothPeriods.Value)
|
||||
.ToList()
|
||||
};
|
||||
}
|
||||
|
||||
private List<CandleStochRsi> MapStochRsiToCandle(List<StochRsiResult> ema, IEnumerable<Candle> candles)
|
||||
{
|
||||
var emaList = new List<CandleStochRsi>();
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using Managing.Core.FixedSizedQueue;
|
||||
using Managing.Domain.Candles;
|
||||
using Managing.Domain.Scenarios;
|
||||
using Managing.Domain.Strategies.Base;
|
||||
using static Managing.Common.Enums;
|
||||
|
||||
namespace Managing.Domain.Strategies
|
||||
@@ -34,6 +35,11 @@ namespace Managing.Domain.Strategies
|
||||
return new List<Signal>();
|
||||
}
|
||||
|
||||
public virtual StrategiesResultBase GetStrategyValues()
|
||||
{
|
||||
return new StrategiesResultBase();
|
||||
}
|
||||
|
||||
public void UpdateCandles(HashSet<Candle> newCandles)
|
||||
{
|
||||
if (newCandles == null || newCandles.Count == 0)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
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;
|
||||
|
||||
@@ -60,6 +61,15 @@ public class SuperTrendStrategy : Strategy
|
||||
}
|
||||
}
|
||||
|
||||
public override StrategiesResultBase GetStrategyValues()
|
||||
{
|
||||
return new StrategiesResultBase()
|
||||
{
|
||||
SuperTrend = Candles.GetSuperTrend(Period.Value, Multiplier.Value).Where(s => s.SuperTrend.HasValue)
|
||||
.ToList()
|
||||
};
|
||||
}
|
||||
|
||||
private List<CandleSuperTrend> MapSuperTrendToCandle(List<SuperTrendResult> superTrend, IEnumerable<Candle> candles)
|
||||
{
|
||||
var superTrends = new List<CandleSuperTrend>();
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Managing.Domain.Candles;
|
||||
using Managing.Domain.Shared.Rules;
|
||||
using Managing.Domain.Strategies.Base;
|
||||
using Managing.Domain.Strategies.Rules;
|
||||
using static Managing.Common.Enums;
|
||||
|
||||
@@ -50,5 +51,10 @@ namespace Managing.Domain.Strategies
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public override StrategiesResultBase GetStrategyValues()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user