Deserialized variant for bundle backtest
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using Managing.Api.Models.Requests;
|
using Managing.Api.Models.Requests;
|
||||||
|
using Managing.Api.Models.Responses;
|
||||||
using Managing.Application.Abstractions.Services;
|
using Managing.Application.Abstractions.Services;
|
||||||
using Managing.Application.Abstractions.Shared;
|
using Managing.Application.Abstractions.Shared;
|
||||||
using Managing.Application.Hubs;
|
using Managing.Application.Hubs;
|
||||||
@@ -677,75 +678,6 @@ public class BacktestController : BaseController
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Generates individual backtest requests from variant configuration
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="request">The bundle backtest request</param>
|
|
||||||
/// <param name="accountName">The account name to use for all backtests</param>
|
|
||||||
/// <returns>List of individual backtest requests</returns>
|
|
||||||
private List<RunBacktestRequest> GenerateBacktestRequests(RunBundleBacktestRequest request, string accountName)
|
|
||||||
{
|
|
||||||
var backtestRequests = new List<RunBacktestRequest>();
|
|
||||||
|
|
||||||
foreach (var dateRange in request.DateTimeRanges)
|
|
||||||
{
|
|
||||||
foreach (var mmVariant in request.MoneyManagementVariants)
|
|
||||||
{
|
|
||||||
foreach (var ticker in request.TickerVariants)
|
|
||||||
{
|
|
||||||
var config = new TradingBotConfigRequest
|
|
||||||
{
|
|
||||||
AccountName = accountName,
|
|
||||||
Ticker = ticker,
|
|
||||||
Timeframe = request.UniversalConfig.Timeframe,
|
|
||||||
IsForWatchingOnly = request.UniversalConfig.IsForWatchingOnly,
|
|
||||||
BotTradingBalance = request.UniversalConfig.BotTradingBalance,
|
|
||||||
Name =
|
|
||||||
$"{request.UniversalConfig.BotName}_{ticker}_{dateRange.StartDate:yyyyMMdd}_{dateRange.EndDate:yyyyMMdd}",
|
|
||||||
FlipPosition = request.UniversalConfig.FlipPosition,
|
|
||||||
CooldownPeriod = request.UniversalConfig.CooldownPeriod,
|
|
||||||
MaxLossStreak = request.UniversalConfig.MaxLossStreak,
|
|
||||||
Scenario = request.UniversalConfig.Scenario,
|
|
||||||
ScenarioName = request.UniversalConfig.ScenarioName,
|
|
||||||
MoneyManagement = mmVariant.MoneyManagement,
|
|
||||||
MaxPositionTimeHours = request.UniversalConfig.MaxPositionTimeHours,
|
|
||||||
CloseEarlyWhenProfitable = request.UniversalConfig.CloseEarlyWhenProfitable,
|
|
||||||
FlipOnlyWhenInProfit = request.UniversalConfig.FlipOnlyWhenInProfit,
|
|
||||||
UseSynthApi = request.UniversalConfig.UseSynthApi,
|
|
||||||
UseForPositionSizing = request.UniversalConfig.UseForPositionSizing,
|
|
||||||
UseForSignalFiltering = request.UniversalConfig.UseForSignalFiltering,
|
|
||||||
UseForDynamicStopLoss = request.UniversalConfig.UseForDynamicStopLoss
|
|
||||||
};
|
|
||||||
|
|
||||||
var backtestRequest = new RunBacktestRequest
|
|
||||||
{
|
|
||||||
Config = config,
|
|
||||||
StartDate = dateRange.StartDate,
|
|
||||||
EndDate = dateRange.EndDate,
|
|
||||||
Balance = request.UniversalConfig.BotTradingBalance,
|
|
||||||
WatchOnly = request.UniversalConfig.WatchOnly,
|
|
||||||
Save = request.UniversalConfig.Save,
|
|
||||||
WithCandles = request.UniversalConfig.WithCandles,
|
|
||||||
MoneyManagement = mmVariant.MoneyManagement != null
|
|
||||||
? new MoneyManagement
|
|
||||||
{
|
|
||||||
Name = mmVariant.MoneyManagement.Name,
|
|
||||||
Timeframe = mmVariant.MoneyManagement.Timeframe,
|
|
||||||
StopLoss = mmVariant.MoneyManagement.StopLoss,
|
|
||||||
TakeProfit = mmVariant.MoneyManagement.TakeProfit,
|
|
||||||
Leverage = mmVariant.MoneyManagement.Leverage
|
|
||||||
}
|
|
||||||
: null
|
|
||||||
};
|
|
||||||
|
|
||||||
backtestRequests.Add(backtestRequest);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return backtestRequests;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Retrieves all bundle backtest requests for the authenticated user.
|
/// Retrieves all bundle backtest requests for the authenticated user.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -781,7 +713,8 @@ public class BacktestController : BaseController
|
|||||||
return NotFound($"Bundle backtest request with ID {id} not found or doesn't belong to the current user.");
|
return NotFound($"Bundle backtest request with ID {id} not found or doesn't belong to the current user.");
|
||||||
}
|
}
|
||||||
|
|
||||||
return Ok(bundleRequest);
|
var viewModel = BundleBacktestRequestViewModel.FromDomain(bundleRequest);
|
||||||
|
return Ok(viewModel);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -0,0 +1,170 @@
|
|||||||
|
#nullable enable
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using System.Text.Json;
|
||||||
|
using Managing.Domain.Backtests;
|
||||||
|
using static Managing.Common.Enums;
|
||||||
|
|
||||||
|
namespace Managing.Api.Models.Responses;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// View model for bundle backtest requests with deserialized variant lists for frontend consumption
|
||||||
|
/// </summary>
|
||||||
|
public class BundleBacktestRequestViewModel
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Unique identifier for the bundle backtest request
|
||||||
|
/// </summary>
|
||||||
|
[Required]
|
||||||
|
public Guid RequestId { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// When the request was created
|
||||||
|
/// </summary>
|
||||||
|
[Required]
|
||||||
|
public DateTime CreatedAt { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// When the request was completed (if completed)
|
||||||
|
/// </summary>
|
||||||
|
public DateTime? CompletedAt { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Current status of the bundle backtest request
|
||||||
|
/// </summary>
|
||||||
|
[Required]
|
||||||
|
public BundleBacktestRequestStatus Status { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Display name for the bundle backtest request
|
||||||
|
/// </summary>
|
||||||
|
[Required]
|
||||||
|
public string Name { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The universal configuration that applies to all backtests
|
||||||
|
/// </summary>
|
||||||
|
[Required]
|
||||||
|
public BundleBacktestUniversalConfig UniversalConfig { get; set; } = new();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The list of DateTime ranges to test
|
||||||
|
/// </summary>
|
||||||
|
[Required]
|
||||||
|
public List<DateTimeRange> DateTimeRanges { get; set; } = new();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The list of money management variants to test
|
||||||
|
/// </summary>
|
||||||
|
[Required]
|
||||||
|
public List<MoneyManagementVariant> MoneyManagementVariants { get; set; } = new();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The list of ticker variants to test
|
||||||
|
/// </summary>
|
||||||
|
[Required]
|
||||||
|
public List<Ticker> TickerVariants { get; set; } = new();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The results of the bundle backtest execution
|
||||||
|
/// </summary>
|
||||||
|
public List<string> Results { get; set; } = new();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Total number of backtests in the bundle
|
||||||
|
/// </summary>
|
||||||
|
[Required]
|
||||||
|
public int TotalBacktests { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Number of backtests completed so far
|
||||||
|
/// </summary>
|
||||||
|
[Required]
|
||||||
|
public int CompletedBacktests { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Number of backtests that failed
|
||||||
|
/// </summary>
|
||||||
|
[Required]
|
||||||
|
public int FailedBacktests { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Progress percentage (0-100)
|
||||||
|
/// </summary>
|
||||||
|
public double ProgressPercentage => TotalBacktests > 0 ? (double)CompletedBacktests / TotalBacktests * 100 : 0;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Error message if the request failed
|
||||||
|
/// </summary>
|
||||||
|
public string? ErrorMessage { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Progress information (JSON serialized)
|
||||||
|
/// </summary>
|
||||||
|
public string? ProgressInfo { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Current backtest being processed
|
||||||
|
/// </summary>
|
||||||
|
public string? CurrentBacktest { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Estimated time remaining in seconds
|
||||||
|
/// </summary>
|
||||||
|
public int? EstimatedTimeRemainingSeconds { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Maps a domain model to a view model by deserializing JSON fields
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="request">The domain bundle backtest request</param>
|
||||||
|
/// <returns>A view model with deserialized lists</returns>
|
||||||
|
public static BundleBacktestRequestViewModel FromDomain(BundleBacktestRequest request)
|
||||||
|
{
|
||||||
|
var viewModel = new BundleBacktestRequestViewModel
|
||||||
|
{
|
||||||
|
RequestId = request.RequestId,
|
||||||
|
CreatedAt = request.CreatedAt,
|
||||||
|
CompletedAt = request.CompletedAt,
|
||||||
|
Status = request.Status,
|
||||||
|
Name = request.Name,
|
||||||
|
Results = request.Results,
|
||||||
|
TotalBacktests = request.TotalBacktests,
|
||||||
|
CompletedBacktests = request.CompletedBacktests,
|
||||||
|
FailedBacktests = request.FailedBacktests,
|
||||||
|
ErrorMessage = request.ErrorMessage,
|
||||||
|
ProgressInfo = request.ProgressInfo,
|
||||||
|
CurrentBacktest = request.CurrentBacktest,
|
||||||
|
EstimatedTimeRemainingSeconds = request.EstimatedTimeRemainingSeconds
|
||||||
|
};
|
||||||
|
|
||||||
|
// Deserialize UniversalConfig
|
||||||
|
if (!string.IsNullOrEmpty(request.UniversalConfigJson))
|
||||||
|
{
|
||||||
|
viewModel.UniversalConfig = JsonSerializer.Deserialize<BundleBacktestUniversalConfig>(request.UniversalConfigJson)
|
||||||
|
?? new BundleBacktestUniversalConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deserialize DateTimeRanges
|
||||||
|
if (!string.IsNullOrEmpty(request.DateTimeRangesJson))
|
||||||
|
{
|
||||||
|
viewModel.DateTimeRanges = JsonSerializer.Deserialize<List<DateTimeRange>>(request.DateTimeRangesJson)
|
||||||
|
?? new List<DateTimeRange>();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deserialize MoneyManagementVariants
|
||||||
|
if (!string.IsNullOrEmpty(request.MoneyManagementVariantsJson))
|
||||||
|
{
|
||||||
|
viewModel.MoneyManagementVariants = JsonSerializer.Deserialize<List<MoneyManagementVariant>>(request.MoneyManagementVariantsJson)
|
||||||
|
?? new List<MoneyManagementVariant>();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deserialize TickerVariants
|
||||||
|
if (!string.IsNullOrEmpty(request.TickerVariantsJson))
|
||||||
|
{
|
||||||
|
viewModel.TickerVariants = JsonSerializer.Deserialize<List<Ticker>>(request.TickerVariantsJson)
|
||||||
|
?? new List<Ticker>();
|
||||||
|
}
|
||||||
|
|
||||||
|
return viewModel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -12,23 +12,23 @@ public class WebhookService : IWebhookService
|
|||||||
private readonly HttpClient _httpClient;
|
private readonly HttpClient _httpClient;
|
||||||
private readonly IConfiguration _configuration;
|
private readonly IConfiguration _configuration;
|
||||||
private readonly ILogger<WebhookService> _logger;
|
private readonly ILogger<WebhookService> _logger;
|
||||||
|
private readonly string _n8nWebhookUrl;
|
||||||
|
|
||||||
public WebhookService(HttpClient httpClient, IConfiguration configuration, ILogger<WebhookService> logger)
|
public WebhookService(HttpClient httpClient, IConfiguration configuration, ILogger<WebhookService> logger)
|
||||||
{
|
{
|
||||||
_httpClient = httpClient;
|
_httpClient = httpClient;
|
||||||
_configuration = configuration;
|
_configuration = configuration;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
|
_n8nWebhookUrl = _configuration["N8n:WebhookUrl"] ?? string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task SendTradeNotification(User user, string message, bool isBadBehavior = false)
|
public async Task SendTradeNotification(User user, string message, bool isBadBehavior = false)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Get the n8n webhook URL from configuration
|
if (string.IsNullOrEmpty(user.TelegramChannel))
|
||||||
var webhookUrl = _configuration["N8n:WebhookUrl"];
|
|
||||||
if (string.IsNullOrEmpty(webhookUrl))
|
|
||||||
{
|
{
|
||||||
_logger.LogWarning("N8n webhook URL not configured, skipping webhook notification");
|
_logger.LogWarning("No telegram channel configured");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,7 +43,7 @@ public class WebhookService : IWebhookService
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Send the webhook notification
|
// Send the webhook notification
|
||||||
var response = await _httpClient.PostAsJsonAsync(webhookUrl, payload);
|
var response = await _httpClient.PostAsJsonAsync(_n8nWebhookUrl, payload);
|
||||||
|
|
||||||
if (response.IsSuccessStatusCode)
|
if (response.IsSuccessStatusCode)
|
||||||
{
|
{
|
||||||
@@ -64,11 +64,9 @@ public class WebhookService : IWebhookService
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Get the n8n webhook URL from configuration
|
if (string.IsNullOrEmpty(telegramChannel))
|
||||||
var webhookUrl = _configuration["N8n:WebhookUrl"];
|
|
||||||
if (string.IsNullOrEmpty(webhookUrl))
|
|
||||||
{
|
{
|
||||||
_logger.LogWarning("N8n webhook URL not configured, skipping webhook message");
|
_logger.LogWarning("No telegram channel configured");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,7 +80,7 @@ public class WebhookService : IWebhookService
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Send the webhook notification
|
// Send the webhook notification
|
||||||
var response = await _httpClient.PostAsJsonAsync(webhookUrl, payload);
|
var response = await _httpClient.PostAsJsonAsync(_n8nWebhookUrl, payload);
|
||||||
|
|
||||||
if (response.IsSuccessStatusCode)
|
if (response.IsSuccessStatusCode)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -872,7 +872,7 @@ export class BacktestClient extends AuthorizedApiBase {
|
|||||||
return Promise.resolve<BundleBacktestRequest>(null as any);
|
return Promise.resolve<BundleBacktestRequest>(null as any);
|
||||||
}
|
}
|
||||||
|
|
||||||
backtest_GetBundleBacktestRequests(): Promise<BundleBacktestRequest[]> {
|
backtest_GetBundleBacktestRequests(): Promise<BundleBacktestRequestViewModel[]> {
|
||||||
let url_ = this.baseUrl + "/Backtest/Bundle";
|
let url_ = this.baseUrl + "/Backtest/Bundle";
|
||||||
url_ = url_.replace(/[?&]$/, "");
|
url_ = url_.replace(/[?&]$/, "");
|
||||||
|
|
||||||
@@ -890,13 +890,13 @@ export class BacktestClient extends AuthorizedApiBase {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
protected processBacktest_GetBundleBacktestRequests(response: Response): Promise<BundleBacktestRequest[]> {
|
protected processBacktest_GetBundleBacktestRequests(response: Response): Promise<BundleBacktestRequestViewModel[]> {
|
||||||
const status = response.status;
|
const status = response.status;
|
||||||
let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); };
|
let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); };
|
||||||
if (status === 200) {
|
if (status === 200) {
|
||||||
return response.text().then((_responseText) => {
|
return response.text().then((_responseText) => {
|
||||||
let result200: any = null;
|
let result200: any = null;
|
||||||
result200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver) as BundleBacktestRequest[];
|
result200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver) as BundleBacktestRequestViewModel[];
|
||||||
return result200;
|
return result200;
|
||||||
});
|
});
|
||||||
} else if (status !== 200 && status !== 204) {
|
} else if (status !== 200 && status !== 204) {
|
||||||
@@ -904,10 +904,10 @@ export class BacktestClient extends AuthorizedApiBase {
|
|||||||
return throwException("An unexpected server error occurred.", status, _responseText, _headers);
|
return throwException("An unexpected server error occurred.", status, _responseText, _headers);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return Promise.resolve<BundleBacktestRequest[]>(null as any);
|
return Promise.resolve<BundleBacktestRequestViewModel[]>(null as any);
|
||||||
}
|
}
|
||||||
|
|
||||||
backtest_GetBundleBacktestRequest(id: string): Promise<BundleBacktestRequest> {
|
backtest_GetBundleBacktestRequest(id: string): Promise<BundleBacktestRequestViewModel> {
|
||||||
let url_ = this.baseUrl + "/Backtest/Bundle/{id}";
|
let url_ = this.baseUrl + "/Backtest/Bundle/{id}";
|
||||||
if (id === undefined || id === null)
|
if (id === undefined || id === null)
|
||||||
throw new Error("The parameter 'id' must be defined.");
|
throw new Error("The parameter 'id' must be defined.");
|
||||||
@@ -928,13 +928,13 @@ export class BacktestClient extends AuthorizedApiBase {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
protected processBacktest_GetBundleBacktestRequest(response: Response): Promise<BundleBacktestRequest> {
|
protected processBacktest_GetBundleBacktestRequest(response: Response): Promise<BundleBacktestRequestViewModel> {
|
||||||
const status = response.status;
|
const status = response.status;
|
||||||
let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); };
|
let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); };
|
||||||
if (status === 200) {
|
if (status === 200) {
|
||||||
return response.text().then((_responseText) => {
|
return response.text().then((_responseText) => {
|
||||||
let result200: any = null;
|
let result200: any = null;
|
||||||
result200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver) as BundleBacktestRequest;
|
result200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver) as BundleBacktestRequestViewModel;
|
||||||
return result200;
|
return result200;
|
||||||
});
|
});
|
||||||
} else if (status !== 200 && status !== 204) {
|
} else if (status !== 200 && status !== 204) {
|
||||||
@@ -942,7 +942,7 @@ export class BacktestClient extends AuthorizedApiBase {
|
|||||||
return throwException("An unexpected server error occurred.", status, _responseText, _headers);
|
return throwException("An unexpected server error occurred.", status, _responseText, _headers);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return Promise.resolve<BundleBacktestRequest>(null as any);
|
return Promise.resolve<BundleBacktestRequestViewModel>(null as any);
|
||||||
}
|
}
|
||||||
|
|
||||||
backtest_DeleteBundleBacktestRequest(id: string): Promise<FileResponse> {
|
backtest_DeleteBundleBacktestRequest(id: string): Promise<FileResponse> {
|
||||||
@@ -4536,6 +4536,27 @@ export interface MoneyManagementVariant {
|
|||||||
moneyManagement?: MoneyManagementRequest;
|
moneyManagement?: MoneyManagementRequest;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface BundleBacktestRequestViewModel {
|
||||||
|
requestId: string;
|
||||||
|
createdAt: Date;
|
||||||
|
completedAt?: Date | null;
|
||||||
|
status: BundleBacktestRequestStatus;
|
||||||
|
name: string;
|
||||||
|
universalConfig: BundleBacktestUniversalConfig;
|
||||||
|
dateTimeRanges: DateTimeRange[];
|
||||||
|
moneyManagementVariants: MoneyManagementVariant[];
|
||||||
|
tickerVariants: Ticker[];
|
||||||
|
results?: string[];
|
||||||
|
totalBacktests: number;
|
||||||
|
completedBacktests: number;
|
||||||
|
failedBacktests: number;
|
||||||
|
progressPercentage?: number;
|
||||||
|
errorMessage?: string | null;
|
||||||
|
progressInfo?: string | null;
|
||||||
|
currentBacktest?: string | null;
|
||||||
|
estimatedTimeRemainingSeconds?: number | null;
|
||||||
|
}
|
||||||
|
|
||||||
export interface GeneticRequest {
|
export interface GeneticRequest {
|
||||||
requestId: string;
|
requestId: string;
|
||||||
user: User;
|
user: User;
|
||||||
|
|||||||
@@ -711,6 +711,27 @@ export interface MoneyManagementVariant {
|
|||||||
moneyManagement?: MoneyManagementRequest;
|
moneyManagement?: MoneyManagementRequest;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface BundleBacktestRequestViewModel {
|
||||||
|
requestId: string;
|
||||||
|
createdAt: Date;
|
||||||
|
completedAt?: Date | null;
|
||||||
|
status: BundleBacktestRequestStatus;
|
||||||
|
name: string;
|
||||||
|
universalConfig: BundleBacktestUniversalConfig;
|
||||||
|
dateTimeRanges: DateTimeRange[];
|
||||||
|
moneyManagementVariants: MoneyManagementVariant[];
|
||||||
|
tickerVariants: Ticker[];
|
||||||
|
results?: string[];
|
||||||
|
totalBacktests: number;
|
||||||
|
completedBacktests: number;
|
||||||
|
failedBacktests: number;
|
||||||
|
progressPercentage?: number;
|
||||||
|
errorMessage?: string | null;
|
||||||
|
progressInfo?: string | null;
|
||||||
|
currentBacktest?: string | null;
|
||||||
|
estimatedTimeRemainingSeconds?: number | null;
|
||||||
|
}
|
||||||
|
|
||||||
export interface GeneticRequest {
|
export interface GeneticRequest {
|
||||||
requestId: string;
|
requestId: string;
|
||||||
user: User;
|
user: User;
|
||||||
|
|||||||
Reference in New Issue
Block a user