Add stats for kaigen

This commit is contained in:
2025-04-24 22:40:10 +07:00
parent 86692b60fa
commit 1d14d31af2
13 changed files with 483 additions and 8 deletions

View File

@@ -4,7 +4,9 @@ using Managing.Application.Hubs;
using Managing.Application.ManageBot.Commands;
using Managing.Application.Workers.Abstractions;
using Managing.Api.Models.Responses;
using Managing.Domain.Bots;
using Managing.Domain.Candles;
using Managing.Domain.Shared.Helpers;
using Managing.Domain.Statistics;
using MediatR;
using Microsoft.AspNetCore.Authorization;
@@ -171,25 +173,25 @@ public class DataController : ControllerBase
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
{
@@ -201,10 +203,130 @@ public class DataController : ControllerBase
})
.ToList()
};
// Cache the result for 10 minutes
_cacheService.SaveValue(cacheKey, topStrategies, TimeSpan.FromMinutes(10));
return Ok(topStrategies);
}
/// <summary>
/// Retrieves list of the active strategies for a user with detailed information
/// </summary>
/// <param name="agentName">The agentName to retrieve strategies for</param>
/// <returns>A list of detailed strategy information</returns>
[HttpGet("GetUserStrategies")]
public async Task<ActionResult<List<UserStrategyDetailsViewModel>>> GetUserStrategies(string agentName)
{
string cacheKey = $"UserStrategies_{agentName}";
// Check if the user strategy details are already cached
var cachedDetails = _cacheService.GetValue<List<UserStrategyDetailsViewModel>>(cacheKey);
if (cachedDetails != null && cachedDetails.Count > 0)
{
return Ok(cachedDetails);
}
// Get all strategies for the specified user
var userStrategies = await _mediator.Send(new GetUserStrategiesCommand(agentName));
// Convert to detailed view model with additional information
var result = userStrategies.Select(strategy => MapStrategyToViewModel(strategy)).ToList();
// Cache the results for 5 minutes
_cacheService.SaveValue(cacheKey, result, TimeSpan.FromMinutes(5));
return Ok(result);
}
/// <summary>
/// Retrieves a specific strategy for a user by strategy name
/// </summary>
/// <param name="agentName">The agent/user name to retrieve the strategy for</param>
/// <param name="strategyName">The name of the strategy to retrieve</param>
/// <returns>Detailed information about the requested strategy</returns>
[HttpGet("GetUserStrategy")]
public async Task<ActionResult<UserStrategyDetailsViewModel>> GetUserStrategy(string agentName, string strategyName)
{
string cacheKey = $"UserStrategy_{agentName}_{strategyName}";
// Check if the user strategy details are already cached
var cachedDetails = _cacheService.GetValue<UserStrategyDetailsViewModel>(cacheKey);
if (cachedDetails != null)
{
return Ok(cachedDetails);
}
// Get the specific strategy for the user
var strategy = await _mediator.Send(new GetUserStrategyCommand(agentName, strategyName));
if (strategy == null)
{
return NotFound($"Strategy '{strategyName}' not found for user '{agentName}'");
}
// Map the strategy to a view model using the shared method
var result = MapStrategyToViewModel(strategy);
// Cache the results for 5 minutes
_cacheService.SaveValue(cacheKey, result, TimeSpan.FromMinutes(5));
return Ok(result);
}
/// <summary>
/// Maps a trading bot to a strategy view model with detailed statistics
/// </summary>
/// <param name="strategy">The trading bot to map</param>
/// <returns>A view model with detailed strategy information</returns>
private UserStrategyDetailsViewModel MapStrategyToViewModel(ITradingBot strategy)
{
// Get the runtime directly from the bot
TimeSpan runtimeSpan = strategy.GetRuntime();
// Get the startup time from the bot's internal property
// If bot is not running, we use MinValue as a placeholder
DateTime startupTime = DateTime.MinValue;
if (strategy is Bot bot && bot.StartupTime != DateTime.MinValue)
{
startupTime = bot.StartupTime;
}
// Calculate ROI percentage based on PnL relative to account value
decimal pnl = strategy.GetProfitAndLoss();
// If we had initial investment amount, we could calculate ROI like:
decimal initialInvestment = 1000; // Example placeholder, ideally should come from the account
decimal roi = pnl != 0 ? (pnl / initialInvestment) * 100 : 0;
// Calculate volume statistics
decimal totalVolume = TradingBox.GetTotalVolumeTraded(strategy.Positions);
decimal volumeLast24h = TradingBox.GetLast24HVolumeTraded(strategy.Positions);
// Calculate win/loss statistics
(int wins, int losses) = TradingBox.GetWinLossCount(strategy.Positions);
// Calculate ROI for last 24h
decimal roiLast24h = TradingBox.GetLast24HROI(strategy.Positions);
return new UserStrategyDetailsViewModel
{
Name = strategy.Name,
StrategyName = strategy.ScenarioName,
State = strategy.GetStatus() == BotStatus.Up.ToString() ? "RUNNING" :
strategy.GetStatus() == BotStatus.Down.ToString() ? "STOPPED" : "UNUSED",
PnL = pnl,
ROIPercentage = roi,
ROILast24H = roiLast24h,
Runtime = startupTime,
WinRate = strategy.GetWinRate(),
TotalVolumeTraded = totalVolume,
VolumeLast24H = volumeLast24h,
Wins = wins,
Losses = losses,
Positions = strategy.Positions.OrderByDescending(p => p.Date).ToList() // Include sorted positions with most recent first
};
}
}

View File

@@ -0,0 +1,76 @@
using Managing.Domain.Trades;
using static Managing.Common.Enums;
namespace Managing.Api.Models.Responses
{
/// <summary>
/// Detailed information about a user's deployed strategy
/// </summary>
public class UserStrategyDetailsViewModel
{
/// <summary>
/// Name of the deployed strategy
/// </summary>
public string Name { get; set; }
/// <summary>
/// Strategy identifier
/// </summary>
public string StrategyName { get; set; }
/// <summary>
/// Current state of the strategy (RUNNING, STOPPED, UNUSED)
/// </summary>
public string State { get; set; }
/// <summary>
/// Total profit or loss generated by the strategy in USD
/// </summary>
public decimal PnL { get; set; }
/// <summary>
/// Return on investment percentage
/// </summary>
public decimal ROIPercentage { get; set; }
/// <summary>
/// Return on investment percentage in the last 24 hours
/// </summary>
public decimal ROILast24H { get; set; }
/// <summary>
/// Date and time when the strategy was started
/// </summary>
public DateTime Runtime { get; set; }
/// <summary>
/// Average percentage of successful trades
/// </summary>
public int WinRate { get; set; }
/// <summary>
/// Total trading volume for all trades
/// </summary>
public decimal TotalVolumeTraded { get; set; }
/// <summary>
/// Trading volume in the last 24 hours
/// </summary>
public decimal VolumeLast24H { get; set; }
/// <summary>
/// Number of winning trades
/// </summary>
public int Wins { get; set; }
/// <summary>
/// Number of losing trades
/// </summary>
public int Losses { get; set; }
/// <summary>
/// List of all positions executed by this strategy
/// </summary>
public List<Position> Positions { get; set; } = new List<Position>();
}
}