Add bundle backtest
This commit is contained in:
@@ -1,7 +1,6 @@
|
|||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using Managing.Api.Models.Requests;
|
using Managing.Api.Models.Requests;
|
||||||
using Managing.Application.Abstractions;
|
using Managing.Application.Abstractions;
|
||||||
using Managing.Application.Abstractions.Repositories;
|
|
||||||
using Managing.Application.Abstractions.Services;
|
using Managing.Application.Abstractions.Services;
|
||||||
using Managing.Application.Hubs;
|
using Managing.Application.Hubs;
|
||||||
using Managing.Domain.Backtests;
|
using Managing.Domain.Backtests;
|
||||||
@@ -12,6 +11,7 @@ using Managing.Domain.Strategies;
|
|||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.AspNetCore.SignalR;
|
using Microsoft.AspNetCore.SignalR;
|
||||||
|
using MoneyManagementRequest = Managing.Domain.Backtests.MoneyManagementRequest;
|
||||||
|
|
||||||
namespace Managing.Api.Controllers;
|
namespace Managing.Api.Controllers;
|
||||||
|
|
||||||
@@ -33,7 +33,6 @@ public class BacktestController : BaseController
|
|||||||
private readonly IAccountService _accountService;
|
private readonly IAccountService _accountService;
|
||||||
private readonly IMoneyManagementService _moneyManagementService;
|
private readonly IMoneyManagementService _moneyManagementService;
|
||||||
private readonly IGeneticService _geneticService;
|
private readonly IGeneticService _geneticService;
|
||||||
private readonly IBacktestRepository _backtestRepository;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="BacktestController"/> class.
|
/// Initializes a new instance of the <see cref="BacktestController"/> class.
|
||||||
@@ -52,7 +51,6 @@ public class BacktestController : BaseController
|
|||||||
IAccountService accountService,
|
IAccountService accountService,
|
||||||
IMoneyManagementService moneyManagementService,
|
IMoneyManagementService moneyManagementService,
|
||||||
IGeneticService geneticService,
|
IGeneticService geneticService,
|
||||||
IBacktestRepository backtestRepository,
|
|
||||||
IUserService userService) : base(userService)
|
IUserService userService) : base(userService)
|
||||||
{
|
{
|
||||||
_hubContext = hubContext;
|
_hubContext = hubContext;
|
||||||
@@ -61,7 +59,6 @@ public class BacktestController : BaseController
|
|||||||
_accountService = accountService;
|
_accountService = accountService;
|
||||||
_moneyManagementService = moneyManagementService;
|
_moneyManagementService = moneyManagementService;
|
||||||
_geneticService = geneticService;
|
_geneticService = geneticService;
|
||||||
_backtestRepository = backtestRepository;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -153,8 +150,8 @@ public class BacktestController : BaseController
|
|||||||
[HttpGet]
|
[HttpGet]
|
||||||
[Route("ByRequestId/{requestId}/Paginated")]
|
[Route("ByRequestId/{requestId}/Paginated")]
|
||||||
public async Task<ActionResult<PaginatedBacktestsResponse>> GetBacktestsByRequestIdPaginated(
|
public async Task<ActionResult<PaginatedBacktestsResponse>> GetBacktestsByRequestIdPaginated(
|
||||||
string requestId,
|
string requestId,
|
||||||
int page = 1,
|
int page = 1,
|
||||||
int pageSize = 50,
|
int pageSize = 50,
|
||||||
string sortBy = "score",
|
string sortBy = "score",
|
||||||
string sortOrder = "desc")
|
string sortOrder = "desc")
|
||||||
@@ -179,10 +176,11 @@ public class BacktestController : BaseController
|
|||||||
return BadRequest("Sort order must be 'asc' or 'desc'");
|
return BadRequest("Sort order must be 'asc' or 'desc'");
|
||||||
}
|
}
|
||||||
|
|
||||||
var (backtests, totalCount) = _backtester.GetBacktestsByRequestIdPaginated(requestId, page, pageSize, sortBy, sortOrder);
|
var (backtests, totalCount) =
|
||||||
|
_backtester.GetBacktestsByRequestIdPaginated(requestId, page, pageSize, sortBy, sortOrder);
|
||||||
|
|
||||||
var totalPages = (int)Math.Ceiling(totalCount / (double)pageSize);
|
var totalPages = (int)Math.Ceiling(totalCount / (double)pageSize);
|
||||||
|
|
||||||
var response = new PaginatedBacktestsResponse
|
var response = new PaginatedBacktestsResponse
|
||||||
{
|
{
|
||||||
Backtests = backtests.Select(b => new LightBacktestResponse
|
Backtests = backtests.Select(b => new LightBacktestResponse
|
||||||
@@ -410,10 +408,12 @@ public class BacktestController : BaseController
|
|||||||
/// This endpoint creates a request that will be processed by a background worker.
|
/// This endpoint creates a request that will be processed by a background worker.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="requests">The list of backtest requests to execute.</param>
|
/// <param name="requests">The list of backtest requests to execute.</param>
|
||||||
|
/// <param name="name">Display name for the bundle (required).</param>
|
||||||
/// <returns>The bundle backtest request with ID for tracking progress.</returns>
|
/// <returns>The bundle backtest request with ID for tracking progress.</returns>
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
[Route("Bundle")]
|
[Route("Bundle")]
|
||||||
public async Task<ActionResult<BundleBacktestRequest>> RunBundle([FromBody] List<RunBacktestRequest> requests)
|
public async Task<ActionResult<BundleBacktestRequest>> RunBundle([FromBody] List<RunBacktestRequest> requests,
|
||||||
|
[FromQuery] string name)
|
||||||
{
|
{
|
||||||
if (requests == null || !requests.Any())
|
if (requests == null || !requests.Any())
|
||||||
{
|
{
|
||||||
@@ -425,10 +425,15 @@ public class BacktestController : BaseController
|
|||||||
return BadRequest("Maximum of 10 backtests allowed per bundle request");
|
return BadRequest("Maximum of 10 backtests allowed per bundle request");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(name))
|
||||||
|
{
|
||||||
|
return BadRequest("Bundle name is required");
|
||||||
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var user = await GetUser();
|
var user = await GetUser();
|
||||||
|
|
||||||
// Validate all requests before creating the bundle
|
// Validate all requests before creating the bundle
|
||||||
foreach (var request in requests)
|
foreach (var request in requests)
|
||||||
{
|
{
|
||||||
@@ -449,7 +454,8 @@ public class BacktestController : BaseController
|
|||||||
|
|
||||||
if (string.IsNullOrEmpty(request.Config.MoneyManagementName) && request.Config.MoneyManagement == null)
|
if (string.IsNullOrEmpty(request.Config.MoneyManagementName) && request.Config.MoneyManagement == null)
|
||||||
{
|
{
|
||||||
return BadRequest("Invalid request: Either money management name or money management object is required");
|
return BadRequest(
|
||||||
|
"Invalid request: Either money management name or money management object is required");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -461,10 +467,11 @@ public class BacktestController : BaseController
|
|||||||
TotalBacktests = requests.Count,
|
TotalBacktests = requests.Count,
|
||||||
CompletedBacktests = 0,
|
CompletedBacktests = 0,
|
||||||
FailedBacktests = 0,
|
FailedBacktests = 0,
|
||||||
Status = BundleBacktestRequestStatus.Pending
|
Status = BundleBacktestRequestStatus.Pending,
|
||||||
|
Name = name
|
||||||
};
|
};
|
||||||
|
|
||||||
_backtestRepository.InsertBundleBacktestRequestForUser(user, bundleRequest);
|
_backtester.InsertBundleBacktestRequestForUser(user, bundleRequest);
|
||||||
|
|
||||||
return Ok(bundleRequest);
|
return Ok(bundleRequest);
|
||||||
}
|
}
|
||||||
@@ -483,7 +490,7 @@ public class BacktestController : BaseController
|
|||||||
public async Task<ActionResult<IEnumerable<BundleBacktestRequest>>> GetBundleBacktestRequests()
|
public async Task<ActionResult<IEnumerable<BundleBacktestRequest>>> GetBundleBacktestRequests()
|
||||||
{
|
{
|
||||||
var user = await GetUser();
|
var user = await GetUser();
|
||||||
var bundleRequests = _backtestRepository.GetBundleBacktestRequestsByUser(user);
|
var bundleRequests = _backtester.GetBundleBacktestRequestsByUser(user);
|
||||||
return Ok(bundleRequests);
|
return Ok(bundleRequests);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -497,7 +504,7 @@ public class BacktestController : BaseController
|
|||||||
public async Task<ActionResult<BundleBacktestRequest>> GetBundleBacktestRequest(string id)
|
public async Task<ActionResult<BundleBacktestRequest>> GetBundleBacktestRequest(string id)
|
||||||
{
|
{
|
||||||
var user = await GetUser();
|
var user = await GetUser();
|
||||||
var bundleRequest = _backtestRepository.GetBundleBacktestRequestByIdForUser(user, id);
|
var bundleRequest = _backtester.GetBundleBacktestRequestByIdForUser(user, id);
|
||||||
|
|
||||||
if (bundleRequest == null)
|
if (bundleRequest == null)
|
||||||
{
|
{
|
||||||
@@ -518,16 +525,17 @@ public class BacktestController : BaseController
|
|||||||
public async Task<ActionResult> DeleteBundleBacktestRequest(string id)
|
public async Task<ActionResult> DeleteBundleBacktestRequest(string id)
|
||||||
{
|
{
|
||||||
var user = await GetUser();
|
var user = await GetUser();
|
||||||
|
|
||||||
// First, delete the bundle request
|
// First, delete the bundle request
|
||||||
_backtestRepository.DeleteBundleBacktestRequestByIdForUser(user, id);
|
_backtester.DeleteBundleBacktestRequestByIdForUser(user, id);
|
||||||
|
|
||||||
// Then, delete all related backtests
|
// Then, delete all related backtests
|
||||||
var backtestsDeleted = _backtester.DeleteBacktestsByRequestId(id);
|
var backtestsDeleted = _backtester.DeleteBacktestsByRequestId(id);
|
||||||
|
|
||||||
return Ok(new {
|
return Ok(new
|
||||||
BundleRequestDeleted = true,
|
{
|
||||||
RelatedBacktestsDeleted = backtestsDeleted
|
BundleRequestDeleted = true,
|
||||||
|
RelatedBacktestsDeleted = backtestsDeleted
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -641,21 +649,21 @@ public class BacktestController : BaseController
|
|||||||
public async Task<ActionResult> DeleteGeneticRequest(string id)
|
public async Task<ActionResult> DeleteGeneticRequest(string id)
|
||||||
{
|
{
|
||||||
var user = await GetUser();
|
var user = await GetUser();
|
||||||
|
|
||||||
// First, delete the genetic request
|
// First, delete the genetic request
|
||||||
_geneticService.DeleteGeneticRequestByIdForUser(user, id);
|
_geneticService.DeleteGeneticRequestByIdForUser(user, id);
|
||||||
|
|
||||||
// Then, delete all related backtests
|
// Then, delete all related backtests
|
||||||
var backtestsDeleted = _backtester.DeleteBacktestsByRequestId(id);
|
var backtestsDeleted = _backtester.DeleteBacktestsByRequestId(id);
|
||||||
|
|
||||||
return Ok(new {
|
return Ok(new
|
||||||
GeneticRequestDeleted = true,
|
{
|
||||||
RelatedBacktestsDeleted = backtestsDeleted
|
GeneticRequestDeleted = true,
|
||||||
|
RelatedBacktestsDeleted = backtestsDeleted
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Notifies subscribers about the backtesting results via SignalR.
|
/// Notifies subscribers about the backtesting results via SignalR.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ using Managing.Application.Abstractions.Services;
|
|||||||
using Managing.Application.Hubs;
|
using Managing.Application.Hubs;
|
||||||
using Managing.Application.ManageBot.Commands;
|
using Managing.Application.ManageBot.Commands;
|
||||||
using Managing.Common;
|
using Managing.Common;
|
||||||
|
using Managing.Domain.Backtests;
|
||||||
using Managing.Domain.Bots;
|
using Managing.Domain.Bots;
|
||||||
using Managing.Domain.MoneyManagements;
|
using Managing.Domain.MoneyManagements;
|
||||||
using Managing.Domain.Scenarios;
|
using Managing.Domain.Scenarios;
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ 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.ManageBot.Commands;
|
||||||
|
using Managing.Domain.Backtests;
|
||||||
using Managing.Domain.Bots;
|
using Managing.Domain.Bots;
|
||||||
using Managing.Domain.Candles;
|
using Managing.Domain.Candles;
|
||||||
using Managing.Domain.Scenarios;
|
using Managing.Domain.Scenarios;
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using Managing.Domain.Backtests;
|
||||||
using static Managing.Common.Enums;
|
using static Managing.Common.Enums;
|
||||||
|
|
||||||
namespace Managing.Api.Models.Requests;
|
namespace Managing.Api.Models.Requests;
|
||||||
@@ -7,8 +8,6 @@ namespace Managing.Api.Models.Requests;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class GetCandlesWithIndicatorsRequest
|
public class GetCandlesWithIndicatorsRequest
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The ticker symbol.
|
/// The ticker symbol.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -33,4 +32,4 @@ public class GetCandlesWithIndicatorsRequest
|
|||||||
/// Optional scenario for calculating indicators.
|
/// Optional scenario for calculating indicators.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ScenarioRequest Scenario { get; set; }
|
public ScenarioRequest Scenario { get; set; }
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using Managing.Domain.Bots;
|
||||||
|
|
||||||
namespace Managing.Api.Models.Requests
|
namespace Managing.Api.Models.Requests
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using Managing.Domain.Bots;
|
||||||
using Managing.Domain.MoneyManagements;
|
using Managing.Domain.MoneyManagements;
|
||||||
|
|
||||||
namespace Managing.Api.Models.Requests;
|
namespace Managing.Api.Models.Requests;
|
||||||
|
|||||||
@@ -62,6 +62,14 @@ namespace Managing.Application.Abstractions.Services
|
|||||||
bool DeleteBacktestsByRequestId(string requestId);
|
bool DeleteBacktestsByRequestId(string requestId);
|
||||||
(IEnumerable<LightBacktest> Backtests, int TotalCount) GetBacktestsByUserPaginated(User user, int page, int pageSize, string sortBy = "score", string sortOrder = "desc");
|
(IEnumerable<LightBacktest> Backtests, int TotalCount) GetBacktestsByUserPaginated(User user, int page, int pageSize, string sortBy = "score", string sortOrder = "desc");
|
||||||
|
|
||||||
|
// Bundle backtest methods
|
||||||
|
void InsertBundleBacktestRequestForUser(User user, BundleBacktestRequest bundleRequest);
|
||||||
|
IEnumerable<BundleBacktestRequest> GetBundleBacktestRequestsByUser(User user);
|
||||||
|
BundleBacktestRequest? GetBundleBacktestRequestByIdForUser(User user, string id);
|
||||||
|
void UpdateBundleBacktestRequest(BundleBacktestRequest bundleRequest);
|
||||||
|
void DeleteBundleBacktestRequestByIdForUser(User user, string id);
|
||||||
|
IEnumerable<BundleBacktestRequest> GetPendingBundleBacktestRequests();
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,8 +1,11 @@
|
|||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using Managing.Application.Abstractions.Repositories;
|
|
||||||
using Managing.Application.Abstractions.Services;
|
using Managing.Application.Abstractions.Services;
|
||||||
using Managing.Application.Workers.Abstractions;
|
using Managing.Application.Workers.Abstractions;
|
||||||
using Managing.Domain.Backtests;
|
using Managing.Domain.Backtests;
|
||||||
|
using Managing.Domain.Bots;
|
||||||
|
using Managing.Domain.MoneyManagements;
|
||||||
|
using Managing.Domain.Scenarios;
|
||||||
|
using Managing.Domain.Strategies;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using static Managing.Common.Enums;
|
using static Managing.Common.Enums;
|
||||||
|
|
||||||
@@ -13,12 +16,11 @@ namespace Managing.Application.Workers;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class BundleBacktestWorker : BaseWorker<BundleBacktestWorker>
|
public class BundleBacktestWorker : BaseWorker<BundleBacktestWorker>
|
||||||
{
|
{
|
||||||
private readonly IBacktestRepository _backtestRepository;
|
// Removed direct repository usage for bundle requests
|
||||||
private readonly IBacktester _backtester;
|
private readonly IBacktester _backtester;
|
||||||
private static readonly WorkerType _workerType = WorkerType.BundleBacktest;
|
private static readonly WorkerType _workerType = WorkerType.BundleBacktest;
|
||||||
|
|
||||||
public BundleBacktestWorker(
|
public BundleBacktestWorker(
|
||||||
IBacktestRepository backtestRepository,
|
|
||||||
IBacktester backtester,
|
IBacktester backtester,
|
||||||
ILogger<BundleBacktestWorker> logger,
|
ILogger<BundleBacktestWorker> logger,
|
||||||
IWorkerService workerService) : base(
|
IWorkerService workerService) : base(
|
||||||
@@ -27,7 +29,6 @@ public class BundleBacktestWorker : BaseWorker<BundleBacktestWorker>
|
|||||||
TimeSpan.FromMinutes(1),
|
TimeSpan.FromMinutes(1),
|
||||||
workerService)
|
workerService)
|
||||||
{
|
{
|
||||||
_backtestRepository = backtestRepository;
|
|
||||||
_backtester = backtester;
|
_backtester = backtester;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -36,7 +37,7 @@ public class BundleBacktestWorker : BaseWorker<BundleBacktestWorker>
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Get pending bundle backtest requests
|
// Get pending bundle backtest requests
|
||||||
var pendingRequests = _backtestRepository.GetPendingBundleBacktestRequests();
|
var pendingRequests = _backtester.GetPendingBundleBacktestRequests();
|
||||||
|
|
||||||
foreach (var bundleRequest in pendingRequests)
|
foreach (var bundleRequest in pendingRequests)
|
||||||
{
|
{
|
||||||
@@ -61,10 +62,12 @@ public class BundleBacktestWorker : BaseWorker<BundleBacktestWorker>
|
|||||||
|
|
||||||
// Update status to running
|
// Update status to running
|
||||||
bundleRequest.Status = BundleBacktestRequestStatus.Running;
|
bundleRequest.Status = BundleBacktestRequestStatus.Running;
|
||||||
_backtestRepository.UpdateBundleBacktestRequest(bundleRequest);
|
_backtester.UpdateBundleBacktestRequest(bundleRequest);
|
||||||
|
|
||||||
// Deserialize the backtest requests as dynamic objects
|
// Deserialize the backtest requests as strongly-typed objects
|
||||||
var backtestRequests = JsonSerializer.Deserialize<List<JsonElement>>(bundleRequest.BacktestRequestsJson);
|
var backtestRequests =
|
||||||
|
JsonSerializer.Deserialize<List<RunBacktestRequest>>(
|
||||||
|
bundleRequest.BacktestRequestsJson);
|
||||||
if (backtestRequests == null)
|
if (backtestRequests == null)
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException("Failed to deserialize backtest requests");
|
throw new InvalidOperationException("Failed to deserialize backtest requests");
|
||||||
@@ -78,28 +81,27 @@ public class BundleBacktestWorker : BaseWorker<BundleBacktestWorker>
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var requestElement = backtestRequests[i];
|
var runBacktestRequest = backtestRequests[i];
|
||||||
|
|
||||||
// Update current backtest being processed
|
// Update current backtest being processed
|
||||||
bundleRequest.CurrentBacktest = $"Backtest {i + 1} of {backtestRequests.Count}";
|
bundleRequest.CurrentBacktest = $"Backtest {i + 1} of {backtestRequests.Count}";
|
||||||
_backtestRepository.UpdateBundleBacktestRequest(bundleRequest);
|
_backtester.UpdateBundleBacktestRequest(bundleRequest);
|
||||||
|
|
||||||
// Convert JSON element to domain model and run backtest
|
// Run the backtest directly with the strongly-typed request
|
||||||
await RunSingleBacktest(requestElement, bundleRequest.RequestId, cancellationToken);
|
await RunSingleBacktest(runBacktestRequest, bundleRequest, i, cancellationToken);
|
||||||
|
|
||||||
// Update progress
|
// Update progress
|
||||||
bundleRequest.CompletedBacktests++;
|
bundleRequest.CompletedBacktests++;
|
||||||
_backtestRepository.UpdateBundleBacktestRequest(bundleRequest);
|
_backtester.UpdateBundleBacktestRequest(bundleRequest);
|
||||||
|
|
||||||
_logger.LogInformation("Completed backtest {Index} for bundle request {RequestId}",
|
_logger.LogInformation("Completed backtest {Index} for bundle request {RequestId}",
|
||||||
i + 1, bundleRequest.RequestId);
|
i + 1, bundleRequest.RequestId);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
_logger.LogError(ex, "Error processing backtest {Index} for bundle request {RequestId}",
|
_logger.LogError(ex, "Error processing backtest {Index} for bundle request {RequestId}",
|
||||||
i + 1, bundleRequest.RequestId);
|
i + 1, bundleRequest.RequestId);
|
||||||
bundleRequest.FailedBacktests++;
|
bundleRequest.FailedBacktests++;
|
||||||
_backtestRepository.UpdateBundleBacktestRequest(bundleRequest);
|
_backtester.UpdateBundleBacktestRequest(bundleRequest);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -121,36 +123,120 @@ public class BundleBacktestWorker : BaseWorker<BundleBacktestWorker>
|
|||||||
|
|
||||||
bundleRequest.CompletedAt = DateTime.UtcNow;
|
bundleRequest.CompletedAt = DateTime.UtcNow;
|
||||||
bundleRequest.CurrentBacktest = null;
|
bundleRequest.CurrentBacktest = null;
|
||||||
_backtestRepository.UpdateBundleBacktestRequest(bundleRequest);
|
_backtester.UpdateBundleBacktestRequest(bundleRequest);
|
||||||
|
|
||||||
_logger.LogInformation("Completed processing bundle backtest request {RequestId} with status {Status}",
|
_logger.LogInformation("Completed processing bundle backtest request {RequestId} with status {Status}",
|
||||||
bundleRequest.RequestId, bundleRequest.Status);
|
bundleRequest.RequestId, bundleRequest.Status);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
_logger.LogError(ex, "Error processing bundle backtest request {RequestId}", bundleRequest.RequestId);
|
_logger.LogError(ex, "Error processing bundle backtest request {RequestId}", bundleRequest.RequestId);
|
||||||
|
|
||||||
bundleRequest.Status = BundleBacktestRequestStatus.Failed;
|
bundleRequest.Status = BundleBacktestRequestStatus.Failed;
|
||||||
bundleRequest.ErrorMessage = ex.Message;
|
bundleRequest.ErrorMessage = ex.Message;
|
||||||
bundleRequest.CompletedAt = DateTime.UtcNow;
|
bundleRequest.CompletedAt = DateTime.UtcNow;
|
||||||
_backtestRepository.UpdateBundleBacktestRequest(bundleRequest);
|
_backtester.UpdateBundleBacktestRequest(bundleRequest);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task RunSingleBacktest(JsonElement requestElement, string bundleRequestId, CancellationToken cancellationToken)
|
// Change RunSingleBacktest to accept RunBacktestRequest directly
|
||||||
|
private async Task RunSingleBacktest(RunBacktestRequest runBacktestRequest, BundleBacktestRequest bundleRequest,
|
||||||
|
int index, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
// For now, we'll use a simplified approach that simulates backtest execution
|
if (runBacktestRequest == null || runBacktestRequest.Config == null)
|
||||||
// In a real implementation, you would parse the JSON and convert to domain models
|
{
|
||||||
|
_logger.LogError("Invalid RunBacktestRequest in bundle (null config)");
|
||||||
// Simulate backtest processing time
|
return;
|
||||||
await Task.Delay(TimeSpan.FromSeconds(2), cancellationToken);
|
}
|
||||||
|
|
||||||
_logger.LogInformation("Processed backtest for bundle request {RequestId}", bundleRequestId);
|
// Map MoneyManagement
|
||||||
|
MoneyManagement moneyManagement = null;
|
||||||
// TODO: Implement actual backtest execution by:
|
if (!string.IsNullOrEmpty(runBacktestRequest.Config.MoneyManagementName))
|
||||||
// 1. Parsing the JSON request element
|
{
|
||||||
// 2. Converting to TradingBotConfig domain model
|
// In worker context, we cannot resolve by name (no user/db), so skip or set null
|
||||||
// 3. Calling _backtester.RunTradingBotBacktest with proper parameters
|
// Optionally, log a warning
|
||||||
// 4. Handling the results and saving to database if needed
|
_logger.LogWarning("MoneyManagementName provided but cannot resolve in worker context: {Name}",
|
||||||
|
(string)runBacktestRequest.Config.MoneyManagementName);
|
||||||
|
}
|
||||||
|
else if (runBacktestRequest.Config.MoneyManagement != null)
|
||||||
|
{
|
||||||
|
var mmReq = runBacktestRequest.Config.MoneyManagement;
|
||||||
|
moneyManagement = new MoneyManagement
|
||||||
|
{
|
||||||
|
Name = mmReq.Name,
|
||||||
|
Timeframe = mmReq.Timeframe,
|
||||||
|
StopLoss = mmReq.StopLoss,
|
||||||
|
TakeProfit = mmReq.TakeProfit,
|
||||||
|
Leverage = mmReq.Leverage
|
||||||
|
};
|
||||||
|
moneyManagement.FormatPercentage();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Map Scenario
|
||||||
|
Scenario scenario = null;
|
||||||
|
if (runBacktestRequest.Config.Scenario != null)
|
||||||
|
{
|
||||||
|
var sReq = runBacktestRequest.Config.Scenario;
|
||||||
|
scenario = new Scenario(sReq.Name, sReq.LoopbackPeriod)
|
||||||
|
{
|
||||||
|
User = null // No user context in worker
|
||||||
|
};
|
||||||
|
foreach (var indicatorRequest in sReq.Indicators)
|
||||||
|
{
|
||||||
|
var indicator = new Indicator(indicatorRequest.Name, indicatorRequest.Type)
|
||||||
|
{
|
||||||
|
SignalType = indicatorRequest.SignalType,
|
||||||
|
MinimumHistory = indicatorRequest.MinimumHistory,
|
||||||
|
Period = indicatorRequest.Period,
|
||||||
|
FastPeriods = indicatorRequest.FastPeriods,
|
||||||
|
SlowPeriods = indicatorRequest.SlowPeriods,
|
||||||
|
SignalPeriods = indicatorRequest.SignalPeriods,
|
||||||
|
Multiplier = indicatorRequest.Multiplier,
|
||||||
|
SmoothPeriods = indicatorRequest.SmoothPeriods,
|
||||||
|
StochPeriods = indicatorRequest.StochPeriods,
|
||||||
|
CyclePeriods = indicatorRequest.CyclePeriods,
|
||||||
|
User = null // No user context in worker
|
||||||
|
};
|
||||||
|
scenario.AddIndicator(indicator);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Map TradingBotConfig
|
||||||
|
var backtestConfig = new TradingBotConfig
|
||||||
|
{
|
||||||
|
AccountName = runBacktestRequest.Config.AccountName,
|
||||||
|
MoneyManagement = moneyManagement,
|
||||||
|
Ticker = runBacktestRequest.Config.Ticker,
|
||||||
|
ScenarioName = runBacktestRequest.Config.ScenarioName,
|
||||||
|
Scenario = scenario,
|
||||||
|
Timeframe = runBacktestRequest.Config.Timeframe,
|
||||||
|
IsForWatchingOnly = runBacktestRequest.Config.IsForWatchingOnly,
|
||||||
|
BotTradingBalance = runBacktestRequest.Config.BotTradingBalance,
|
||||||
|
IsForBacktest = true,
|
||||||
|
CooldownPeriod = runBacktestRequest.Config.CooldownPeriod,
|
||||||
|
MaxLossStreak = runBacktestRequest.Config.MaxLossStreak,
|
||||||
|
MaxPositionTimeHours = runBacktestRequest.Config.MaxPositionTimeHours,
|
||||||
|
FlipOnlyWhenInProfit = runBacktestRequest.Config.FlipOnlyWhenInProfit,
|
||||||
|
FlipPosition = runBacktestRequest.Config.FlipPosition,
|
||||||
|
Name = $"{bundleRequest.Name} #{index + 1}",
|
||||||
|
CloseEarlyWhenProfitable = runBacktestRequest.Config.CloseEarlyWhenProfitable,
|
||||||
|
UseSynthApi = runBacktestRequest.Config.UseSynthApi,
|
||||||
|
UseForPositionSizing = runBacktestRequest.Config.UseForPositionSizing,
|
||||||
|
UseForSignalFiltering = runBacktestRequest.Config.UseForSignalFiltering,
|
||||||
|
UseForDynamicStopLoss = runBacktestRequest.Config.UseForDynamicStopLoss
|
||||||
|
};
|
||||||
|
|
||||||
|
// Run the backtest (no user context)
|
||||||
|
var result = await _backtester.RunTradingBotBacktest(
|
||||||
|
backtestConfig,
|
||||||
|
runBacktestRequest.StartDate,
|
||||||
|
runBacktestRequest.EndDate,
|
||||||
|
null, // No user context in worker
|
||||||
|
runBacktestRequest.Save,
|
||||||
|
runBacktestRequest.WithCandles,
|
||||||
|
bundleRequest.RequestId // Use bundleRequestId as requestId for traceability
|
||||||
|
);
|
||||||
|
|
||||||
|
_logger.LogInformation("Processed backtest for bundle request {RequestId}", bundleRequest.RequestId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -573,5 +573,36 @@ namespace Managing.Application.Backtesting
|
|||||||
_backtestRepository.GetBacktestsByUserPaginated(user, page, pageSize, sortBy, sortOrder);
|
_backtestRepository.GetBacktestsByUserPaginated(user, page, pageSize, sortBy, sortOrder);
|
||||||
return (backtests, totalCount);
|
return (backtests, totalCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Bundle backtest methods
|
||||||
|
public void InsertBundleBacktestRequestForUser(User user, BundleBacktestRequest bundleRequest)
|
||||||
|
{
|
||||||
|
_backtestRepository.InsertBundleBacktestRequestForUser(user, bundleRequest);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<BundleBacktestRequest> GetBundleBacktestRequestsByUser(User user)
|
||||||
|
{
|
||||||
|
return _backtestRepository.GetBundleBacktestRequestsByUser(user);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BundleBacktestRequest? GetBundleBacktestRequestByIdForUser(User user, string id)
|
||||||
|
{
|
||||||
|
return _backtestRepository.GetBundleBacktestRequestByIdForUser(user, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateBundleBacktestRequest(BundleBacktestRequest bundleRequest)
|
||||||
|
{
|
||||||
|
_backtestRepository.UpdateBundleBacktestRequest(bundleRequest);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DeleteBundleBacktestRequestByIdForUser(User user, string id)
|
||||||
|
{
|
||||||
|
_backtestRepository.DeleteBundleBacktestRequestByIdForUser(user, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<BundleBacktestRequest> GetPendingBundleBacktestRequests()
|
||||||
|
{
|
||||||
|
return _backtestRepository.GetPendingBundleBacktestRequests();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -59,6 +59,12 @@ public class BundleBacktestRequest
|
|||||||
[Required]
|
[Required]
|
||||||
public BundleBacktestRequestStatus Status { get; set; }
|
public BundleBacktestRequestStatus Status { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Display name for the bundle backtest request
|
||||||
|
/// </summary>
|
||||||
|
[Required]
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The list of backtest requests to execute (serialized as JSON)
|
/// The list of backtest requests to execute (serialized as JSON)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -143,4 +149,4 @@ public enum BundleBacktestRequestStatus
|
|||||||
/// Request was cancelled
|
/// Request was cancelled
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Cancelled
|
Cancelled
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using static Managing.Common.Enums;
|
using static Managing.Common.Enums;
|
||||||
|
|
||||||
namespace Managing.Api.Models.Requests;
|
namespace Managing.Domain.Backtests;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Request model for indicator configuration without user information
|
/// Request model for indicator configuration without user information
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using Managing.Common;
|
using Managing.Common;
|
||||||
|
|
||||||
namespace Managing.Api.Models.Requests;
|
namespace Managing.Domain.Backtests;
|
||||||
|
|
||||||
public class MoneyManagementRequest
|
public class MoneyManagementRequest
|
||||||
{
|
{
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
using Managing.Domain.MoneyManagements;
|
using Managing.Domain.Bots;
|
||||||
|
using Managing.Domain.MoneyManagements;
|
||||||
|
|
||||||
namespace Managing.Api.Models.Requests;
|
namespace Managing.Domain.Backtests;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Request model for running a backtest
|
/// Request model for running a backtest
|
||||||
@@ -37,6 +38,12 @@ public class RunBacktestRequest
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public bool Save { get; set; } = false;
|
public bool Save { get; set; } = false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether to include candles and indicators values in the response.
|
||||||
|
/// Set to false to reduce response size dramatically.
|
||||||
|
/// </summary>
|
||||||
|
public bool WithCandles { get; set; } = false;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The name of the money management to use (optional if MoneyManagement is provided)
|
/// The name of the money management to use (optional if MoneyManagement is provided)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -46,4 +53,4 @@ public class RunBacktestRequest
|
|||||||
/// The money management details (optional if MoneyManagementName is provided)
|
/// The money management details (optional if MoneyManagementName is provided)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public MoneyManagement? MoneyManagement { get; set; }
|
public MoneyManagement? MoneyManagement { get; set; }
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
namespace Managing.Api.Models.Requests;
|
namespace Managing.Domain.Backtests;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Request model for scenario configuration without user information
|
/// Request model for scenario configuration without user information
|
||||||
@@ -1,7 +1,8 @@
|
|||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using Managing.Domain.Backtests;
|
||||||
using static Managing.Common.Enums;
|
using static Managing.Common.Enums;
|
||||||
|
|
||||||
namespace Managing.Api.Models.Requests;
|
namespace Managing.Domain.Bots;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Simplified trading bot configuration request with only primary properties
|
/// Simplified trading bot configuration request with only primary properties
|
||||||
@@ -314,7 +314,7 @@ public class BacktestRepository : IBacktestRepository
|
|||||||
public void InsertBundleBacktestRequestForUser(User user, BundleBacktestRequest bundleRequest)
|
public void InsertBundleBacktestRequestForUser(User user, BundleBacktestRequest bundleRequest)
|
||||||
{
|
{
|
||||||
bundleRequest.User = user;
|
bundleRequest.User = user;
|
||||||
var dto = MapToDto(bundleRequest);
|
var dto = MongoMappers.Map(bundleRequest);
|
||||||
_bundleBacktestRepository.InsertOne(dto);
|
_bundleBacktestRepository.InsertOne(dto);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -324,7 +324,7 @@ public class BacktestRepository : IBacktestRepository
|
|||||||
.Where(b => b.User.Name == user.Name)
|
.Where(b => b.User.Name == user.Name)
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
return bundleRequests.Select(MapToDomain);
|
return bundleRequests.Select(MongoMappers.Map);
|
||||||
}
|
}
|
||||||
|
|
||||||
public BundleBacktestRequest? GetBundleBacktestRequestByIdForUser(User user, string id)
|
public BundleBacktestRequest? GetBundleBacktestRequestByIdForUser(User user, string id)
|
||||||
@@ -333,7 +333,7 @@ public class BacktestRepository : IBacktestRepository
|
|||||||
|
|
||||||
if (bundleRequest != null && bundleRequest.User.Name == user.Name)
|
if (bundleRequest != null && bundleRequest.User.Name == user.Name)
|
||||||
{
|
{
|
||||||
return MapToDomain(bundleRequest);
|
return MongoMappers.Map(bundleRequest);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
@@ -341,7 +341,7 @@ public class BacktestRepository : IBacktestRepository
|
|||||||
|
|
||||||
public void UpdateBundleBacktestRequest(BundleBacktestRequest bundleRequest)
|
public void UpdateBundleBacktestRequest(BundleBacktestRequest bundleRequest)
|
||||||
{
|
{
|
||||||
var dto = MapToDto(bundleRequest);
|
var dto = MongoMappers.Map(bundleRequest);
|
||||||
_bundleBacktestRepository.ReplaceOne(dto);
|
_bundleBacktestRepository.ReplaceOne(dto);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -361,55 +361,6 @@ public class BacktestRepository : IBacktestRepository
|
|||||||
.Where(b => b.Status == BundleBacktestRequestStatus.Pending)
|
.Where(b => b.Status == BundleBacktestRequestStatus.Pending)
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
return pendingRequests.Select(MapToDomain);
|
return pendingRequests.Select(MongoMappers.Map);
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Maps a domain model to DTO
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="domain">The domain model</param>
|
|
||||||
/// <returns>The DTO</returns>
|
|
||||||
private static BundleBacktestRequestDto MapToDto(BundleBacktestRequest domain)
|
|
||||||
{
|
|
||||||
return new BundleBacktestRequestDto
|
|
||||||
{
|
|
||||||
RequestId = domain.RequestId,
|
|
||||||
User = MongoMappers.Map(domain.User),
|
|
||||||
CompletedAt = domain.CompletedAt,
|
|
||||||
Status = domain.Status,
|
|
||||||
BacktestRequestsJson = domain.BacktestRequestsJson,
|
|
||||||
TotalBacktests = domain.TotalBacktests,
|
|
||||||
CompletedBacktests = domain.CompletedBacktests,
|
|
||||||
FailedBacktests = domain.FailedBacktests,
|
|
||||||
ErrorMessage = domain.ErrorMessage,
|
|
||||||
ProgressInfo = domain.ProgressInfo,
|
|
||||||
CurrentBacktest = domain.CurrentBacktest,
|
|
||||||
EstimatedTimeRemainingSeconds = domain.EstimatedTimeRemainingSeconds
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Maps a DTO to domain model
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="dto">The DTO</param>
|
|
||||||
/// <returns>The domain model</returns>
|
|
||||||
private static BundleBacktestRequest MapToDomain(BundleBacktestRequestDto dto)
|
|
||||||
{
|
|
||||||
return new BundleBacktestRequest
|
|
||||||
{
|
|
||||||
RequestId = dto.RequestId,
|
|
||||||
User = MongoMappers.Map(dto.User),
|
|
||||||
CreatedAt = dto.CreatedAt,
|
|
||||||
CompletedAt = dto.CompletedAt,
|
|
||||||
Status = dto.Status,
|
|
||||||
BacktestRequestsJson = dto.BacktestRequestsJson,
|
|
||||||
TotalBacktests = dto.TotalBacktests,
|
|
||||||
CompletedBacktests = dto.CompletedBacktests,
|
|
||||||
FailedBacktests = dto.FailedBacktests,
|
|
||||||
ErrorMessage = dto.ErrorMessage,
|
|
||||||
ProgressInfo = dto.ProgressInfo,
|
|
||||||
CurrentBacktest = dto.CurrentBacktest,
|
|
||||||
EstimatedTimeRemainingSeconds = dto.EstimatedTimeRemainingSeconds
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -19,4 +19,5 @@ public class BundleBacktestRequestDto : Document
|
|||||||
public string? ProgressInfo { get; set; }
|
public string? ProgressInfo { get; set; }
|
||||||
public string? CurrentBacktest { get; set; }
|
public string? CurrentBacktest { get; set; }
|
||||||
public int? EstimatedTimeRemainingSeconds { get; set; }
|
public int? EstimatedTimeRemainingSeconds { get; set; }
|
||||||
}
|
public string Name { get; set; } = string.Empty;
|
||||||
|
}
|
||||||
@@ -1108,4 +1108,51 @@ public static class MongoMappers
|
|||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region BundleBacktestRequests
|
||||||
|
|
||||||
|
public static BundleBacktestRequestDto Map(BundleBacktestRequest domain)
|
||||||
|
{
|
||||||
|
if (domain == null) return null;
|
||||||
|
return new BundleBacktestRequestDto
|
||||||
|
{
|
||||||
|
RequestId = domain.RequestId,
|
||||||
|
User = Map(domain.User),
|
||||||
|
CompletedAt = domain.CompletedAt,
|
||||||
|
Status = domain.Status,
|
||||||
|
BacktestRequestsJson = domain.BacktestRequestsJson,
|
||||||
|
TotalBacktests = domain.TotalBacktests,
|
||||||
|
CompletedBacktests = domain.CompletedBacktests,
|
||||||
|
FailedBacktests = domain.FailedBacktests,
|
||||||
|
ErrorMessage = domain.ErrorMessage,
|
||||||
|
ProgressInfo = domain.ProgressInfo,
|
||||||
|
CurrentBacktest = domain.CurrentBacktest,
|
||||||
|
EstimatedTimeRemainingSeconds = domain.EstimatedTimeRemainingSeconds,
|
||||||
|
Name = domain.Name
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BundleBacktestRequest Map(BundleBacktestRequestDto dto)
|
||||||
|
{
|
||||||
|
if (dto == null) return null;
|
||||||
|
return new BundleBacktestRequest
|
||||||
|
{
|
||||||
|
RequestId = dto.RequestId,
|
||||||
|
User = Map(dto.User),
|
||||||
|
CreatedAt = dto.CreatedAt,
|
||||||
|
CompletedAt = dto.CompletedAt,
|
||||||
|
Status = dto.Status,
|
||||||
|
BacktestRequestsJson = dto.BacktestRequestsJson,
|
||||||
|
TotalBacktests = dto.TotalBacktests,
|
||||||
|
CompletedBacktests = dto.CompletedBacktests,
|
||||||
|
FailedBacktests = dto.FailedBacktests,
|
||||||
|
ErrorMessage = dto.ErrorMessage,
|
||||||
|
ProgressInfo = dto.ProgressInfo,
|
||||||
|
CurrentBacktest = dto.CurrentBacktest,
|
||||||
|
EstimatedTimeRemainingSeconds = dto.EstimatedTimeRemainingSeconds,
|
||||||
|
Name = dto.Name
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
@@ -716,6 +716,163 @@ export class BacktestClient extends AuthorizedApiBase {
|
|||||||
return Promise.resolve<Backtest>(null as any);
|
return Promise.resolve<Backtest>(null as any);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
backtest_RunBundle(name: string | null | undefined, requests: RunBacktestRequest[]): Promise<BundleBacktestRequest> {
|
||||||
|
let url_ = this.baseUrl + "/Backtest/Bundle?";
|
||||||
|
if (name !== undefined && name !== null)
|
||||||
|
url_ += "name=" + encodeURIComponent("" + name) + "&";
|
||||||
|
url_ = url_.replace(/[?&]$/, "");
|
||||||
|
|
||||||
|
const content_ = JSON.stringify(requests);
|
||||||
|
|
||||||
|
let options_: RequestInit = {
|
||||||
|
body: content_,
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"Accept": "application/json"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return this.transformOptions(options_).then(transformedOptions_ => {
|
||||||
|
return this.http.fetch(url_, transformedOptions_);
|
||||||
|
}).then((_response: Response) => {
|
||||||
|
return this.processBacktest_RunBundle(_response);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected processBacktest_RunBundle(response: Response): Promise<BundleBacktestRequest> {
|
||||||
|
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 BundleBacktestRequest;
|
||||||
|
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<BundleBacktestRequest>(null as any);
|
||||||
|
}
|
||||||
|
|
||||||
|
backtest_GetBundleBacktestRequests(): Promise<BundleBacktestRequest[]> {
|
||||||
|
let url_ = this.baseUrl + "/Backtest/Bundle";
|
||||||
|
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.processBacktest_GetBundleBacktestRequests(_response);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected processBacktest_GetBundleBacktestRequests(response: Response): Promise<BundleBacktestRequest[]> {
|
||||||
|
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 BundleBacktestRequest[];
|
||||||
|
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<BundleBacktestRequest[]>(null as any);
|
||||||
|
}
|
||||||
|
|
||||||
|
backtest_GetBundleBacktestRequest(id: string): Promise<BundleBacktestRequest> {
|
||||||
|
let url_ = this.baseUrl + "/Backtest/Bundle/{id}";
|
||||||
|
if (id === undefined || id === null)
|
||||||
|
throw new Error("The parameter 'id' must be defined.");
|
||||||
|
url_ = url_.replace("{id}", encodeURIComponent("" + id));
|
||||||
|
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.processBacktest_GetBundleBacktestRequest(_response);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected processBacktest_GetBundleBacktestRequest(response: Response): Promise<BundleBacktestRequest> {
|
||||||
|
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 BundleBacktestRequest;
|
||||||
|
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<BundleBacktestRequest>(null as any);
|
||||||
|
}
|
||||||
|
|
||||||
|
backtest_DeleteBundleBacktestRequest(id: string): Promise<FileResponse> {
|
||||||
|
let url_ = this.baseUrl + "/Backtest/Bundle/{id}";
|
||||||
|
if (id === undefined || id === null)
|
||||||
|
throw new Error("The parameter 'id' must be defined.");
|
||||||
|
url_ = url_.replace("{id}", encodeURIComponent("" + id));
|
||||||
|
url_ = url_.replace(/[?&]$/, "");
|
||||||
|
|
||||||
|
let options_: RequestInit = {
|
||||||
|
method: "DELETE",
|
||||||
|
headers: {
|
||||||
|
"Accept": "application/octet-stream"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return this.transformOptions(options_).then(transformedOptions_ => {
|
||||||
|
return this.http.fetch(url_, transformedOptions_);
|
||||||
|
}).then((_response: Response) => {
|
||||||
|
return this.processBacktest_DeleteBundleBacktestRequest(_response);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected processBacktest_DeleteBundleBacktestRequest(response: Response): Promise<FileResponse> {
|
||||||
|
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 || status === 206) {
|
||||||
|
const contentDisposition = response.headers ? response.headers.get("content-disposition") : undefined;
|
||||||
|
let fileNameMatch = contentDisposition ? /filename\*=(?:(\\?['"])(.*?)\1|(?:[^\s]+'.*?')?([^;\n]*))/g.exec(contentDisposition) : undefined;
|
||||||
|
let fileName = fileNameMatch && fileNameMatch.length > 1 ? fileNameMatch[3] || fileNameMatch[2] : undefined;
|
||||||
|
if (fileName) {
|
||||||
|
fileName = decodeURIComponent(fileName);
|
||||||
|
} else {
|
||||||
|
fileNameMatch = contentDisposition ? /filename="?([^"]*?)"?(;|$)/g.exec(contentDisposition) : undefined;
|
||||||
|
fileName = fileNameMatch && fileNameMatch.length > 1 ? fileNameMatch[1] : undefined;
|
||||||
|
}
|
||||||
|
return response.blob().then(blob => { return { fileName: fileName, data: blob, status: status, headers: _headers }; });
|
||||||
|
} else if (status !== 200 && status !== 204) {
|
||||||
|
return response.text().then((_responseText) => {
|
||||||
|
return throwException("An unexpected server error occurred.", status, _responseText, _headers);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return Promise.resolve<FileResponse>(null as any);
|
||||||
|
}
|
||||||
|
|
||||||
backtest_RunGenetic(request: RunGeneticRequest): Promise<GeneticRequest> {
|
backtest_RunGenetic(request: RunGeneticRequest): Promise<GeneticRequest> {
|
||||||
let url_ = this.baseUrl + "/Backtest/Genetic";
|
let url_ = this.baseUrl + "/Backtest/Genetic";
|
||||||
url_ = url_.replace(/[?&]$/, "");
|
url_ = url_.replace(/[?&]$/, "");
|
||||||
@@ -3880,6 +4037,33 @@ export interface MoneyManagementRequest {
|
|||||||
leverage: number;
|
leverage: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface BundleBacktestRequest {
|
||||||
|
requestId: string;
|
||||||
|
user: User;
|
||||||
|
createdAt: Date;
|
||||||
|
completedAt?: Date | null;
|
||||||
|
status: BundleBacktestRequestStatus;
|
||||||
|
name: string;
|
||||||
|
backtestRequestsJson: string;
|
||||||
|
results?: Backtest[] | null;
|
||||||
|
totalBacktests: number;
|
||||||
|
completedBacktests: number;
|
||||||
|
failedBacktests: number;
|
||||||
|
progressPercentage?: number;
|
||||||
|
errorMessage?: string | null;
|
||||||
|
progressInfo?: string | null;
|
||||||
|
currentBacktest?: string | null;
|
||||||
|
estimatedTimeRemainingSeconds?: number | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum BundleBacktestRequestStatus {
|
||||||
|
Pending = "Pending",
|
||||||
|
Running = "Running",
|
||||||
|
Completed = "Completed",
|
||||||
|
Failed = "Failed",
|
||||||
|
Cancelled = "Cancelled",
|
||||||
|
}
|
||||||
|
|
||||||
export interface GeneticRequest {
|
export interface GeneticRequest {
|
||||||
requestId: string;
|
requestId: string;
|
||||||
user: User;
|
user: User;
|
||||||
|
|||||||
@@ -686,6 +686,33 @@ export interface MoneyManagementRequest {
|
|||||||
leverage: number;
|
leverage: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface BundleBacktestRequest {
|
||||||
|
requestId: string;
|
||||||
|
user: User;
|
||||||
|
createdAt: Date;
|
||||||
|
completedAt?: Date | null;
|
||||||
|
status: BundleBacktestRequestStatus;
|
||||||
|
name: string;
|
||||||
|
backtestRequestsJson: string;
|
||||||
|
results?: Backtest[] | null;
|
||||||
|
totalBacktests: number;
|
||||||
|
completedBacktests: number;
|
||||||
|
failedBacktests: number;
|
||||||
|
progressPercentage?: number;
|
||||||
|
errorMessage?: string | null;
|
||||||
|
progressInfo?: string | null;
|
||||||
|
currentBacktest?: string | null;
|
||||||
|
estimatedTimeRemainingSeconds?: number | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum BundleBacktestRequestStatus {
|
||||||
|
Pending = "Pending",
|
||||||
|
Running = "Running",
|
||||||
|
Completed = "Completed",
|
||||||
|
Failed = "Failed",
|
||||||
|
Cancelled = "Cancelled",
|
||||||
|
}
|
||||||
|
|
||||||
export interface GeneticRequest {
|
export interface GeneticRequest {
|
||||||
requestId: string;
|
requestId: string;
|
||||||
user: User;
|
user: User;
|
||||||
|
|||||||
Reference in New Issue
Block a user