diff --git a/src/Managing.Application.Tests/BacktestTests.cs b/src/Managing.Application.Tests/BacktestTests.cs
index de603162..4a8c559e 100644
--- a/src/Managing.Application.Tests/BacktestTests.cs
+++ b/src/Managing.Application.Tests/BacktestTests.cs
@@ -212,18 +212,18 @@ public class BacktestTests : BaseTests
Assert.NotNull(backtestResult);
// Financial metrics - using decimal precision
- Assert.Equal(-105.45m, Math.Round(backtestResult.FinalPnl, 2));
- Assert.Equal(-210.40m, Math.Round(backtestResult.NetPnl, 2));
- Assert.Equal(104.94m, Math.Round(backtestResult.Fees, 2));
+ Assert.Equal(-106.56m, Math.Round(backtestResult.FinalPnl, 2));
+ Assert.Equal(-187.36m, Math.Round(backtestResult.NetPnl, 2));
+ Assert.Equal(80.80m, Math.Round(backtestResult.Fees, 2));
Assert.Equal(1000.0m, backtestResult.InitialBalance);
// Performance metrics
Assert.Equal(31, backtestResult.WinRate);
- Assert.Equal(-10.55m, Math.Round(backtestResult.GrowthPercentage, 2));
+ Assert.Equal(-10.66m, Math.Round(backtestResult.GrowthPercentage, 2));
Assert.Equal(-0.67m, Math.Round(backtestResult.HodlPercentage, 2));
// Risk metrics
- Assert.Equal(243.84m, Math.Round(backtestResult.MaxDrawdown.Value, 2));
+ Assert.Equal(247.62m, Math.Round(backtestResult.MaxDrawdown.Value, 2));
Assert.Equal(-0.021, Math.Round(backtestResult.SharpeRatio.Value, 3));
Assert.Equal(0.0, backtestResult.Score);
diff --git a/src/Managing.Application/Bots/TradingBotBase.cs b/src/Managing.Application/Bots/TradingBotBase.cs
index 6593e14c..0755fba3 100644
--- a/src/Managing.Application/Bots/TradingBotBase.cs
+++ b/src/Managing.Application/Bots/TradingBotBase.cs
@@ -169,6 +169,57 @@ public class TradingBotBase : ITradingBot
});
}
+ ///
+ /// Verifies the actual USDC balance and updates the config if the actual balance is less than the configured balance.
+ /// This prevents bots from trying to trade with more funds than are actually available.
+ ///
+ public async Task VerifyAndUpdateBalance()
+ {
+ if (Config.IsForBacktest) return;
+ if (Account == null)
+ {
+ Logger.LogWarning("Cannot verify balance: Account is null");
+ return;
+ }
+
+ try
+ {
+ // Fetch actual USDC balance
+ var actualBalance = await ServiceScopeHelpers.WithScopedService(_scopeFactory,
+ async exchangeService =>
+ {
+ var balances = await exchangeService.GetBalances(Account);
+ var usdcBalance = balances.FirstOrDefault(b => b.TokenName?.ToUpper() == "USDC");
+ return usdcBalance?.Amount ?? 0;
+ });
+
+ // Check if actual balance is less than configured balance
+ if (actualBalance < Config.BotTradingBalance)
+ {
+ Logger.LogWarning(
+ "Actual USDC balance ({ActualBalance:F2}) is less than configured balance ({ConfiguredBalance:F2}). Updating configuration.",
+ actualBalance, Config.BotTradingBalance);
+
+ // Create new config with updated balance
+ var newConfig = Config;
+ newConfig.BotTradingBalance = actualBalance;
+
+ // Use UpdateConfiguration to notify and log the change
+ await UpdateConfiguration(newConfig);
+ }
+ else
+ {
+ Logger.LogDebug(
+ "Balance verification passed. Actual: {ActualBalance:F2}, Configured: {ConfiguredBalance:F2}",
+ actualBalance, Config.BotTradingBalance);
+ }
+ }
+ catch (Exception ex)
+ {
+ Logger.LogError(ex, "Error verifying and updating balance");
+ }
+ }
+
public async Task Run()
{
// Update signals for live trading only
@@ -970,6 +1021,12 @@ public class TradingBotBase : ITradingBot
try
{
+ // Verify actual balance before opening position
+ if (!Config.IsForBacktest)
+ {
+ await VerifyAndUpdateBalance();
+ }
+
var command = new OpenPositionRequest(
Config.AccountName,
Config.MoneyManagement,