using Marathon.Application.Abstractions; using Marathon.Application.Storage; using Marathon.Domain.Backtesting; using Microsoft.Extensions.Logging; namespace Marathon.Application.UseCases; /// One saved strategy preset paired with its backtest result over a shared window. public sealed record StrategyComparison(Guid StrategyId, string Name, BacktestResult Result); /// /// Runs every saved strategy preset over the same anomaly window and returns their /// backtest results side by side, so the user can see which staking configuration wins. /// /// /// Delegates to once per preset — the anomaly set is /// re-loaded per run, which is fine for the handful of presets a user keeps. Keeping the /// composition at the use-case level (rather than re-implementing candidate loading) means /// the comparison stays bug-for-bug identical to a single backtest run. /// public sealed class CompareStrategiesUseCase { private readonly ISavedStrategyRepository _strategies; private readonly RunBacktestUseCase _backtest; private readonly ILogger _logger; public CompareStrategiesUseCase( ISavedStrategyRepository strategies, RunBacktestUseCase backtest, ILogger logger) { _strategies = strategies ?? throw new ArgumentNullException(nameof(strategies)); _backtest = backtest ?? throw new ArgumentNullException(nameof(backtest)); _logger = logger ?? throw new ArgumentNullException(nameof(logger)); } /// /// Backtests each saved preset over (null = all graded /// anomalies). Returns one row per preset in saved (name-ascending) order; empty when /// the user has saved no strategies. /// public async Task> ExecuteAsync( DateRange? dateRange, CancellationToken ct = default) { var presets = await _strategies.ListAsync(ct).ConfigureAwait(false); if (presets.Count == 0) return Array.Empty(); var rows = new List(presets.Count); foreach (var preset in presets) { ct.ThrowIfCancellationRequested(); var result = await _backtest.ExecuteAsync(preset.Strategy, dateRange, ct).ConfigureAwait(false); rows.Add(new StrategyComparison(preset.Id, preset.Name, result)); } _logger.LogInformation("CompareStrategiesUseCase: compared {Count} preset(s)", rows.Count); return rows; } }