Add stats for kaigen

This commit is contained in:
2025-04-24 20:33:13 +07:00
parent c22c925087
commit 86692b60fa
4 changed files with 157 additions and 3 deletions

View File

@@ -1,9 +1,12 @@
using Managing.Application.Abstractions; using Managing.Application.Abstractions;
using Managing.Application.Abstractions.Services; using Managing.Application.Abstractions.Services;
using Managing.Application.Hubs; using Managing.Application.Hubs;
using Managing.Application.ManageBot.Commands;
using Managing.Application.Workers.Abstractions; using Managing.Application.Workers.Abstractions;
using Managing.Api.Models.Responses;
using Managing.Domain.Candles; using Managing.Domain.Candles;
using Managing.Domain.Statistics; using Managing.Domain.Statistics;
using MediatR;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.SignalR; using Microsoft.AspNetCore.SignalR;
@@ -16,7 +19,6 @@ namespace Managing.Api.Controllers;
/// Requires authorization for access. /// Requires authorization for access.
/// </summary> /// </summary>
[ApiController] [ApiController]
[Authorize]
[Route("[controller]")] [Route("[controller]")]
public class DataController : ControllerBase public class DataController : ControllerBase
{ {
@@ -25,6 +27,7 @@ public class DataController : ControllerBase
private readonly ICacheService _cacheService; private readonly ICacheService _cacheService;
private readonly IStatisticService _statisticService; private readonly IStatisticService _statisticService;
private readonly IHubContext<CandleHub> _hubContext; private readonly IHubContext<CandleHub> _hubContext;
private readonly IMediator _mediator;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="DataController"/> class. /// Initializes a new instance of the <see cref="DataController"/> class.
@@ -34,18 +37,21 @@ 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="hubContext">SignalR hub context for real-time communication.</param> /// <param name="hubContext">SignalR hub context for real-time communication.</param>
/// <param name="mediator">Mediator for handling commands and queries.</param>
public DataController( public DataController(
IExchangeService exchangeService, IExchangeService exchangeService,
IAccountService accountService, IAccountService accountService,
ICacheService cacheService, ICacheService cacheService,
IStatisticService statisticService, IStatisticService statisticService,
IHubContext<CandleHub> hubContext) IHubContext<CandleHub> hubContext,
IMediator mediator)
{ {
_exchangeService = exchangeService; _exchangeService = exchangeService;
_accountService = accountService; _accountService = accountService;
_cacheService = cacheService; _cacheService = cacheService;
_statisticService = statisticService; _statisticService = statisticService;
_hubContext = hubContext; _hubContext = hubContext;
_mediator = mediator;
} }
/// <summary> /// <summary>
@@ -72,6 +78,7 @@ public class DataController : ControllerBase
/// Retrieves the latest spotlight overview, using caching to enhance response times. /// Retrieves the latest spotlight overview, using caching to enhance response times.
/// </summary> /// </summary>
/// <returns>A <see cref="SpotlightOverview"/> object containing spotlight data.</returns> /// <returns>A <see cref="SpotlightOverview"/> object containing spotlight data.</returns>
[Authorize]
[HttpGet("Spotlight")] [HttpGet("Spotlight")]
public ActionResult<SpotlightOverview> GetSpotlight() public ActionResult<SpotlightOverview> GetSpotlight()
{ {
@@ -94,10 +101,110 @@ public class DataController : ControllerBase
/// <param name="startDate">The start date for the candle data.</param> /// <param name="startDate">The start date for the candle data.</param>
/// <param name="timeframe">The timeframe for the candle data.</param> /// <param name="timeframe">The timeframe for the candle data.</param>
/// <returns>A list of <see cref="Candle"/> objects.</returns> /// <returns>A list of <see cref="Candle"/> objects.</returns>
[Authorize]
[HttpGet("GetCandles")] [HttpGet("GetCandles")]
public async Task<ActionResult<List<Candle>>> GetCandles(TradingExchanges exchange, Ticker ticker, public async Task<ActionResult<List<Candle>>> GetCandles(TradingExchanges exchange, Ticker ticker,
DateTime startDate, Timeframe timeframe) DateTime startDate, Timeframe timeframe)
{ {
return Ok(await _exchangeService.GetCandlesInflux(exchange, ticker, startDate, timeframe)); return Ok(await _exchangeService.GetCandlesInflux(exchange, ticker, startDate, timeframe));
} }
/// <summary>
/// Retrieves statistics about currently running bots and their change in the last 24 hours.
/// </summary>
/// <returns>A <see cref="StrategiesStatisticsViewModel"/> containing bot statistics.</returns>
[HttpGet("GetStrategiesStatistics")]
public async Task<ActionResult<StrategiesStatisticsViewModel>> GetStrategiesStatistics()
{
const string cacheKey = "StrategiesStatistics";
const string previousCountKey = "PreviousBotsCount";
// Check if the statistics are already cached
var cachedStats = _cacheService.GetValue<StrategiesStatisticsViewModel>(cacheKey);
if (cachedStats != null)
{
return Ok(cachedStats);
}
// Get active bots
var activeBots = await _mediator.Send(new GetActiveBotsCommand());
var currentCount = activeBots.Count;
// Get previous count from cache
var previousCount = _cacheService.GetValue<int>(previousCountKey);
// Calculate change - if no previous value, set current count as the change (all are new)
int change;
if (previousCount == 0)
{
// First time running - assume all bots are new (positive change)
change = currentCount;
}
else
{
// Calculate actual difference between current and previous count
change = currentCount - previousCount;
}
// Create the response
var botsStatistics = new StrategiesStatisticsViewModel
{
TotalStrategiesRunning = currentCount,
ChangeInLast24Hours = change
};
// Store current count for future comparison (with 24 hour expiration)
_cacheService.SaveValue(previousCountKey, currentCount, TimeSpan.FromHours(24));
// Cache the statistics for 5 minutes
_cacheService.SaveValue(cacheKey, botsStatistics, TimeSpan.FromMinutes(5));
return Ok(botsStatistics);
}
/// <summary>
/// Retrieves the top 3 performing strategies based on ROI.
/// </summary>
/// <returns>A <see cref="TopStrategiesViewModel"/> containing the top performing strategies.</returns>
[HttpGet("GetTopStrategies")]
public async Task<ActionResult<TopStrategiesViewModel>> GetTopStrategies()
{
const string cacheKey = "TopStrategies";
// Check if the top strategies are already cached
var cachedStrategies = _cacheService.GetValue<TopStrategiesViewModel>(cacheKey);
if (cachedStrategies != null)
{
return Ok(cachedStrategies);
}
// Get active bots
var activeBots = await _mediator.Send(new GetActiveBotsCommand());
// Calculate PnL for each bot once and store in a list of tuples
var botsWithPnL = activeBots
.Select(bot => new { Bot = bot, PnL = bot.GetProfitAndLoss() })
.OrderByDescending(item => item.PnL)
.Take(3)
.ToList();
// Map to view model
var topStrategies = new TopStrategiesViewModel
{
TopStrategies = botsWithPnL
.Select(item => new StrategyPerformance
{
StrategyName = item.Bot.Name,
PnL = item.PnL
})
.ToList()
};
// Cache the result for 10 minutes
_cacheService.SaveValue(cacheKey, topStrategies, TimeSpan.FromMinutes(10));
return Ok(topStrategies);
}
} }

View File

@@ -0,0 +1,18 @@
namespace Managing.Api.Models.Responses
{
/// <summary>
/// View model representing statistics about active bots
/// </summary>
public class StrategiesStatisticsViewModel
{
/// <summary>
/// Total number of bots currently running
/// </summary>
public int TotalStrategiesRunning { get; set; }
/// <summary>
/// Change in bot count over the last 24 hours
/// </summary>
public int ChangeInLast24Hours { get; set; }
}
}

View File

@@ -0,0 +1,29 @@
namespace Managing.Api.Models.Responses
{
/// <summary>
/// Represents a high-performing strategy with its name and PnL value
/// </summary>
public class StrategyPerformance
{
/// <summary>
/// Name of the strategy bot
/// </summary>
public string StrategyName { get; set; }
/// <summary>
/// Profit and Loss value of the strategy
/// </summary>
public decimal PnL { get; set; }
}
/// <summary>
/// View model containing the top performing strategies by ROI
/// </summary>
public class TopStrategiesViewModel
{
/// <summary>
/// List of the top performing strategies by ROI
/// </summary>
public List<StrategyPerformance> TopStrategies { get; set; } = new List<StrategyPerformance>();
}
}

View File

@@ -15,7 +15,7 @@ test('GMX Position Opening', async (t) => {
2, 2,
50003, 50003,
96001, 96001,
35002 85002
) )
console.log('Position opening result:', result) console.log('Position opening result:', result)
assert.ok(result, 'Position opening result should be defined') assert.ok(result, 'Position opening result should be defined')