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)
|
||||
{
|
||||
// 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
|
||||
};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using Managing.Api.Models.Requests;
|
||||
using Managing.Api.Models.Requests;
|
||||
using Managing.Api.Models.Responses;
|
||||
using Managing.Application.Abstractions;
|
||||
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="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="sortDirection">Sort direction. Default is "Desc".</param>
|
||||
/// <param name="sortDirection">Sort direction. Default is Desc.</param>
|
||||
/// <returns>A paginated response containing trading bots</returns>
|
||||
[HttpGet]
|
||||
[Route("Paginated")]
|
||||
@@ -442,7 +442,7 @@ public class BotController : BaseController
|
||||
string? ticker = null,
|
||||
string? agentName = null,
|
||||
BotSortableColumn sortBy = BotSortableColumn.CreateDate,
|
||||
string sortDirection = "Desc")
|
||||
SortDirection sortDirection = SortDirection.Desc)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -770,7 +770,7 @@ public class BotController : BaseController
|
||||
if (request.Config.Scenario != null)
|
||||
{
|
||||
// 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
|
||||
};
|
||||
@@ -931,7 +931,7 @@ public class BotController : BaseController
|
||||
if (request.Config.Scenario != null)
|
||||
{
|
||||
// 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
|
||||
};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using Managing.Api.Models.Requests;
|
||||
using Managing.Api.Models.Requests;
|
||||
using Managing.Api.Models.Responses;
|
||||
using Managing.Application.Abstractions;
|
||||
using Managing.Application.Abstractions.Grains;
|
||||
@@ -715,7 +715,9 @@ public class DataController : ControllerBase
|
||||
var showOnlyProfitable = _configuration.GetValue<bool>("showOnlyProfitable", false);
|
||||
|
||||
// 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 agentSummaries = result.Results;
|
||||
var totalCount = result.TotalCount;
|
||||
@@ -819,7 +821,7 @@ public class DataController : ControllerBase
|
||||
/// <returns>A domain Scenario object.</returns>
|
||||
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)
|
||||
{
|
||||
@@ -907,7 +909,7 @@ public class DataController : ControllerBase
|
||||
/// <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="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>
|
||||
[HttpGet("GetStrategiesPaginated")]
|
||||
public async Task<ActionResult<PaginatedResponse<TradingBotResponse>>> GetStrategiesPaginated(
|
||||
@@ -917,7 +919,7 @@ public class DataController : ControllerBase
|
||||
string? ticker = null,
|
||||
string? agentName = null,
|
||||
BotSortableColumn sortBy = BotSortableColumn.CreateDate,
|
||||
string sortDirection = "Desc")
|
||||
SortDirection sortDirection = SortDirection.Desc)
|
||||
{
|
||||
// Validate pagination parameters
|
||||
if (pageNumber < 1)
|
||||
@@ -930,11 +932,6 @@ public class DataController : ControllerBase
|
||||
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
|
||||
{
|
||||
|
||||
@@ -191,7 +191,7 @@ public class ScenarioController : BaseController
|
||||
return new ScenarioViewModel
|
||||
{
|
||||
Name = scenario.Name,
|
||||
LoopbackPeriod = scenario.LoopbackPeriod,
|
||||
LoopbackPeriod = scenario.LookbackPeriod,
|
||||
UserName = scenario.User?.Name,
|
||||
Indicators = scenario.Indicators?.Select(MapToIndicatorViewModel).ToList() ?? new List<IndicatorViewModel>()
|
||||
};
|
||||
|
||||
@@ -49,7 +49,7 @@ public class GetBotsPaginatedRequest
|
||||
public BotSortableColumn SortBy { get; set; } = BotSortableColumn.CreateDate;
|
||||
|
||||
/// <summary>
|
||||
/// Sort direction. Default is "Desc" (descending).
|
||||
/// Sort direction. Default is Desc (descending).
|
||||
/// </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;
|
||||
|
||||
namespace Managing.Api.Models.Responses
|
||||
@@ -10,41 +11,49 @@ namespace Managing.Api.Models.Responses
|
||||
/// <summary>
|
||||
/// Name of the deployed strategy
|
||||
/// </summary>
|
||||
[Required]
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Current state of the strategy (RUNNING, STOPPED, UNUSED)
|
||||
/// </summary>
|
||||
[Required]
|
||||
public Enums.BotStatus State { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Total profit or loss generated by the strategy in USD (gross, before fees)
|
||||
/// </summary>
|
||||
[Required]
|
||||
public decimal PnL { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Net profit or loss generated by the strategy in USD (after fees)
|
||||
/// </summary>
|
||||
[Required]
|
||||
public decimal NetPnL { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Return on investment percentage
|
||||
/// </summary>
|
||||
[Required]
|
||||
public decimal ROIPercentage { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Date and time when the strategy was started (only present when running, for live ticker)
|
||||
/// </summary>
|
||||
[Required]
|
||||
public DateTime? Runtime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Total accumulated runtime in seconds (including current session if running)
|
||||
/// </summary>
|
||||
[Required]
|
||||
public long TotalRuntimeSeconds { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Time when the current or last session started
|
||||
/// </summary>
|
||||
[Required]
|
||||
public DateTime? LastStartTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
@@ -55,42 +64,49 @@ namespace Managing.Api.Models.Responses
|
||||
/// <summary>
|
||||
/// Total accumulated runtime across all past sessions (seconds)
|
||||
/// </summary>
|
||||
[Required]
|
||||
public long AccumulatedRunTimeSeconds { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Average percentage of successful trades
|
||||
/// </summary>
|
||||
[Required]
|
||||
public int WinRate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Total trading volume for all trades
|
||||
/// </summary>
|
||||
[Required]
|
||||
public decimal TotalVolumeTraded { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Trading volume in the last 24 hours
|
||||
/// </summary>
|
||||
[Required]
|
||||
public decimal VolumeLast24H { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Number of winning trades
|
||||
/// </summary>
|
||||
[Required]
|
||||
public int Wins { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Number of losing trades
|
||||
/// </summary>
|
||||
[Required]
|
||||
public int Losses { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Dictionary of all positions executed by this strategy, keyed by position identifier
|
||||
/// </summary>
|
||||
[Required]
|
||||
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 Enums.Ticker Ticker { get; set; }
|
||||
[Required] public Enums.Ticker Ticker { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The agent name of the master bot's owner (for copy trading bots)
|
||||
|
||||
@@ -37,7 +37,7 @@ public interface IBotRepository
|
||||
string? ticker = null,
|
||||
string? agentName = null,
|
||||
BotSortableColumn sortBy = BotSortableColumn.CreateDate,
|
||||
string sortDirection = "Desc",
|
||||
SortDirection sortDirection = SortDirection.Desc,
|
||||
bool showOnlyProfitable = false);
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -158,7 +158,7 @@ public class BacktestTests : BaseTests
|
||||
var scenario = new Scenario("ETH_BacktestScenario");
|
||||
var rsiDivIndicator = ScenarioHelpers.BuildIndicator(IndicatorType.RsiDivergence, "RsiDiv", period: 14);
|
||||
scenario.Indicators = new List<IndicatorBase> { (IndicatorBase)rsiDivIndicator };
|
||||
scenario.LoopbackPeriod = 15;
|
||||
scenario.LookbackPeriod = 15;
|
||||
|
||||
var config = new TradingBotConfig
|
||||
{
|
||||
|
||||
@@ -47,7 +47,7 @@ public interface IBotService
|
||||
/// <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="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>
|
||||
/// <returns>Tuple containing the bots for the current page and total count</returns>
|
||||
Task<(IEnumerable<Bot> Bots, int TotalCount)> GetBotsPaginatedAsync(
|
||||
@@ -58,7 +58,7 @@ public interface IBotService
|
||||
string? ticker = null,
|
||||
string? agentName = null,
|
||||
BotSortableColumn sortBy = BotSortableColumn.CreateDate,
|
||||
string sortDirection = "Desc",
|
||||
SortDirection sortDirection = SortDirection.Desc,
|
||||
bool showOnlyProfitable = false);
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -7,7 +7,7 @@ namespace Managing.Application.Abstractions
|
||||
{
|
||||
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<bool> UpdateScenario(string name, List<string> strategies, int? loopbackPeriod);
|
||||
|
||||
|
||||
@@ -151,7 +151,7 @@ public class JobService
|
||||
if (backtestRequest.Config.Scenario != null)
|
||||
{
|
||||
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)
|
||||
{
|
||||
|
||||
@@ -176,7 +176,7 @@ public class BacktestFuturesBot : TradingBotBase, ITradingBot
|
||||
throw new ArgumentNullException(nameof(Config.Scenario), "Config.Scenario cannot be null");
|
||||
|
||||
// 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);
|
||||
if (backtestSignal == null) return;
|
||||
|
||||
|
||||
@@ -180,7 +180,7 @@ public class BacktestSpotBot : TradingBotBase, ITradingBot
|
||||
throw new ArgumentNullException(nameof(Config.Scenario), "Config.Scenario cannot be null");
|
||||
|
||||
// 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);
|
||||
if (backtestSignal == null) return;
|
||||
|
||||
|
||||
@@ -487,7 +487,7 @@ namespace Managing.Application.ManageBot
|
||||
string? ticker = null,
|
||||
string? agentName = null,
|
||||
BotSortableColumn sortBy = BotSortableColumn.CreateDate,
|
||||
string sortDirection = "Desc",
|
||||
SortDirection sortDirection = SortDirection.Desc,
|
||||
bool showOnlyProfitable = false)
|
||||
{
|
||||
return await ServiceScopeHelpers.WithScopedService<IBotRepository, (IEnumerable<Bot> Bots, int TotalCount)>(
|
||||
|
||||
@@ -88,7 +88,7 @@ public class ScenarioRunnerGrain : Grain, IScenarioRunnerGrain
|
||||
candlesList,
|
||||
config.Scenario,
|
||||
previousSignals,
|
||||
config.Scenario?.LoopbackPeriod ?? 1);
|
||||
config.Scenario?.LookbackPeriod ?? 1);
|
||||
|
||||
if (signal != null && signal.Date > candle.Date)
|
||||
{
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace Managing.Application.Scenarios
|
||||
_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);
|
||||
|
||||
@@ -77,7 +77,7 @@ namespace Managing.Application.Scenarios
|
||||
scenario.AddIndicator(await _tradingService.GetIndicatorByNameAsync(strategy));
|
||||
}
|
||||
|
||||
scenario.LoopbackPeriod = loopbackPeriod ?? 1;
|
||||
scenario.LookbackPeriod = loopbackPeriod ?? 1;
|
||||
await _tradingService.UpdateScenarioAsync(scenario);
|
||||
return true;
|
||||
}
|
||||
@@ -262,7 +262,7 @@ namespace Managing.Application.Scenarios
|
||||
}
|
||||
|
||||
scenario.Indicators.Clear();
|
||||
scenario.LoopbackPeriod = loopbackPeriod ?? 1;
|
||||
scenario.LookbackPeriod = loopbackPeriod ?? 1;
|
||||
|
||||
foreach (var strategyName in strategies)
|
||||
{
|
||||
|
||||
@@ -225,7 +225,7 @@ public class BundleBacktestWorker : BaseWorker<BundleBacktestWorker>
|
||||
if (runBacktestRequest.Config.Scenario != null)
|
||||
{
|
||||
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)
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace Managing.Common;
|
||||
namespace Managing.Common;
|
||||
|
||||
public static class Enums
|
||||
{
|
||||
@@ -101,6 +101,15 @@ public static class Enums
|
||||
AgentName
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sort direction for pagination endpoints
|
||||
/// </summary>
|
||||
public enum SortDirection
|
||||
{
|
||||
Asc,
|
||||
Desc
|
||||
}
|
||||
|
||||
public enum SignalStatus
|
||||
{
|
||||
WaitingForPosition,
|
||||
|
||||
@@ -22,5 +22,5 @@ public class ScenarioRequest
|
||||
/// <summary>
|
||||
/// The loopback period for the scenario
|
||||
/// </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.
|
||||
/// </summary>
|
||||
[Id(12)]
|
||||
[Required]
|
||||
public LightScenario Scenario { get; set; }
|
||||
|
||||
/// <summary>
|
||||
@@ -104,6 +105,7 @@ public class TradingBotConfig
|
||||
/// </summary>
|
||||
[Id(20)]
|
||||
public bool UseForDynamicStopLoss { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Parameter to indicate if the bot is for copy trading
|
||||
/// </summary>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Managing.Domain.Scenarios;
|
||||
using Orleans;
|
||||
using static Managing.Common.Enums;
|
||||
@@ -18,11 +19,11 @@ public class LightIndicator
|
||||
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; }
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Managing.Domain.Strategies;
|
||||
using Orleans;
|
||||
|
||||
@@ -10,25 +11,25 @@ namespace Managing.Domain.Scenarios;
|
||||
[GenerateSerializer]
|
||||
public class LightScenario
|
||||
{
|
||||
public LightScenario(string name, int? loopbackPeriod = 1)
|
||||
public LightScenario(string name, int lookbackPeriod = 1)
|
||||
{
|
||||
Name = name;
|
||||
Indicators = new List<LightIndicator>();
|
||||
LoopbackPeriod = loopbackPeriod;
|
||||
LookbackPeriod = lookbackPeriod;
|
||||
}
|
||||
|
||||
[Id(0)] public string Name { 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>
|
||||
/// Converts a full Scenario to a LightScenario
|
||||
/// </summary>
|
||||
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() ??
|
||||
new List<LightIndicator>()
|
||||
@@ -41,7 +42,7 @@ public class LightScenario
|
||||
/// </summary>
|
||||
public Scenario ToScenario()
|
||||
{
|
||||
var scenario = new Scenario(Name, LoopbackPeriod)
|
||||
var scenario = new Scenario(Name, LookbackPeriod)
|
||||
{
|
||||
Indicators = Indicators?.Select(li => li.LightToBase()).ToList()
|
||||
};
|
||||
|
||||
@@ -7,18 +7,18 @@ namespace Managing.Domain.Scenarios
|
||||
[GenerateSerializer]
|
||||
public class Scenario
|
||||
{
|
||||
public Scenario(string name, int? loopbackPeriod = 1)
|
||||
public Scenario(string name, int lookbackPeriod = 1)
|
||||
{
|
||||
Name = name;
|
||||
Indicators = new List<IndicatorBase>();
|
||||
LoopbackPeriod = loopbackPeriod;
|
||||
LookbackPeriod = lookbackPeriod;
|
||||
}
|
||||
|
||||
[Id(0)] public string Name { 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; }
|
||||
|
||||
|
||||
@@ -206,7 +206,7 @@ public class PostgreSqlBotRepository : IBotRepository
|
||||
string? ticker = null,
|
||||
string? agentName = null,
|
||||
BotSortableColumn sortBy = BotSortableColumn.CreateDate,
|
||||
string sortDirection = "Desc",
|
||||
SortDirection sortDirection = SortDirection.Desc,
|
||||
bool showOnlyProfitable = false)
|
||||
{
|
||||
// Build the query with filters
|
||||
@@ -249,33 +249,33 @@ public class PostgreSqlBotRepository : IBotRepository
|
||||
// Apply sorting
|
||||
query = sortBy switch
|
||||
{
|
||||
BotSortableColumn.Name => sortDirection.ToLower() == "asc"
|
||||
BotSortableColumn.Name => sortDirection == SortDirection.Asc
|
||||
? query.OrderBy(b => b.Name)
|
||||
: query.OrderByDescending(b => b.Name),
|
||||
BotSortableColumn.Ticker => sortDirection.ToLower() == "asc"
|
||||
BotSortableColumn.Ticker => sortDirection == SortDirection.Asc
|
||||
? query.OrderBy(b => b.Ticker)
|
||||
: query.OrderByDescending(b => b.Ticker),
|
||||
BotSortableColumn.Status => sortDirection.ToLower() == "asc"
|
||||
BotSortableColumn.Status => sortDirection == SortDirection.Asc
|
||||
? query.OrderBy(b => b.Status)
|
||||
: query.OrderByDescending(b => b.Status),
|
||||
BotSortableColumn.StartupTime => sortDirection.ToLower() == "asc"
|
||||
BotSortableColumn.StartupTime => sortDirection == SortDirection.Asc
|
||||
? query.OrderBy(b => b.StartupTime)
|
||||
: query.OrderByDescending(b => b.StartupTime),
|
||||
BotSortableColumn.Roi => sortDirection.ToLower() == "asc"
|
||||
BotSortableColumn.Roi => sortDirection == SortDirection.Asc
|
||||
? query.OrderBy(b => b.Roi)
|
||||
: query.OrderByDescending(b => b.Roi),
|
||||
BotSortableColumn.Pnl => sortDirection.ToLower() == "asc"
|
||||
BotSortableColumn.Pnl => sortDirection == SortDirection.Asc
|
||||
? query.OrderBy(b => b.Pnl)
|
||||
: query.OrderByDescending(b => b.Pnl),
|
||||
BotSortableColumn.WinRate => sortDirection.ToLower() == "asc"
|
||||
BotSortableColumn.WinRate => sortDirection == SortDirection.Asc
|
||||
? query.OrderBy(b =>
|
||||
(b.TradeWins + b.TradeLosses) > 0 ? (double)b.TradeWins / (b.TradeWins + b.TradeLosses) : 0)
|
||||
: query.OrderByDescending(b =>
|
||||
(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.OrderByDescending(b => b.User.AgentName),
|
||||
_ => sortDirection.ToLower() == "asc"
|
||||
_ => sortDirection == SortDirection.Asc
|
||||
? query.OrderBy(b => b.CreateDate)
|
||||
: query.OrderByDescending(b => b.CreateDate)
|
||||
};
|
||||
|
||||
@@ -360,7 +360,9 @@ public static class PostgreSqlMappers
|
||||
Duration = backtest.EndDate - backtest.StartDate,
|
||||
MoneyManagementJson = JsonConvert.SerializeObject(backtest.Config?.MoneyManagement, jsonSettings),
|
||||
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,
|
||||
MaxDrawdown = backtest.Statistics?.MaxDrawdown ?? 0m,
|
||||
MaxDrawdownRecoveryTime = backtest.Statistics?.MaxDrawdownRecoveryTime ?? TimeSpan.Zero,
|
||||
@@ -503,7 +505,7 @@ public static class PostgreSqlMappers
|
||||
return new ScenarioEntity
|
||||
{
|
||||
Name = scenario.Name,
|
||||
LoopbackPeriod = scenario.LoopbackPeriod ?? 1,
|
||||
LoopbackPeriod = scenario.LookbackPeriod,
|
||||
UserId = scenario.User?.Id ?? 0
|
||||
};
|
||||
}
|
||||
|
||||
@@ -13,7 +13,8 @@ namespace Managing.Infrastructure.Databases.PostgreSql;
|
||||
|
||||
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)
|
||||
{
|
||||
}
|
||||
@@ -154,7 +155,7 @@ public class PostgreSqlTradingRepository : BaseRepositoryWithLogging, ITradingRe
|
||||
|
||||
if (entity != null)
|
||||
{
|
||||
entity.LoopbackPeriod = scenario.LoopbackPeriod ?? 1;
|
||||
entity.LoopbackPeriod = scenario.LookbackPeriod;
|
||||
entity.UserId = scenario.User?.Id ?? 0;
|
||||
entity.UpdatedAt = DateTime.UtcNow;
|
||||
|
||||
@@ -463,7 +464,8 @@ public class PostgreSqlTradingRepository : BaseRepositoryWithLogging, ITradingRe
|
||||
{
|
||||
await PostgreSqlConnectionHelper.SafeCloseConnectionAsync(_context);
|
||||
}
|
||||
}, nameof(UpdatePositionAsync), ("positionIdentifier", position.Identifier), ("positionStatus", position.Status));
|
||||
}, nameof(UpdatePositionAsync), ("positionIdentifier", position.Identifier),
|
||||
("positionStatus", position.Status));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -355,7 +355,7 @@ export interface TradingBotConfig {
|
||||
flipPosition: boolean;
|
||||
name: string;
|
||||
riskManagement?: RiskManagement | null;
|
||||
scenario?: LightScenario | null;
|
||||
scenario: LightScenario;
|
||||
scenarioName?: string | null;
|
||||
maxPositionTimeHours?: number | null;
|
||||
closeEarlyWhenProfitable?: boolean;
|
||||
@@ -420,13 +420,13 @@ export enum RiskToleranceLevel {
|
||||
export interface LightScenario {
|
||||
name?: string | null;
|
||||
indicators?: LightIndicator[] | null;
|
||||
loopbackPeriod?: number | null;
|
||||
lookbackPeriod: number;
|
||||
}
|
||||
|
||||
export interface LightIndicator {
|
||||
name?: string | null;
|
||||
type?: IndicatorType;
|
||||
signalType?: SignalType;
|
||||
name: string;
|
||||
type: IndicatorType;
|
||||
signalType: SignalType;
|
||||
minimumHistory?: number;
|
||||
period?: number | null;
|
||||
fastPeriods?: number | null;
|
||||
@@ -728,7 +728,7 @@ export interface TradingBotConfigRequest {
|
||||
export interface ScenarioRequest {
|
||||
name: string;
|
||||
indicators: IndicatorRequest[];
|
||||
loopbackPeriod?: number | null;
|
||||
lookbackPeriod?: number;
|
||||
}
|
||||
|
||||
export interface IndicatorRequest {
|
||||
@@ -1014,6 +1014,11 @@ export enum BotSortableColumn {
|
||||
AgentName = "AgentName",
|
||||
}
|
||||
|
||||
export enum SortDirection {
|
||||
Asc = "Asc",
|
||||
Desc = "Desc",
|
||||
}
|
||||
|
||||
export interface CreateManualSignalRequest {
|
||||
identifier?: string;
|
||||
direction?: TradeDirection;
|
||||
@@ -1052,7 +1057,7 @@ export interface Spotlight {
|
||||
export interface Scenario {
|
||||
name?: string | null;
|
||||
indicators?: IndicatorBase[] | null;
|
||||
loopbackPeriod?: number | null;
|
||||
lookbackPeriod?: number;
|
||||
user?: User | null;
|
||||
}
|
||||
|
||||
@@ -1231,25 +1236,25 @@ export interface StrategyRoiPerformance {
|
||||
}
|
||||
|
||||
export interface UserStrategyDetailsViewModel {
|
||||
name?: string | null;
|
||||
state?: BotStatus;
|
||||
pnL?: number;
|
||||
netPnL?: number;
|
||||
roiPercentage?: number;
|
||||
runtime?: Date | null;
|
||||
totalRuntimeSeconds?: number;
|
||||
lastStartTime?: Date | null;
|
||||
name: string;
|
||||
state: BotStatus;
|
||||
pnL: number;
|
||||
netPnL: number;
|
||||
roiPercentage: number;
|
||||
runtime: Date;
|
||||
totalRuntimeSeconds: number;
|
||||
lastStartTime: Date;
|
||||
lastStopTime?: Date | null;
|
||||
accumulatedRunTimeSeconds?: number;
|
||||
winRate?: number;
|
||||
totalVolumeTraded?: number;
|
||||
volumeLast24H?: number;
|
||||
wins?: number;
|
||||
losses?: number;
|
||||
positions?: PositionViewModel[] | null;
|
||||
identifier?: string;
|
||||
accumulatedRunTimeSeconds: number;
|
||||
winRate: number;
|
||||
totalVolumeTraded: number;
|
||||
volumeLast24H: number;
|
||||
wins: number;
|
||||
losses: number;
|
||||
positions: PositionViewModel[];
|
||||
identifier: string;
|
||||
walletBalances?: { [key: string]: number; } | null;
|
||||
ticker?: Ticker;
|
||||
ticker: Ticker;
|
||||
masterAgentName?: string | null;
|
||||
}
|
||||
|
||||
|
||||
@@ -1917,7 +1917,7 @@ export class BotClient extends AuthorizedApiBase {
|
||||
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?";
|
||||
if (pageNumber === 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.");
|
||||
else if (sortBy !== undefined)
|
||||
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_ = url_.replace(/[?&]$/, "");
|
||||
|
||||
@@ -2599,7 +2601,7 @@ export class DataClient extends AuthorizedApiBase {
|
||||
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?";
|
||||
if (pageNumber === 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.");
|
||||
else if (sortBy !== undefined)
|
||||
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_ = url_.replace(/[?&]$/, "");
|
||||
|
||||
@@ -4854,7 +4858,7 @@ export interface TradingBotConfig {
|
||||
flipPosition: boolean;
|
||||
name: string;
|
||||
riskManagement?: RiskManagement | null;
|
||||
scenario?: LightScenario | null;
|
||||
scenario: LightScenario;
|
||||
scenarioName?: string | null;
|
||||
maxPositionTimeHours?: number | null;
|
||||
closeEarlyWhenProfitable?: boolean;
|
||||
@@ -4919,13 +4923,13 @@ export enum RiskToleranceLevel {
|
||||
export interface LightScenario {
|
||||
name?: string | null;
|
||||
indicators?: LightIndicator[] | null;
|
||||
loopbackPeriod?: number | null;
|
||||
lookbackPeriod: number;
|
||||
}
|
||||
|
||||
export interface LightIndicator {
|
||||
name?: string | null;
|
||||
type?: IndicatorType;
|
||||
signalType?: SignalType;
|
||||
name: string;
|
||||
type: IndicatorType;
|
||||
signalType: SignalType;
|
||||
minimumHistory?: number;
|
||||
period?: number | null;
|
||||
fastPeriods?: number | null;
|
||||
@@ -5227,7 +5231,7 @@ export interface TradingBotConfigRequest {
|
||||
export interface ScenarioRequest {
|
||||
name: string;
|
||||
indicators: IndicatorRequest[];
|
||||
loopbackPeriod?: number | null;
|
||||
lookbackPeriod?: number;
|
||||
}
|
||||
|
||||
export interface IndicatorRequest {
|
||||
@@ -5513,6 +5517,11 @@ export enum BotSortableColumn {
|
||||
AgentName = "AgentName",
|
||||
}
|
||||
|
||||
export enum SortDirection {
|
||||
Asc = "Asc",
|
||||
Desc = "Desc",
|
||||
}
|
||||
|
||||
export interface CreateManualSignalRequest {
|
||||
identifier?: string;
|
||||
direction?: TradeDirection;
|
||||
@@ -5551,7 +5560,7 @@ export interface Spotlight {
|
||||
export interface Scenario {
|
||||
name?: string | null;
|
||||
indicators?: IndicatorBase[] | null;
|
||||
loopbackPeriod?: number | null;
|
||||
lookbackPeriod?: number;
|
||||
user?: User | null;
|
||||
}
|
||||
|
||||
@@ -5730,25 +5739,25 @@ export interface StrategyRoiPerformance {
|
||||
}
|
||||
|
||||
export interface UserStrategyDetailsViewModel {
|
||||
name?: string | null;
|
||||
state?: BotStatus;
|
||||
pnL?: number;
|
||||
netPnL?: number;
|
||||
roiPercentage?: number;
|
||||
runtime?: Date | null;
|
||||
totalRuntimeSeconds?: number;
|
||||
lastStartTime?: Date | null;
|
||||
name: string;
|
||||
state: BotStatus;
|
||||
pnL: number;
|
||||
netPnL: number;
|
||||
roiPercentage: number;
|
||||
runtime: Date;
|
||||
totalRuntimeSeconds: number;
|
||||
lastStartTime: Date;
|
||||
lastStopTime?: Date | null;
|
||||
accumulatedRunTimeSeconds?: number;
|
||||
winRate?: number;
|
||||
totalVolumeTraded?: number;
|
||||
volumeLast24H?: number;
|
||||
wins?: number;
|
||||
losses?: number;
|
||||
positions?: PositionViewModel[] | null;
|
||||
identifier?: string;
|
||||
accumulatedRunTimeSeconds: number;
|
||||
winRate: number;
|
||||
totalVolumeTraded: number;
|
||||
volumeLast24H: number;
|
||||
wins: number;
|
||||
losses: number;
|
||||
positions: PositionViewModel[];
|
||||
identifier: string;
|
||||
walletBalances?: { [key: string]: number; } | null;
|
||||
ticker?: Ticker;
|
||||
ticker: Ticker;
|
||||
masterAgentName?: string | null;
|
||||
}
|
||||
|
||||
|
||||
@@ -355,7 +355,7 @@ export interface TradingBotConfig {
|
||||
flipPosition: boolean;
|
||||
name: string;
|
||||
riskManagement?: RiskManagement | null;
|
||||
scenario?: LightScenario | null;
|
||||
scenario: LightScenario;
|
||||
scenarioName?: string | null;
|
||||
maxPositionTimeHours?: number | null;
|
||||
closeEarlyWhenProfitable?: boolean;
|
||||
@@ -420,13 +420,13 @@ export enum RiskToleranceLevel {
|
||||
export interface LightScenario {
|
||||
name?: string | null;
|
||||
indicators?: LightIndicator[] | null;
|
||||
loopbackPeriod?: number | null;
|
||||
lookbackPeriod: number;
|
||||
}
|
||||
|
||||
export interface LightIndicator {
|
||||
name?: string | null;
|
||||
type?: IndicatorType;
|
||||
signalType?: SignalType;
|
||||
name: string;
|
||||
type: IndicatorType;
|
||||
signalType: SignalType;
|
||||
minimumHistory?: number;
|
||||
period?: number | null;
|
||||
fastPeriods?: number | null;
|
||||
@@ -728,7 +728,7 @@ export interface TradingBotConfigRequest {
|
||||
export interface ScenarioRequest {
|
||||
name: string;
|
||||
indicators: IndicatorRequest[];
|
||||
loopbackPeriod?: number | null;
|
||||
lookbackPeriod?: number;
|
||||
}
|
||||
|
||||
export interface IndicatorRequest {
|
||||
@@ -1014,6 +1014,11 @@ export enum BotSortableColumn {
|
||||
AgentName = "AgentName",
|
||||
}
|
||||
|
||||
export enum SortDirection {
|
||||
Asc = "Asc",
|
||||
Desc = "Desc",
|
||||
}
|
||||
|
||||
export interface CreateManualSignalRequest {
|
||||
identifier?: string;
|
||||
direction?: TradeDirection;
|
||||
@@ -1052,7 +1057,7 @@ export interface Spotlight {
|
||||
export interface Scenario {
|
||||
name?: string | null;
|
||||
indicators?: IndicatorBase[] | null;
|
||||
loopbackPeriod?: number | null;
|
||||
lookbackPeriod?: number;
|
||||
user?: User | null;
|
||||
}
|
||||
|
||||
@@ -1231,25 +1236,25 @@ export interface StrategyRoiPerformance {
|
||||
}
|
||||
|
||||
export interface UserStrategyDetailsViewModel {
|
||||
name?: string | null;
|
||||
state?: BotStatus;
|
||||
pnL?: number;
|
||||
netPnL?: number;
|
||||
roiPercentage?: number;
|
||||
runtime?: Date | null;
|
||||
totalRuntimeSeconds?: number;
|
||||
lastStartTime?: Date | null;
|
||||
name: string;
|
||||
state: BotStatus;
|
||||
pnL: number;
|
||||
netPnL: number;
|
||||
roiPercentage: number;
|
||||
runtime: Date;
|
||||
totalRuntimeSeconds: number;
|
||||
lastStartTime: Date;
|
||||
lastStopTime?: Date | null;
|
||||
accumulatedRunTimeSeconds?: number;
|
||||
winRate?: number;
|
||||
totalVolumeTraded?: number;
|
||||
volumeLast24H?: number;
|
||||
wins?: number;
|
||||
losses?: number;
|
||||
positions?: PositionViewModel[] | null;
|
||||
identifier?: string;
|
||||
accumulatedRunTimeSeconds: number;
|
||||
winRate: number;
|
||||
totalVolumeTraded: number;
|
||||
volumeLast24H: number;
|
||||
wins: number;
|
||||
losses: number;
|
||||
positions: PositionViewModel[];
|
||||
identifier: string;
|
||||
walletBalances?: { [key: string]: number; } | null;
|
||||
ticker?: Ticker;
|
||||
ticker: Ticker;
|
||||
masterAgentName?: string | null;
|
||||
}
|
||||
|
||||
|
||||
@@ -112,7 +112,7 @@ public class BacktestExecutorTests : BaseTests, IDisposable
|
||||
var scenario = new Scenario("ETH_BacktestScenario");
|
||||
var rsiDivIndicator = ScenarioHelpers.BuildIndicator(IndicatorType.RsiDivergence, "RsiDiv", period: 14);
|
||||
scenario.Indicators = new List<IndicatorBase> { (IndicatorBase)rsiDivIndicator };
|
||||
scenario.LoopbackPeriod = 15;
|
||||
scenario.LookbackPeriod = 15;
|
||||
|
||||
var config = new TradingBotConfig
|
||||
{
|
||||
@@ -207,7 +207,7 @@ public class BacktestExecutorTests : BaseTests, IDisposable
|
||||
var scenario = new Scenario("ETH_BacktestScenario");
|
||||
var rsiDivIndicator = ScenarioHelpers.BuildIndicator(IndicatorType.RsiDivergence, "RsiDiv", period: 14);
|
||||
scenario.Indicators = new List<IndicatorBase> { (IndicatorBase)rsiDivIndicator };
|
||||
scenario.LoopbackPeriod = 15;
|
||||
scenario.LookbackPeriod = 15;
|
||||
|
||||
var config = new TradingBotConfig
|
||||
{
|
||||
@@ -297,7 +297,7 @@ public class BacktestExecutorTests : BaseTests, IDisposable
|
||||
var scenario = new Scenario("ETH_BacktestScenario");
|
||||
var rsiDivIndicator = ScenarioHelpers.BuildIndicator(IndicatorType.RsiDivergence, "RsiDiv", period: 14);
|
||||
scenario.Indicators = new List<IndicatorBase> { (IndicatorBase)rsiDivIndicator };
|
||||
scenario.LoopbackPeriod = 15;
|
||||
scenario.LookbackPeriod = 15;
|
||||
|
||||
var config = new TradingBotConfig
|
||||
{
|
||||
@@ -387,7 +387,7 @@ public class BacktestExecutorTests : BaseTests, IDisposable
|
||||
var emaCrossIndicator = ScenarioHelpers.BuildIndicator(IndicatorType.EmaCross, "EmaCross", period: 21);
|
||||
scenario.Indicators = new List<IndicatorBase>
|
||||
{ (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
|
||||
{
|
||||
@@ -488,7 +488,7 @@ public class BacktestExecutorTests : BaseTests, IDisposable
|
||||
Console.WriteLine($"📈 Win Rate: {result.WinRate}% (Expected: {expectedWinRatePercent}%)");
|
||||
Console.WriteLine($"📈 Growth: {result.GrowthPercentage:F2}% (Expected: {expectedGrowthPercentage:F2}%)");
|
||||
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
|
||||
Assert.True(candlesPerSecond > 200,
|
||||
@@ -510,7 +510,7 @@ public class BacktestExecutorTests : BaseTests, IDisposable
|
||||
var scenario = new Scenario("ETH_Spot_BacktestScenario");
|
||||
var rsiDivIndicator = ScenarioHelpers.BuildIndicator(IndicatorType.RsiDivergence, "RsiDiv", period: 14);
|
||||
scenario.Indicators = new List<IndicatorBase> { (IndicatorBase)rsiDivIndicator };
|
||||
scenario.LoopbackPeriod = 15;
|
||||
scenario.LookbackPeriod = 15;
|
||||
|
||||
var config = new TradingBotConfig
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user