Add signalr

This commit is contained in:
2025-07-21 19:54:04 +07:00
parent a32e9c33a8
commit 83ed78a1fa
11 changed files with 441 additions and 10 deletions

View File

@@ -27,7 +27,7 @@ namespace Managing.Api.Controllers;
[Produces("application/json")]
public class BacktestController : BaseController
{
private readonly IHubContext<BotHub> _hubContext;
private readonly IHubContext<BacktestHub> _hubContext;
private readonly IBacktester _backtester;
private readonly IScenarioService _scenarioService;
private readonly IAccountService _accountService;
@@ -45,7 +45,7 @@ public class BacktestController : BaseController
/// <param name="geneticService">The service for genetic algorithm operations.</param>
/// <param name="backtestRepository">The repository for backtest operations.</param>
public BacktestController(
IHubContext<BotHub> hubContext,
IHubContext<BacktestHub> hubContext,
IBacktester backtester,
IScenarioService scenarioService,
IAccountService accountService,
@@ -537,6 +537,47 @@ public class BacktestController : BaseController
});
}
/// <summary>
/// Subscribes the client to real-time updates for a bundle backtest request via SignalR.
/// The client will receive LightBacktestResponse objects as new backtests are generated.
/// </summary>
/// <param name="requestId">The bundle request ID to subscribe to.</param>
[HttpPost]
[Route("Bundle/Subscribe")] // POST /Backtest/Bundle/Subscribe
public async Task<IActionResult> SubscribeToBundle([FromQuery] string requestId)
{
if (string.IsNullOrWhiteSpace(requestId))
return BadRequest("RequestId is required");
// Get the connection ID from the SignalR context (assume it's passed via header or query)
var connectionId = HttpContext.Request.Headers["X-SignalR-ConnectionId"].ToString();
if (string.IsNullOrEmpty(connectionId))
return BadRequest("SignalR connection ID is required in X-SignalR-ConnectionId header");
// Add the connection to the SignalR group for this bundle
await _hubContext.Groups.AddToGroupAsync(connectionId, $"bundle-{requestId}");
return Ok(new { Subscribed = true, RequestId = requestId });
}
/// <summary>
/// Unsubscribes the client from real-time updates for a bundle backtest request via SignalR.
/// </summary>
/// <param name="requestId">The bundle request ID to unsubscribe from.</param>
[HttpPost]
[Route("Bundle/Unsubscribe")] // POST /Backtest/Bundle/Unsubscribe
public async Task<IActionResult> UnsubscribeFromBundle([FromQuery] string requestId)
{
if (string.IsNullOrWhiteSpace(requestId))
return BadRequest("RequestId is required");
var connectionId = HttpContext.Request.Headers["X-SignalR-ConnectionId"].ToString();
if (string.IsNullOrEmpty(connectionId))
return BadRequest("SignalR connection ID is required in X-SignalR-ConnectionId header");
await _hubContext.Groups.RemoveFromGroupAsync(connectionId, $"bundle-{requestId}");
return Ok(new { Unsubscribed = true, RequestId = requestId });
}
/// <summary>
/// Runs a genetic algorithm optimization with the specified configuration.
/// This endpoint saves the genetic request to the database and returns the request ID.

View File

@@ -1,4 +1,5 @@
using System.ComponentModel.DataAnnotations;
using Managing.Domain.Backtests;
using Managing.Domain.Bots;
namespace Managing.Api.Models.Requests;
@@ -19,4 +20,28 @@ public class LightBacktestResponse
[Required] public double? SharpeRatio { get; set; }
[Required] public double Score { get; set; }
[Required] public string ScoreMessage { get; set; } = string.Empty;
}
public static class LightBacktestResponseMapper
{
public static LightBacktestResponse MapFromDomain(Backtest b)
{
if (b == null) return null;
return new LightBacktestResponse
{
Id = b.Id,
Config = b.Config,
FinalPnl = b.FinalPnl,
WinRate = b.WinRate,
GrowthPercentage = b.GrowthPercentage,
HodlPercentage = b.HodlPercentage,
StartDate = b.StartDate,
EndDate = b.EndDate,
MaxDrawdown = b.Statistics?.MaxDrawdown,
Fees = b.Fees,
SharpeRatio = (double?)b.Statistics?.SharpeRatio,
Score = b.Score,
ScoreMessage = b.ScoreMessage
};
}
}