From 976c1a6580c673bb6084ec4a286a461ec62187af Mon Sep 17 00:00:00 2001 From: cryptooda Date: Sun, 5 Oct 2025 17:14:47 +0700 Subject: [PATCH] Fix volume when position not open --- .../Bots/TradingBotBase.cs | 64 +++++++++++++++---- 1 file changed, 50 insertions(+), 14 deletions(-) diff --git a/src/Managing.Application/Bots/TradingBotBase.cs b/src/Managing.Application/Bots/TradingBotBase.cs index e7fe495d..c4044e58 100644 --- a/src/Managing.Application/Bots/TradingBotBase.cs +++ b/src/Managing.Application/Bots/TradingBotBase.cs @@ -368,6 +368,16 @@ public class TradingBotBase : ITradingBot { try { + // Skip processing if position is already canceled or rejected (never filled) + if (positionForSignal.Status == PositionStatus.Canceled || + positionForSignal.Status == PositionStatus.Rejected) + { + Logger.LogDebug( + "Skipping update for position {PositionId} - status is {Status} (never filled)", + positionForSignal.Identifier, positionForSignal.Status); + return; + } + Position internalPosition = null; List brokerPositions = null; await ServiceScopeHelpers.WithScopedService(_scopeFactory, async tradingService => @@ -566,8 +576,12 @@ public class TradingBotBase : ITradingBot else { await LogWarning( - $"❌ **Position Closed**\nNo position on exchange and no orders\nSignal: `{signal.Identifier}`\nPosition have been closed."); - await HandleClosedPosition(positionForSignal); + $"❌ **Position Never Filled**\nNo position on exchange and no orders\nSignal: `{signal.Identifier}`\nPosition was never filled and will be marked as canceled."); + + // Position was never filled (still in New status), so just mark it as canceled + // Don't call HandleClosedPosition as that would incorrectly add volume/PnL + await SetPositionStatus(signal.Identifier, PositionStatus.Canceled); + SetSignalStatus(signal.Identifier, SignalStatus.Expired); } } else if (internalPosition.Status == PositionStatus.Finished || @@ -1395,22 +1409,44 @@ public class TradingBotBase : ITradingBot { position.Status = PositionStatus.Finished; await UpdatePositionDatabase(position); - await NotifyAgentAndPlatformGrainAsync(NotificationEventType.PositionClosed, position); + + // Only send PositionClosed notification if the position was actually filled + // Check if Open trade was filled (means position was opened on the broker) + if (position.Open?.Status == TradeStatus.Filled) + { + await NotifyAgentAndPlatformGrainAsync(NotificationEventType.PositionClosed, position); + + // Update the last position closing time for cooldown period tracking + // Only update if position was actually filled + LastPositionClosingTime = Config.IsForBacktest ? currentCandle.Date : DateTime.UtcNow; + } + else + { + Logger.LogDebug( + "Skipping PositionClosed notification for position {PositionId} - position was never filled (Open trade status: {OpenStatus})", + position.Identifier, position.Open?.Status); + } } - // Update the last position closing time for cooldown period tracking - LastPositionClosingTime = Config.IsForBacktest ? currentCandle.Date : DateTime.UtcNow; - - Logger.LogInformation( - $"✅ **Position Closed Successfully**\nPosition: `{position.SignalIdentifier}`\nPnL: `${position.ProfitAndLoss?.Realized:F2}`"); - - if (position.ProfitAndLoss != null) + // Only update balance and log success if position was actually filled + if (position.Open?.Status == TradeStatus.Filled) { - Config.BotTradingBalance += position.ProfitAndLoss.Realized; - Logger.LogInformation( - string.Format("💰 **Balance Updated**\nNew bot trading balance: `${0:F2}`", - Config.BotTradingBalance)); + $"✅ **Position Closed Successfully**\nPosition: `{position.SignalIdentifier}`\nPnL: `${position.ProfitAndLoss?.Realized:F2}`"); + + if (position.ProfitAndLoss != null) + { + Config.BotTradingBalance += position.ProfitAndLoss.Realized; + + Logger.LogInformation( + string.Format("💰 **Balance Updated**\nNew bot trading balance: `${0:F2}`", + Config.BotTradingBalance)); + } + } + else + { + Logger.LogInformation( + $"✅ **Position Cleanup**\nPosition: `{position.SignalIdentifier}` was never filled - no balance or PnL changes"); } } else