Enhance DataController and BotService with new configuration and bot name checks
- Added IConfiguration dependency to DataController for environment variable access. - Updated GetPaginatedAgentSummariesCommand to include a flag for filtering profitable agents. - Implemented HasUserBotWithNameAsync method in IBotService and BotService to check for existing bots by name. - Modified StartBotCommandHandler and StartCopyTradingCommandHandler to prevent duplicate bot names during strategy creation.
This commit is contained in:
@@ -17,6 +17,7 @@ using Managing.Domain.Trades;
|
|||||||
using MediatR;
|
using MediatR;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
using static Managing.Common.Enums;
|
using static Managing.Common.Enums;
|
||||||
using DailySnapshot = Managing.Api.Models.Responses.DailySnapshot;
|
using DailySnapshot = Managing.Api.Models.Responses.DailySnapshot;
|
||||||
|
|
||||||
@@ -41,6 +42,7 @@ public class DataController : ControllerBase
|
|||||||
private readonly IGrainFactory _grainFactory;
|
private readonly IGrainFactory _grainFactory;
|
||||||
private readonly IServiceScopeFactory _serviceScopeFactory;
|
private readonly IServiceScopeFactory _serviceScopeFactory;
|
||||||
private readonly IBotService _botService;
|
private readonly IBotService _botService;
|
||||||
|
private readonly IConfiguration _configuration;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="DataController"/> class.
|
/// Initializes a new instance of the <see cref="DataController"/> class.
|
||||||
@@ -50,12 +52,12 @@ public class DataController : ControllerBase
|
|||||||
/// <param name="cacheService">Service for caching data.</param>
|
/// <param name="cacheService">Service for caching data.</param>
|
||||||
/// <param name="statisticService">Service for statistical analysis.</param>
|
/// <param name="statisticService">Service for statistical analysis.</param>
|
||||||
/// <param name="agentService">Service for agents</param>
|
/// <param name="agentService">Service for agents</param>
|
||||||
/// <param name="hubContext">SignalR hub context for real-time communication.</param>
|
|
||||||
/// <param name="mediator">Mediator for handling commands and queries.</param>
|
/// <param name="mediator">Mediator for handling commands and queries.</param>
|
||||||
/// <param name="tradingService">Service for trading operations.</param>
|
/// <param name="tradingService">Service for trading operations.</param>
|
||||||
/// <param name="grainFactory">Orleans grain factory for accessing grains.</param>
|
/// <param name="grainFactory">Orleans grain factory for accessing grains.</param>
|
||||||
/// <param name="serviceScopeFactory">Service scope factory for creating scoped services.</param>
|
/// <param name="serviceScopeFactory">Service scope factory for creating scoped services.</param>
|
||||||
/// <param name="botService">Service for bot operations.</param>
|
/// <param name="botService">Service for bot operations.</param>
|
||||||
|
/// <param name="configuration">Configuration for accessing environment variables.</param>
|
||||||
public DataController(
|
public DataController(
|
||||||
IExchangeService exchangeService,
|
IExchangeService exchangeService,
|
||||||
IAccountService accountService,
|
IAccountService accountService,
|
||||||
@@ -66,7 +68,8 @@ public class DataController : ControllerBase
|
|||||||
ITradingService tradingService,
|
ITradingService tradingService,
|
||||||
IGrainFactory grainFactory,
|
IGrainFactory grainFactory,
|
||||||
IServiceScopeFactory serviceScopeFactory,
|
IServiceScopeFactory serviceScopeFactory,
|
||||||
IBotService botService)
|
IBotService botService,
|
||||||
|
IConfiguration configuration)
|
||||||
{
|
{
|
||||||
_exchangeService = exchangeService;
|
_exchangeService = exchangeService;
|
||||||
_accountService = accountService;
|
_accountService = accountService;
|
||||||
@@ -78,6 +81,7 @@ public class DataController : ControllerBase
|
|||||||
_grainFactory = grainFactory;
|
_grainFactory = grainFactory;
|
||||||
_serviceScopeFactory = serviceScopeFactory;
|
_serviceScopeFactory = serviceScopeFactory;
|
||||||
_botService = botService;
|
_botService = botService;
|
||||||
|
_configuration = configuration;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -706,8 +710,11 @@ public class DataController : ControllerBase
|
|||||||
.ToList();
|
.ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check environment variable for filtering profitable agents only
|
||||||
|
var showOnlyProfitableAgent = _configuration.GetValue<bool>("showOnlyProfitableAgent", false);
|
||||||
|
|
||||||
// Get paginated results from database
|
// Get paginated results from database
|
||||||
var command = new GetPaginatedAgentSummariesCommand(page, pageSize, sortBy, sortOrder, agentNamesList);
|
var command = new GetPaginatedAgentSummariesCommand(page, pageSize, sortBy, sortOrder, agentNamesList, showOnlyProfitableAgent);
|
||||||
var result = await _mediator.Send(command);
|
var result = await _mediator.Send(command);
|
||||||
var agentSummaries = result.Results;
|
var agentSummaries = result.Results;
|
||||||
var totalCount = result.TotalCount;
|
var totalCount = result.TotalCount;
|
||||||
|
|||||||
@@ -20,13 +20,15 @@ public interface IAgentSummaryRepository
|
|||||||
/// <param name="sortBy">Field to sort by</param>
|
/// <param name="sortBy">Field to sort by</param>
|
||||||
/// <param name="sortOrder">Sort order (asc or desc)</param>
|
/// <param name="sortOrder">Sort order (asc or desc)</param>
|
||||||
/// <param name="agentNames">Optional list of agent names to filter by</param>
|
/// <param name="agentNames">Optional list of agent names to filter by</param>
|
||||||
|
/// <param name="showOnlyProfitableAgent">Whether to show only agents with ROI > 0</param>
|
||||||
/// <returns>Tuple containing the paginated results and total count</returns>
|
/// <returns>Tuple containing the paginated results and total count</returns>
|
||||||
Task<(IEnumerable<AgentSummary> Results, int TotalCount)> GetPaginatedAsync(
|
Task<(IEnumerable<AgentSummary> Results, int TotalCount)> GetPaginatedAsync(
|
||||||
int page,
|
int page,
|
||||||
int pageSize,
|
int pageSize,
|
||||||
SortableFields sortBy,
|
SortableFields sortBy,
|
||||||
string sortOrder,
|
string sortOrder,
|
||||||
IEnumerable<string>? agentNames = null);
|
IEnumerable<string>? agentNames = null,
|
||||||
|
bool showOnlyProfitableAgent = false);
|
||||||
Task<IEnumerable<AgentSummary>> GetAllAgentWithRunningBots();
|
Task<IEnumerable<AgentSummary>> GetAllAgentWithRunningBots();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -73,4 +73,12 @@ public interface IBotService
|
|||||||
/// <param name="ticker">The ticker to check</param>
|
/// <param name="ticker">The ticker to check</param>
|
||||||
/// <returns>True if the user has a bot on this ticker, false otherwise</returns>
|
/// <returns>True if the user has a bot on this ticker, false otherwise</returns>
|
||||||
Task<bool> HasUserBotOnTickerAsync(int userId, Ticker ticker);
|
Task<bool> HasUserBotOnTickerAsync(int userId, Ticker ticker);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks if the user already has a bot (Running or Saved) with the specified name
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="userId">The user ID</param>
|
||||||
|
/// <param name="name">The bot name to check</param>
|
||||||
|
/// <returns>True if the user has a bot with this name, false otherwise</returns>
|
||||||
|
Task<bool> HasUserBotWithNameAsync(int userId, string name);
|
||||||
}
|
}
|
||||||
@@ -559,5 +559,13 @@ namespace Managing.Application.ManageBot
|
|||||||
bot.Ticker == ticker &&
|
bot.Ticker == ticker &&
|
||||||
(bot.Status == BotStatus.Running || bot.Status == BotStatus.Saved));
|
(bot.Status == BotStatus.Running || bot.Status == BotStatus.Saved));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<bool> HasUserBotWithNameAsync(int userId, string name)
|
||||||
|
{
|
||||||
|
var userBots = await _botRepository.GetBotsByUserIdAsync(userId);
|
||||||
|
return userBots.Any(bot =>
|
||||||
|
bot.Name.Equals(name, StringComparison.OrdinalIgnoreCase) &&
|
||||||
|
(bot.Status == BotStatus.Running || bot.Status == BotStatus.Saved));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -34,18 +34,25 @@ namespace Managing.Application.ManageBot.Commands
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public IEnumerable<string>? AgentNames { get; }
|
public IEnumerable<string>? AgentNames { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether to show only profitable agents (ROI > 0)
|
||||||
|
/// </summary>
|
||||||
|
public bool ShowOnlyProfitableAgent { get; }
|
||||||
|
|
||||||
public GetPaginatedAgentSummariesCommand(
|
public GetPaginatedAgentSummariesCommand(
|
||||||
int page = 1,
|
int page = 1,
|
||||||
int pageSize = 10,
|
int pageSize = 10,
|
||||||
SortableFields sortBy = SortableFields.NetPnL,
|
SortableFields sortBy = SortableFields.NetPnL,
|
||||||
string sortOrder = "desc",
|
string sortOrder = "desc",
|
||||||
IEnumerable<string>? agentNames = null)
|
IEnumerable<string>? agentNames = null,
|
||||||
|
bool showOnlyProfitableAgent = false)
|
||||||
{
|
{
|
||||||
Page = page;
|
Page = page;
|
||||||
PageSize = pageSize;
|
PageSize = pageSize;
|
||||||
SortBy = sortBy;
|
SortBy = sortBy;
|
||||||
SortOrder = sortOrder;
|
SortOrder = sortOrder;
|
||||||
AgentNames = agentNames;
|
AgentNames = agentNames;
|
||||||
|
ShowOnlyProfitableAgent = showOnlyProfitableAgent;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -27,7 +27,8 @@ namespace Managing.Application.ManageBot
|
|||||||
request.PageSize,
|
request.PageSize,
|
||||||
request.SortBy,
|
request.SortBy,
|
||||||
request.SortOrder,
|
request.SortOrder,
|
||||||
request.AgentNames);
|
request.AgentNames,
|
||||||
|
request.ShowOnlyProfitableAgent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -54,6 +54,15 @@ namespace Managing.Application.ManageBot
|
|||||||
"You cannot create multiple strategies on the same ticker.");
|
"You cannot create multiple strategies on the same ticker.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if user already has a bot with this name
|
||||||
|
var hasExistingBotWithName = await _botService.HasUserBotWithNameAsync(request.User.Id, request.Config.Name);
|
||||||
|
if (hasExistingBotWithName)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException(
|
||||||
|
$"You already have a strategy running or saved with the name '{request.Config.Name}'. " +
|
||||||
|
"You cannot create multiple strategies with the same name.");
|
||||||
|
}
|
||||||
|
|
||||||
Account account;
|
Account account;
|
||||||
if (string.IsNullOrEmpty(request.Config.AccountName))
|
if (string.IsNullOrEmpty(request.Config.AccountName))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -95,6 +95,15 @@ namespace Managing.Application.ManageBot
|
|||||||
"You cannot create multiple strategies on the same ticker.");
|
"You cannot create multiple strategies on the same ticker.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if user already has a bot with the same name as the master bot
|
||||||
|
var hasExistingBotWithName = await _botService.HasUserBotWithNameAsync(request.User.Id, masterConfig.Name);
|
||||||
|
if (hasExistingBotWithName)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException(
|
||||||
|
$"You already have a strategy running or saved with the name '{masterConfig.Name}'. " +
|
||||||
|
"You cannot create multiple strategies with the same name.");
|
||||||
|
}
|
||||||
|
|
||||||
// Get account information from the requesting user's accounts
|
// Get account information from the requesting user's accounts
|
||||||
var userAccounts = await _accountService.GetAccountsByUserAsync(request.User, true, true);
|
var userAccounts = await _accountService.GetAccountsByUserAsync(request.User, true, true);
|
||||||
var firstAccount = userAccounts.FirstOrDefault();
|
var firstAccount = userAccounts.FirstOrDefault();
|
||||||
|
|||||||
@@ -170,7 +170,8 @@ public class AgentSummaryRepository : IAgentSummaryRepository
|
|||||||
int pageSize,
|
int pageSize,
|
||||||
SortableFields sortBy,
|
SortableFields sortBy,
|
||||||
string sortOrder,
|
string sortOrder,
|
||||||
IEnumerable<string>? agentNames = null)
|
IEnumerable<string>? agentNames = null,
|
||||||
|
bool showOnlyProfitableAgent = false)
|
||||||
{
|
{
|
||||||
// Start with base query
|
// Start with base query
|
||||||
var query = _context.AgentSummaries.Include(a => a.User).AsQueryable();
|
var query = _context.AgentSummaries.Include(a => a.User).AsQueryable();
|
||||||
@@ -181,6 +182,12 @@ public class AgentSummaryRepository : IAgentSummaryRepository
|
|||||||
query = query.Where(a => agentNames.Contains(a.AgentName));
|
query = query.Where(a => agentNames.Contains(a.AgentName));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Apply profitable agent filtering if specified
|
||||||
|
if (showOnlyProfitableAgent)
|
||||||
|
{
|
||||||
|
query = query.Where(a => a.TotalROI > 0);
|
||||||
|
}
|
||||||
|
|
||||||
// Get total count before applying pagination
|
// Get total count before applying pagination
|
||||||
var totalCount = await query.CountAsync();
|
var totalCount = await query.CountAsync();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user