Add test for executor

This commit is contained in:
2025-11-11 02:15:57 +07:00
parent d02a07f86b
commit e8e2ec5a43
18 changed files with 81418 additions and 170 deletions

View File

@@ -0,0 +1,180 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Managing.Application.Abstractions;
using Managing.Application.Abstractions.Repositories;
using Managing.Application.Abstractions.Services;
using Managing.Application.Backtests;
using Managing.Application.Bots;
using Managing.Application.Tests;
using Managing.Core;
using Managing.Domain.Accounts;
using Managing.Domain.Backtests;
using Managing.Domain.Bots;
using Managing.Domain.Candles;
using Managing.Domain.Scenarios;
using Managing.Domain.Strategies;
using Managing.Domain.Users;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Moq;
using Newtonsoft.Json;
using Xunit;
using static Managing.Common.Enums;
namespace Managing.Workers.Tests;
public class BacktestExecutorTests : BaseTests
{
private readonly BacktestExecutor _backtestExecutor;
private readonly Mock<IServiceScopeFactory> _scopeFactory;
private readonly Mock<IBacktestRepository> _backtestRepository;
private readonly Mock<IScenarioService> _scenarioService;
private readonly Mock<IMessengerService> _messengerService;
private readonly User _testUser;
public BacktestExecutorTests() : base()
{
// Setup mock dependencies
_backtestRepository = new Mock<IBacktestRepository>();
_scenarioService = new Mock<IScenarioService>();
_messengerService = new Mock<IMessengerService>();
// Setup service scope factory
_scopeFactory = new Mock<IServiceScopeFactory>();
var mockScope = new Mock<IServiceScope>();
var mockServiceProvider = new Mock<IServiceProvider>();
// Setup TradingBotBase logger
var tradingBotLogger = TradingBaseTests.CreateTradingBotLogger();
mockServiceProvider.Setup(x => x.GetService(typeof(ILogger<TradingBotBase>)))
.Returns(tradingBotLogger);
// Setup all services that TradingBotBase might need
mockServiceProvider.Setup(x => x.GetService(typeof(IExchangeService)))
.Returns(_exchangeService);
mockServiceProvider.Setup(x => x.GetService(typeof(IAccountService)))
.Returns(_accountService.Object);
mockServiceProvider.Setup(x => x.GetService(typeof(ITradingService)))
.Returns(_tradingService.Object);
mockServiceProvider.Setup(x => x.GetService(typeof(IMoneyManagementService)))
.Returns(_moneyManagementService.Object);
mockServiceProvider.Setup(x => x.GetService(typeof(IBotService)))
.Returns(new Mock<IBotService>().Object);
mockServiceProvider.Setup(x => x.GetService(typeof(IMessengerService)))
.Returns(_messengerService.Object);
mockScope.Setup(x => x.ServiceProvider).Returns(mockServiceProvider.Object);
_scopeFactory.Setup(x => x.CreateScope()).Returns(mockScope.Object);
// Create test user with account
_testUser = new User
{
Id = 1,
Name = "Test User",
Accounts = new List<Account> { _account }
};
// Create BacktestExecutor instance
var logger = new Mock<ILogger<BacktestExecutor>>().Object;
_backtestExecutor = new BacktestExecutor(
logger,
_scopeFactory.Object,
_backtestRepository.Object,
_scenarioService.Object,
_accountService.Object,
_messengerService.Object);
}
[Fact]
public async Task ExecuteBacktest_With_ETH_FifteenMinutes_Data_Should_Return_LightBacktest()
{
// Arrange
var candles = FileHelpers.ReadJson<List<Candle>>("Data/ETH-FifteenMinutes-candles.json");
Assert.NotNull(candles);
Assert.NotEmpty(candles);
var scenario = new Scenario("ETH_BacktestScenario");
var rsiDivIndicator = ScenarioHelpers.BuildIndicator(IndicatorType.RsiDivergence, "RsiDiv", period: 14);
scenario.Indicators = new List<IndicatorBase> { (IndicatorBase)rsiDivIndicator };
scenario.LoopbackPeriod = 15;
var config = new TradingBotConfig
{
AccountName = _account.Name,
MoneyManagement = MoneyManagement,
Ticker = Ticker.ETH,
Scenario = LightScenario.FromScenario(scenario),
Timeframe = Timeframe.FifteenMinutes,
IsForWatchingOnly = false,
BotTradingBalance = 1000,
IsForBacktest = true,
CooldownPeriod = 1,
MaxLossStreak = 0,
FlipPosition = false,
Name = "ETH_FifteenMinutes_Test",
FlipOnlyWhenInProfit = true,
MaxPositionTimeHours = null,
CloseEarlyWhenProfitable = false
};
// Act
var result = await _backtestExecutor.ExecuteAsync(
config,
candles.ToHashSet(),
_testUser,
save: false,
withCandles: false,
requestId: null,
bundleRequestId: null,
metadata: null,
progressCallback: null);
// Output the result to console for review
var json = JsonConvert.SerializeObject(new
{
result.FinalPnl,
result.WinRate,
result.GrowthPercentage,
result.HodlPercentage,
result.Fees,
result.NetPnl,
result.MaxDrawdown,
result.SharpeRatio,
result.Score,
result.InitialBalance,
StartDate = result.StartDate.ToString("yyyy-MM-dd HH:mm:ss"),
EndDate = result.EndDate.ToString("yyyy-MM-dd HH:mm:ss")
}, Formatting.Indented);
Console.WriteLine("BacktestExecutor Results:");
Console.WriteLine(json);
// Assert - Validate specific backtest results
Assert.NotNull(result);
Assert.IsType<LightBacktest>(result);
// Validate key metrics
Assert.Equal(1000.0m, result.InitialBalance);
Assert.Equal(-59.882047336208884979534923000m, result.FinalPnl);
Assert.Equal(31, result.WinRate);
Assert.Equal(-5.9882047336208884979534923m, result.GrowthPercentage);
Assert.Equal(-0.67091284426766023865867781m, result.HodlPercentage);
Assert.Equal(56.951749553070862317498561018m, result.Fees);
Assert.Equal(-116.83379688927974729703348402m, result.NetPnl);
Assert.Equal(109.9278709774429014669107321m, result.MaxDrawdown);
Assert.Equal((double?)-0.014233294246603566m, result.SharpeRatio);
Assert.Equal((double)0.0m, result.Score);
// Validate dates
Assert.Equal(new DateTime(2025, 10, 14, 12, 0, 0), result.StartDate);
Assert.Equal(new DateTime(2025, 10, 24, 11, 45, 0), result.EndDate);
Assert.True(result.StartDate < result.EndDate);
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,29 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>disable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<None Update="Data\ETH-FifteenMinutes-candles.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Managing.Application.Tests\Managing.Application.Tests.csproj"/>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0"/>
<PackageReference Include="Moq" Version="4.20.72"/>
<PackageReference Include="xunit" Version="2.8.0"/>
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
</Project>