GMX v2 - Trading (#7)

* Move PrivateKeys.cs

* Update gitignore

* Update gitignore

* updt

* Extract GmxServiceTests.cs

* Refact

* update todo

* Update code

* Fix hashdata

* Replace static token hashed datas

* Set allowance

* Add get orders

* Add get orders tests

* Add ignore

* add close orders

* revert

* Add get gas limit

* Start increasePosition. Todo: Finish GetExecutionFee and estimateGas

* little refact

* Update gitignore

* Fix namespaces and clean repo

* Add tests samples

* Add execution fee

* Add increase position

* Handle backtest on the frontend

* Add tests

* Update increase

* Test increase

* fix increase

* Fix size

* Start get position

* Update get positions

* Fix get position

* Update rpc and trade mappers

* Finish close position

* Fix leverage
This commit is contained in:
Oda
2025-01-30 23:06:22 +07:00
committed by GitHub
parent ecaa89c67b
commit 65bdb8e34f
156 changed files with 11253 additions and 4073 deletions

View File

@@ -1,12 +1,16 @@
using Managing.Application.Abstractions;
using System.Collections;
using System.Diagnostics;
using Managing.Application.Abstractions;
using Managing.Application.Abstractions.Repositories;
using Managing.Application.Abstractions.Services;
using Managing.Application.Backtesting;
using Managing.Application.Bots.Base;
using Managing.Core;
using Managing.Domain.Candles;
using Managing.Domain.MoneyManagements;
using Managing.Domain.Scenarios;
using Moq;
using System.Collections;
using System.Diagnostics;
using Newtonsoft.Json;
using Xunit;
using static Managing.Common.Enums;
@@ -22,7 +26,7 @@ namespace Managing.Application.Tests
private readonly string _s = "|";
private List<double> _elapsedTimes { get; set; }
public BotsTests() : base ()
public BotsTests() : base()
{
var backtestRepository = new Mock<IBacktestRepository>().Object;
var discordService = new Mock<IMessengerService>().Object;
@@ -41,17 +45,24 @@ namespace Managing.Application.Tests
}
[Theory]
[InlineData(Ticker.BTC, Timeframe.OneDay, -100)]
public void SwingBot_Should_Return_Positiv_Profit_For_Every_Position(Ticker ticker, Timeframe timeframe, int days)
[InlineData(Ticker.BTC, Timeframe.FifteenMinutes, -10)]
public void SwingBot_Should_Return_Positiv_Profit_For_Every_Position(Ticker ticker, Timeframe timeframe,
int days)
{
// Arrange
var scenario = new Scenario("ScalpingScenario");
var scenario = new Scenario("FlippingScenario");
var strategy = ScenarioHelpers.BuildStrategy(StrategyType.RsiDivergence, timeframe, "RsiDiv", period: 14);
scenario.AddStrategy(strategy);
var localCandles =
FileHelpers.ReadJson<List<Candle>>($"{ticker.ToString()}-{timeframe.ToString()}-candles.json");
// Act
var backtestResult = _backtester.RunFlippingBotBacktest(Account, MoneyManagement, ticker, scenario, timeframe, Convert.ToDouble(days*2), 1000);
WriteCsvReport(backtestResult.GetStringReport());
var backtestResult = _backtester.RunFlippingBotBacktest(_account, MoneyManagement, ticker, scenario,
timeframe, Convert.ToDouble(days), 1000, initialCandles: localCandles.TakeLast(500).ToList());
var json = JsonConvert.SerializeObject(backtestResult, Formatting.None);
File.WriteAllText($"{ticker.ToString()}-{timeframe.ToString()}-{Guid.NewGuid()}.json", json);
// WriteCsvReport(backtestResult.GetStringReport());
// Assert
Assert.True(backtestResult.FinalPnl > 0);
@@ -67,7 +78,8 @@ namespace Managing.Application.Tests
//[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)
public void ScalpingBot_Should_Return_Positiv_Profit_For_Every_Position(Ticker ticker, Timeframe timeframe,
int days)
{
// Arrange
var scenario = new Scenario("ScalpingScenario");
@@ -75,7 +87,8 @@ namespace Managing.Application.Tests
scenario.AddStrategy(strategy);
// Act
var backtestResult = _backtester.RunScalpingBotBacktest(Account, MoneyManagement, ticker, scenario, timeframe, Convert.ToDouble(days), 1000);
var backtestResult = _backtester.RunScalpingBotBacktest(_account, MoneyManagement, ticker, scenario,
timeframe, Convert.ToDouble(days), 1000);
//WriteCsvReport(backtestResult.GetStringReport());
// Assert
@@ -86,11 +99,13 @@ namespace Managing.Application.Tests
[Theory]
[InlineData(Ticker.BTC, Timeframe.FifteenMinutes, -8)]
public void MacdCross_Should_Return_Positiv_Profit_For_Every_Position(Ticker ticker, Timeframe timeframe, int days)
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);
var strategy = ScenarioHelpers.BuildStrategy(StrategyType.MacdCross, timeframe, "RsiDiv", fastPeriods: 12,
slowPeriods: 26, signalPeriods: 9);
scenario.AddStrategy(strategy);
var moneyManagement = new MoneyManagement()
@@ -103,7 +118,8 @@ namespace Managing.Application.Tests
};
// Act
var backtestResult = _backtester.RunScalpingBotBacktest(Account, moneyManagement, ticker, scenario, timeframe, Convert.ToDouble(days), 1000);
var backtestResult = _backtester.RunScalpingBotBacktest(_account, moneyManagement, ticker, scenario,
timeframe, Convert.ToDouble(days), 1000);
WriteCsvReport(backtestResult.GetStringReport());
// Assert
@@ -115,7 +131,8 @@ namespace Managing.Application.Tests
[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)
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>();
@@ -124,24 +141,27 @@ namespace Managing.Application.Tests
MaxDegreeOfParallelism = 4
};
var periodRange = new List<int>() { 2, 7};
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;
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;
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 => {
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);
@@ -150,7 +170,7 @@ namespace Managing.Application.Tests
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])
for (decimal t = takeProfitRange[0]; t < takeProfitRange[1]; t += takeProfitRange[2])
{
var moneyManagement = new MoneyManagement()
{
@@ -165,25 +185,29 @@ namespace Managing.Application.Tests
{
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),
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
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);
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);
}
@@ -199,7 +223,8 @@ namespace Managing.Application.Tests
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}");
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)
@@ -208,7 +233,8 @@ namespace Managing.Application.Tests
}
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}%");
WriteCsvAnalyse(
$"Best result : {bestResult.Item1} - Rsi Period : {bestResult.Item2} - {bestResult.Item3} - SL : {bestResult.Item4}% - TP : {bestResult.Item5}%");
Assert.True(result.Any());
}
@@ -217,7 +243,8 @@ namespace Managing.Application.Tests
[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)
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>();
@@ -230,20 +257,23 @@ namespace Managing.Application.Tests
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;
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;
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);
var strategy = ScenarioHelpers.BuildStrategy(strategyType, timeframe, "RsiDiv", fastPeriods: 12,
slowPeriods: 26, signalPeriods: 9);
scenario.AddStrategy(strategy);
// -0.5 to -5
@@ -268,8 +298,10 @@ namespace Managing.Application.Tests
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),
BotType.ScalpingBot => _backtester.RunScalpingBotBacktest(_account, moneyManagement,
scenario, timeframe, candles, 1000),
BotType.FlippingBot => _backtester.RunFlippingBotBacktest(_account, moneyManagement,
scenario, timeframe, candles, 1000),
_ => throw new NotImplementedException(),
};
@@ -277,8 +309,10 @@ namespace Managing.Application.Tests
&& (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);
var currentResult = new Tuple<string, decimal, decimal, decimal, decimal>(
ticker.ToString(),
backtestResult.FinalPnl, s, t,
backtestResult.GrowthPercentage - backtestResult.HodlPercentage);
result.Add(currentResult);
}
@@ -290,6 +324,7 @@ namespace Managing.Application.Tests
completedTest++;
errors.Add($"{ticker}{_s}{s}{_s}{t}{_s}{ex.Message}");
}
timer.Stop();
}
}
@@ -297,7 +332,8 @@ namespace Managing.Application.Tests
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}");
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)
@@ -306,7 +342,8 @@ namespace Managing.Application.Tests
}
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}%");
WriteCsvAnalyse(
$"Best result : {bestResult.Item1} - Rsi Period : {bestResult.Item2} - {bestResult.Item3} - SL : {bestResult.Item4}% - TP : {bestResult.Item5}%");
Assert.True(result.Any());
}
@@ -321,8 +358,8 @@ namespace Managing.Application.Tests
{
if (!string.IsNullOrEmpty(fileIdentifier))
_analysePath += $"-{fileIdentifier}-{DateTime.Now.ToString("dd-MM-HH-mm")}.csv";
File.AppendAllLines(_analysePath , new[] { line });
File.AppendAllLines(_analysePath, new[] { line });
}
private void WriteCsvErrors(string line)
@@ -335,12 +372,14 @@ namespace Managing.Application.Tests
WriteCsvAnalyse("", fileIdentifier);
}
private decimal GetTotalTrades(List<int> periodRange, List<decimal> stopLossRange, List<decimal> takeProfitRange)
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;
var totalTrades = GetTotalTradeForStopLossTakeProfit(stopLossRange, takeProfitRange) *
stopLossRangeTotalTest * takeProfitRangeTotalTest;
return totalTrades;
}
@@ -406,4 +445,4 @@ namespace Managing.Application.Tests
}
}
}
}
}