Remove candle from backtest return + fix message when good backtest
This commit is contained in:
@@ -383,8 +383,7 @@ public class BacktestExecutor
|
|||||||
var finalRequestId = requestId != null ? Guid.Parse(requestId) : Guid.NewGuid();
|
var finalRequestId = requestId != null ? Guid.Parse(requestId) : Guid.NewGuid();
|
||||||
|
|
||||||
// Create backtest result with conditional candles and indicators values
|
// Create backtest result with conditional candles and indicators values
|
||||||
var result = new Backtest(config, tradingBot.Positions, tradingBot.Signals,
|
var result = new Backtest(config, tradingBot.Positions, tradingBot.Signals)
|
||||||
withCandles ? candles : new HashSet<Candle>())
|
|
||||||
{
|
{
|
||||||
FinalPnl = realizedPnl, // Realized PnL before fees
|
FinalPnl = realizedPnl, // Realized PnL before fees
|
||||||
WinRate = winRate,
|
WinRate = winRate,
|
||||||
@@ -485,7 +484,9 @@ public class BacktestExecutor
|
|||||||
string.Join(", ", bottlenecks));
|
string.Join(", ", bottlenecks));
|
||||||
}
|
}
|
||||||
|
|
||||||
_logger.LogInformation("🎯 Backtest completed successfully - RequestId: {RequestId} - Score: {Score} - Realized PnL: {RealizedPnl} - Net PnL: {NetPnl} - Fees: {Fees}", finalRequestId, result.Score, result.FinalPnl, result.NetPnl, result.Fees);
|
_logger.LogInformation(
|
||||||
|
"🎯 Backtest completed successfully - RequestId: {RequestId} - Score: {Score} - Realized PnL: {RealizedPnl} - Net PnL: {NetPnl} - Fees: {Fees}",
|
||||||
|
finalRequestId, result.Score, result.FinalPnl, result.NetPnl, result.Fees);
|
||||||
|
|
||||||
// Convert Backtest to LightBacktest
|
// Convert Backtest to LightBacktest
|
||||||
return ConvertToLightBacktest(result);
|
return ConvertToLightBacktest(result);
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ using Managing.Application.Abstractions.Repositories;
|
|||||||
using Managing.Application.Abstractions.Services;
|
using Managing.Application.Abstractions.Services;
|
||||||
using Managing.Application.Abstractions.Shared;
|
using Managing.Application.Abstractions.Shared;
|
||||||
using Managing.Application.Hubs;
|
using Managing.Application.Hubs;
|
||||||
using Managing.Domain.Accounts;
|
|
||||||
using Managing.Domain.Backtests;
|
using Managing.Domain.Backtests;
|
||||||
using Managing.Domain.Bots;
|
using Managing.Domain.Bots;
|
||||||
using Managing.Domain.Candles;
|
using Managing.Domain.Candles;
|
||||||
@@ -136,7 +135,8 @@ namespace Managing.Application.Backtests
|
|||||||
var startDate = candles.Min(c => c.Date);
|
var startDate = candles.Min(c => c.Date);
|
||||||
var endDate = candles.Max(c => c.Date);
|
var endDate = candles.Max(c => c.Date);
|
||||||
|
|
||||||
return await RunTradingBotBacktest(config, startDate, endDate, user, false, withCandles, requestId, metadata);
|
return await RunTradingBotBacktest(config, startDate, endDate, user, false, withCandles, requestId,
|
||||||
|
metadata);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<bool> DeleteBacktestAsync(string id)
|
public async Task<bool> DeleteBacktestAsync(string id)
|
||||||
@@ -215,31 +215,6 @@ namespace Managing.Application.Backtests
|
|||||||
if (backtest == null)
|
if (backtest == null)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
if (backtest.Candles == null || backtest.Candles.Count == 0 || backtest.Candles.Count < 10)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var account = new Account
|
|
||||||
{ Name = backtest.Config.AccountName, Exchange = TradingExchanges.Evm };
|
|
||||||
|
|
||||||
var candles = await _exchangeService.GetCandlesInflux(
|
|
||||||
account.Exchange,
|
|
||||||
backtest.Config.Ticker,
|
|
||||||
backtest.StartDate,
|
|
||||||
backtest.Config.Timeframe,
|
|
||||||
backtest.EndDate);
|
|
||||||
|
|
||||||
if (candles != null && candles.Count > 0)
|
|
||||||
{
|
|
||||||
backtest.Candles = candles;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_logger.LogError(ex, "Failed to retrieve candles for backtest {Id}", id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return backtest;
|
return backtest;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -348,12 +323,12 @@ namespace Managing.Application.Backtests
|
|||||||
{
|
{
|
||||||
// Generate backtest requests from variants (same logic as BundleBacktestGrain)
|
// Generate backtest requests from variants (same logic as BundleBacktestGrain)
|
||||||
var backtestRequests = await GenerateBacktestRequestsFromVariants(bundleRequest);
|
var backtestRequests = await GenerateBacktestRequestsFromVariants(bundleRequest);
|
||||||
|
|
||||||
if (backtestRequests != null && backtestRequests.Any())
|
if (backtestRequests != null && backtestRequests.Any())
|
||||||
{
|
{
|
||||||
// Create jobs for all variants
|
// Create jobs for all variants
|
||||||
await _jobService.CreateBundleJobsAsync(bundleRequest, backtestRequests);
|
await _jobService.CreateBundleJobsAsync(bundleRequest, backtestRequests);
|
||||||
|
|
||||||
_logger.LogInformation(
|
_logger.LogInformation(
|
||||||
"Created {JobCount} backtest jobs for bundle request {BundleRequestId}",
|
"Created {JobCount} backtest jobs for bundle request {BundleRequestId}",
|
||||||
backtestRequests.Count, bundleRequest.RequestId);
|
backtestRequests.Count, bundleRequest.RequestId);
|
||||||
@@ -380,12 +355,12 @@ namespace Managing.Application.Backtests
|
|||||||
{
|
{
|
||||||
// Generate backtest requests from variants
|
// Generate backtest requests from variants
|
||||||
var backtestRequests = await GenerateBacktestRequestsFromVariants(bundleRequest);
|
var backtestRequests = await GenerateBacktestRequestsFromVariants(bundleRequest);
|
||||||
|
|
||||||
if (backtestRequests != null && backtestRequests.Any())
|
if (backtestRequests != null && backtestRequests.Any())
|
||||||
{
|
{
|
||||||
// Create jobs for all variants
|
// Create jobs for all variants
|
||||||
await _jobService.CreateBundleJobsAsync(bundleRequest, backtestRequests);
|
await _jobService.CreateBundleJobsAsync(bundleRequest, backtestRequests);
|
||||||
|
|
||||||
_logger.LogInformation(
|
_logger.LogInformation(
|
||||||
"Created {JobCount} backtest jobs for bundle request {BundleRequestId}",
|
"Created {JobCount} backtest jobs for bundle request {BundleRequestId}",
|
||||||
backtestRequests.Count, bundleRequest.RequestId);
|
backtestRequests.Count, bundleRequest.RequestId);
|
||||||
@@ -399,8 +374,8 @@ namespace Managing.Application.Backtests
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
_logger.LogError(ex,
|
_logger.LogError(ex,
|
||||||
"Error creating jobs for bundle request {BundleRequestId}",
|
"Error creating jobs for bundle request {BundleRequestId}",
|
||||||
bundleRequest.RequestId);
|
bundleRequest.RequestId);
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
@@ -431,7 +406,9 @@ namespace Managing.Application.Backtests
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get the first account for the user
|
// Get the first account for the user
|
||||||
var accounts = await _accountService.GetAccountsByUserAsync(bundleRequest.User, hideSecrets: true, getBalance: false);
|
var accounts =
|
||||||
|
await _accountService.GetAccountsByUserAsync(bundleRequest.User, hideSecrets: true,
|
||||||
|
getBalance: false);
|
||||||
var firstAccount = accounts.FirstOrDefault();
|
var firstAccount = accounts.FirstOrDefault();
|
||||||
|
|
||||||
if (firstAccount == null)
|
if (firstAccount == null)
|
||||||
@@ -573,15 +550,17 @@ namespace Managing.Application.Backtests
|
|||||||
return (bundleRequests, totalCount);
|
return (bundleRequests, totalCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<(IEnumerable<BundleBacktestRequest> BundleRequests, int TotalCount)> GetBundleBacktestRequestsPaginatedAsync(
|
public async Task<(IEnumerable<BundleBacktestRequest> BundleRequests, int TotalCount)>
|
||||||
int page,
|
GetBundleBacktestRequestsPaginatedAsync(
|
||||||
int pageSize,
|
int page,
|
||||||
BundleBacktestRequestSortableColumn sortBy = BundleBacktestRequestSortableColumn.CreatedAt,
|
int pageSize,
|
||||||
string sortOrder = "desc",
|
BundleBacktestRequestSortableColumn sortBy = BundleBacktestRequestSortableColumn.CreatedAt,
|
||||||
BundleBacktestRequestsFilter? filter = null)
|
string sortOrder = "desc",
|
||||||
|
BundleBacktestRequestsFilter? filter = null)
|
||||||
{
|
{
|
||||||
var (bundleRequests, totalCount) =
|
var (bundleRequests, totalCount) =
|
||||||
await _backtestRepository.GetBundleBacktestRequestsPaginatedAsync(page, pageSize, sortBy, sortOrder, filter);
|
await _backtestRepository.GetBundleBacktestRequestsPaginatedAsync(page, pageSize, sortBy, sortOrder,
|
||||||
|
filter);
|
||||||
return (bundleRequests, totalCount);
|
return (bundleRequests, totalCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ public class BacktestTradingBotGrain : Grain, IBacktestTradingBotGrain
|
|||||||
var lastYieldTime = DateTime.UtcNow;
|
var lastYieldTime = DateTime.UtcNow;
|
||||||
const int yieldIntervalMs = 5000; // Yield control every 5 seconds to prevent timeout
|
const int yieldIntervalMs = 5000; // Yield control every 5 seconds to prevent timeout
|
||||||
const int candlesPerBatch = 100; // Process in batches to allow Orleans to check for cancellation
|
const int candlesPerBatch = 100; // Process in batches to allow Orleans to check for cancellation
|
||||||
|
|
||||||
// Process all candles following the exact pattern from GetBacktestingResult
|
// Process all candles following the exact pattern from GetBacktestingResult
|
||||||
foreach (var candle in candles)
|
foreach (var candle in candles)
|
||||||
{
|
{
|
||||||
@@ -164,8 +164,7 @@ public class BacktestTradingBotGrain : Grain, IBacktestTradingBotGrain
|
|||||||
var finalRequestId = requestId != null ? Guid.Parse(requestId) : Guid.NewGuid();
|
var finalRequestId = requestId != null ? Guid.Parse(requestId) : Guid.NewGuid();
|
||||||
|
|
||||||
// Create backtest result with conditional candles and indicators values
|
// Create backtest result with conditional candles and indicators values
|
||||||
var result = new Backtest(config, tradingBot.Positions, tradingBot.Signals,
|
var result = new Backtest(config, tradingBot.Positions, tradingBot.Signals)
|
||||||
withCandles ? candles : new HashSet<Candle>())
|
|
||||||
{
|
{
|
||||||
FinalPnl = finalPnl,
|
FinalPnl = finalPnl,
|
||||||
WinRate = winRate,
|
WinRate = winRate,
|
||||||
|
|||||||
@@ -257,7 +257,7 @@ public class MessengerService : IMessengerService
|
|||||||
var score = backtest.Score;
|
var score = backtest.Score;
|
||||||
var winRate = backtest.WinRate;
|
var winRate = backtest.WinRate;
|
||||||
var tradeCount = backtest.Positions?.Count ?? 0;
|
var tradeCount = backtest.Positions?.Count ?? 0;
|
||||||
var finalPnl = backtest.FinalPnl;
|
var netPnl = backtest.NetPnl;
|
||||||
var growthPercentage = backtest.GrowthPercentage;
|
var growthPercentage = backtest.GrowthPercentage;
|
||||||
var maxDrawdown = backtest.Statistics?.MaxDrawdown ?? 0;
|
var maxDrawdown = backtest.Statistics?.MaxDrawdown ?? 0;
|
||||||
var sharpeRatio = (backtest.Statistics?.SharpeRatio * 100) ?? 0;
|
var sharpeRatio = (backtest.Statistics?.SharpeRatio * 100) ?? 0;
|
||||||
@@ -288,8 +288,8 @@ public class MessengerService : IMessengerService
|
|||||||
$"🔍 Score Analysis: {backtest.ScoreMessage}\n" +
|
$"🔍 Score Analysis: {backtest.ScoreMessage}\n" +
|
||||||
$"🏆 Win Rate: {winRate:F1}%\n" +
|
$"🏆 Win Rate: {winRate:F1}%\n" +
|
||||||
$"📊 Total Trades: {tradeCount}\n" +
|
$"📊 Total Trades: {tradeCount}\n" +
|
||||||
$"💰 Final PnL: ${finalPnl:F2}\n" +
|
$"💰 Net PnL: ${netPnl:F2}\n" +
|
||||||
$"📈 Growth: {growthPercentage:F1}%\n" +
|
$"📈 ROI: {growthPercentage:F1}%\n" +
|
||||||
$"📉 Max Drawdown: ${maxDrawdown:N}\n" +
|
$"📉 Max Drawdown: ${maxDrawdown:N}\n" +
|
||||||
$"📊 Sharpe Ratio: {sharpeRatio:F2}\n\n" +
|
$"📊 Sharpe Ratio: {sharpeRatio:F2}\n\n" +
|
||||||
$"🆔 Backtest ID: {backtest.Id}";
|
$"🆔 Backtest ID: {backtest.Id}";
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using Exilion.TradingAtomics;
|
using Exilion.TradingAtomics;
|
||||||
using Managing.Domain.Bots;
|
using Managing.Domain.Bots;
|
||||||
using Managing.Domain.Candles;
|
|
||||||
using Managing.Domain.Indicators;
|
using Managing.Domain.Indicators;
|
||||||
using Managing.Domain.Trades;
|
using Managing.Domain.Trades;
|
||||||
using Managing.Domain.Users;
|
using Managing.Domain.Users;
|
||||||
@@ -14,26 +13,12 @@ public class Backtest
|
|||||||
public Backtest(
|
public Backtest(
|
||||||
TradingBotConfig config,
|
TradingBotConfig config,
|
||||||
Dictionary<Guid, Position> positions,
|
Dictionary<Guid, Position> positions,
|
||||||
Dictionary<string, LightSignal> signals,
|
Dictionary<string, LightSignal> signals)
|
||||||
HashSet<Candle> candles = null)
|
|
||||||
{
|
{
|
||||||
Config = config;
|
Config = config;
|
||||||
Positions = positions;
|
Positions = positions;
|
||||||
Signals = signals;
|
Signals = signals;
|
||||||
Candles = candles != null ? candles : new HashSet<Candle>();
|
|
||||||
WalletBalances = new List<KeyValuePair<DateTime, decimal>>();
|
WalletBalances = new List<KeyValuePair<DateTime, decimal>>();
|
||||||
|
|
||||||
// Initialize start and end dates if candles are provided
|
|
||||||
if (candles != null && candles.Count > 0)
|
|
||||||
{
|
|
||||||
StartDate = candles.Min(c => c.Date);
|
|
||||||
EndDate = candles.Max(c => c.Date);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
StartDate = DateTime.UtcNow.AddDays(-30);
|
|
||||||
EndDate = DateTime.UtcNow;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Required] public string Id { get; set; }
|
[Required] public string Id { get; set; }
|
||||||
@@ -44,7 +29,6 @@ public class Backtest
|
|||||||
[Required] public TradingBotConfig Config { get; }
|
[Required] public TradingBotConfig Config { get; }
|
||||||
[Required] public Dictionary<Guid, Position> Positions { get; }
|
[Required] public Dictionary<Guid, Position> Positions { get; }
|
||||||
[Required] public Dictionary<string, LightSignal> Signals { get; }
|
[Required] public Dictionary<string, LightSignal> Signals { get; }
|
||||||
[Required] public HashSet<Candle> Candles { get; set; }
|
|
||||||
[Required] public DateTime StartDate { get; set; }
|
[Required] public DateTime StartDate { get; set; }
|
||||||
[Required] public DateTime EndDate { get; set; }
|
[Required] public DateTime EndDate { get; set; }
|
||||||
[Required] public PerformanceMetrics Statistics { get; set; }
|
[Required] public PerformanceMetrics Statistics { get; set; }
|
||||||
|
|||||||
@@ -4736,7 +4736,6 @@ export interface Backtest {
|
|||||||
config: TradingBotConfig;
|
config: TradingBotConfig;
|
||||||
positions: { [key: string]: Position; };
|
positions: { [key: string]: Position; };
|
||||||
signals: { [key: string]: LightSignal; };
|
signals: { [key: string]: LightSignal; };
|
||||||
candles: Candle[];
|
|
||||||
startDate: Date;
|
startDate: Date;
|
||||||
endDate: Date;
|
endDate: Date;
|
||||||
statistics: PerformanceMetrics;
|
statistics: PerformanceMetrics;
|
||||||
|
|||||||
@@ -298,7 +298,6 @@ export interface Backtest {
|
|||||||
config: TradingBotConfig;
|
config: TradingBotConfig;
|
||||||
positions: { [key: string]: Position; };
|
positions: { [key: string]: Position; };
|
||||||
signals: { [key: string]: LightSignal; };
|
signals: { [key: string]: LightSignal; };
|
||||||
candles: Candle[];
|
|
||||||
startDate: Date;
|
startDate: Date;
|
||||||
endDate: Date;
|
endDate: Date;
|
||||||
statistics: PerformanceMetrics;
|
statistics: PerformanceMetrics;
|
||||||
|
|||||||
Reference in New Issue
Block a user