Refactor pagination sorting parameters across multiple controllers and services to use the new SortDirection enum; update related API models and TypeScript definitions for consistency. Fix minor documentation and naming inconsistencies in the Bot and Data controllers.
This commit is contained in:
@@ -538,7 +538,7 @@ public class BacktestController : BaseController
|
|||||||
if (request.Config.Scenario != null)
|
if (request.Config.Scenario != null)
|
||||||
{
|
{
|
||||||
// Convert ScenarioRequest to Scenario domain object
|
// Convert ScenarioRequest to Scenario domain object
|
||||||
scenario = new Scenario(request.Config.Scenario.Name, request.Config.Scenario.LoopbackPeriod)
|
scenario = new Scenario(request.Config.Scenario.Name, request.Config.Scenario.LookbackPeriod)
|
||||||
{
|
{
|
||||||
User = user
|
User = user
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using Managing.Api.Models.Requests;
|
using Managing.Api.Models.Requests;
|
||||||
using Managing.Api.Models.Responses;
|
using Managing.Api.Models.Responses;
|
||||||
using Managing.Application.Abstractions;
|
using Managing.Application.Abstractions;
|
||||||
using Managing.Application.Abstractions.Services;
|
using Managing.Application.Abstractions.Services;
|
||||||
@@ -430,7 +430,7 @@ public class BotController : BaseController
|
|||||||
/// <param name="ticker">Filter by ticker (partial match, case-insensitive). If null, no ticker filtering is applied.</param>
|
/// <param name="ticker">Filter by ticker (partial match, case-insensitive). If null, no ticker filtering is applied.</param>
|
||||||
/// <param name="agentName">Filter by agent name (partial match, case-insensitive). If null, no agent name filtering is applied.</param>
|
/// <param name="agentName">Filter by agent name (partial match, case-insensitive). If null, no agent name filtering is applied.</param>
|
||||||
/// <param name="sortBy">Sort field. Valid values: "Name", "Ticker", "Status", "CreateDate", "StartupTime", "Pnl", "WinRate", "AgentName". Default is "CreateDate".</param>
|
/// <param name="sortBy">Sort field. Valid values: "Name", "Ticker", "Status", "CreateDate", "StartupTime", "Pnl", "WinRate", "AgentName". Default is "CreateDate".</param>
|
||||||
/// <param name="sortDirection">Sort direction. Default is "Desc".</param>
|
/// <param name="sortDirection">Sort direction. Default is Desc.</param>
|
||||||
/// <returns>A paginated response containing trading bots</returns>
|
/// <returns>A paginated response containing trading bots</returns>
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
[Route("Paginated")]
|
[Route("Paginated")]
|
||||||
@@ -442,7 +442,7 @@ public class BotController : BaseController
|
|||||||
string? ticker = null,
|
string? ticker = null,
|
||||||
string? agentName = null,
|
string? agentName = null,
|
||||||
BotSortableColumn sortBy = BotSortableColumn.CreateDate,
|
BotSortableColumn sortBy = BotSortableColumn.CreateDate,
|
||||||
string sortDirection = "Desc")
|
SortDirection sortDirection = SortDirection.Desc)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -770,7 +770,7 @@ public class BotController : BaseController
|
|||||||
if (request.Config.Scenario != null)
|
if (request.Config.Scenario != null)
|
||||||
{
|
{
|
||||||
// Convert ScenarioRequest to Scenario domain object
|
// Convert ScenarioRequest to Scenario domain object
|
||||||
scenarioForUpdate = new Scenario(request.Config.Scenario.Name, request.Config.Scenario.LoopbackPeriod)
|
scenarioForUpdate = new Scenario(request.Config.Scenario.Name, request.Config.Scenario.LookbackPeriod)
|
||||||
{
|
{
|
||||||
User = user
|
User = user
|
||||||
};
|
};
|
||||||
@@ -931,7 +931,7 @@ public class BotController : BaseController
|
|||||||
if (request.Config.Scenario != null)
|
if (request.Config.Scenario != null)
|
||||||
{
|
{
|
||||||
// Convert ScenarioRequest to Scenario domain object
|
// Convert ScenarioRequest to Scenario domain object
|
||||||
scenario = new Scenario(request.Config.Scenario.Name, request.Config.Scenario.LoopbackPeriod)
|
scenario = new Scenario(request.Config.Scenario.Name, request.Config.Scenario.LookbackPeriod)
|
||||||
{
|
{
|
||||||
User = user
|
User = user
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using Managing.Api.Models.Requests;
|
using Managing.Api.Models.Requests;
|
||||||
using Managing.Api.Models.Responses;
|
using Managing.Api.Models.Responses;
|
||||||
using Managing.Application.Abstractions;
|
using Managing.Application.Abstractions;
|
||||||
using Managing.Application.Abstractions.Grains;
|
using Managing.Application.Abstractions.Grains;
|
||||||
@@ -715,7 +715,9 @@ public class DataController : ControllerBase
|
|||||||
var showOnlyProfitable = _configuration.GetValue<bool>("showOnlyProfitable", false);
|
var showOnlyProfitable = _configuration.GetValue<bool>("showOnlyProfitable", false);
|
||||||
|
|
||||||
// Get paginated results from database
|
// Get paginated results from database
|
||||||
var command = new GetPaginatedAgentSummariesCommand(page, pageSize, sortBy, sortOrder, agentNamesList, showOnlyProfitable);
|
var command =
|
||||||
|
new GetPaginatedAgentSummariesCommand(page, pageSize, sortBy, sortOrder, agentNamesList,
|
||||||
|
showOnlyProfitable);
|
||||||
var result = await _mediator.Send(command);
|
var result = await _mediator.Send(command);
|
||||||
var agentSummaries = result.Results;
|
var agentSummaries = result.Results;
|
||||||
var totalCount = result.TotalCount;
|
var totalCount = result.TotalCount;
|
||||||
@@ -819,7 +821,7 @@ public class DataController : ControllerBase
|
|||||||
/// <returns>A domain Scenario object.</returns>
|
/// <returns>A domain Scenario object.</returns>
|
||||||
private Scenario MapScenarioRequestToScenario(ScenarioRequest scenarioRequest)
|
private Scenario MapScenarioRequestToScenario(ScenarioRequest scenarioRequest)
|
||||||
{
|
{
|
||||||
var scenario = new Scenario(scenarioRequest.Name, scenarioRequest.LoopbackPeriod);
|
var scenario = new Scenario(scenarioRequest.Name, scenarioRequest.LookbackPeriod);
|
||||||
|
|
||||||
foreach (var indicatorRequest in scenarioRequest.Indicators)
|
foreach (var indicatorRequest in scenarioRequest.Indicators)
|
||||||
{
|
{
|
||||||
@@ -907,7 +909,7 @@ public class DataController : ControllerBase
|
|||||||
/// <param name="ticker">Filter by ticker (partial match, case-insensitive)</param>
|
/// <param name="ticker">Filter by ticker (partial match, case-insensitive)</param>
|
||||||
/// <param name="agentName">Filter by agent name (partial match, case-insensitive)</param>
|
/// <param name="agentName">Filter by agent name (partial match, case-insensitive)</param>
|
||||||
/// <param name="sortBy">Sort field (defaults to CreateDate)</param>
|
/// <param name="sortBy">Sort field (defaults to CreateDate)</param>
|
||||||
/// <param name="sortDirection">Sort direction - "Asc" or "Desc" (defaults to "Desc")</param>
|
/// <param name="sortDirection">Sort direction - Asc or Desc (defaults to Desc)</param>
|
||||||
/// <returns>A paginated list of strategies excluding Saved status bots</returns>
|
/// <returns>A paginated list of strategies excluding Saved status bots</returns>
|
||||||
[HttpGet("GetStrategiesPaginated")]
|
[HttpGet("GetStrategiesPaginated")]
|
||||||
public async Task<ActionResult<PaginatedResponse<TradingBotResponse>>> GetStrategiesPaginated(
|
public async Task<ActionResult<PaginatedResponse<TradingBotResponse>>> GetStrategiesPaginated(
|
||||||
@@ -917,7 +919,7 @@ public class DataController : ControllerBase
|
|||||||
string? ticker = null,
|
string? ticker = null,
|
||||||
string? agentName = null,
|
string? agentName = null,
|
||||||
BotSortableColumn sortBy = BotSortableColumn.CreateDate,
|
BotSortableColumn sortBy = BotSortableColumn.CreateDate,
|
||||||
string sortDirection = "Desc")
|
SortDirection sortDirection = SortDirection.Desc)
|
||||||
{
|
{
|
||||||
// Validate pagination parameters
|
// Validate pagination parameters
|
||||||
if (pageNumber < 1)
|
if (pageNumber < 1)
|
||||||
@@ -930,11 +932,6 @@ public class DataController : ControllerBase
|
|||||||
return BadRequest("Page size must be between 1 and 100");
|
return BadRequest("Page size must be between 1 and 100");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate sort direction
|
|
||||||
if (sortDirection != "Asc" && sortDirection != "Desc")
|
|
||||||
{
|
|
||||||
return BadRequest("Sort direction must be 'Asc' or 'Desc'");
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -191,7 +191,7 @@ public class ScenarioController : BaseController
|
|||||||
return new ScenarioViewModel
|
return new ScenarioViewModel
|
||||||
{
|
{
|
||||||
Name = scenario.Name,
|
Name = scenario.Name,
|
||||||
LoopbackPeriod = scenario.LoopbackPeriod,
|
LoopbackPeriod = scenario.LookbackPeriod,
|
||||||
UserName = scenario.User?.Name,
|
UserName = scenario.User?.Name,
|
||||||
Indicators = scenario.Indicators?.Select(MapToIndicatorViewModel).ToList() ?? new List<IndicatorViewModel>()
|
Indicators = scenario.Indicators?.Select(MapToIndicatorViewModel).ToList() ?? new List<IndicatorViewModel>()
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ public class GetBotsPaginatedRequest
|
|||||||
public BotSortableColumn SortBy { get; set; } = BotSortableColumn.CreateDate;
|
public BotSortableColumn SortBy { get; set; } = BotSortableColumn.CreateDate;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sort direction. Default is "Desc" (descending).
|
/// Sort direction. Default is Desc (descending).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string SortDirection { get; set; } = "Desc";
|
public SortDirection SortDirection { get; set; } = SortDirection.Desc;
|
||||||
}
|
}
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
using Managing.Common;
|
using Managing.Common;
|
||||||
|
|
||||||
namespace Managing.Api.Models.Responses
|
namespace Managing.Api.Models.Responses
|
||||||
@@ -10,41 +11,49 @@ namespace Managing.Api.Models.Responses
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Name of the deployed strategy
|
/// Name of the deployed strategy
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[Required]
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Current state of the strategy (RUNNING, STOPPED, UNUSED)
|
/// Current state of the strategy (RUNNING, STOPPED, UNUSED)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[Required]
|
||||||
public Enums.BotStatus State { get; set; }
|
public Enums.BotStatus State { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Total profit or loss generated by the strategy in USD (gross, before fees)
|
/// Total profit or loss generated by the strategy in USD (gross, before fees)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[Required]
|
||||||
public decimal PnL { get; set; }
|
public decimal PnL { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Net profit or loss generated by the strategy in USD (after fees)
|
/// Net profit or loss generated by the strategy in USD (after fees)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[Required]
|
||||||
public decimal NetPnL { get; set; }
|
public decimal NetPnL { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Return on investment percentage
|
/// Return on investment percentage
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[Required]
|
||||||
public decimal ROIPercentage { get; set; }
|
public decimal ROIPercentage { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Date and time when the strategy was started (only present when running, for live ticker)
|
/// Date and time when the strategy was started (only present when running, for live ticker)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[Required]
|
||||||
public DateTime? Runtime { get; set; }
|
public DateTime? Runtime { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Total accumulated runtime in seconds (including current session if running)
|
/// Total accumulated runtime in seconds (including current session if running)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[Required]
|
||||||
public long TotalRuntimeSeconds { get; set; }
|
public long TotalRuntimeSeconds { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Time when the current or last session started
|
/// Time when the current or last session started
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[Required]
|
||||||
public DateTime? LastStartTime { get; set; }
|
public DateTime? LastStartTime { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -55,42 +64,49 @@ namespace Managing.Api.Models.Responses
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Total accumulated runtime across all past sessions (seconds)
|
/// Total accumulated runtime across all past sessions (seconds)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[Required]
|
||||||
public long AccumulatedRunTimeSeconds { get; set; }
|
public long AccumulatedRunTimeSeconds { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Average percentage of successful trades
|
/// Average percentage of successful trades
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[Required]
|
||||||
public int WinRate { get; set; }
|
public int WinRate { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Total trading volume for all trades
|
/// Total trading volume for all trades
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[Required]
|
||||||
public decimal TotalVolumeTraded { get; set; }
|
public decimal TotalVolumeTraded { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Trading volume in the last 24 hours
|
/// Trading volume in the last 24 hours
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[Required]
|
||||||
public decimal VolumeLast24H { get; set; }
|
public decimal VolumeLast24H { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Number of winning trades
|
/// Number of winning trades
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[Required]
|
||||||
public int Wins { get; set; }
|
public int Wins { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Number of losing trades
|
/// Number of losing trades
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[Required]
|
||||||
public int Losses { get; set; }
|
public int Losses { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Dictionary of all positions executed by this strategy, keyed by position identifier
|
/// Dictionary of all positions executed by this strategy, keyed by position identifier
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[Required]
|
||||||
public List<PositionViewModel> Positions { get; set; } = new List<PositionViewModel>();
|
public List<PositionViewModel> Positions { get; set; } = new List<PositionViewModel>();
|
||||||
|
|
||||||
public Guid Identifier { get; set; }
|
[Required] public Guid Identifier { get; set; }
|
||||||
|
|
||||||
public Dictionary<DateTime, decimal> WalletBalances { get; set; } = new Dictionary<DateTime, decimal>();
|
public Dictionary<DateTime, decimal> WalletBalances { get; set; } = new Dictionary<DateTime, decimal>();
|
||||||
public Enums.Ticker Ticker { get; set; }
|
[Required] public Enums.Ticker Ticker { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The agent name of the master bot's owner (for copy trading bots)
|
/// The agent name of the master bot's owner (for copy trading bots)
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ public interface IBotRepository
|
|||||||
string? ticker = null,
|
string? ticker = null,
|
||||||
string? agentName = null,
|
string? agentName = null,
|
||||||
BotSortableColumn sortBy = BotSortableColumn.CreateDate,
|
BotSortableColumn sortBy = BotSortableColumn.CreateDate,
|
||||||
string sortDirection = "Desc",
|
SortDirection sortDirection = SortDirection.Desc,
|
||||||
bool showOnlyProfitable = false);
|
bool showOnlyProfitable = false);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -158,7 +158,7 @@ public class BacktestTests : BaseTests
|
|||||||
var scenario = new Scenario("ETH_BacktestScenario");
|
var scenario = new Scenario("ETH_BacktestScenario");
|
||||||
var rsiDivIndicator = ScenarioHelpers.BuildIndicator(IndicatorType.RsiDivergence, "RsiDiv", period: 14);
|
var rsiDivIndicator = ScenarioHelpers.BuildIndicator(IndicatorType.RsiDivergence, "RsiDiv", period: 14);
|
||||||
scenario.Indicators = new List<IndicatorBase> { (IndicatorBase)rsiDivIndicator };
|
scenario.Indicators = new List<IndicatorBase> { (IndicatorBase)rsiDivIndicator };
|
||||||
scenario.LoopbackPeriod = 15;
|
scenario.LookbackPeriod = 15;
|
||||||
|
|
||||||
var config = new TradingBotConfig
|
var config = new TradingBotConfig
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ public interface IBotService
|
|||||||
/// <param name="ticker">Filter by ticker (partial match, case-insensitive)</param>
|
/// <param name="ticker">Filter by ticker (partial match, case-insensitive)</param>
|
||||||
/// <param name="agentName">Filter by agent name (partial match, case-insensitive)</param>
|
/// <param name="agentName">Filter by agent name (partial match, case-insensitive)</param>
|
||||||
/// <param name="sortBy">Sort field</param>
|
/// <param name="sortBy">Sort field</param>
|
||||||
/// <param name="sortDirection">Sort direction ("Asc" or "Desc")</param>
|
/// <param name="sortDirection">Sort direction</param>
|
||||||
/// <param name="showOnlyProfitable">Whether to show only profitable bots (ROI > 0)</param>
|
/// <param name="showOnlyProfitable">Whether to show only profitable bots (ROI > 0)</param>
|
||||||
/// <returns>Tuple containing the bots for the current page and total count</returns>
|
/// <returns>Tuple containing the bots for the current page and total count</returns>
|
||||||
Task<(IEnumerable<Bot> Bots, int TotalCount)> GetBotsPaginatedAsync(
|
Task<(IEnumerable<Bot> Bots, int TotalCount)> GetBotsPaginatedAsync(
|
||||||
@@ -58,7 +58,7 @@ public interface IBotService
|
|||||||
string? ticker = null,
|
string? ticker = null,
|
||||||
string? agentName = null,
|
string? agentName = null,
|
||||||
BotSortableColumn sortBy = BotSortableColumn.CreateDate,
|
BotSortableColumn sortBy = BotSortableColumn.CreateDate,
|
||||||
string sortDirection = "Desc",
|
SortDirection sortDirection = SortDirection.Desc,
|
||||||
bool showOnlyProfitable = false);
|
bool showOnlyProfitable = false);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ namespace Managing.Application.Abstractions
|
|||||||
{
|
{
|
||||||
public interface IScenarioService
|
public interface IScenarioService
|
||||||
{
|
{
|
||||||
Task<Scenario> CreateScenario(string name, List<string> strategies, int? loopbackPeriod = 1);
|
Task<Scenario> CreateScenario(string name, List<string> strategies, int loopbackPeriod = 1);
|
||||||
Task<IEnumerable<IndicatorBase>> GetIndicatorsAsync();
|
Task<IEnumerable<IndicatorBase>> GetIndicatorsAsync();
|
||||||
Task<bool> UpdateScenario(string name, List<string> strategies, int? loopbackPeriod);
|
Task<bool> UpdateScenario(string name, List<string> strategies, int? loopbackPeriod);
|
||||||
|
|
||||||
|
|||||||
@@ -151,7 +151,7 @@ public class JobService
|
|||||||
if (backtestRequest.Config.Scenario != null)
|
if (backtestRequest.Config.Scenario != null)
|
||||||
{
|
{
|
||||||
var sReq = backtestRequest.Config.Scenario;
|
var sReq = backtestRequest.Config.Scenario;
|
||||||
scenario = new LightScenario(sReq.Name, sReq.LoopbackPeriod)
|
scenario = new LightScenario(sReq.Name, sReq.LookbackPeriod)
|
||||||
{
|
{
|
||||||
Indicators = sReq.Indicators?.Select(ind => new LightIndicator(ind.Name, ind.Type)
|
Indicators = sReq.Indicators?.Select(ind => new LightIndicator(ind.Name, ind.Type)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -176,7 +176,7 @@ public class BacktestFuturesBot : TradingBotBase, ITradingBot
|
|||||||
throw new ArgumentNullException(nameof(Config.Scenario), "Config.Scenario cannot be null");
|
throw new ArgumentNullException(nameof(Config.Scenario), "Config.Scenario cannot be null");
|
||||||
|
|
||||||
// Use TradingBox.GetSignal for backtest with pre-calculated indicators
|
// Use TradingBox.GetSignal for backtest with pre-calculated indicators
|
||||||
var backtestSignal = TradingBox.GetSignal(candles, Config.Scenario, Signals, Config.Scenario.LoopbackPeriod,
|
var backtestSignal = TradingBox.GetSignal(candles, Config.Scenario, Signals, Config.Scenario.LookbackPeriod,
|
||||||
preCalculatedIndicatorValues);
|
preCalculatedIndicatorValues);
|
||||||
if (backtestSignal == null) return;
|
if (backtestSignal == null) return;
|
||||||
|
|
||||||
|
|||||||
@@ -180,7 +180,7 @@ public class BacktestSpotBot : TradingBotBase, ITradingBot
|
|||||||
throw new ArgumentNullException(nameof(Config.Scenario), "Config.Scenario cannot be null");
|
throw new ArgumentNullException(nameof(Config.Scenario), "Config.Scenario cannot be null");
|
||||||
|
|
||||||
// Use TradingBox.GetSignal for backtest with pre-calculated indicators
|
// Use TradingBox.GetSignal for backtest with pre-calculated indicators
|
||||||
var backtestSignal = TradingBox.GetSignal(candles, Config.Scenario, Signals, Config.Scenario.LoopbackPeriod,
|
var backtestSignal = TradingBox.GetSignal(candles, Config.Scenario, Signals, Config.Scenario.LookbackPeriod,
|
||||||
preCalculatedIndicatorValues);
|
preCalculatedIndicatorValues);
|
||||||
if (backtestSignal == null) return;
|
if (backtestSignal == null) return;
|
||||||
|
|
||||||
|
|||||||
@@ -487,7 +487,7 @@ namespace Managing.Application.ManageBot
|
|||||||
string? ticker = null,
|
string? ticker = null,
|
||||||
string? agentName = null,
|
string? agentName = null,
|
||||||
BotSortableColumn sortBy = BotSortableColumn.CreateDate,
|
BotSortableColumn sortBy = BotSortableColumn.CreateDate,
|
||||||
string sortDirection = "Desc",
|
SortDirection sortDirection = SortDirection.Desc,
|
||||||
bool showOnlyProfitable = false)
|
bool showOnlyProfitable = false)
|
||||||
{
|
{
|
||||||
return await ServiceScopeHelpers.WithScopedService<IBotRepository, (IEnumerable<Bot> Bots, int TotalCount)>(
|
return await ServiceScopeHelpers.WithScopedService<IBotRepository, (IEnumerable<Bot> Bots, int TotalCount)>(
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ public class ScenarioRunnerGrain : Grain, IScenarioRunnerGrain
|
|||||||
candlesList,
|
candlesList,
|
||||||
config.Scenario,
|
config.Scenario,
|
||||||
previousSignals,
|
previousSignals,
|
||||||
config.Scenario?.LoopbackPeriod ?? 1);
|
config.Scenario?.LookbackPeriod ?? 1);
|
||||||
|
|
||||||
if (signal != null && signal.Date > candle.Date)
|
if (signal != null && signal.Date > candle.Date)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ namespace Managing.Application.Scenarios
|
|||||||
_tradingService = tradingService;
|
_tradingService = tradingService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<Scenario> CreateScenario(string name, List<string> strategies, int? loopbackPeriod = 1)
|
public async Task<Scenario> CreateScenario(string name, List<string> strategies, int loopbackPeriod = 1)
|
||||||
{
|
{
|
||||||
var scenario = new Scenario(name, loopbackPeriod);
|
var scenario = new Scenario(name, loopbackPeriod);
|
||||||
|
|
||||||
@@ -77,7 +77,7 @@ namespace Managing.Application.Scenarios
|
|||||||
scenario.AddIndicator(await _tradingService.GetIndicatorByNameAsync(strategy));
|
scenario.AddIndicator(await _tradingService.GetIndicatorByNameAsync(strategy));
|
||||||
}
|
}
|
||||||
|
|
||||||
scenario.LoopbackPeriod = loopbackPeriod ?? 1;
|
scenario.LookbackPeriod = loopbackPeriod ?? 1;
|
||||||
await _tradingService.UpdateScenarioAsync(scenario);
|
await _tradingService.UpdateScenarioAsync(scenario);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -262,7 +262,7 @@ namespace Managing.Application.Scenarios
|
|||||||
}
|
}
|
||||||
|
|
||||||
scenario.Indicators.Clear();
|
scenario.Indicators.Clear();
|
||||||
scenario.LoopbackPeriod = loopbackPeriod ?? 1;
|
scenario.LookbackPeriod = loopbackPeriod ?? 1;
|
||||||
|
|
||||||
foreach (var strategyName in strategies)
|
foreach (var strategyName in strategies)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -225,7 +225,7 @@ public class BundleBacktestWorker : BaseWorker<BundleBacktestWorker>
|
|||||||
if (runBacktestRequest.Config.Scenario != null)
|
if (runBacktestRequest.Config.Scenario != null)
|
||||||
{
|
{
|
||||||
var sReq = runBacktestRequest.Config.Scenario;
|
var sReq = runBacktestRequest.Config.Scenario;
|
||||||
scenario = new LightScenario(sReq.Name, sReq.LoopbackPeriod)
|
scenario = new LightScenario(sReq.Name, sReq.LookbackPeriod)
|
||||||
{
|
{
|
||||||
Indicators = sReq.Indicators?.Select(i => new LightIndicator(i.Name, i.Type)
|
Indicators = sReq.Indicators?.Select(i => new LightIndicator(i.Name, i.Type)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace Managing.Common;
|
namespace Managing.Common;
|
||||||
|
|
||||||
public static class Enums
|
public static class Enums
|
||||||
{
|
{
|
||||||
@@ -101,6 +101,15 @@ public static class Enums
|
|||||||
AgentName
|
AgentName
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sort direction for pagination endpoints
|
||||||
|
/// </summary>
|
||||||
|
public enum SortDirection
|
||||||
|
{
|
||||||
|
Asc,
|
||||||
|
Desc
|
||||||
|
}
|
||||||
|
|
||||||
public enum SignalStatus
|
public enum SignalStatus
|
||||||
{
|
{
|
||||||
WaitingForPosition,
|
WaitingForPosition,
|
||||||
|
|||||||
@@ -22,5 +22,5 @@ public class ScenarioRequest
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The loopback period for the scenario
|
/// The loopback period for the scenario
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int? LoopbackPeriod { get; set; }
|
public int LookbackPeriod { get; set; }
|
||||||
}
|
}
|
||||||
@@ -45,6 +45,7 @@ public class TradingBotConfig
|
|||||||
/// Orleans-friendly version without FixedSizeQueue and User properties.
|
/// Orleans-friendly version without FixedSizeQueue and User properties.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Id(12)]
|
[Id(12)]
|
||||||
|
[Required]
|
||||||
public LightScenario Scenario { get; set; }
|
public LightScenario Scenario { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -104,6 +105,7 @@ public class TradingBotConfig
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
[Id(20)]
|
[Id(20)]
|
||||||
public bool UseForDynamicStopLoss { get; set; } = true;
|
public bool UseForDynamicStopLoss { get; set; } = true;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Parameter to indicate if the bot is for copy trading
|
/// Parameter to indicate if the bot is for copy trading
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
using Managing.Domain.Scenarios;
|
using Managing.Domain.Scenarios;
|
||||||
using Orleans;
|
using Orleans;
|
||||||
using static Managing.Common.Enums;
|
using static Managing.Common.Enums;
|
||||||
@@ -18,11 +19,11 @@ public class LightIndicator
|
|||||||
SignalType = ScenarioHelpers.GetSignalType(type);
|
SignalType = ScenarioHelpers.GetSignalType(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Id(0)] public string Name { get; set; }
|
[Id(0)] [Required] public string Name { get; set; }
|
||||||
|
|
||||||
[Id(1)] public IndicatorType Type { get; set; }
|
[Id(1)] [Required] public IndicatorType Type { get; set; }
|
||||||
|
|
||||||
[Id(2)] public SignalType SignalType { get; set; }
|
[Id(2)] [Required] public SignalType SignalType { get; set; }
|
||||||
|
|
||||||
[Id(3)] public int MinimumHistory { get; set; }
|
[Id(3)] public int MinimumHistory { get; set; }
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
using Managing.Domain.Strategies;
|
using Managing.Domain.Strategies;
|
||||||
using Orleans;
|
using Orleans;
|
||||||
|
|
||||||
@@ -10,25 +11,25 @@ namespace Managing.Domain.Scenarios;
|
|||||||
[GenerateSerializer]
|
[GenerateSerializer]
|
||||||
public class LightScenario
|
public class LightScenario
|
||||||
{
|
{
|
||||||
public LightScenario(string name, int? loopbackPeriod = 1)
|
public LightScenario(string name, int lookbackPeriod = 1)
|
||||||
{
|
{
|
||||||
Name = name;
|
Name = name;
|
||||||
Indicators = new List<LightIndicator>();
|
Indicators = new List<LightIndicator>();
|
||||||
LoopbackPeriod = loopbackPeriod;
|
LookbackPeriod = lookbackPeriod;
|
||||||
}
|
}
|
||||||
|
|
||||||
[Id(0)] public string Name { get; set; }
|
[Id(0)] public string Name { get; set; }
|
||||||
|
|
||||||
[Id(1)] public List<LightIndicator> Indicators { get; set; }
|
[Id(1)] public List<LightIndicator> Indicators { get; set; }
|
||||||
|
|
||||||
[Id(2)] public int? LoopbackPeriod { get; set; }
|
[Id(2)] [Required] public int LookbackPeriod { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Converts a full Scenario to a LightScenario
|
/// Converts a full Scenario to a LightScenario
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static LightScenario FromScenario(Scenario scenario)
|
public static LightScenario FromScenario(Scenario scenario)
|
||||||
{
|
{
|
||||||
var lightScenario = new LightScenario(scenario.Name, scenario.LoopbackPeriod)
|
var lightScenario = new LightScenario(scenario.Name, scenario.LookbackPeriod)
|
||||||
{
|
{
|
||||||
Indicators = scenario.Indicators?.Select(ScenarioHelpers.BaseToLight).ToList() ??
|
Indicators = scenario.Indicators?.Select(ScenarioHelpers.BaseToLight).ToList() ??
|
||||||
new List<LightIndicator>()
|
new List<LightIndicator>()
|
||||||
@@ -41,7 +42,7 @@ public class LightScenario
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public Scenario ToScenario()
|
public Scenario ToScenario()
|
||||||
{
|
{
|
||||||
var scenario = new Scenario(Name, LoopbackPeriod)
|
var scenario = new Scenario(Name, LookbackPeriod)
|
||||||
{
|
{
|
||||||
Indicators = Indicators?.Select(li => li.LightToBase()).ToList()
|
Indicators = Indicators?.Select(li => li.LightToBase()).ToList()
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -7,18 +7,18 @@ namespace Managing.Domain.Scenarios
|
|||||||
[GenerateSerializer]
|
[GenerateSerializer]
|
||||||
public class Scenario
|
public class Scenario
|
||||||
{
|
{
|
||||||
public Scenario(string name, int? loopbackPeriod = 1)
|
public Scenario(string name, int lookbackPeriod = 1)
|
||||||
{
|
{
|
||||||
Name = name;
|
Name = name;
|
||||||
Indicators = new List<IndicatorBase>();
|
Indicators = new List<IndicatorBase>();
|
||||||
LoopbackPeriod = loopbackPeriod;
|
LookbackPeriod = lookbackPeriod;
|
||||||
}
|
}
|
||||||
|
|
||||||
[Id(0)] public string Name { get; set; }
|
[Id(0)] public string Name { get; set; }
|
||||||
|
|
||||||
[Id(1)] public List<IndicatorBase> Indicators { get; set; }
|
[Id(1)] public List<IndicatorBase> Indicators { get; set; }
|
||||||
|
|
||||||
[Id(2)] public int? LoopbackPeriod { get; set; }
|
[Id(2)] public int LookbackPeriod { get; set; }
|
||||||
|
|
||||||
[Id(3)] public User User { get; set; }
|
[Id(3)] public User User { get; set; }
|
||||||
|
|
||||||
|
|||||||
@@ -206,7 +206,7 @@ public class PostgreSqlBotRepository : IBotRepository
|
|||||||
string? ticker = null,
|
string? ticker = null,
|
||||||
string? agentName = null,
|
string? agentName = null,
|
||||||
BotSortableColumn sortBy = BotSortableColumn.CreateDate,
|
BotSortableColumn sortBy = BotSortableColumn.CreateDate,
|
||||||
string sortDirection = "Desc",
|
SortDirection sortDirection = SortDirection.Desc,
|
||||||
bool showOnlyProfitable = false)
|
bool showOnlyProfitable = false)
|
||||||
{
|
{
|
||||||
// Build the query with filters
|
// Build the query with filters
|
||||||
@@ -249,33 +249,33 @@ public class PostgreSqlBotRepository : IBotRepository
|
|||||||
// Apply sorting
|
// Apply sorting
|
||||||
query = sortBy switch
|
query = sortBy switch
|
||||||
{
|
{
|
||||||
BotSortableColumn.Name => sortDirection.ToLower() == "asc"
|
BotSortableColumn.Name => sortDirection == SortDirection.Asc
|
||||||
? query.OrderBy(b => b.Name)
|
? query.OrderBy(b => b.Name)
|
||||||
: query.OrderByDescending(b => b.Name),
|
: query.OrderByDescending(b => b.Name),
|
||||||
BotSortableColumn.Ticker => sortDirection.ToLower() == "asc"
|
BotSortableColumn.Ticker => sortDirection == SortDirection.Asc
|
||||||
? query.OrderBy(b => b.Ticker)
|
? query.OrderBy(b => b.Ticker)
|
||||||
: query.OrderByDescending(b => b.Ticker),
|
: query.OrderByDescending(b => b.Ticker),
|
||||||
BotSortableColumn.Status => sortDirection.ToLower() == "asc"
|
BotSortableColumn.Status => sortDirection == SortDirection.Asc
|
||||||
? query.OrderBy(b => b.Status)
|
? query.OrderBy(b => b.Status)
|
||||||
: query.OrderByDescending(b => b.Status),
|
: query.OrderByDescending(b => b.Status),
|
||||||
BotSortableColumn.StartupTime => sortDirection.ToLower() == "asc"
|
BotSortableColumn.StartupTime => sortDirection == SortDirection.Asc
|
||||||
? query.OrderBy(b => b.StartupTime)
|
? query.OrderBy(b => b.StartupTime)
|
||||||
: query.OrderByDescending(b => b.StartupTime),
|
: query.OrderByDescending(b => b.StartupTime),
|
||||||
BotSortableColumn.Roi => sortDirection.ToLower() == "asc"
|
BotSortableColumn.Roi => sortDirection == SortDirection.Asc
|
||||||
? query.OrderBy(b => b.Roi)
|
? query.OrderBy(b => b.Roi)
|
||||||
: query.OrderByDescending(b => b.Roi),
|
: query.OrderByDescending(b => b.Roi),
|
||||||
BotSortableColumn.Pnl => sortDirection.ToLower() == "asc"
|
BotSortableColumn.Pnl => sortDirection == SortDirection.Asc
|
||||||
? query.OrderBy(b => b.Pnl)
|
? query.OrderBy(b => b.Pnl)
|
||||||
: query.OrderByDescending(b => b.Pnl),
|
: query.OrderByDescending(b => b.Pnl),
|
||||||
BotSortableColumn.WinRate => sortDirection.ToLower() == "asc"
|
BotSortableColumn.WinRate => sortDirection == SortDirection.Asc
|
||||||
? query.OrderBy(b =>
|
? query.OrderBy(b =>
|
||||||
(b.TradeWins + b.TradeLosses) > 0 ? (double)b.TradeWins / (b.TradeWins + b.TradeLosses) : 0)
|
(b.TradeWins + b.TradeLosses) > 0 ? (double)b.TradeWins / (b.TradeWins + b.TradeLosses) : 0)
|
||||||
: query.OrderByDescending(b =>
|
: query.OrderByDescending(b =>
|
||||||
(b.TradeWins + b.TradeLosses) > 0 ? (double)b.TradeWins / (b.TradeWins + b.TradeLosses) : 0),
|
(b.TradeWins + b.TradeLosses) > 0 ? (double)b.TradeWins / (b.TradeWins + b.TradeLosses) : 0),
|
||||||
BotSortableColumn.AgentName => sortDirection.ToLower() == "asc"
|
BotSortableColumn.AgentName => sortDirection == SortDirection.Asc
|
||||||
? query.OrderBy(b => b.User.AgentName)
|
? query.OrderBy(b => b.User.AgentName)
|
||||||
: query.OrderByDescending(b => b.User.AgentName),
|
: query.OrderByDescending(b => b.User.AgentName),
|
||||||
_ => sortDirection.ToLower() == "asc"
|
_ => sortDirection == SortDirection.Asc
|
||||||
? query.OrderBy(b => b.CreateDate)
|
? query.OrderBy(b => b.CreateDate)
|
||||||
: query.OrderByDescending(b => b.CreateDate)
|
: query.OrderByDescending(b => b.CreateDate)
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -360,7 +360,9 @@ public static class PostgreSqlMappers
|
|||||||
Duration = backtest.EndDate - backtest.StartDate,
|
Duration = backtest.EndDate - backtest.StartDate,
|
||||||
MoneyManagementJson = JsonConvert.SerializeObject(backtest.Config?.MoneyManagement, jsonSettings),
|
MoneyManagementJson = JsonConvert.SerializeObject(backtest.Config?.MoneyManagement, jsonSettings),
|
||||||
UserId = backtest.User?.Id ?? 0,
|
UserId = backtest.User?.Id ?? 0,
|
||||||
StatisticsJson = backtest.Statistics != null ? JsonConvert.SerializeObject(backtest.Statistics, jsonSettings) : null,
|
StatisticsJson = backtest.Statistics != null
|
||||||
|
? JsonConvert.SerializeObject(backtest.Statistics, jsonSettings)
|
||||||
|
: null,
|
||||||
SharpeRatio = backtest.Statistics?.SharpeRatio ?? 0m,
|
SharpeRatio = backtest.Statistics?.SharpeRatio ?? 0m,
|
||||||
MaxDrawdown = backtest.Statistics?.MaxDrawdown ?? 0m,
|
MaxDrawdown = backtest.Statistics?.MaxDrawdown ?? 0m,
|
||||||
MaxDrawdownRecoveryTime = backtest.Statistics?.MaxDrawdownRecoveryTime ?? TimeSpan.Zero,
|
MaxDrawdownRecoveryTime = backtest.Statistics?.MaxDrawdownRecoveryTime ?? TimeSpan.Zero,
|
||||||
@@ -503,7 +505,7 @@ public static class PostgreSqlMappers
|
|||||||
return new ScenarioEntity
|
return new ScenarioEntity
|
||||||
{
|
{
|
||||||
Name = scenario.Name,
|
Name = scenario.Name,
|
||||||
LoopbackPeriod = scenario.LoopbackPeriod ?? 1,
|
LoopbackPeriod = scenario.LookbackPeriod,
|
||||||
UserId = scenario.User?.Id ?? 0
|
UserId = scenario.User?.Id ?? 0
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,8 @@ namespace Managing.Infrastructure.Databases.PostgreSql;
|
|||||||
|
|
||||||
public class PostgreSqlTradingRepository : BaseRepositoryWithLogging, ITradingRepository
|
public class PostgreSqlTradingRepository : BaseRepositoryWithLogging, ITradingRepository
|
||||||
{
|
{
|
||||||
public PostgreSqlTradingRepository(ManagingDbContext context, ILogger<SqlQueryLogger> logger, SentrySqlMonitoringService sentryMonitoringService)
|
public PostgreSqlTradingRepository(ManagingDbContext context, ILogger<SqlQueryLogger> logger,
|
||||||
|
SentrySqlMonitoringService sentryMonitoringService)
|
||||||
: base(context, logger, sentryMonitoringService)
|
: base(context, logger, sentryMonitoringService)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -154,7 +155,7 @@ public class PostgreSqlTradingRepository : BaseRepositoryWithLogging, ITradingRe
|
|||||||
|
|
||||||
if (entity != null)
|
if (entity != null)
|
||||||
{
|
{
|
||||||
entity.LoopbackPeriod = scenario.LoopbackPeriod ?? 1;
|
entity.LoopbackPeriod = scenario.LookbackPeriod;
|
||||||
entity.UserId = scenario.User?.Id ?? 0;
|
entity.UserId = scenario.User?.Id ?? 0;
|
||||||
entity.UpdatedAt = DateTime.UtcNow;
|
entity.UpdatedAt = DateTime.UtcNow;
|
||||||
|
|
||||||
@@ -463,7 +464,8 @@ public class PostgreSqlTradingRepository : BaseRepositoryWithLogging, ITradingRe
|
|||||||
{
|
{
|
||||||
await PostgreSqlConnectionHelper.SafeCloseConnectionAsync(_context);
|
await PostgreSqlConnectionHelper.SafeCloseConnectionAsync(_context);
|
||||||
}
|
}
|
||||||
}, nameof(UpdatePositionAsync), ("positionIdentifier", position.Identifier), ("positionStatus", position.Status));
|
}, nameof(UpdatePositionAsync), ("positionIdentifier", position.Identifier),
|
||||||
|
("positionStatus", position.Status));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -355,7 +355,7 @@ export interface TradingBotConfig {
|
|||||||
flipPosition: boolean;
|
flipPosition: boolean;
|
||||||
name: string;
|
name: string;
|
||||||
riskManagement?: RiskManagement | null;
|
riskManagement?: RiskManagement | null;
|
||||||
scenario?: LightScenario | null;
|
scenario: LightScenario;
|
||||||
scenarioName?: string | null;
|
scenarioName?: string | null;
|
||||||
maxPositionTimeHours?: number | null;
|
maxPositionTimeHours?: number | null;
|
||||||
closeEarlyWhenProfitable?: boolean;
|
closeEarlyWhenProfitable?: boolean;
|
||||||
@@ -420,13 +420,13 @@ export enum RiskToleranceLevel {
|
|||||||
export interface LightScenario {
|
export interface LightScenario {
|
||||||
name?: string | null;
|
name?: string | null;
|
||||||
indicators?: LightIndicator[] | null;
|
indicators?: LightIndicator[] | null;
|
||||||
loopbackPeriod?: number | null;
|
lookbackPeriod: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface LightIndicator {
|
export interface LightIndicator {
|
||||||
name?: string | null;
|
name: string;
|
||||||
type?: IndicatorType;
|
type: IndicatorType;
|
||||||
signalType?: SignalType;
|
signalType: SignalType;
|
||||||
minimumHistory?: number;
|
minimumHistory?: number;
|
||||||
period?: number | null;
|
period?: number | null;
|
||||||
fastPeriods?: number | null;
|
fastPeriods?: number | null;
|
||||||
@@ -728,7 +728,7 @@ export interface TradingBotConfigRequest {
|
|||||||
export interface ScenarioRequest {
|
export interface ScenarioRequest {
|
||||||
name: string;
|
name: string;
|
||||||
indicators: IndicatorRequest[];
|
indicators: IndicatorRequest[];
|
||||||
loopbackPeriod?: number | null;
|
lookbackPeriod?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IndicatorRequest {
|
export interface IndicatorRequest {
|
||||||
@@ -1014,6 +1014,11 @@ export enum BotSortableColumn {
|
|||||||
AgentName = "AgentName",
|
AgentName = "AgentName",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum SortDirection {
|
||||||
|
Asc = "Asc",
|
||||||
|
Desc = "Desc",
|
||||||
|
}
|
||||||
|
|
||||||
export interface CreateManualSignalRequest {
|
export interface CreateManualSignalRequest {
|
||||||
identifier?: string;
|
identifier?: string;
|
||||||
direction?: TradeDirection;
|
direction?: TradeDirection;
|
||||||
@@ -1052,7 +1057,7 @@ export interface Spotlight {
|
|||||||
export interface Scenario {
|
export interface Scenario {
|
||||||
name?: string | null;
|
name?: string | null;
|
||||||
indicators?: IndicatorBase[] | null;
|
indicators?: IndicatorBase[] | null;
|
||||||
loopbackPeriod?: number | null;
|
lookbackPeriod?: number;
|
||||||
user?: User | null;
|
user?: User | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1231,25 +1236,25 @@ export interface StrategyRoiPerformance {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface UserStrategyDetailsViewModel {
|
export interface UserStrategyDetailsViewModel {
|
||||||
name?: string | null;
|
name: string;
|
||||||
state?: BotStatus;
|
state: BotStatus;
|
||||||
pnL?: number;
|
pnL: number;
|
||||||
netPnL?: number;
|
netPnL: number;
|
||||||
roiPercentage?: number;
|
roiPercentage: number;
|
||||||
runtime?: Date | null;
|
runtime: Date;
|
||||||
totalRuntimeSeconds?: number;
|
totalRuntimeSeconds: number;
|
||||||
lastStartTime?: Date | null;
|
lastStartTime: Date;
|
||||||
lastStopTime?: Date | null;
|
lastStopTime?: Date | null;
|
||||||
accumulatedRunTimeSeconds?: number;
|
accumulatedRunTimeSeconds: number;
|
||||||
winRate?: number;
|
winRate: number;
|
||||||
totalVolumeTraded?: number;
|
totalVolumeTraded: number;
|
||||||
volumeLast24H?: number;
|
volumeLast24H: number;
|
||||||
wins?: number;
|
wins: number;
|
||||||
losses?: number;
|
losses: number;
|
||||||
positions?: PositionViewModel[] | null;
|
positions: PositionViewModel[];
|
||||||
identifier?: string;
|
identifier: string;
|
||||||
walletBalances?: { [key: string]: number; } | null;
|
walletBalances?: { [key: string]: number; } | null;
|
||||||
ticker?: Ticker;
|
ticker: Ticker;
|
||||||
masterAgentName?: string | null;
|
masterAgentName?: string | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1917,7 +1917,7 @@ export class BotClient extends AuthorizedApiBase {
|
|||||||
return Promise.resolve<TradingBotResponse[]>(null as any);
|
return Promise.resolve<TradingBotResponse[]>(null as any);
|
||||||
}
|
}
|
||||||
|
|
||||||
bot_GetBotsPaginated(pageNumber: number | undefined, pageSize: number | undefined, status: BotStatus | null | undefined, name: string | null | undefined, ticker: string | null | undefined, agentName: string | null | undefined, sortBy: BotSortableColumn | undefined, sortDirection: string | null | undefined): Promise<PaginatedResponseOfTradingBotResponse> {
|
bot_GetBotsPaginated(pageNumber: number | undefined, pageSize: number | undefined, status: BotStatus | null | undefined, name: string | null | undefined, ticker: string | null | undefined, agentName: string | null | undefined, sortBy: BotSortableColumn | undefined, sortDirection: SortDirection | undefined): Promise<PaginatedResponseOfTradingBotResponse> {
|
||||||
let url_ = this.baseUrl + "/Bot/Paginated?";
|
let url_ = this.baseUrl + "/Bot/Paginated?";
|
||||||
if (pageNumber === null)
|
if (pageNumber === null)
|
||||||
throw new Error("The parameter 'pageNumber' cannot be null.");
|
throw new Error("The parameter 'pageNumber' cannot be null.");
|
||||||
@@ -1939,7 +1939,9 @@ export class BotClient extends AuthorizedApiBase {
|
|||||||
throw new Error("The parameter 'sortBy' cannot be null.");
|
throw new Error("The parameter 'sortBy' cannot be null.");
|
||||||
else if (sortBy !== undefined)
|
else if (sortBy !== undefined)
|
||||||
url_ += "sortBy=" + encodeURIComponent("" + sortBy) + "&";
|
url_ += "sortBy=" + encodeURIComponent("" + sortBy) + "&";
|
||||||
if (sortDirection !== undefined && sortDirection !== null)
|
if (sortDirection === null)
|
||||||
|
throw new Error("The parameter 'sortDirection' cannot be null.");
|
||||||
|
else if (sortDirection !== undefined)
|
||||||
url_ += "sortDirection=" + encodeURIComponent("" + sortDirection) + "&";
|
url_ += "sortDirection=" + encodeURIComponent("" + sortDirection) + "&";
|
||||||
url_ = url_.replace(/[?&]$/, "");
|
url_ = url_.replace(/[?&]$/, "");
|
||||||
|
|
||||||
@@ -2599,7 +2601,7 @@ export class DataClient extends AuthorizedApiBase {
|
|||||||
return Promise.resolve<string[]>(null as any);
|
return Promise.resolve<string[]>(null as any);
|
||||||
}
|
}
|
||||||
|
|
||||||
data_GetStrategiesPaginated(pageNumber: number | undefined, pageSize: number | undefined, name: string | null | undefined, ticker: string | null | undefined, agentName: string | null | undefined, sortBy: BotSortableColumn | undefined, sortDirection: string | null | undefined): Promise<PaginatedResponseOfTradingBotResponse> {
|
data_GetStrategiesPaginated(pageNumber: number | undefined, pageSize: number | undefined, name: string | null | undefined, ticker: string | null | undefined, agentName: string | null | undefined, sortBy: BotSortableColumn | undefined, sortDirection: SortDirection | undefined): Promise<PaginatedResponseOfTradingBotResponse> {
|
||||||
let url_ = this.baseUrl + "/Data/GetStrategiesPaginated?";
|
let url_ = this.baseUrl + "/Data/GetStrategiesPaginated?";
|
||||||
if (pageNumber === null)
|
if (pageNumber === null)
|
||||||
throw new Error("The parameter 'pageNumber' cannot be null.");
|
throw new Error("The parameter 'pageNumber' cannot be null.");
|
||||||
@@ -2619,7 +2621,9 @@ export class DataClient extends AuthorizedApiBase {
|
|||||||
throw new Error("The parameter 'sortBy' cannot be null.");
|
throw new Error("The parameter 'sortBy' cannot be null.");
|
||||||
else if (sortBy !== undefined)
|
else if (sortBy !== undefined)
|
||||||
url_ += "sortBy=" + encodeURIComponent("" + sortBy) + "&";
|
url_ += "sortBy=" + encodeURIComponent("" + sortBy) + "&";
|
||||||
if (sortDirection !== undefined && sortDirection !== null)
|
if (sortDirection === null)
|
||||||
|
throw new Error("The parameter 'sortDirection' cannot be null.");
|
||||||
|
else if (sortDirection !== undefined)
|
||||||
url_ += "sortDirection=" + encodeURIComponent("" + sortDirection) + "&";
|
url_ += "sortDirection=" + encodeURIComponent("" + sortDirection) + "&";
|
||||||
url_ = url_.replace(/[?&]$/, "");
|
url_ = url_.replace(/[?&]$/, "");
|
||||||
|
|
||||||
@@ -4854,7 +4858,7 @@ export interface TradingBotConfig {
|
|||||||
flipPosition: boolean;
|
flipPosition: boolean;
|
||||||
name: string;
|
name: string;
|
||||||
riskManagement?: RiskManagement | null;
|
riskManagement?: RiskManagement | null;
|
||||||
scenario?: LightScenario | null;
|
scenario: LightScenario;
|
||||||
scenarioName?: string | null;
|
scenarioName?: string | null;
|
||||||
maxPositionTimeHours?: number | null;
|
maxPositionTimeHours?: number | null;
|
||||||
closeEarlyWhenProfitable?: boolean;
|
closeEarlyWhenProfitable?: boolean;
|
||||||
@@ -4919,13 +4923,13 @@ export enum RiskToleranceLevel {
|
|||||||
export interface LightScenario {
|
export interface LightScenario {
|
||||||
name?: string | null;
|
name?: string | null;
|
||||||
indicators?: LightIndicator[] | null;
|
indicators?: LightIndicator[] | null;
|
||||||
loopbackPeriod?: number | null;
|
lookbackPeriod: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface LightIndicator {
|
export interface LightIndicator {
|
||||||
name?: string | null;
|
name: string;
|
||||||
type?: IndicatorType;
|
type: IndicatorType;
|
||||||
signalType?: SignalType;
|
signalType: SignalType;
|
||||||
minimumHistory?: number;
|
minimumHistory?: number;
|
||||||
period?: number | null;
|
period?: number | null;
|
||||||
fastPeriods?: number | null;
|
fastPeriods?: number | null;
|
||||||
@@ -5227,7 +5231,7 @@ export interface TradingBotConfigRequest {
|
|||||||
export interface ScenarioRequest {
|
export interface ScenarioRequest {
|
||||||
name: string;
|
name: string;
|
||||||
indicators: IndicatorRequest[];
|
indicators: IndicatorRequest[];
|
||||||
loopbackPeriod?: number | null;
|
lookbackPeriod?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IndicatorRequest {
|
export interface IndicatorRequest {
|
||||||
@@ -5513,6 +5517,11 @@ export enum BotSortableColumn {
|
|||||||
AgentName = "AgentName",
|
AgentName = "AgentName",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum SortDirection {
|
||||||
|
Asc = "Asc",
|
||||||
|
Desc = "Desc",
|
||||||
|
}
|
||||||
|
|
||||||
export interface CreateManualSignalRequest {
|
export interface CreateManualSignalRequest {
|
||||||
identifier?: string;
|
identifier?: string;
|
||||||
direction?: TradeDirection;
|
direction?: TradeDirection;
|
||||||
@@ -5551,7 +5560,7 @@ export interface Spotlight {
|
|||||||
export interface Scenario {
|
export interface Scenario {
|
||||||
name?: string | null;
|
name?: string | null;
|
||||||
indicators?: IndicatorBase[] | null;
|
indicators?: IndicatorBase[] | null;
|
||||||
loopbackPeriod?: number | null;
|
lookbackPeriod?: number;
|
||||||
user?: User | null;
|
user?: User | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5730,25 +5739,25 @@ export interface StrategyRoiPerformance {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface UserStrategyDetailsViewModel {
|
export interface UserStrategyDetailsViewModel {
|
||||||
name?: string | null;
|
name: string;
|
||||||
state?: BotStatus;
|
state: BotStatus;
|
||||||
pnL?: number;
|
pnL: number;
|
||||||
netPnL?: number;
|
netPnL: number;
|
||||||
roiPercentage?: number;
|
roiPercentage: number;
|
||||||
runtime?: Date | null;
|
runtime: Date;
|
||||||
totalRuntimeSeconds?: number;
|
totalRuntimeSeconds: number;
|
||||||
lastStartTime?: Date | null;
|
lastStartTime: Date;
|
||||||
lastStopTime?: Date | null;
|
lastStopTime?: Date | null;
|
||||||
accumulatedRunTimeSeconds?: number;
|
accumulatedRunTimeSeconds: number;
|
||||||
winRate?: number;
|
winRate: number;
|
||||||
totalVolumeTraded?: number;
|
totalVolumeTraded: number;
|
||||||
volumeLast24H?: number;
|
volumeLast24H: number;
|
||||||
wins?: number;
|
wins: number;
|
||||||
losses?: number;
|
losses: number;
|
||||||
positions?: PositionViewModel[] | null;
|
positions: PositionViewModel[];
|
||||||
identifier?: string;
|
identifier: string;
|
||||||
walletBalances?: { [key: string]: number; } | null;
|
walletBalances?: { [key: string]: number; } | null;
|
||||||
ticker?: Ticker;
|
ticker: Ticker;
|
||||||
masterAgentName?: string | null;
|
masterAgentName?: string | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -355,7 +355,7 @@ export interface TradingBotConfig {
|
|||||||
flipPosition: boolean;
|
flipPosition: boolean;
|
||||||
name: string;
|
name: string;
|
||||||
riskManagement?: RiskManagement | null;
|
riskManagement?: RiskManagement | null;
|
||||||
scenario?: LightScenario | null;
|
scenario: LightScenario;
|
||||||
scenarioName?: string | null;
|
scenarioName?: string | null;
|
||||||
maxPositionTimeHours?: number | null;
|
maxPositionTimeHours?: number | null;
|
||||||
closeEarlyWhenProfitable?: boolean;
|
closeEarlyWhenProfitable?: boolean;
|
||||||
@@ -420,13 +420,13 @@ export enum RiskToleranceLevel {
|
|||||||
export interface LightScenario {
|
export interface LightScenario {
|
||||||
name?: string | null;
|
name?: string | null;
|
||||||
indicators?: LightIndicator[] | null;
|
indicators?: LightIndicator[] | null;
|
||||||
loopbackPeriod?: number | null;
|
lookbackPeriod: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface LightIndicator {
|
export interface LightIndicator {
|
||||||
name?: string | null;
|
name: string;
|
||||||
type?: IndicatorType;
|
type: IndicatorType;
|
||||||
signalType?: SignalType;
|
signalType: SignalType;
|
||||||
minimumHistory?: number;
|
minimumHistory?: number;
|
||||||
period?: number | null;
|
period?: number | null;
|
||||||
fastPeriods?: number | null;
|
fastPeriods?: number | null;
|
||||||
@@ -728,7 +728,7 @@ export interface TradingBotConfigRequest {
|
|||||||
export interface ScenarioRequest {
|
export interface ScenarioRequest {
|
||||||
name: string;
|
name: string;
|
||||||
indicators: IndicatorRequest[];
|
indicators: IndicatorRequest[];
|
||||||
loopbackPeriod?: number | null;
|
lookbackPeriod?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IndicatorRequest {
|
export interface IndicatorRequest {
|
||||||
@@ -1014,6 +1014,11 @@ export enum BotSortableColumn {
|
|||||||
AgentName = "AgentName",
|
AgentName = "AgentName",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum SortDirection {
|
||||||
|
Asc = "Asc",
|
||||||
|
Desc = "Desc",
|
||||||
|
}
|
||||||
|
|
||||||
export interface CreateManualSignalRequest {
|
export interface CreateManualSignalRequest {
|
||||||
identifier?: string;
|
identifier?: string;
|
||||||
direction?: TradeDirection;
|
direction?: TradeDirection;
|
||||||
@@ -1052,7 +1057,7 @@ export interface Spotlight {
|
|||||||
export interface Scenario {
|
export interface Scenario {
|
||||||
name?: string | null;
|
name?: string | null;
|
||||||
indicators?: IndicatorBase[] | null;
|
indicators?: IndicatorBase[] | null;
|
||||||
loopbackPeriod?: number | null;
|
lookbackPeriod?: number;
|
||||||
user?: User | null;
|
user?: User | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1231,25 +1236,25 @@ export interface StrategyRoiPerformance {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface UserStrategyDetailsViewModel {
|
export interface UserStrategyDetailsViewModel {
|
||||||
name?: string | null;
|
name: string;
|
||||||
state?: BotStatus;
|
state: BotStatus;
|
||||||
pnL?: number;
|
pnL: number;
|
||||||
netPnL?: number;
|
netPnL: number;
|
||||||
roiPercentage?: number;
|
roiPercentage: number;
|
||||||
runtime?: Date | null;
|
runtime: Date;
|
||||||
totalRuntimeSeconds?: number;
|
totalRuntimeSeconds: number;
|
||||||
lastStartTime?: Date | null;
|
lastStartTime: Date;
|
||||||
lastStopTime?: Date | null;
|
lastStopTime?: Date | null;
|
||||||
accumulatedRunTimeSeconds?: number;
|
accumulatedRunTimeSeconds: number;
|
||||||
winRate?: number;
|
winRate: number;
|
||||||
totalVolumeTraded?: number;
|
totalVolumeTraded: number;
|
||||||
volumeLast24H?: number;
|
volumeLast24H: number;
|
||||||
wins?: number;
|
wins: number;
|
||||||
losses?: number;
|
losses: number;
|
||||||
positions?: PositionViewModel[] | null;
|
positions: PositionViewModel[];
|
||||||
identifier?: string;
|
identifier: string;
|
||||||
walletBalances?: { [key: string]: number; } | null;
|
walletBalances?: { [key: string]: number; } | null;
|
||||||
ticker?: Ticker;
|
ticker: Ticker;
|
||||||
masterAgentName?: string | null;
|
masterAgentName?: string | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -112,7 +112,7 @@ public class BacktestExecutorTests : BaseTests, IDisposable
|
|||||||
var scenario = new Scenario("ETH_BacktestScenario");
|
var scenario = new Scenario("ETH_BacktestScenario");
|
||||||
var rsiDivIndicator = ScenarioHelpers.BuildIndicator(IndicatorType.RsiDivergence, "RsiDiv", period: 14);
|
var rsiDivIndicator = ScenarioHelpers.BuildIndicator(IndicatorType.RsiDivergence, "RsiDiv", period: 14);
|
||||||
scenario.Indicators = new List<IndicatorBase> { (IndicatorBase)rsiDivIndicator };
|
scenario.Indicators = new List<IndicatorBase> { (IndicatorBase)rsiDivIndicator };
|
||||||
scenario.LoopbackPeriod = 15;
|
scenario.LookbackPeriod = 15;
|
||||||
|
|
||||||
var config = new TradingBotConfig
|
var config = new TradingBotConfig
|
||||||
{
|
{
|
||||||
@@ -207,7 +207,7 @@ public class BacktestExecutorTests : BaseTests, IDisposable
|
|||||||
var scenario = new Scenario("ETH_BacktestScenario");
|
var scenario = new Scenario("ETH_BacktestScenario");
|
||||||
var rsiDivIndicator = ScenarioHelpers.BuildIndicator(IndicatorType.RsiDivergence, "RsiDiv", period: 14);
|
var rsiDivIndicator = ScenarioHelpers.BuildIndicator(IndicatorType.RsiDivergence, "RsiDiv", period: 14);
|
||||||
scenario.Indicators = new List<IndicatorBase> { (IndicatorBase)rsiDivIndicator };
|
scenario.Indicators = new List<IndicatorBase> { (IndicatorBase)rsiDivIndicator };
|
||||||
scenario.LoopbackPeriod = 15;
|
scenario.LookbackPeriod = 15;
|
||||||
|
|
||||||
var config = new TradingBotConfig
|
var config = new TradingBotConfig
|
||||||
{
|
{
|
||||||
@@ -297,7 +297,7 @@ public class BacktestExecutorTests : BaseTests, IDisposable
|
|||||||
var scenario = new Scenario("ETH_BacktestScenario");
|
var scenario = new Scenario("ETH_BacktestScenario");
|
||||||
var rsiDivIndicator = ScenarioHelpers.BuildIndicator(IndicatorType.RsiDivergence, "RsiDiv", period: 14);
|
var rsiDivIndicator = ScenarioHelpers.BuildIndicator(IndicatorType.RsiDivergence, "RsiDiv", period: 14);
|
||||||
scenario.Indicators = new List<IndicatorBase> { (IndicatorBase)rsiDivIndicator };
|
scenario.Indicators = new List<IndicatorBase> { (IndicatorBase)rsiDivIndicator };
|
||||||
scenario.LoopbackPeriod = 15;
|
scenario.LookbackPeriod = 15;
|
||||||
|
|
||||||
var config = new TradingBotConfig
|
var config = new TradingBotConfig
|
||||||
{
|
{
|
||||||
@@ -387,7 +387,7 @@ public class BacktestExecutorTests : BaseTests, IDisposable
|
|||||||
var emaCrossIndicator = ScenarioHelpers.BuildIndicator(IndicatorType.EmaCross, "EmaCross", period: 21);
|
var emaCrossIndicator = ScenarioHelpers.BuildIndicator(IndicatorType.EmaCross, "EmaCross", period: 21);
|
||||||
scenario.Indicators = new List<IndicatorBase>
|
scenario.Indicators = new List<IndicatorBase>
|
||||||
{ (IndicatorBase)rsiDivIndicator, (IndicatorBase)emaCrossIndicator };
|
{ (IndicatorBase)rsiDivIndicator, (IndicatorBase)emaCrossIndicator };
|
||||||
scenario.LoopbackPeriod = 15; // 15 minutes loopback period as requested
|
scenario.LookbackPeriod = 15; // 15 minutes loopback period as requested
|
||||||
|
|
||||||
var config = new TradingBotConfig
|
var config = new TradingBotConfig
|
||||||
{
|
{
|
||||||
@@ -488,7 +488,7 @@ public class BacktestExecutorTests : BaseTests, IDisposable
|
|||||||
Console.WriteLine($"📈 Win Rate: {result.WinRate}% (Expected: {expectedWinRatePercent}%)");
|
Console.WriteLine($"📈 Win Rate: {result.WinRate}% (Expected: {expectedWinRatePercent}%)");
|
||||||
Console.WriteLine($"📈 Growth: {result.GrowthPercentage:F2}% (Expected: {expectedGrowthPercentage:F2}%)");
|
Console.WriteLine($"📈 Growth: {result.GrowthPercentage:F2}% (Expected: {expectedGrowthPercentage:F2}%)");
|
||||||
Console.WriteLine(
|
Console.WriteLine(
|
||||||
$"🎭 Scenario: {scenario.Name} ({scenario.Indicators.Count} indicators, LoopbackPeriod: {scenario.LoopbackPeriod})");
|
$"🎭 Scenario: {scenario.Name} ({scenario.Indicators.Count} indicators, LoopbackPeriod: {scenario.LookbackPeriod})");
|
||||||
|
|
||||||
// Performance assertion - should be reasonably fast even with 2 indicators
|
// Performance assertion - should be reasonably fast even with 2 indicators
|
||||||
Assert.True(candlesPerSecond > 200,
|
Assert.True(candlesPerSecond > 200,
|
||||||
@@ -510,7 +510,7 @@ public class BacktestExecutorTests : BaseTests, IDisposable
|
|||||||
var scenario = new Scenario("ETH_Spot_BacktestScenario");
|
var scenario = new Scenario("ETH_Spot_BacktestScenario");
|
||||||
var rsiDivIndicator = ScenarioHelpers.BuildIndicator(IndicatorType.RsiDivergence, "RsiDiv", period: 14);
|
var rsiDivIndicator = ScenarioHelpers.BuildIndicator(IndicatorType.RsiDivergence, "RsiDiv", period: 14);
|
||||||
scenario.Indicators = new List<IndicatorBase> { (IndicatorBase)rsiDivIndicator };
|
scenario.Indicators = new List<IndicatorBase> { (IndicatorBase)rsiDivIndicator };
|
||||||
scenario.LoopbackPeriod = 15;
|
scenario.LookbackPeriod = 15;
|
||||||
|
|
||||||
var config = new TradingBotConfig
|
var config = new TradingBotConfig
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user