docker files fixes from liaqat
This commit is contained in:
408
src/Managing.Application.Tests/BotsTests.cs
Normal file
408
src/Managing.Application.Tests/BotsTests.cs
Normal file
@@ -0,0 +1,408 @@
|
||||
using Managing.Application.Abstractions;
|
||||
using Managing.Application.Abstractions.Services;
|
||||
using Managing.Application.Backtesting;
|
||||
using Managing.Application.Bots.Base;
|
||||
using Managing.Domain.MoneyManagements;
|
||||
using Managing.Domain.Scenarios;
|
||||
using Moq;
|
||||
using System.Collections;
|
||||
using System.Diagnostics;
|
||||
using Xunit;
|
||||
using static Managing.Common.Enums;
|
||||
|
||||
namespace Managing.Application.Tests
|
||||
{
|
||||
public class BotsTests : BaseTests
|
||||
{
|
||||
private readonly IBotFactory _botFactory;
|
||||
private readonly IBacktester _backtester;
|
||||
private readonly string _reportPath = "D:\\BacktestingReports\\backtesting.csv";
|
||||
private string _analysePath = "D:\\BacktestingReports\\analyse";
|
||||
private readonly string _errorsPath = "D:\\BacktestingReports\\errorsAnalyse.csv";
|
||||
private readonly string _s = "|";
|
||||
private List<double> _elapsedTimes { get; set; }
|
||||
|
||||
public BotsTests() : base ()
|
||||
{
|
||||
var backtestRepository = new Mock<IBacktestRepository>().Object;
|
||||
var discordService = new Mock<IMessengerService>().Object;
|
||||
var tradingBotLogger = TradingBaseTests.CreateTradingBotLogger();
|
||||
var backtestLogger = TradingBaseTests.CreateBacktesterLogger();
|
||||
_botFactory = new BotFactory(
|
||||
_exchangeService,
|
||||
tradingBotLogger,
|
||||
_moneyManagementService.Object,
|
||||
discordService,
|
||||
_accountService.Object,
|
||||
_tradingService.Object);
|
||||
_backtester = new Backtester(_exchangeService, _botFactory, backtestRepository, backtestLogger);
|
||||
_elapsedTimes = new List<double>();
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(Ticker.BTC, Timeframe.OneDay, -100)]
|
||||
public void SwingBot_Should_Return_Positiv_Profit_For_Every_Position(Ticker ticker, Timeframe timeframe, int days)
|
||||
{
|
||||
// Arrange
|
||||
var scenario = new Scenario("ScalpingScenario");
|
||||
var strategy = ScenarioHelpers.BuildStrategy(StrategyType.RsiDivergence, timeframe, "RsiDiv", period: 14);
|
||||
scenario.AddStrategy(strategy);
|
||||
|
||||
// Act
|
||||
var backtestResult = _backtester.RunFlippingBotBacktest(Account, MoneyManagement, ticker, scenario, timeframe, Convert.ToDouble(days*2), 1000);
|
||||
WriteCsvReport(backtestResult.GetStringReport());
|
||||
|
||||
// Assert
|
||||
Assert.True(backtestResult.FinalPnl > 0);
|
||||
Assert.True(backtestResult.WinRate >= 30);
|
||||
Assert.True(backtestResult.GrowthPercentage > backtestResult.HodlPercentage);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
//[InlineData(Enums.Exchanges.Binance, "ADAUSDT", Timeframe.ThirtyMinutes, -5)]
|
||||
//[InlineData(Enums.Exchanges.Binance, "ADAUSDT", Timeframe.FifteenMinutes, -5)]
|
||||
//[InlineData(Enums.Exchanges.Binance, "SOLUSDT", Timeframe.ThirtyMinutes, -4)]
|
||||
//[InlineData(Enums.Exchanges.Binance, "SOLUSDT", Timeframe.FifteenMinutes, -4)]
|
||||
//[InlineData(Enums.Exchanges.Binance, "BTCUSDT", Timeframe.ThirtyMinutes, -4)]
|
||||
//[InlineData(Enums.Exchanges.Binance, "BTCUSDT", Timeframe.FifteenMinutes, -4)]
|
||||
[InlineData(Ticker.BTC, Timeframe.FifteenMinutes, -14)]
|
||||
public void ScalpingBot_Should_Return_Positiv_Profit_For_Every_Position(Ticker ticker, Timeframe timeframe, int days)
|
||||
{
|
||||
// Arrange
|
||||
var scenario = new Scenario("ScalpingScenario");
|
||||
var strategy = ScenarioHelpers.BuildStrategy(StrategyType.RsiDivergence, timeframe, "RsiDiv", period: 5);
|
||||
scenario.AddStrategy(strategy);
|
||||
|
||||
// Act
|
||||
var backtestResult = _backtester.RunScalpingBotBacktest(Account, MoneyManagement, ticker, scenario, timeframe, Convert.ToDouble(days), 1000);
|
||||
//WriteCsvReport(backtestResult.GetStringReport());
|
||||
|
||||
// Assert
|
||||
Assert.True(backtestResult.FinalPnl > 0);
|
||||
Assert.True(backtestResult.WinRate >= 30);
|
||||
Assert.True(backtestResult.GrowthPercentage > backtestResult.HodlPercentage);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(Ticker.BTC, Timeframe.FifteenMinutes, -8)]
|
||||
public void MacdCross_Should_Return_Positiv_Profit_For_Every_Position(Ticker ticker, Timeframe timeframe, int days)
|
||||
{
|
||||
// Arrange
|
||||
var scenario = new Scenario("ScalpingScenario");
|
||||
var strategy = ScenarioHelpers.BuildStrategy(StrategyType.MacdCross, timeframe, "RsiDiv", fastPeriods: 12, slowPeriods: 26, signalPeriods: 9);
|
||||
scenario.AddStrategy(strategy);
|
||||
|
||||
var moneyManagement = new MoneyManagement()
|
||||
{
|
||||
BalanceAtRisk = 0.05m,
|
||||
Leverage = 1,
|
||||
Timeframe = timeframe,
|
||||
StopLoss = 0.01m,
|
||||
TakeProfit = 0.02m
|
||||
};
|
||||
|
||||
// Act
|
||||
var backtestResult = _backtester.RunScalpingBotBacktest(Account, moneyManagement, ticker, scenario, timeframe, Convert.ToDouble(days), 1000);
|
||||
WriteCsvReport(backtestResult.GetStringReport());
|
||||
|
||||
// Assert
|
||||
Assert.True(backtestResult.FinalPnl > 0);
|
||||
Assert.True(backtestResult.WinRate >= 30);
|
||||
Assert.True(backtestResult.GrowthPercentage > backtestResult.HodlPercentage);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(Timeframe.FifteenMinutes, -6, StrategyType.RsiDivergenceConfirm, BotType.ScalpingBot)]
|
||||
//[InlineData(Timeframe.FifteenMinutes, -6, Enums.StrategyType.RsiDivergenceConfirm, Enums.BotType.FlippingBot)]
|
||||
public void GetBestPeriodRsiForDivergenceFlippingBot(Timeframe timeframe, int days, StrategyType strategyType, BotType botType)
|
||||
{
|
||||
var result = new List<Tuple<string, int, decimal, decimal, decimal, decimal>>();
|
||||
var errors = new List<string>();
|
||||
var options = new ParallelOptions()
|
||||
{
|
||||
MaxDegreeOfParallelism = 4
|
||||
};
|
||||
|
||||
var periodRange = new List<int>() { 2, 7};
|
||||
var stopLossRange = new List<decimal>() { 0.005m, 0.05m, 0.005m };
|
||||
var takeProfitRange = new List<decimal>() { 0.01m, 0.1m, 0.02m };
|
||||
var fileIdentifier = $"{strategyType}-{timeframe}";
|
||||
var completedTest = 0;
|
||||
var totalTests = GetTotalTrades(periodRange, stopLossRange, takeProfitRange) * Enum.GetNames(typeof(Ticker)).Length;
|
||||
|
||||
CleanAnalyseFile(fileIdentifier);
|
||||
UpdateProgression(totalTests, completedTest);
|
||||
|
||||
Parallel.ForEach((Ticker[])Enum.GetValues(typeof(Ticker)), options, ticker => {
|
||||
|
||||
var candles = _exchangeService.GetCandles(Account, ticker, DateTime.Now.AddDays(Convert.ToDouble(days)), timeframe).Result;
|
||||
|
||||
if (candles == null || candles.Count == 0)
|
||||
return;
|
||||
|
||||
Parallel.For(periodRange[0], periodRange[1], options, i => {
|
||||
var scenario = new Scenario("ScalpingScenario");
|
||||
var strategy = ScenarioHelpers.BuildStrategy(strategyType, timeframe, "RsiDiv", period: i);
|
||||
scenario.AddStrategy(strategy);
|
||||
|
||||
// -0.5 to -5
|
||||
for (decimal s = stopLossRange[0]; s < stopLossRange[1]; s += stopLossRange[2])
|
||||
{
|
||||
// +1% to +10% in 1%
|
||||
for(decimal t = takeProfitRange[0]; t < takeProfitRange[1]; t += takeProfitRange[2])
|
||||
{
|
||||
var moneyManagement = new MoneyManagement()
|
||||
{
|
||||
BalanceAtRisk = 0.05m,
|
||||
Leverage = 1,
|
||||
Timeframe = timeframe,
|
||||
StopLoss = s,
|
||||
TakeProfit = t
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
var timer = new Stopwatch();
|
||||
timer.Start();
|
||||
|
||||
var backtestResult = botType switch
|
||||
{
|
||||
BotType.SimpleBot => throw new NotImplementedException(),
|
||||
BotType.ScalpingBot => _backtester.RunScalpingBotBacktest(Account, moneyManagement, scenario, timeframe, candles, 1000),
|
||||
BotType.FlippingBot => _backtester.RunFlippingBotBacktest(Account, moneyManagement, scenario, timeframe, candles, 1000),
|
||||
_ => throw new NotImplementedException(),
|
||||
};
|
||||
timer.Stop();
|
||||
|
||||
if (backtestResult.FinalPnl > 0
|
||||
&& (backtestResult.GrowthPercentage - backtestResult.HodlPercentage) > 30
|
||||
&& backtestResult.Statistics.MaxDrawdown < 3)
|
||||
{
|
||||
var currentResult = new Tuple<string, int, decimal, decimal, decimal, decimal>(ticker.ToString(), i,
|
||||
backtestResult.FinalPnl, s, t, backtestResult.GrowthPercentage - backtestResult.HodlPercentage);
|
||||
result.Add(currentResult);
|
||||
}
|
||||
|
||||
completedTest++;
|
||||
UpdateProgression(totalTests, completedTest, timer.Elapsed.TotalSeconds);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
completedTest++;
|
||||
errors.Add($"{ticker}{_s}{i}{_s}{s}{_s}{t}{_s}{ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
foreach (var r in result)
|
||||
{
|
||||
WriteCsvAnalyse($"{r.Item1}{_s}{r.Item2}{_s}{r.Item3.ToString("0.000")}{_s}{r.Item4 * 100}{_s}{r.Item5 * 100}{_s}{r.Item6}");
|
||||
}
|
||||
|
||||
foreach (var e in errors)
|
||||
{
|
||||
WriteCsvErrors(e);
|
||||
}
|
||||
|
||||
var bestResult = result.OrderByDescending(b => b.Item3).FirstOrDefault();
|
||||
WriteCsvAnalyse($"Best result : {bestResult.Item1} - Rsi Period : {bestResult.Item2} - {bestResult.Item3} - SL : {bestResult.Item4}% - TP : {bestResult.Item5}%");
|
||||
|
||||
Assert.True(result.Any());
|
||||
}
|
||||
|
||||
|
||||
[Theory]
|
||||
[InlineData(Timeframe.OneHour, -30, StrategyType.MacdCross, BotType.FlippingBot)]
|
||||
[InlineData(Timeframe.OneHour, -30, StrategyType.MacdCross, BotType.ScalpingBot)]
|
||||
public void GetBestMMForMacdFlippingBot(Timeframe timeframe, int days, StrategyType strategyType, BotType botType)
|
||||
{
|
||||
var result = new List<Tuple<string, decimal, decimal, decimal, decimal>>();
|
||||
var errors = new List<string>();
|
||||
var options = new ParallelOptions()
|
||||
{
|
||||
MaxDegreeOfParallelism = 4
|
||||
};
|
||||
|
||||
var stopLossRange = new List<decimal>() { 0.005m, 0.05m, 0.005m };
|
||||
var takeProfitRange = new List<decimal>() { 0.01m, 0.1m, 0.02m };
|
||||
var fileIdentifier = $"{strategyType}-{timeframe}-{botType}";
|
||||
var completedTest = 0;
|
||||
var totalTests = GetTotalTradeForStopLossTakeProfit(stopLossRange, takeProfitRange) * Enum.GetNames(typeof(Ticker)).Length;
|
||||
|
||||
CleanAnalyseFile(fileIdentifier);
|
||||
UpdateProgression(totalTests, completedTest);
|
||||
|
||||
Parallel.ForEach((Ticker[])Enum.GetValues(typeof(Ticker)), options, ticker => {
|
||||
|
||||
var candles = _exchangeService.GetCandles(Account, ticker, DateTime.Now.AddDays(Convert.ToDouble(days)), timeframe).Result;
|
||||
|
||||
if (candles == null || candles.Count == 0)
|
||||
return;
|
||||
|
||||
var scenario = new Scenario("ScalpingScenario");
|
||||
var strategy = ScenarioHelpers.BuildStrategy(strategyType, timeframe, "RsiDiv", fastPeriods: 12, slowPeriods: 26, signalPeriods: 9);
|
||||
scenario.AddStrategy(strategy);
|
||||
|
||||
// -0.5 to -5
|
||||
for (decimal s = stopLossRange[0]; s < stopLossRange[1]; s += stopLossRange[2])
|
||||
{
|
||||
// +1% to +10% in 1%
|
||||
for (decimal t = takeProfitRange[0]; t < takeProfitRange[1]; t += takeProfitRange[2])
|
||||
{
|
||||
var timer = new Stopwatch();
|
||||
timer.Start();
|
||||
try
|
||||
{
|
||||
var moneyManagement = new MoneyManagement()
|
||||
{
|
||||
BalanceAtRisk = 0.05m,
|
||||
Leverage = 1,
|
||||
Timeframe = timeframe,
|
||||
StopLoss = s,
|
||||
TakeProfit = t
|
||||
};
|
||||
|
||||
var backtestResult = botType switch
|
||||
{
|
||||
BotType.SimpleBot => throw new NotImplementedException(),
|
||||
BotType.ScalpingBot => _backtester.RunScalpingBotBacktest(Account, moneyManagement, scenario, timeframe, candles, 1000),
|
||||
BotType.FlippingBot => _backtester.RunFlippingBotBacktest(Account, moneyManagement, scenario, timeframe, candles, 1000),
|
||||
_ => throw new NotImplementedException(),
|
||||
};
|
||||
|
||||
if (backtestResult.FinalPnl > 0
|
||||
&& (backtestResult.GrowthPercentage - backtestResult.HodlPercentage) > 30
|
||||
&& backtestResult.Statistics.MaxDrawdown < 3)
|
||||
{
|
||||
var currentResult = new Tuple<string, decimal, decimal, decimal, decimal>(ticker.ToString(),
|
||||
backtestResult.FinalPnl, s, t, backtestResult.GrowthPercentage - backtestResult.HodlPercentage);
|
||||
result.Add(currentResult);
|
||||
}
|
||||
|
||||
completedTest++;
|
||||
UpdateProgression(totalTests, completedTest, timer.Elapsed.TotalSeconds);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
completedTest++;
|
||||
errors.Add($"{ticker}{_s}{s}{_s}{t}{_s}{ex.Message}");
|
||||
}
|
||||
timer.Stop();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
foreach (var r in result)
|
||||
{
|
||||
WriteCsvAnalyse($"{r.Item1}{_s}{r.Item2.ToString("0.000")}{_s}{r.Item3 * 100}{_s}{r.Item4 * 100}{_s}{r.Item5}");
|
||||
}
|
||||
|
||||
foreach (var e in errors)
|
||||
{
|
||||
WriteCsvErrors(e);
|
||||
}
|
||||
|
||||
var bestResult = result.OrderByDescending(b => b.Item3).FirstOrDefault();
|
||||
WriteCsvAnalyse($"Best result : {bestResult.Item1} - Rsi Period : {bestResult.Item2} - {bestResult.Item3} - SL : {bestResult.Item4}% - TP : {bestResult.Item5}%");
|
||||
|
||||
Assert.True(result.Any());
|
||||
}
|
||||
|
||||
|
||||
private void WriteCsvReport(string line)
|
||||
{
|
||||
File.AppendAllLines(_reportPath, new[] { line });
|
||||
}
|
||||
|
||||
private void WriteCsvAnalyse(string line, string fileIdentifier = null)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(fileIdentifier))
|
||||
_analysePath += $"-{fileIdentifier}-{DateTime.Now.ToString("dd-MM-HH-mm")}.csv";
|
||||
|
||||
File.AppendAllLines(_analysePath , new[] { line });
|
||||
}
|
||||
|
||||
private void WriteCsvErrors(string line)
|
||||
{
|
||||
File.AppendAllLines(_errorsPath, new[] { line });
|
||||
}
|
||||
|
||||
private void CleanAnalyseFile(string fileIdentifier)
|
||||
{
|
||||
WriteCsvAnalyse("", fileIdentifier);
|
||||
}
|
||||
|
||||
private decimal GetTotalTrades(List<int> periodRange, List<decimal> stopLossRange, List<decimal> takeProfitRange)
|
||||
{
|
||||
var stopLossRangeTotalTest = stopLossRange[1] / stopLossRange[2];
|
||||
var takeProfitRangeTotalTest = takeProfitRange[1] / takeProfitRange[2];
|
||||
|
||||
var totalTrades = GetTotalTradeForStopLossTakeProfit(stopLossRange, takeProfitRange) * stopLossRangeTotalTest * takeProfitRangeTotalTest;
|
||||
return totalTrades;
|
||||
}
|
||||
|
||||
private decimal GetTotalTradeForStopLossTakeProfit(List<decimal> stopLossRange, List<decimal> takeProfitRange)
|
||||
{
|
||||
var stopLossRangeTotalTest = stopLossRange[1] / stopLossRange[2];
|
||||
var takeProfitRangeTotalTest = takeProfitRange[1] / takeProfitRange[2];
|
||||
|
||||
var totalTrades = stopLossRangeTotalTest * takeProfitRangeTotalTest;
|
||||
return totalTrades;
|
||||
}
|
||||
|
||||
|
||||
private void UpdateProgression(decimal totalTest, int completedTest, double? elapsed = null)
|
||||
{
|
||||
var timeRemaining = "";
|
||||
if (elapsed.HasValue && completedTest > 0)
|
||||
{
|
||||
//_elapsedTimes.Add((elapsed.Value / completedTest) * ((double)totalTest - completedTest));
|
||||
_elapsedTimes.Add(elapsed.Value);
|
||||
//var t = (_elapsedTimes.Average() / completedTest) * ((double)totalTest - completedTest);
|
||||
var t = (_elapsedTimes.Average() * (double)(totalTest - completedTest));
|
||||
timeRemaining = $" Remaining time: {t} seconds - Estimated end date: {DateTime.Now.AddSeconds(t)}";
|
||||
}
|
||||
|
||||
ModifyFirstRow(_analysePath, $"{completedTest}/{totalTest}{timeRemaining}");
|
||||
}
|
||||
|
||||
private void ModifyFirstRow(string filepath, string newValue)
|
||||
{
|
||||
ArrayList rows = new ArrayList();
|
||||
|
||||
using (StreamReader reader = new StreamReader(filepath))
|
||||
{
|
||||
string row = null;
|
||||
|
||||
while ((row = reader.ReadLine()) != null)
|
||||
{
|
||||
rows.Add(row);
|
||||
}
|
||||
}
|
||||
|
||||
// Determ if the file even contains rows.
|
||||
if (rows.Count > 0)
|
||||
{
|
||||
// Replace the first row.
|
||||
rows[0] = newValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Add the new value because there
|
||||
// where no rows found in the file.
|
||||
rows.Add(newValue);
|
||||
}
|
||||
|
||||
// Write the modified content to the file.
|
||||
using (StreamWriter writer = new StreamWriter(filepath, false))
|
||||
{
|
||||
foreach (String row in rows)
|
||||
{
|
||||
writer.WriteLine(row);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user