Add netpnl and initialBalance to backtests
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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; }
|
||||
}
|
||||
@@ -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");
|
||||
|
||||
@@ -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; }
|
||||
}
|
||||
@@ -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
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user