feat(backtest): optional date-range window
- RunBacktestUseCase gains an ExecuteAsync(strategy, DateRange?, ct) overload that pushes the date filter to SQL via IAnomalyRepository.ListByDateRangeAsync; the existing no-range overload is preserved. +1 use-case test. - BacktestForm carries optional From/To (Moscow dates) with From<=To validation and a ToDateRange() helper; BacktestService threads it through. Backtest page gains two clearable date pickers (empty = all anomalies). - Localization (en+ru) for the backtest date fields and the settings-validation keys (shared resx).
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
using Marathon.Application.Abstractions;
|
||||
using Marathon.Application.Storage;
|
||||
using Marathon.Domain.AnomalyDetection;
|
||||
using Marathon.Domain.Backtesting;
|
||||
using Marathon.Domain.Entities;
|
||||
@@ -46,17 +47,32 @@ public sealed class RunBacktestUseCase
|
||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||
}
|
||||
|
||||
public async Task<BacktestResult> ExecuteAsync(
|
||||
/// <summary>Runs the backtest over every graded anomaly (no date filter).</summary>
|
||||
public Task<BacktestResult> ExecuteAsync(
|
||||
BacktestStrategy strategy,
|
||||
CancellationToken ct = default)
|
||||
=> ExecuteAsync(strategy, dateRange: null, ct);
|
||||
|
||||
/// <summary>
|
||||
/// Runs the backtest over anomalies detected within <paramref name="dateRange"/>
|
||||
/// (inclusive); pass <c>null</c> to include every graded anomaly. The date filter
|
||||
/// is pushed to SQL via <see cref="IAnomalyRepository.ListByDateRangeAsync"/>.
|
||||
/// </summary>
|
||||
public async Task<BacktestResult> ExecuteAsync(
|
||||
BacktestStrategy strategy,
|
||||
DateRange? dateRange,
|
||||
CancellationToken ct)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(strategy);
|
||||
|
||||
_logger.LogInformation(
|
||||
"RunBacktestUseCase: started — bankroll={Bankroll}, minScore={MinScore}, stakeRule={Rule}",
|
||||
strategy.StartingBankroll, strategy.MinScore, strategy.StakeRule);
|
||||
"RunBacktestUseCase: started — bankroll={Bankroll}, minScore={MinScore}, stakeRule={Rule}, range={Range}",
|
||||
strategy.StartingBankroll, strategy.MinScore, strategy.StakeRule,
|
||||
dateRange is null ? "all" : $"{dateRange.From:O}..{dateRange.To:O}");
|
||||
|
||||
var anomalies = await _anomalies.ListAsync(ct).ConfigureAwait(false);
|
||||
var anomalies = dateRange is null
|
||||
? await _anomalies.ListAsync(ct).ConfigureAwait(false)
|
||||
: await _anomalies.ListByDateRangeAsync(dateRange.From, dateRange.To, ct).ConfigureAwait(false);
|
||||
if (anomalies.Count == 0)
|
||||
{
|
||||
_logger.LogInformation("RunBacktestUseCase: no anomalies — empty result");
|
||||
|
||||
Reference in New Issue
Block a user