diff --git a/src/Managing.Api/Controllers/BacktestController.cs b/src/Managing.Api/Controllers/BacktestController.cs index a26e8fc..28161d0 100644 --- a/src/Managing.Api/Controllers/BacktestController.cs +++ b/src/Managing.Api/Controllers/BacktestController.cs @@ -176,18 +176,11 @@ public class BacktestController : BaseController switch (request.Config.BotType) { case BotType.SimpleBot: + // SimpleBot backtest not implemented yet break; case BotType.ScalpingBot: - backtestResult = await _backtester.RunScalpingBotBacktest( - backtestConfig, - request.StartDate, - request.EndDate, - user, - request.Save, - null); - break; case BotType.FlippingBot: - backtestResult = await _backtester.RunFlippingBotBacktest( + backtestResult = await _backtester.RunTradingBotBacktest( backtestConfig, request.StartDate, request.EndDate, diff --git a/src/Managing.Application.Abstractions/Services/IBacktester.cs b/src/Managing.Application.Abstractions/Services/IBacktester.cs index 1fcdd83..2ef352d 100644 --- a/src/Managing.Application.Abstractions/Services/IBacktester.cs +++ b/src/Managing.Application.Abstractions/Services/IBacktester.cs @@ -7,6 +7,39 @@ namespace Managing.Application.Abstractions.Services { public interface IBacktester { + /// + /// Runs a unified trading bot backtest with the specified configuration and date range. + /// Automatically handles ScalpingBot and FlippingBot behavior based on config.BotType. + /// + /// The trading bot configuration + /// The start date for the backtest + /// The end date for the backtest + /// The user running the backtest + /// Whether to save the backtest results + /// Optional pre-loaded candles + /// The backtest results + Task RunTradingBotBacktest( + TradingBotConfig config, + DateTime startDate, + DateTime endDate, + User user = null, + bool save = false, + List? initialCandles = null); + + /// + /// Runs a unified trading bot backtest with pre-loaded candles. + /// Automatically handles ScalpingBot and FlippingBot behavior based on config.BotType. + /// + /// The trading bot configuration + /// The candles to use for backtesting + /// The user running the backtest + /// The backtest results + Task RunTradingBotBacktest( + TradingBotConfig config, + List candles, + User user = null); + + // Legacy methods - maintained for backward compatibility Task RunScalpingBotBacktest( TradingBotConfig config, DateTime startDate, diff --git a/src/Managing.Application/Abstractions/IBotFactory.cs b/src/Managing.Application/Abstractions/IBotFactory.cs index 25a7f97..4431d55 100644 --- a/src/Managing.Application/Abstractions/IBotFactory.cs +++ b/src/Managing.Application/Abstractions/IBotFactory.cs @@ -1,5 +1,4 @@ -using Managing.Application.Bots; -using Managing.Domain.Bots; +using Managing.Domain.Bots; using Managing.Domain.Workflows; namespace Managing.Application.Abstractions @@ -7,6 +6,22 @@ namespace Managing.Application.Abstractions public interface IBotFactory { IBot CreateSimpleBot(string botName, Workflow workflow); + + /// + /// Creates a trading bot using the unified TradingBot class + /// + /// The trading bot configuration + /// ITradingBot instance + ITradingBot CreateTradingBot(TradingBotConfig config); + + /// + /// Creates a trading bot for backtesting using the unified TradingBot class + /// + /// The trading bot configuration + /// ITradingBot instance configured for backtesting + ITradingBot CreateBacktestTradingBot(TradingBotConfig config); + + // Legacy methods - these will use TradingBot internally but maintain backward compatibility ITradingBot CreateScalpingBot(TradingBotConfig config); ITradingBot CreateBacktestScalpingBot(TradingBotConfig config); ITradingBot CreateFlippingBot(TradingBotConfig config); diff --git a/src/Managing.Application/Abstractions/IBotService.cs b/src/Managing.Application/Abstractions/IBotService.cs index 6f2a4cf..4ce07c7 100644 --- a/src/Managing.Application/Abstractions/IBotService.cs +++ b/src/Managing.Application/Abstractions/IBotService.cs @@ -15,6 +15,21 @@ public interface IBotService void StartBotFromBackup(BotBackup backupBot); BotBackup GetBotBackup(string identifier); + /// + /// Creates a trading bot using the unified TradingBot class + /// + /// The trading bot configuration + /// ITradingBot instance + ITradingBot CreateTradingBot(TradingBotConfig config); + + /// + /// Creates a trading bot for backtesting using the unified TradingBot class + /// + /// The trading bot configuration + /// ITradingBot instance configured for backtesting + ITradingBot CreateBacktestTradingBot(TradingBotConfig config); + + // Legacy methods - these will use TradingBot internally but maintain backward compatibility ITradingBot CreateScalpingBot(TradingBotConfig config); ITradingBot CreateBacktestScalpingBot(TradingBotConfig config); ITradingBot CreateFlippingBot(TradingBotConfig config); diff --git a/src/Managing.Application/Backtesting/Backtester.cs b/src/Managing.Application/Backtesting/Backtester.cs index 4ad0d72..3b8ef7a 100644 --- a/src/Managing.Application/Backtesting/Backtester.cs +++ b/src/Managing.Application/Backtesting/Backtester.cs @@ -55,7 +55,18 @@ namespace Managing.Application.Backtesting return result; } - public async Task RunScalpingBotBacktest( + /// + /// Runs a unified trading bot backtest with the specified configuration and date range. + /// Automatically handles ScalpingBot and FlippingBot behavior based on config.BotType. + /// + /// The trading bot configuration + /// The start date for the backtest + /// The end date for the backtest + /// The user running the backtest + /// Whether to save the backtest results + /// Optional pre-loaded candles + /// The backtest results + public async Task RunTradingBotBacktest( TradingBotConfig config, DateTime startDate, DateTime endDate, @@ -64,12 +75,17 @@ namespace Managing.Application.Backtesting List? initialCandles = null) { var account = await GetAccountFromConfig(config); - var scalpingBot = _botFactory.CreateBacktestScalpingBot(config); - scalpingBot.LoadScenario(config.ScenarioName); - scalpingBot.User = user; - await scalpingBot.LoadAccount(); + + // Set FlipPosition based on BotType + config.FlipPosition = config.BotType == BotType.FlippingBot; + + var tradingBot = _botFactory.CreateBacktestTradingBot(config); + tradingBot.LoadScenario(config.ScenarioName); + tradingBot.User = user; + await tradingBot.LoadAccount(); + var candles = initialCandles ?? GetCandles(account, config.Ticker, config.Timeframe, startDate, endDate); - var result = GetBacktestingResult(config, scalpingBot, candles); + var result = GetBacktestingResult(config, tradingBot, candles); if (user != null) { @@ -88,6 +104,52 @@ namespace Managing.Application.Backtesting return result; } + /// + /// Runs a unified trading bot backtest with pre-loaded candles. + /// Automatically handles ScalpingBot and FlippingBot behavior based on config.BotType. + /// + /// The trading bot configuration + /// The candles to use for backtesting + /// The user running the backtest + /// The backtest results + public async Task RunTradingBotBacktest( + TradingBotConfig config, + List candles, + User user = null) + { + var account = await GetAccountFromConfig(config); + + // Set FlipPosition based on BotType + config.FlipPosition = config.BotType == BotType.FlippingBot; + + var tradingBot = _botFactory.CreateBacktestTradingBot(config); + tradingBot.LoadScenario(config.ScenarioName); + tradingBot.User = user; + await tradingBot.LoadAccount(); + + var result = GetBacktestingResult(config, tradingBot, candles); + + if (user != null) + { + result.User = user; + } + + return result; + } + + // Legacy methods - maintained for backward compatibility + public async Task RunScalpingBotBacktest( + TradingBotConfig config, + DateTime startDate, + DateTime endDate, + User user = null, + bool save = false, + List? initialCandles = null) + { + config.BotType = BotType.ScalpingBot; // Ensure correct type + return await RunTradingBotBacktest(config, startDate, endDate, user, save, initialCandles); + } + public async Task RunFlippingBotBacktest( TradingBotConfig config, DateTime startDate, @@ -96,30 +158,8 @@ namespace Managing.Application.Backtesting bool save = false, List? initialCandles = null) { - var account = await GetAccountFromConfig(config); - var flippingBot = _botFactory.CreateBacktestFlippingBot(config); - flippingBot.LoadScenario(config.ScenarioName); - flippingBot.User = user; - await flippingBot.LoadAccount(); - - var candles = initialCandles ?? GetCandles(account, config.Ticker, config.Timeframe, startDate, endDate); - var result = GetBacktestingResult(config, flippingBot, candles); - - if (user != null) - { - result.User = user; - } - - // Set start and end dates - result.StartDate = startDate; - result.EndDate = endDate; - - if (save) - { - _backtestRepository.InsertBacktestForUser(user, result); - } - - return result; + config.BotType = BotType.FlippingBot; // Ensure correct type + return await RunTradingBotBacktest(config, startDate, endDate, user, save, initialCandles); } public async Task RunScalpingBotBacktest( @@ -127,20 +167,8 @@ namespace Managing.Application.Backtesting List candles, User user = null) { - var account = await GetAccountFromConfig(config); - var bot = _botFactory.CreateBacktestScalpingBot(config); - bot.LoadScenario(config.ScenarioName); - bot.User = user; - await bot.LoadAccount(); - - var result = GetBacktestingResult(config, bot, candles); - - if (user != null) - { - result.User = user; - } - - return result; + config.BotType = BotType.ScalpingBot; // Ensure correct type + return await RunTradingBotBacktest(config, candles, user); } public async Task RunFlippingBotBacktest( @@ -148,20 +176,8 @@ namespace Managing.Application.Backtesting List candles, User user = null) { - var account = await GetAccountFromConfig(config); - var bot = _botFactory.CreateBacktestFlippingBot(config); - bot.LoadScenario(config.ScenarioName); - bot.User = user; - await bot.LoadAccount(); - - var result = GetBacktestingResult(config, bot, candles); - - if (user != null) - { - result.User = user; - } - - return result; + config.BotType = BotType.FlippingBot; // Ensure correct type + return await RunTradingBotBacktest(config, candles, user); } private async Task GetAccountFromConfig(TradingBotConfig config) diff --git a/src/Managing.Application/Bots/Base/BotFactory.cs b/src/Managing.Application/Bots/Base/BotFactory.cs index fffa32d..f0ecb99 100644 --- a/src/Managing.Application/Bots/Base/BotFactory.cs +++ b/src/Managing.Application/Bots/Base/BotFactory.cs @@ -37,10 +37,37 @@ namespace Managing.Application.Bots.Base return new SimpleBot(botName, _tradingBotLogger, workflow, _botService); } + ITradingBot IBotFactory.CreateTradingBot(TradingBotConfig config) + { + return new TradingBot( + _exchangeService, + _tradingBotLogger, + _tradingService, + _accountService, + _messengerService, + _botService, + config); + } + + ITradingBot IBotFactory.CreateBacktestTradingBot(TradingBotConfig config) + { + config.IsForBacktest = true; + return new TradingBot( + _exchangeService, + _tradingBotLogger, + _tradingService, + _accountService, + _messengerService, + _botService, + config); + } + + // Legacy methods for backward compatibility - will be deprecated ITradingBot IBotFactory.CreateScalpingBot(TradingBotConfig config) { config.BotType = BotType.ScalpingBot; - return new ScalpingBot( + config.FlipPosition = false; + return new TradingBot( _exchangeService, _tradingBotLogger, _tradingService, @@ -54,7 +81,8 @@ namespace Managing.Application.Bots.Base { config.BotType = BotType.ScalpingBot; config.IsForBacktest = true; - return new ScalpingBot( + config.FlipPosition = false; + return new TradingBot( _exchangeService, _tradingBotLogger, _tradingService, @@ -67,7 +95,8 @@ namespace Managing.Application.Bots.Base public ITradingBot CreateFlippingBot(TradingBotConfig config) { config.BotType = BotType.FlippingBot; - return new FlippingBot( + config.FlipPosition = true; + return new TradingBot( _exchangeService, _tradingBotLogger, _tradingService, @@ -81,7 +110,8 @@ namespace Managing.Application.Bots.Base { config.BotType = BotType.FlippingBot; config.IsForBacktest = true; - return new FlippingBot( + config.FlipPosition = true; + return new TradingBot( _exchangeService, _tradingBotLogger, _tradingService, diff --git a/src/Managing.Application/Bots/FlippingBot.cs b/src/Managing.Application/Bots/FlippingBot.cs deleted file mode 100644 index 45d283a..0000000 --- a/src/Managing.Application/Bots/FlippingBot.cs +++ /dev/null @@ -1,32 +0,0 @@ -using Managing.Application.Abstractions; -using Managing.Application.Abstractions.Services; -using Managing.Domain.Bots; -using Microsoft.Extensions.Logging; -using static Managing.Common.Enums; - -namespace Managing.Application.Bots -{ - public class FlippingBot : TradingBot - { - public FlippingBot( - IExchangeService exchangeService, - ILogger logger, - ITradingService tradingService, - IAccountService accountService, - IMessengerService messengerService, - IBotService botService, - TradingBotConfig config) - : base(exchangeService, logger, tradingService, accountService, messengerService, botService, config) - { - Config.BotType = BotType.FlippingBot; - Config.FlipPosition = true; - } - - public sealed override void Start() - { - Logger.LogInformation($"{Name} - Bot Started"); - base.Start(); - Logger.LogInformation($"Starting {Name} bot - Status : {Status}"); - } - } -} \ No newline at end of file diff --git a/src/Managing.Application/Bots/ScalpingBot.cs b/src/Managing.Application/Bots/ScalpingBot.cs deleted file mode 100644 index 1d92e5a..0000000 --- a/src/Managing.Application/Bots/ScalpingBot.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Managing.Application.Abstractions; -using Managing.Application.Abstractions.Services; -using Managing.Domain.Bots; -using Microsoft.Extensions.Logging; -using static Managing.Common.Enums; - -namespace Managing.Application.Bots -{ - public class ScalpingBot : TradingBot - { - public ScalpingBot( - IExchangeService exchangeService, - ILogger logger, - ITradingService tradingService, - IAccountService accountService, - IMessengerService messengerService, - IBotService botService, - TradingBotConfig config) - : base(exchangeService, logger, tradingService, accountService, messengerService, botService, config) - { - Config.BotType = BotType.ScalpingBot; - } - - public sealed override void Start() - { - Logger.LogInformation($"{Name} - Bot Started"); - base.Start(); - Logger.LogInformation($"Starting {Name} bot - Status : {Status}"); - } - } -} \ No newline at end of file diff --git a/src/Managing.Application/Bots/TradingBot.cs b/src/Managing.Application/Bots/TradingBot.cs index 34863ed..2023c7b 100644 --- a/src/Managing.Application/Bots/TradingBot.cs +++ b/src/Managing.Application/Bots/TradingBot.cs @@ -471,51 +471,74 @@ public class TradingBot : Bot, ITradingBot // Check time-based position management (only if MaxPositionTimeHours is set) if (Config.MaxPositionTimeHours.HasValue) { - var isPositionInProfit = await IsPositionInProfit(positionForSignal, lastCandle.Close); - var isAtBreakeven = Math.Abs(lastCandle.Close - positionForSignal.Open.Price) < 0.01m; // Small tolerance for breakeven var hasExceededTimeLimit = HasPositionExceededTimeLimit(positionForSignal, currentTime); - + // Calculate current unrealized PNL for logging var currentPnl = CalculateUnrealizedPnl(positionForSignal, lastCandle.Close); - var pnlPercentage = Math.Round((currentPnl / (positionForSignal.Open.Price * positionForSignal.Open.Quantity)) * 100, 2); + var pnlPercentage = + Math.Round( + (currentPnl / (positionForSignal.Open.Price * positionForSignal.Open.Quantity)) * 100, 2); // Early closure logic when CloseEarlyWhenProfitable is enabled - if (Config.CloseEarlyWhenProfitable && (isPositionInProfit || isAtBreakeven)) + if (Config.CloseEarlyWhenProfitable) { - await LogInformation( - $"Closing position early due to profitability - Position opened at {positionForSignal.Open.Date}, " + - $"current time {currentTime}. Position is {(isPositionInProfit ? "in profit" : "at breakeven")} " + - $"(entry: {positionForSignal.Open.Price}, current: {lastCandle.Close}). " + - $"Current PNL: ${currentPnl:F2} ({pnlPercentage:F2}%). " + - $"CloseEarlyWhenProfitable is enabled."); - await CloseTrade(signal, positionForSignal, positionForSignal.Open, lastCandle.Close, true); - return; - } - - // Time limit exceeded logic - if (hasExceededTimeLimit) - { - if (Config.CloseEarlyWhenProfitable || isPositionInProfit || isAtBreakeven) + var isPositionInProfit = await IsPositionInProfit(positionForSignal, lastCandle.Close); + var isAtBreakeven = + Math.Abs(lastCandle.Close - positionForSignal.Open.Price) < + 0.01m; // Small tolerance for breakeven + + if (isPositionInProfit || isAtBreakeven) { - // Close when time limit is reached if: - // 1. CloseEarlyWhenProfitable is enabled (safety net), OR - // 2. Position is in profit/breakeven (when CloseEarlyWhenProfitable is disabled) await LogInformation( - $"Closing position due to time limit - Position opened at {positionForSignal.Open.Date}, " + - $"current time {currentTime}, max time limit {Config.MaxPositionTimeHours} hours. " + - $"Position is {(isPositionInProfit ? "in profit" : isAtBreakeven ? "at breakeven" : "at a loss")} " + + $"Closing position early due to profitability - Position opened at {positionForSignal.Open.Date}, " + + $"current time {currentTime}. Position is {(isPositionInProfit ? "in profit" : "at breakeven")} " + $"(entry: {positionForSignal.Open.Price}, current: {lastCandle.Close}). " + - $"Current PNL: ${currentPnl:F2} ({pnlPercentage:F2}%)"); + $"Current PNL: ${currentPnl:F2} ({pnlPercentage:F2}%). " + + $"CloseEarlyWhenProfitable is enabled."); await CloseTrade(signal, positionForSignal, positionForSignal.Open, lastCandle.Close, true); return; } - else + + // Time limit exceeded logic when CloseEarlyWhenProfitable is enabled + if (hasExceededTimeLimit && (isPositionInProfit || isAtBreakeven)) + { + await LogInformation( + $"Closing position due to time limit - Position opened at {positionForSignal.Open.Date}, " + + $"current time {currentTime}, max time limit {Config.MaxPositionTimeHours} hours. " + + $"Position is {(isPositionInProfit ? "in profit" : "at breakeven")} " + + $"(entry: {positionForSignal.Open.Price}, current: {lastCandle.Close}). " + + $"Current PNL: ${currentPnl:F2} ({pnlPercentage:F2}%). " + + $"CloseEarlyWhenProfitable is enabled."); + await CloseTrade(signal, positionForSignal, positionForSignal.Open, lastCandle.Close, true); + return; + } + else if (hasExceededTimeLimit) { await LogInformation( $"Position has exceeded time limit ({Config.MaxPositionTimeHours} hours) but is at a loss " + $"(entry: {positionForSignal.Open.Price}, current: {lastCandle.Close}). " + $"Current PNL: ${currentPnl:F2} ({pnlPercentage:F2}%). " + - $"CloseEarlyWhenProfitable is disabled - waiting for profit or breakeven before closing."); + $"CloseEarlyWhenProfitable is enabled - waiting for profit or breakeven before closing."); + } + } + else + { + // Time limit exceeded logic when CloseEarlyWhenProfitable is disabled + if (hasExceededTimeLimit) + { + var isPositionInProfit = await IsPositionInProfit(positionForSignal, lastCandle.Close); + var profitStatus = isPositionInProfit ? "in profit" : + Math.Abs(lastCandle.Close - positionForSignal.Open.Price) < 0.01m ? "at breakeven" : "at a loss"; + + await LogInformation( + $"Closing position due to time limit - Position opened at {positionForSignal.Open.Date}, " + + $"current time {currentTime}, max time limit {Config.MaxPositionTimeHours} hours. " + + $"Position is {profitStatus} " + + $"(entry: {positionForSignal.Open.Price}, current: {lastCandle.Close}). " + + $"Current PNL: ${currentPnl:F2} ({pnlPercentage:F2}%). " + + $"CloseEarlyWhenProfitable is disabled - closing regardless of profit status."); + await CloseTrade(signal, positionForSignal, positionForSignal.Open, lastCandle.Close, true); + return; } } } @@ -665,7 +688,6 @@ public class TradingBot : Bot, ITradingBot $"Position {previousSignal.Identifier} is not in profit (entry: {openedPosition.Open.Price}, current: {lastPrice}). " + $"Signal {signal.Identifier} will wait for position to become profitable before flipping."); - // Keep signal in waiting status to check again on next execution SetSignalStatus(signal.Identifier, SignalStatus.Expired); return; } @@ -1046,7 +1068,7 @@ public class TradingBot : Bot, ITradingBot private void SetSignalStatus(string signalIdentifier, SignalStatus signalStatus) { - if (Signals.Any(s => s.Identifier == signalIdentifier)) + if (Signals.Any(s => s.Identifier == signalIdentifier && s.Status != signalStatus)) { Signals.First(s => s.Identifier == signalIdentifier).Status = signalStatus; Logger.LogInformation($"Signal {signalIdentifier} is now {signalStatus}"); @@ -1294,7 +1316,7 @@ public class TradingBot : Bot, ITradingBot var timeOpen = currentTime - position.Open.Date; var maxTimeAllowed = TimeSpan.FromHours((double)Config.MaxPositionTimeHours.Value); - + return timeOpen >= maxTimeAllowed; } @@ -1360,11 +1382,11 @@ public class TradingBot : Bot, ITradingBot // Log the configuration update await LogInformation($"Updating bot configuration. Previous config: " + - $"Balance: {Config.BotTradingBalance}, " + - $"MaxTime: {Config.MaxPositionTimeHours?.ToString() ?? "Disabled"}, " + - $"FlipOnlyProfit: {Config.FlipOnlyWhenInProfit}, " + - $"Cooldown: {Config.CooldownPeriod}, " + - $"MaxLoss: {Config.MaxLossStreak}"); + $"Balance: {Config.BotTradingBalance}, " + + $"MaxTime: {Config.MaxPositionTimeHours?.ToString() ?? "Disabled"}, " + + $"FlipOnlyProfit: {Config.FlipOnlyWhenInProfit}, " + + $"Cooldown: {Config.CooldownPeriod}, " + + $"MaxLoss: {Config.MaxLossStreak}"); // Update the configuration Config = newConfig; @@ -1388,11 +1410,11 @@ public class TradingBot : Bot, ITradingBot } await LogInformation($"Bot configuration updated successfully. New config: " + - $"Balance: {Config.BotTradingBalance}, " + - $"MaxTime: {Config.MaxPositionTimeHours?.ToString() ?? "Disabled"}, " + - $"FlipOnlyProfit: {Config.FlipOnlyWhenInProfit}, " + - $"Cooldown: {Config.CooldownPeriod}, " + - $"MaxLoss: {Config.MaxLossStreak}"); + $"Balance: {Config.BotTradingBalance}, " + + $"MaxTime: {Config.MaxPositionTimeHours?.ToString() ?? "Disabled"}, " + + $"FlipOnlyProfit: {Config.FlipOnlyWhenInProfit}, " + + $"Cooldown: {Config.CooldownPeriod}, " + + $"MaxLoss: {Config.MaxLossStreak}"); // Save the updated configuration as backup if (!Config.IsForBacktest) diff --git a/src/Managing.Application/ManageBot/BotService.cs b/src/Managing.Application/ManageBot/BotService.cs index 24739ca..6e570a0 100644 --- a/src/Managing.Application/ManageBot/BotService.cs +++ b/src/Managing.Application/ManageBot/BotService.cs @@ -146,7 +146,7 @@ namespace Managing.Application.ManageBot CloseEarlyWhenProfitable = scalpingBotData.CloseEarlyWhenProfitable }; - bot = CreateScalpingBot(scalpingConfig); + bot = CreateTradingBot(scalpingConfig); botTask = Task.Run(() => InitBot((ITradingBot)bot, backupBot)); break; @@ -176,7 +176,7 @@ namespace Managing.Application.ManageBot CloseEarlyWhenProfitable = flippingBotData.CloseEarlyWhenProfitable }; - bot = CreateFlippingBot(flippingConfig); + bot = CreateTradingBot(flippingConfig); botTask = Task.Run(() => InitBot((ITradingBot)bot, backupBot)); break; } @@ -282,9 +282,35 @@ namespace Managing.Application.ManageBot return false; } + public ITradingBot CreateTradingBot(TradingBotConfig config) + { + return new TradingBot( + _exchangeService, + _tradingBotLogger, + _tradingService, + _accountService, + _messengerService, + this, + config); + } + + public ITradingBot CreateBacktestTradingBot(TradingBotConfig config) + { + config.IsForBacktest = true; + return new TradingBot( + _exchangeService, + _tradingBotLogger, + _tradingService, + _accountService, + _messengerService, + this, + config); + } + public ITradingBot CreateScalpingBot(TradingBotConfig config) { - return new ScalpingBot( + config.FlipPosition = false; + return new TradingBot( _exchangeService, _tradingBotLogger, _tradingService, @@ -297,7 +323,8 @@ namespace Managing.Application.ManageBot public ITradingBot CreateBacktestScalpingBot(TradingBotConfig config) { config.IsForBacktest = true; - return new ScalpingBot( + config.FlipPosition = false; + return new TradingBot( _exchangeService, _tradingBotLogger, _tradingService, @@ -309,7 +336,8 @@ namespace Managing.Application.ManageBot public ITradingBot CreateFlippingBot(TradingBotConfig config) { - return new FlippingBot( + config.FlipPosition = true; + return new TradingBot( _exchangeService, _tradingBotLogger, _tradingService, @@ -322,7 +350,8 @@ namespace Managing.Application.ManageBot public ITradingBot CreateBacktestFlippingBot(TradingBotConfig config) { config.IsForBacktest = true; - return new FlippingBot( + config.FlipPosition = true; + return new TradingBot( _exchangeService, _tradingBotLogger, _tradingService, diff --git a/src/Managing.Application/ManageBot/StartBotCommandHandler.cs b/src/Managing.Application/ManageBot/StartBotCommandHandler.cs index f8b656b..dfcdbe8 100644 --- a/src/Managing.Application/ManageBot/StartBotCommandHandler.cs +++ b/src/Managing.Application/ManageBot/StartBotCommandHandler.cs @@ -73,7 +73,7 @@ namespace Managing.Application.ManageBot MaxLossStreak = request.Config.MaxLossStreak, MaxPositionTimeHours = request.Config.MaxPositionTimeHours, // Properly handle nullable value FlipOnlyWhenInProfit = request.Config.FlipOnlyWhenInProfit, - FlipPosition = request.Config.FlipPosition, + FlipPosition = request.Config.BotType == BotType.FlippingBot, // Set FlipPosition based on BotType Name = request.Config.Name ?? request.Name, CloseEarlyWhenProfitable = request.Config.CloseEarlyWhenProfitable }; @@ -87,24 +87,15 @@ namespace Managing.Application.ManageBot return bot.GetStatus(); case BotType.ScalpingBot: - var sBot = _botFactory.CreateScalpingBot(configToUse); - sBot.User = request.User; - - // Log the configuration being used - await LogBotConfigurationAsync(sBot, "ScalpingBot created"); - - _botService.AddTradingBotToCache(sBot); - return sBot.GetStatus(); - case BotType.FlippingBot: - var fBot = _botFactory.CreateFlippingBot(configToUse); - fBot.User = request.User; + var tradingBot = _botFactory.CreateTradingBot(configToUse); + tradingBot.User = request.User; // Log the configuration being used - await LogBotConfigurationAsync(fBot, "FlippingBot created"); + await LogBotConfigurationAsync(tradingBot, $"{configToUse.BotType} created"); - _botService.AddTradingBotToCache(fBot); - return fBot.GetStatus(); + _botService.AddTradingBotToCache(tradingBot); + return tradingBot.GetStatus(); } return botStatus.ToString(); @@ -127,6 +118,7 @@ namespace Managing.Application.ManageBot $"Balance: {config.BotTradingBalance}, " + $"MaxTime: {config.MaxPositionTimeHours?.ToString() ?? "Disabled"}, " + $"FlipOnlyProfit: {config.FlipOnlyWhenInProfit}, " + + $"FlipPosition: {config.FlipPosition}, " + $"Cooldown: {config.CooldownPeriod}, " + $"MaxLoss: {config.MaxLossStreak}"; diff --git a/src/Managing.Bootstrap/WorkersBootstrap.cs b/src/Managing.Bootstrap/WorkersBootstrap.cs index cd9dea7..f99feaa 100644 --- a/src/Managing.Bootstrap/WorkersBootstrap.cs +++ b/src/Managing.Bootstrap/WorkersBootstrap.cs @@ -101,6 +101,7 @@ public static class WorkersBootstrap // Repositories services.AddTransient(); + services.AddTransient(); services.AddTransient(); services.AddTransient(); services.AddTransient();