diff --git a/src/Managing.Api/Controllers/DataController.cs b/src/Managing.Api/Controllers/DataController.cs index 92199fb..4e4b6dd 100644 --- a/src/Managing.Api/Controllers/DataController.cs +++ b/src/Managing.Api/Controllers/DataController.cs @@ -400,6 +400,49 @@ public class DataController : ControllerBase return Ok(topStrategiesByRoi); } + /// + /// Retrieves the top 3 performing agents based on PnL. + /// + /// A containing the top performing agents by PnL. + [HttpGet("GetTopAgentsByPnL")] + public async Task> GetTopAgentsByPnL() + { + try + { + // Get all agent summaries + var allAgentSummaries = await _mediator.Send(new GetAllAgentSummariesCommand("Total")); + + // Filter agents with valid PnL data and order by PnL + var agentsWithPnL = allAgentSummaries + .Where(agent => agent.TotalPnL != 0) // Only include agents with actual PnL + .OrderByDescending(agent => agent.TotalPnL) + .Take(3) + .ToList(); + + // Map to view model + var topAgentsByPnL = new TopAgentsByPnLViewModel + { + TopAgentsByPnL = agentsWithPnL + .Select(agent => new AgentPerformance + { + AgentName = agent.AgentName, + PnL = agent.TotalPnL, + TotalROI = agent.TotalROI, + TotalVolume = agent.TotalVolume, + ActiveStrategiesCount = agent.ActiveStrategiesCount, + TotalBalance = agent.TotalBalance + }) + .ToList() + }; + + return Ok(topAgentsByPnL); + } + catch (Exception ex) + { + return StatusCode(500, $"Error retrieving top agents by PnL: {ex.Message}"); + } + } + /// /// Retrieves list of the active strategies for a user with detailed information /// diff --git a/src/Managing.Api/Models/Responses/TopStrategiesViewModel.cs b/src/Managing.Api/Models/Responses/TopStrategiesViewModel.cs index 4a9aaf0..10c8541 100644 --- a/src/Managing.Api/Models/Responses/TopStrategiesViewModel.cs +++ b/src/Managing.Api/Models/Responses/TopStrategiesViewModel.cs @@ -65,4 +65,51 @@ namespace Managing.Api.Models.Responses /// public List TopStrategiesByRoi { get; set; } = new List(); } + + /// + /// Represents a high-performing agent with its name and PnL value + /// + public class AgentPerformance + { + /// + /// Name of the agent + /// + public string AgentName { get; set; } + + /// + /// Profit and Loss value of the agent + /// + public decimal PnL { get; set; } + + /// + /// Total ROI percentage of the agent + /// + public decimal TotalROI { get; set; } + + /// + /// Total volume traded by the agent + /// + public decimal TotalVolume { get; set; } + + /// + /// Number of active strategies for this agent + /// + public int ActiveStrategiesCount { get; set; } + + /// + /// Total balance including USDC and open position values + /// + public decimal TotalBalance { get; set; } + } + + /// + /// View model containing the top performing agents by PnL + /// + public class TopAgentsByPnLViewModel + { + /// + /// List of the top performing agents by PnL + /// + public List TopAgentsByPnL { get; set; } = new List(); + } } \ No newline at end of file diff --git a/src/Managing.WebApp/src/generated/ManagingApi.ts b/src/Managing.WebApp/src/generated/ManagingApi.ts index 16030d3..e75e799 100644 --- a/src/Managing.WebApp/src/generated/ManagingApi.ts +++ b/src/Managing.WebApp/src/generated/ManagingApi.ts @@ -1939,6 +1939,41 @@ export class DataClient extends AuthorizedApiBase { return Promise.resolve(null as any); } + data_GetTopAgentsByPnL(): Promise { + let url_ = this.baseUrl + "/Data/GetTopAgentsByPnL"; + url_ = url_.replace(/[?&]$/, ""); + + let options_: RequestInit = { + method: "GET", + headers: { + "Accept": "application/json" + } + }; + + return this.transformOptions(options_).then(transformedOptions_ => { + return this.http.fetch(url_, transformedOptions_); + }).then((_response: Response) => { + return this.processData_GetTopAgentsByPnL(_response); + }); + } + + protected processData_GetTopAgentsByPnL(response: Response): Promise { + const status = response.status; + let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); }; + if (status === 200) { + return response.text().then((_responseText) => { + let result200: any = null; + result200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver) as TopAgentsByPnLViewModel; + return result200; + }); + } else if (status !== 200 && status !== 204) { + return response.text().then((_responseText) => { + return throwException("An unexpected server error occurred.", status, _responseText, _headers); + }); + } + return Promise.resolve(null as any); + } + data_GetUserStrategies(agentName: string | null | undefined): Promise { let url_ = this.baseUrl + "/Data/GetUserStrategies?"; if (agentName !== undefined && agentName !== null) @@ -4602,6 +4637,19 @@ export interface StrategyRoiPerformance { volume?: number; } +export interface TopAgentsByPnLViewModel { + topAgentsByPnL?: AgentPerformance[] | null; +} + +export interface AgentPerformance { + agentName?: string | null; + pnL?: number; + totalROI?: number; + totalVolume?: number; + activeStrategiesCount?: number; + totalBalance?: number; +} + export interface UserStrategyDetailsViewModel { name?: string | null; state?: BotStatus; diff --git a/src/Managing.WebApp/src/generated/ManagingApiTypes.ts b/src/Managing.WebApp/src/generated/ManagingApiTypes.ts index c4bb9ba..7cc5fca 100644 --- a/src/Managing.WebApp/src/generated/ManagingApiTypes.ts +++ b/src/Managing.WebApp/src/generated/ManagingApiTypes.ts @@ -957,6 +957,19 @@ export interface StrategyRoiPerformance { volume?: number; } +export interface TopAgentsByPnLViewModel { + topAgentsByPnL?: AgentPerformance[] | null; +} + +export interface AgentPerformance { + agentName?: string | null; + pnL?: number; + totalROI?: number; + totalVolume?: number; + activeStrategiesCount?: number; + totalBalance?: number; +} + export interface UserStrategyDetailsViewModel { name?: string | null; state?: BotStatus; diff --git a/src/Managing.WebApp/src/pages/dashboardPage/platformSummary.tsx b/src/Managing.WebApp/src/pages/dashboardPage/platformSummary.tsx index 9f58236..8d82d13 100644 --- a/src/Managing.WebApp/src/pages/dashboardPage/platformSummary.tsx +++ b/src/Managing.WebApp/src/pages/dashboardPage/platformSummary.tsx @@ -24,6 +24,7 @@ function PlatformSummary({index}: { index: number }) { const platformData = data?.platform const topStrategies = data?.topStrategies const topStrategiesByRoi = data?.topStrategiesByRoi + const topAgentsByPnL = data?.topAgentsByPnL const formatCurrency = (value: number) => { if (value >= 1000000) { @@ -210,6 +211,46 @@ function PlatformSummary({index}: { index: number }) { )} + + {/* Top 3 Agents by PnL */} + + + 👥 + Top 3 Agents by PnL + + + {topAgentsByPnL?.topAgentsByPnL?.slice(0, 3).map((agent, index) => ( + + + + + {agent.agentName?.charAt(0) || 'A'} + + + + + {agent.agentName || '[Agent Name]'} + + + {agent.activeStrategiesCount || 0} strategies + + + + + = 0 ? 'text-green-500' : 'text-red-500'}`}> + {(agent.pnL || 0) >= 0 ? '+' : ''}{formatCurrency(agent.pnL || 0)} + + + {(agent.totalROI || 0).toFixed(2)}% ROI + + + + )) || ( + No agent data available + )} + + {/* Platform Summary Stats */} diff --git a/src/Managing.WebApp/src/services/platformService.ts b/src/Managing.WebApp/src/services/platformService.ts index 19df2cb..77e754f 100644 --- a/src/Managing.WebApp/src/services/platformService.ts +++ b/src/Managing.WebApp/src/services/platformService.ts @@ -2,28 +2,32 @@ import { DataClient, type PlatformSummaryViewModel, type TopStrategiesByRoiViewModel, - type TopStrategiesViewModel + type TopStrategiesViewModel, + type TopAgentsByPnLViewModel } from '../generated/ManagingApi' export interface PlatformData { platform: PlatformSummaryViewModel topStrategies: TopStrategiesViewModel topStrategiesByRoi: TopStrategiesByRoiViewModel + topAgentsByPnL: TopAgentsByPnLViewModel } export const fetchPlatformData = async (apiUrl: string): Promise => { const client = new DataClient({}, apiUrl) // Fetch all platform data in parallel - const [platform, topStrategies, topStrategiesByRoi] = await Promise.all([ + const [platform, topStrategies, topStrategiesByRoi, topAgentsByPnL] = await Promise.all([ client.data_GetPlatformSummary(), client.data_GetTopStrategies(), - client.data_GetTopStrategiesByRoi() + client.data_GetTopStrategiesByRoi(), + client.data_GetTopAgentsByPnL() ]) return { platform, topStrategies, - topStrategiesByRoi + topStrategiesByRoi, + topAgentsByPnL } }