Add agent index with pagination

This commit is contained in:
2025-07-30 22:27:01 +07:00
parent 20b0881084
commit 4b0da0e864
10 changed files with 844 additions and 76 deletions

View File

@@ -664,6 +664,198 @@ public class DataController : ControllerBase
return Ok(agentIndex);
}
/// <summary>
/// Retrieves a paginated list of agent summaries for the agent index page
/// </summary>
/// <param name="timeFilter">Time filter to apply (24H, 3D, 1W, 1M, 1Y, Total)</param>
/// <param name="page">Page number (defaults to 1)</param>
/// <param name="pageSize">Number of items per page (defaults to 10, max 100)</param>
/// <param name="sortBy">Field to sort by (TotalPnL, PnLLast24h, TotalROI, ROILast24h, Wins, Losses, AverageWinRate, ActiveStrategiesCount, TotalVolume, VolumeLast24h)</param>
/// <param name="sortOrder">Sort order - "asc" or "desc" (defaults to "desc")</param>
/// <returns>A paginated list of agent summaries sorted by the specified field</returns>
[HttpGet("GetAgentIndexPaginated")]
public async Task<ActionResult<PaginatedAgentIndexResponse>> GetAgentIndexPaginated(
string timeFilter = "Total",
int page = 1,
int pageSize = 10,
string sortBy = "TotalPnL",
string sortOrder = "desc")
{
// Validate time filter
var validTimeFilters = new[] { "24H", "3D", "1W", "1M", "1Y", "Total" };
if (!validTimeFilters.Contains(timeFilter))
{
timeFilter = "Total"; // Default to Total if invalid
}
// Validate pagination parameters
if (page < 1)
{
return BadRequest("Page must be greater than 0");
}
if (pageSize < 1 || pageSize > 100)
{
return BadRequest("Page size must be between 1 and 100");
}
// Validate sort order
if (sortOrder != "asc" && sortOrder != "desc")
{
return BadRequest("Sort order must be 'asc' or 'desc'");
}
// Validate sort by field
var validSortFields = new[] { "TotalPnL", "PnLLast24h", "TotalROI", "ROILast24h", "Wins", "Losses", "AverageWinRate", "ActiveStrategiesCount", "TotalVolume", "VolumeLast24h" };
if (!validSortFields.Contains(sortBy))
{
sortBy = "TotalPnL"; // Default to TotalPnL if invalid
}
string cacheKey = $"AgentIndex_{timeFilter}";
// Check if the agent index is already cached
var cachedIndex = _cacheService.GetValue<AgentIndexViewModel>(cacheKey);
List<AgentSummaryViewModel> allAgentSummaries;
if (cachedIndex != null)
{
allAgentSummaries = cachedIndex.AgentSummaries.ToList();
}
else
{
// Get all agents and their strategies
var agentsWithStrategies = await _mediator.Send(new GetAllAgentsCommand(timeFilter));
allAgentSummaries = new List<AgentSummaryViewModel>();
// Create summaries for each agent
foreach (var agent in agentsWithStrategies)
{
var user = agent.Key;
var strategies = agent.Value;
if (strategies.Count == 0)
{
continue; // Skip agents with no strategies
}
// Combine all positions from all strategies
var allPositions = strategies.SelectMany<ITradingBot, Position>(s => s.Positions).ToList();
// Calculate agent metrics
decimal totalPnL = TradingBox.GetPnLInTimeRange(allPositions, timeFilter);
decimal pnlLast24h = TradingBox.GetPnLInTimeRange(allPositions, "24H");
decimal totalROI = TradingBox.GetROIInTimeRange(allPositions, timeFilter);
decimal roiLast24h = TradingBox.GetROIInTimeRange(allPositions, "24H");
(int wins, int losses) = TradingBox.GetWinLossCountInTimeRange(allPositions, timeFilter);
// Calculate trading volumes
decimal totalVolume = TradingBox.GetTotalVolumeTraded(allPositions);
decimal volumeLast24h = TradingBox.GetLast24HVolumeTraded(allPositions);
// Calculate win rate
int averageWinRate = 0;
if (wins + losses > 0)
{
averageWinRate = (wins * 100) / (wins + losses);
}
// Add to agent summaries
var agentSummary = new AgentSummaryViewModel
{
AgentName = user.AgentName,
TotalPnL = totalPnL,
PnLLast24h = pnlLast24h,
TotalROI = totalROI,
ROILast24h = roiLast24h,
Wins = wins,
Losses = losses,
AverageWinRate = averageWinRate,
ActiveStrategiesCount = strategies.Count,
TotalVolume = totalVolume,
VolumeLast24h = volumeLast24h
};
allAgentSummaries.Add(agentSummary);
}
// Cache the results for 5 minutes
var agentIndex = new AgentIndexViewModel
{
TimeFilter = timeFilter,
AgentSummaries = allAgentSummaries
};
_cacheService.SaveValue(cacheKey, agentIndex, TimeSpan.FromMinutes(5));
}
// Apply sorting
var sortedSummaries = sortBy switch
{
"TotalPnL" => sortOrder == "desc"
? allAgentSummaries.OrderByDescending(a => a.TotalPnL)
: allAgentSummaries.OrderBy(a => a.TotalPnL),
"PnLLast24h" => sortOrder == "desc"
? allAgentSummaries.OrderByDescending(a => a.PnLLast24h)
: allAgentSummaries.OrderBy(a => a.PnLLast24h),
"TotalROI" => sortOrder == "desc"
? allAgentSummaries.OrderByDescending(a => a.TotalROI)
: allAgentSummaries.OrderBy(a => a.TotalROI),
"ROILast24h" => sortOrder == "desc"
? allAgentSummaries.OrderByDescending(a => a.ROILast24h)
: allAgentSummaries.OrderBy(a => a.ROILast24h),
"Wins" => sortOrder == "desc"
? allAgentSummaries.OrderByDescending(a => a.Wins)
: allAgentSummaries.OrderBy(a => a.Wins),
"Losses" => sortOrder == "desc"
? allAgentSummaries.OrderByDescending(a => a.Losses)
: allAgentSummaries.OrderBy(a => a.Losses),
"AverageWinRate" => sortOrder == "desc"
? allAgentSummaries.OrderByDescending(a => a.AverageWinRate)
: allAgentSummaries.OrderBy(a => a.AverageWinRate),
"ActiveStrategiesCount" => sortOrder == "desc"
? allAgentSummaries.OrderByDescending(a => a.ActiveStrategiesCount)
: allAgentSummaries.OrderBy(a => a.ActiveStrategiesCount),
"TotalVolume" => sortOrder == "desc"
? allAgentSummaries.OrderByDescending(a => a.TotalVolume)
: allAgentSummaries.OrderBy(a => a.TotalVolume),
"VolumeLast24h" => sortOrder == "desc"
? allAgentSummaries.OrderByDescending(a => a.VolumeLast24h)
: allAgentSummaries.OrderBy(a => a.VolumeLast24h),
_ => sortOrder == "desc"
? allAgentSummaries.OrderByDescending(a => a.TotalPnL)
: allAgentSummaries.OrderBy(a => a.TotalPnL)
};
var totalCount = allAgentSummaries.Count;
var totalPages = (int)Math.Ceiling(totalCount / (double)pageSize);
// Apply pagination
var paginatedSummaries = sortedSummaries
.Skip((page - 1) * pageSize)
.Take(pageSize)
.ToList();
var response = new PaginatedAgentIndexResponse
{
AgentSummaries = paginatedSummaries,
TotalCount = totalCount,
CurrentPage = page,
PageSize = pageSize,
TotalPages = totalPages,
HasNextPage = page < totalPages,
HasPreviousPage = page > 1,
TimeFilter = timeFilter,
SortBy = sortBy,
SortOrder = sortOrder
};
return Ok(response);
}
/// <summary>
/// Retrieves balance history for a specific agent within a date range
/// </summary>