6e12dd73c3
New /anomalies/compare page runs every saved strategy preset over the same window and ranks them by ROI — bets, W–L, hit-rate, net, and max drawdown side by side, with the best ROI flagged. Auto-runs on load with an optional date-range refine. - CompareStrategiesUseCase fans RunBacktestUseCase over saved presets (re-loads the anomaly set per preset — fine for the handful a user keeps; stays bug-for-bug identical to a single backtest run). - StrategyComparisonService.BuildVm (pure) computes per-row hit-rate + a single best-by-ROI flag; nav entry + en/ru resx. - 6 tests: use-case fan-out + BuildVm best/tie/no-bets/hit-rate.
76 lines
3.7 KiB
C#
76 lines
3.7 KiB
C#
using Marathon.Application.Storage;
|
|
using Microsoft.Extensions.Configuration;
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
using MudBlazor.Services;
|
|
|
|
namespace Marathon.UI.Services;
|
|
|
|
/// <summary>
|
|
/// DI registration helpers for the Marathon.UI Razor Class Library.
|
|
/// Hosts call <see cref="AddMarathonUi(IServiceCollection, IConfiguration, string)"/>
|
|
/// during startup.
|
|
/// </summary>
|
|
public static class UiServicesExtensions
|
|
{
|
|
/// <summary>
|
|
/// Registers MudBlazor services, localization, the theme/locale observable
|
|
/// state objects, the file-backed settings writer, and binds all
|
|
/// configuration sections that the Settings page surfaces.
|
|
/// </summary>
|
|
/// <param name="services">DI container.</param>
|
|
/// <param name="configuration">Host configuration root.</param>
|
|
/// <param name="settingsLocalPath">
|
|
/// Absolute path to <c>appsettings.Local.json</c>, used by the writer.
|
|
/// </param>
|
|
public static IServiceCollection AddMarathonUi(
|
|
this IServiceCollection services,
|
|
IConfiguration configuration,
|
|
string settingsLocalPath)
|
|
{
|
|
ArgumentNullException.ThrowIfNull(services);
|
|
ArgumentNullException.ThrowIfNull(configuration);
|
|
ArgumentException.ThrowIfNullOrEmpty(settingsLocalPath);
|
|
|
|
services.AddMudServices();
|
|
|
|
// No ResourcesPath: the SharedResource type already lives in the
|
|
// Marathon.UI.Resources namespace, so its compiled .resources name
|
|
// is "Marathon.UI.Resources.SharedResource.{culture}.resources" which
|
|
// matches the type's FullName directly. Setting ResourcesPath="Resources"
|
|
// here would cause the resolver to look for "...Resources.Resources..."
|
|
// and silently fall back to displaying the keys.
|
|
services.AddLocalization();
|
|
|
|
// Strongly typed options bound to appsettings.json sections.
|
|
services.Configure<LocalizationOptions>(configuration.GetSection(LocalizationOptions.SectionName));
|
|
services.Configure<WorkerOptions>(configuration.GetSection(WorkerOptions.SectionName));
|
|
services.Configure<AnomalyOptions>(configuration.GetSection(AnomalyOptions.SectionName));
|
|
services.Configure<StorageOptions>(configuration.GetSection(StorageOptions.SectionName));
|
|
services.Configure<ScrapingSettingsForm>(configuration.GetSection(ScrapingSettingsForm.SectionName));
|
|
services.Configure<PaperTradingSettingsForm>(configuration.GetSection(PaperTradingSettingsForm.SectionName));
|
|
|
|
// Singletons that drive UI chrome state.
|
|
services.AddSingleton<ThemeState>();
|
|
services.AddSingleton<LocaleState>();
|
|
services.AddSingleton<EventBrowsingState>();
|
|
services.AddSingleton<AnomalyBrowsingState>();
|
|
|
|
// Browsing facades — Scoped so they capture the per-circuit repository scope.
|
|
services.AddScoped<IEventBrowsingService, EventBrowsingService>();
|
|
services.AddScoped<IAnomalyBrowsingService, AnomalyBrowsingService>();
|
|
services.AddScoped<IAnomalyInsightsService, AnomalyInsightsService>();
|
|
services.AddScoped<IResultsBrowsingService, ResultsBrowsingService>();
|
|
services.AddScoped<IBetJournalService, BetJournalService>();
|
|
services.AddScoped<IBacktestService, BacktestService>();
|
|
services.AddScoped<IStrategyComparisonService, StrategyComparisonService>();
|
|
services.AddScoped<IDashboardSummaryService, DashboardSummaryService>();
|
|
services.AddScoped<IPipelineHealthService, PipelineHealthService>();
|
|
services.AddScoped<IPaperTradingService, PaperTradingService>();
|
|
|
|
// Settings writer — file path is host-resolved.
|
|
services.AddSingleton<ISettingsWriter>(_ => new JsonSettingsWriter(settingsLocalPath));
|
|
|
|
return services;
|
|
}
|
|
}
|