diff --git a/src/Managing.Api/Controllers/BotController.cs b/src/Managing.Api/Controllers/BotController.cs
index d4dbfb67..0dc0ba70 100644
--- a/src/Managing.Api/Controllers/BotController.cs
+++ b/src/Managing.Api/Controllers/BotController.cs
@@ -139,6 +139,11 @@ public class BotController : BaseController
await NotifyBotSubscriberAsync();
return Ok(result);
}
+ catch (InvalidOperationException ex) when (ex.Message.Contains("already have a strategy"))
+ {
+ // Return 400 for validation errors about existing strategies on same ticker
+ return BadRequest(ex.Message);
+ }
catch (Exception ex)
{
_logger.LogError(ex, "Error starting bot");
@@ -168,6 +173,11 @@ public class BotController : BaseController
await NotifyBotSubscriberAsync();
return Ok(result);
}
+ catch (InvalidOperationException ex) when (ex.Message.Contains("already have a strategy"))
+ {
+ // Return 400 for validation errors about existing strategies on same ticker
+ return BadRequest(ex.Message);
+ }
catch (Exception ex)
{
_logger.LogError(ex, "Error starting copy trading bot");
@@ -192,6 +202,11 @@ public class BotController : BaseController
return Ok(result);
}
+ catch (InvalidOperationException ex) when (ex.Message.Contains("already have a strategy"))
+ {
+ // Return 400 for validation errors about existing strategies on same ticker
+ return BadRequest(ex.Message);
+ }
catch (Exception ex)
{
_logger.LogError(ex, "Error saving bot");
@@ -319,6 +334,11 @@ public class BotController : BaseController
return Ok(result);
}
+ catch (InvalidOperationException ex) when (ex.Message.Contains("already have another strategy"))
+ {
+ // Return 400 for validation errors about existing strategies on same ticker
+ return BadRequest(ex.Message);
+ }
catch (Exception ex)
{
_logger.LogError(ex, "Error restarting bot");
diff --git a/src/Managing.Application/Abstractions/IBotService.cs b/src/Managing.Application/Abstractions/IBotService.cs
index 2ebb717b..7262e611 100644
--- a/src/Managing.Application/Abstractions/IBotService.cs
+++ b/src/Managing.Application/Abstractions/IBotService.cs
@@ -64,4 +64,12 @@ public interface IBotService
/// The account to check balances for
/// Balance check result
Task CheckAccountBalancesAsync(Account account);
+
+ ///
+ /// Checks if the user already has a bot (Running or Saved) on the specified ticker
+ ///
+ /// The user ID
+ /// The ticker to check
+ /// True if the user has a bot on this ticker, false otherwise
+ Task HasUserBotOnTickerAsync(int userId, Ticker ticker);
}
\ No newline at end of file
diff --git a/src/Managing.Application/ManageBot/BotService.cs b/src/Managing.Application/ManageBot/BotService.cs
index a78094df..d4bd3294 100644
--- a/src/Managing.Application/ManageBot/BotService.cs
+++ b/src/Managing.Application/ManageBot/BotService.cs
@@ -524,5 +524,13 @@ namespace Managing.Application.ManageBot
};
}
}
+
+ public async Task HasUserBotOnTickerAsync(int userId, Ticker ticker)
+ {
+ var userBots = await _botRepository.GetBotsByUserIdAsync(userId);
+ return userBots.Any(bot =>
+ bot.Ticker == ticker &&
+ (bot.Status == BotStatus.Running || bot.Status == BotStatus.Saved));
+ }
}
}
\ No newline at end of file
diff --git a/src/Managing.Application/ManageBot/RestartBotCommandHandler.cs b/src/Managing.Application/ManageBot/RestartBotCommandHandler.cs
index baf5fe99..4aa96307 100644
--- a/src/Managing.Application/ManageBot/RestartBotCommandHandler.cs
+++ b/src/Managing.Application/ManageBot/RestartBotCommandHandler.cs
@@ -16,6 +16,27 @@ namespace Managing.Application.ManageBot
public async Task Handle(RestartBotCommand request, CancellationToken cancellationToken)
{
+ // Get the bot being restarted to check its ticker
+ var bot = await _botService.GetBotByIdentifier(request.Identifier);
+ if (bot == null)
+ {
+ throw new ArgumentException($"Bot with identifier {request.Identifier} not found");
+ }
+
+ // Check if user already has another bot on this ticker (excluding the one being restarted)
+ var userBots = await _botService.GetBotsByUser(bot.User.Id);
+ var hasAnotherBotOnSameTicker = userBots.Any(b =>
+ b.Identifier != request.Identifier && // Exclude the bot being restarted
+ b.Ticker == bot.Ticker &&
+ (b.Status == BotStatus.Running || b.Status == BotStatus.Saved));
+
+ if (hasAnotherBotOnSameTicker)
+ {
+ throw new InvalidOperationException(
+ $"You already have another strategy running or saved on ticker {bot.Ticker}. " +
+ "You cannot restart this bot while you have multiple strategies on the same ticker.");
+ }
+
return await _botService.RestartBot(request.Identifier);
}
}
diff --git a/src/Managing.Application/ManageBot/StartBotCommandHandler.cs b/src/Managing.Application/ManageBot/StartBotCommandHandler.cs
index 63484fb4..ac26d199 100644
--- a/src/Managing.Application/ManageBot/StartBotCommandHandler.cs
+++ b/src/Managing.Application/ManageBot/StartBotCommandHandler.cs
@@ -43,6 +43,15 @@ namespace Managing.Application.ManageBot
$"Bot trading balance must be greater than {Constants.GMX.Config.MinimumPositionAmount}");
}
+ // Check if user already has a bot on this ticker
+ var hasExistingBotOnTicker = await _botService.HasUserBotOnTickerAsync(request.User.Id, request.Config.Ticker);
+ if (hasExistingBotOnTicker)
+ {
+ throw new InvalidOperationException(
+ $"You already have a strategy running or saved on ticker {request.Config.Ticker}. " +
+ "You cannot create multiple strategies on the same ticker.");
+ }
+
Account account;
if (string.IsNullOrEmpty(request.Config.AccountName))
{
diff --git a/src/Managing.Application/ManageBot/StartCopyTradingCommandHandler.cs b/src/Managing.Application/ManageBot/StartCopyTradingCommandHandler.cs
index ddb893bb..2f8446e3 100644
--- a/src/Managing.Application/ManageBot/StartCopyTradingCommandHandler.cs
+++ b/src/Managing.Application/ManageBot/StartCopyTradingCommandHandler.cs
@@ -72,6 +72,15 @@ namespace Managing.Application.ManageBot
throw new InvalidOperationException($"Could not retrieve configuration for master bot {request.MasterBotIdentifier}");
}
+ // Check if user already has a bot on this ticker (same as master bot)
+ var hasExistingBotOnTicker = await _botService.HasUserBotOnTickerAsync(request.User.Id, masterConfig.Ticker);
+ if (hasExistingBotOnTicker)
+ {
+ throw new InvalidOperationException(
+ $"You already have a strategy running or saved on ticker {masterConfig.Ticker}. " +
+ "You cannot create multiple strategies on the same ticker.");
+ }
+
// Get account information from the requesting user's accounts
var userAccounts = await _accountService.GetAccountsByUserAsync(request.User, true, true);
var firstAccount = userAccounts.FirstOrDefault();