Add delete backtests by filters

This commit is contained in:
2025-10-15 00:28:25 +07:00
parent 48c2d20d70
commit b3f3bccd72
8 changed files with 326 additions and 1 deletions

View File

@@ -118,6 +118,100 @@ public class BacktestController : BaseController
return Ok(await _backtester.DeleteBacktestsByIdsForUserAsync(user, request.BacktestIds));
}
/// <summary>
/// Deletes backtests based on filter criteria for the authenticated user.
/// Uses the same filter parameters as GetBacktestsPaginated.
/// </summary>
/// <param name="scoreMin">Minimum score filter (0-100)</param>
/// <param name="scoreMax">Maximum score filter (0-100)</param>
/// <param name="winrateMin">Minimum winrate filter (0-100)</param>
/// <param name="winrateMax">Maximum winrate filter (0-100)</param>
/// <param name="maxDrawdownMax">Maximum drawdown filter</param>
/// <param name="tickers">Comma-separated list of tickers to filter by</param>
/// <param name="indicators">Comma-separated list of indicators to filter by</param>
/// <param name="durationMinDays">Minimum duration in days</param>
/// <param name="durationMaxDays">Maximum duration in days</param>
/// <param name="name">Name contains filter</param>
/// <returns>An ActionResult indicating the number of backtests deleted.</returns>
[HttpDelete("ByFilters")]
public async Task<ActionResult> DeleteBacktestsByFilters(
[FromQuery] double? scoreMin = null,
[FromQuery] double? scoreMax = null,
[FromQuery] int? winrateMin = null,
[FromQuery] int? winrateMax = null,
[FromQuery] decimal? maxDrawdownMax = null,
[FromQuery] string? tickers = null,
[FromQuery] string? indicators = null,
[FromQuery] double? durationMinDays = null,
[FromQuery] double? durationMaxDays = null,
[FromQuery] string? name = null)
{
var user = await GetUser();
// Validate score and winrate ranges [0,100]
if (scoreMin.HasValue && (scoreMin < 0 || scoreMin > 100))
{
return BadRequest("scoreMin must be between 0 and 100");
}
if (scoreMax.HasValue && (scoreMax < 0 || scoreMax > 100))
{
return BadRequest("scoreMax must be between 0 and 100");
}
if (winrateMin.HasValue && (winrateMin < 0 || winrateMin > 100))
{
return BadRequest("winrateMin must be between 0 and 100");
}
if (winrateMax.HasValue && (winrateMax < 0 || winrateMax > 100))
{
return BadRequest("winrateMax must be between 0 and 100");
}
if (scoreMin.HasValue && scoreMax.HasValue && scoreMin > scoreMax)
{
return BadRequest("scoreMin must be less than or equal to scoreMax");
}
if (winrateMin.HasValue && winrateMax.HasValue && winrateMin > winrateMax)
{
return BadRequest("winrateMin must be less than or equal to winrateMax");
}
if (maxDrawdownMax.HasValue && maxDrawdownMax < 0)
{
return BadRequest("maxDrawdownMax must be greater than or equal to 0");
}
// Parse multi-selects if provided (comma-separated)
var tickerList = string.IsNullOrWhiteSpace(tickers)
? Array.Empty<string>()
: tickers.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
var indicatorList = string.IsNullOrWhiteSpace(indicators)
? Array.Empty<string>()
: indicators.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
var filter = new BacktestsFilter
{
NameContains = string.IsNullOrWhiteSpace(name) ? null : name.Trim(),
ScoreMin = scoreMin,
ScoreMax = scoreMax,
WinrateMin = winrateMin,
WinrateMax = winrateMax,
MaxDrawdownMax = maxDrawdownMax,
Tickers = tickerList,
Indicators = indicatorList,
DurationMin = durationMinDays.HasValue ? TimeSpan.FromDays(durationMinDays.Value) : (TimeSpan?)null,
DurationMax = durationMaxDays.HasValue ? TimeSpan.FromDays(durationMaxDays.Value) : (TimeSpan?)null
};
try
{
var deletedCount = await _backtester.DeleteBacktestsByFiltersAsync(user, filter);
return Ok(new { DeletedCount = deletedCount });
}
catch (Exception ex)
{
return StatusCode(500, $"Error deleting backtests: {ex.Message}");
}
}
/// <summary>
/// Retrieves all backtests for a specific genetic request ID.
/// This endpoint is used to view the results of a genetic algorithm optimization.