Add netpnl and initialBalance to backtests

This commit is contained in:
2025-10-16 17:19:22 +07:00
parent 661f91f537
commit 472c507801
9 changed files with 50 additions and 10 deletions

View File

@@ -301,7 +301,9 @@ public class BacktestController : BaseController
Fees = b.Fees,
SharpeRatio = b.SharpeRatio,
Score = b.Score,
ScoreMessage = b.ScoreMessage
ScoreMessage = b.ScoreMessage,
InitialBalance = b.InitialBalance,
NetPnl = b.NetPnl
}),
TotalCount = totalCount,
CurrentPage = page,
@@ -435,7 +437,9 @@ public class BacktestController : BaseController
Fees = b.Fees,
SharpeRatio = b.SharpeRatio,
Score = b.Score,
ScoreMessage = b.ScoreMessage
ScoreMessage = b.ScoreMessage,
InitialBalance = b.InitialBalance,
NetPnl = b.NetPnl
}),
TotalCount = totalCount,
CurrentPage = page,

View File

@@ -20,6 +20,8 @@ public class LightBacktestResponse
[Required] public double? SharpeRatio { get; set; }
[Required] public double Score { get; set; }
[Required] public string ScoreMessage { get; set; } = string.Empty;
[Required] public decimal InitialBalance { get; set; }
[Required] public decimal NetPnl { get; set; }
}
public static class LightBacktestResponseMapper
@@ -41,7 +43,9 @@ public static class LightBacktestResponseMapper
Fees = b.Fees,
SharpeRatio = (double?)b.Statistics?.SharpeRatio,
Score = b.Score,
ScoreMessage = b.ScoreMessage
ScoreMessage = b.ScoreMessage,
InitialBalance = b.InitialBalance,
NetPnl = b.NetPnl
};
}
}

View File

@@ -166,6 +166,8 @@ public class BacktestTradingBotGrain : Grain, IBacktestTradingBotGrain
Metadata = metadata,
StartDate = candles.FirstOrDefault()!.OpenTime,
EndDate = candles.LastOrDefault()!.OpenTime,
InitialBalance = tradingBot.WalletBalances.FirstOrDefault().Value,
NetPnl = finalPnl - fees,
};
if (save && user != null)
@@ -201,7 +203,9 @@ public class BacktestTradingBotGrain : Grain, IBacktestTradingBotGrain
Fees = backtest.Fees,
SharpeRatio = (double?)backtest.Statistics?.SharpeRatio,
Score = backtest.Score,
ScoreMessage = backtest.ScoreMessage
ScoreMessage = backtest.ScoreMessage,
InitialBalance = backtest.InitialBalance,
NetPnl = backtest.NetPnl
};
}

View File

@@ -172,7 +172,8 @@ public class LiveTradingBotGrain : Grain, ILiveTradingBotGrain, IRemindable
// Fallback: Get the first account for the user
if (_state.State.User == null)
{
throw new InvalidOperationException($"Bot '{config.Name}' (ID: {_state.State.Identifier}) has no user information. Cannot determine fallback account.");
throw new InvalidOperationException(
$"Bot '{config.Name}' (ID: {_state.State.Identifier}) has no user information. Cannot determine fallback account.");
}
var firstAccount = await ServiceScopeHelpers.WithScopedService<IAccountService, Account>(
@@ -183,8 +184,10 @@ public class LiveTradingBotGrain : Grain, ILiveTradingBotGrain, IRemindable
var account = userAccounts.FirstOrDefault();
if (account == null)
{
throw new InvalidOperationException($"User '{_state.State.User.Name}' has no accounts configured.");
throw new InvalidOperationException(
$"User '{_state.State.User.Name}' has no accounts configured.");
}
return account;
});
@@ -193,7 +196,8 @@ public class LiveTradingBotGrain : Grain, ILiveTradingBotGrain, IRemindable
_state.State.Config = config;
await _state.WriteStateAsync();
_logger.LogInformation("Bot '{BotName}' (ID: {BotId}) using fallback account '{AccountName}' for user '{UserName}'",
_logger.LogInformation(
"Bot '{BotName}' (ID: {BotId}) using fallback account '{AccountName}' for user '{UserName}'",
config.Name, _state.State.Identifier, firstAccount.Name, _state.State.User.Name);
}
@@ -461,6 +465,7 @@ public class LiveTradingBotGrain : Grain, ILiveTradingBotGrain, IRemindable
{
_logger.LogError(ex, "Error during coordinated balance check for bot {BotId}",
_state.State.Identifier);
SentrySdk.CaptureException(ex);
// Continue execution to avoid stopping the bot due to coordination errors
}
}
@@ -1046,7 +1051,8 @@ public class LiveTradingBotGrain : Grain, ILiveTradingBotGrain, IRemindable
{
if (_state.State.User == null)
{
throw new InvalidOperationException($"Bot '{_state.State.Config?.Name}' (ID: {_state.State.Identifier}) has no user information.");
throw new InvalidOperationException(
$"Bot '{_state.State.Config?.Name}' (ID: {_state.State.Identifier}) has no user information.");
}
return Task.FromResult(_state.State.User);

View File

@@ -55,6 +55,8 @@ public class Backtest
public Guid RequestId { get; set; }
public object? Metadata { get; set; }
public string ScoreMessage { get; set; } = string.Empty;
[Required] public decimal InitialBalance { get; set; }
[Required] public decimal NetPnl { get; set; }
/// <summary>
/// Creates a new TradingBotConfig based on this backtest's configuration for starting a live bot.

View File

@@ -25,4 +25,6 @@ public class LightBacktest
[Id(12)] public string ScoreMessage { get; set; } = string.Empty;
[Id(13)] public object Metadata { get; set; }
[Id(14)] public string Ticker { get; set; } = string.Empty;
[Id(15)] public decimal InitialBalance { get; set; }
[Id(16)] public decimal NetPnl { get; set; }
}

View File

@@ -189,6 +189,9 @@ namespace Managing.Infrastructure.Databases.Migrations
.IsRequired()
.HasColumnType("text");
b.Property<decimal>("InitialBalance")
.HasColumnType("decimal(18,8)");
b.Property<decimal>("MaxDrawdown")
.ValueGeneratedOnAdd()
.HasColumnType("decimal(18,8)")
@@ -211,6 +214,9 @@ namespace Managing.Infrastructure.Databases.Migrations
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b.Property<decimal>("NetPnl")
.HasColumnType("decimal(18,8)");
b.Property<string>("PositionsJson")
.IsRequired()
.HasColumnType("jsonb");

View File

@@ -120,4 +120,12 @@ public class BacktestEntity
[Required]
public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
[Required]
[Column(TypeName = "decimal(18,8)")]
public decimal InitialBalance { get; set; }
[Required]
[Column(TypeName = "decimal(18,8)")]
public decimal NetPnl { get; set; }
}

View File

@@ -313,7 +313,9 @@ public static class PostgreSqlMappers
Score = entity.Score,
ScoreMessage = entity.ScoreMessage,
RequestId = entity.RequestId,
Metadata = entity.Metadata
Metadata = entity.Metadata,
InitialBalance = entity.InitialBalance,
NetPnl = entity.NetPnl
};
return backtest;
@@ -353,7 +355,9 @@ public static class PostgreSqlMappers
ScoreMessage = backtest.ScoreMessage ?? string.Empty,
Metadata = backtest.Metadata?.ToString(),
CreatedAt = DateTime.UtcNow,
UpdatedAt = DateTime.UtcNow
UpdatedAt = DateTime.UtcNow,
InitialBalance = backtest.InitialBalance,
NetPnl = backtest.NetPnl
};
}