From df8c199ccebeaec88c9e2e8116f52615a7f63f86 Mon Sep 17 00:00:00 2001 From: cryptooda Date: Thu, 11 Dec 2025 14:10:38 +0700 Subject: [PATCH] Clean tradingbot and spot and future --- .../Bots/BacktestFuturesBot.cs | 21 +++++++--------- .../Bots/BacktestSpotBot.cs | 24 +++++++------------ src/Managing.Application/Bots/FuturesBot.cs | 21 +++++++--------- src/Managing.Application/Bots/SpotBot.cs | 16 ++++--------- .../Bots/TradingBotBase.cs | 11 ++------- 5 files changed, 32 insertions(+), 61 deletions(-) diff --git a/src/Managing.Application/Bots/BacktestFuturesBot.cs b/src/Managing.Application/Bots/BacktestFuturesBot.cs index 05e4f984..f6a6d5cb 100644 --- a/src/Managing.Application/Bots/BacktestFuturesBot.cs +++ b/src/Managing.Application/Bots/BacktestFuturesBot.cs @@ -36,12 +36,12 @@ public class BacktestFuturesBot : TradingBotBase, ITradingBot // Backtest mode: Skip account loading and broker initialization // Just log basic startup info await LogInformation($"🔬 Backtest Bot Started\n" + - $"📊 Testing Setup:\n" + - $"🎯 Ticker: `{Config.Ticker}`\n" + - $"⏰ Timeframe: `{Config.Timeframe}`\n" + - $"🎮 Scenario: `{Config.Scenario?.Name ?? "Unknown"}`\n" + - $"💰 Initial Balance: `${Config.BotTradingBalance:F2}`\n" + - $"✅ Ready to run backtest simulation"); + $"📊 Testing Setup:\n" + + $"🎯 Ticker: `{Config.Ticker}`\n" + + $"⏰ Timeframe: `{Config.Timeframe}`\n" + + $"🎮 Scenario: `{Config.Scenario?.Name ?? "Unknown"}`\n" + + $"💰 Initial Balance: `${Config.BotTradingBalance:F2}`\n" + + $"✅ Ready to run backtest simulation"); } public override async Task Run() @@ -68,12 +68,6 @@ public class BacktestFuturesBot : TradingBotBase, ITradingBot return position; } - protected override async Task> GetBrokerPositionsForUpdate(Account account) - { - // In backtest mode, return empty list (no broker positions to check) - return new List(); - } - protected override async Task UpdatePositionWithBrokerData(Position position, List brokerPositions) { // In backtest mode, skip broker synchronization @@ -289,7 +283,8 @@ public class BacktestFuturesBot : TradingBotBase, ITradingBot _scopeFactory, async (exchangeService, accountService, tradingService) => { closedPosition = - await new CloseBacktestFuturesPositionCommandHandler(exchangeService, accountService, tradingService, + await new CloseBacktestFuturesPositionCommandHandler(exchangeService, accountService, + tradingService, _scopeFactory) .Handle(command); }); diff --git a/src/Managing.Application/Bots/BacktestSpotBot.cs b/src/Managing.Application/Bots/BacktestSpotBot.cs index 7fe79bf7..b08163f9 100644 --- a/src/Managing.Application/Bots/BacktestSpotBot.cs +++ b/src/Managing.Application/Bots/BacktestSpotBot.cs @@ -36,12 +36,12 @@ public class BacktestSpotBot : TradingBotBase, ITradingBot // Backtest mode: Skip account loading and broker initialization // Just log basic startup info await LogInformation($"🔬 Backtest Spot Bot Started\n" + - $"📊 Testing Setup:\n" + - $"🎯 Ticker: `{Config.Ticker}`\n" + - $"⏰ Timeframe: `{Config.Timeframe}`\n" + - $"🎮 Scenario: `{Config.Scenario?.Name ?? "Unknown"}`\n" + - $"💰 Initial Balance: `${Config.BotTradingBalance:F2}`\n" + - $"✅ Ready to run spot backtest simulation"); + $"📊 Testing Setup:\n" + + $"🎯 Ticker: `{Config.Ticker}`\n" + + $"⏰ Timeframe: `{Config.Timeframe}`\n" + + $"🎮 Scenario: `{Config.Scenario?.Name ?? "Unknown"}`\n" + + $"💰 Initial Balance: `${Config.BotTradingBalance:F2}`\n" + + $"✅ Ready to run spot backtest simulation"); } public override async Task Run() @@ -67,12 +67,6 @@ public class BacktestSpotBot : TradingBotBase, ITradingBot return position; } - protected override async Task> GetBrokerPositionsForUpdate(Account account) - { - // In backtest mode, return empty list (no broker positions to check) - return new List(); - } - protected override async Task UpdatePositionWithBrokerData(Position position, List brokerPositions) { // In backtest mode, skip broker synchronization @@ -247,7 +241,8 @@ public class BacktestSpotBot : TradingBotBase, ITradingBot // Only LONG signals should reach here (SHORT signals are filtered out earlier) if (signal.Direction != TradeDirection.Long) { - throw new InvalidOperationException($"Only LONG signals can open positions in spot trading. Received: {signal.Direction}"); + throw new InvalidOperationException( + $"Only LONG signals can open positions in spot trading. Received: {signal.Direction}"); } if (Account == null || Account.User == null) @@ -330,5 +325,4 @@ public class BacktestSpotBot : TradingBotBase, ITradingBot } } } -} - +} \ No newline at end of file diff --git a/src/Managing.Application/Bots/FuturesBot.cs b/src/Managing.Application/Bots/FuturesBot.cs index 654f8137..56e80063 100644 --- a/src/Managing.Application/Bots/FuturesBot.cs +++ b/src/Managing.Application/Bots/FuturesBot.cs @@ -75,14 +75,6 @@ public class FuturesBot : TradingBotBase, ITradingBot async tradingService => { return await tradingService.GetPositionByIdentifierAsync(position.Identifier); }); } - protected override async Task> GetBrokerPositionsForUpdate(Account account) - { - // For live trading, get real broker positions - return await ServiceScopeHelpers.WithScopedService>( - _scopeFactory, - async exchangeService => { return [.. await exchangeService.GetBrokerPositions(Account)]; }); - } - protected override async Task UpdatePositionWithBrokerData(Position position, List brokerPositions) { // Live trading broker position synchronization logic is handled in the base UpdatePosition method @@ -210,11 +202,16 @@ public class FuturesBot : TradingBotBase, ITradingBot } - protected override async Task SynchronizeWithBrokerPositions(Position internalPosition, Position positionForSignal, - List brokerPositions) + protected override async Task SynchronizeWithBrokerPositions( + Position internalPosition, + Position positionForSignal) { + var liveBrokerPositions = await ServiceScopeHelpers.WithScopedService>( + _scopeFactory, + async exchangeService => [.. await exchangeService.GetBrokerPositions(Account)]); + // Improved broker position matching with more robust logic - var brokerPosition = brokerPositions + var brokerPosition = liveBrokerPositions .Where(p => p.Ticker == Config.Ticker) .OrderByDescending(p => p.Open?.Date ?? DateTime.MinValue) .FirstOrDefault(p => p.OriginDirection == positionForSignal.OriginDirection); @@ -284,7 +281,7 @@ public class FuturesBot : TradingBotBase, ITradingBot Logger.LogWarning( $"⚠️ Position Sync Issue Detected\n" + $"Internal position {internalPosition.Identifier} shows Filled\n" + - $"But not found in broker positions list (Count: {brokerPositions.Count})\n" + + $"But not found in broker positions list (Count: {liveBrokerPositions.Count})\n" + $"Checking position history before marking as closed..."); // Verify in exchange history before assuming it's closed diff --git a/src/Managing.Application/Bots/SpotBot.cs b/src/Managing.Application/Bots/SpotBot.cs index 59b562b2..4788ce47 100644 --- a/src/Managing.Application/Bots/SpotBot.cs +++ b/src/Managing.Application/Bots/SpotBot.cs @@ -1,3 +1,4 @@ +#nullable enable using Managing.Application.Abstractions.Grains; using Managing.Application.Abstractions.Services; using Managing.Application.Trading.Commands; @@ -68,15 +69,7 @@ public class SpotBot : TradingBotBase // For live trading, get position from database via trading service return await ServiceScopeHelpers.WithScopedService( _scopeFactory, - async tradingService => { return await tradingService.GetPositionByIdentifierAsync(position.Identifier); }); - } - - protected override async Task> GetBrokerPositionsForUpdate(Account account) - { - // For live spot trading, we don't have broker positions like futures - // Positions are verified via token balances in UpdatePositionWithBrokerData and SynchronizeWithBrokerPositions - // Return empty list - actual verification happens in those methods - return new List(); + async tradingService => await tradingService.GetPositionByIdentifierAsync(position.Identifier)); } protected override async Task UpdatePositionWithBrokerData(Position position, List brokerPositions) @@ -88,7 +81,7 @@ public class SpotBot : TradingBotBase _scopeFactory, async exchangeService => await exchangeService.GetBalance(Account, Config.Ticker)); - if (tokenBalance == null || tokenBalance.Amount <= 0) + if (tokenBalance is not { Amount: > 0 }) { // No token balance found - position might be closed return; @@ -225,8 +218,7 @@ public class SpotBot : TradingBotBase } - protected override async Task SynchronizeWithBrokerPositions(Position internalPosition, Position positionForSignal, - List brokerPositions) + protected override async Task SynchronizeWithBrokerPositions(Position internalPosition, Position positionForSignal) { // For spot trading, fetch token balance directly and verify/match with internal position try diff --git a/src/Managing.Application/Bots/TradingBotBase.cs b/src/Managing.Application/Bots/TradingBotBase.cs index 0211975f..f4fd65c3 100644 --- a/src/Managing.Application/Bots/TradingBotBase.cs +++ b/src/Managing.Application/Bots/TradingBotBase.cs @@ -462,10 +462,9 @@ public abstract class TradingBotBase : ITradingBot } Position internalPosition = await GetInternalPositionForUpdate(positionForSignal); - var brokerPositions = await GetBrokerPositionsForUpdate(Account); // Handle broker position synchronization (futures-specific logic) - await SynchronizeWithBrokerPositions(internalPosition, positionForSignal, brokerPositions); + await SynchronizeWithBrokerPositions(internalPosition, positionForSignal); // Handle order management and position status (futures-specific logic) await HandleOrderManagementAndPositionStatus(signal, internalPosition, positionForSignal); @@ -650,8 +649,7 @@ public abstract class TradingBotBase : ITradingBot } // Virtual methods for trading mode-specific behavior - protected virtual async Task SynchronizeWithBrokerPositions(Position internalPosition, Position positionForSignal, - List brokerPositions) + protected virtual async Task SynchronizeWithBrokerPositions(Position internalPosition, Position positionForSignal) { // Default implementation: do nothing (for backtest) } @@ -1999,11 +1997,6 @@ public abstract class TradingBotBase : ITradingBot return position; // Default implementation for backtest } - protected virtual async Task> GetBrokerPositionsForUpdate(Account account) - { - return new List(); // Default implementation for backtest - } - protected virtual async Task UpdatePositionWithBrokerData(Position position, List brokerPositions) { // Default: do nothing for backtest