From 76306ef59b3873c594384af185c7de8a47594b19 Mon Sep 17 00:00:00 2001 From: "alexei.dolgolyov" Date: Fri, 29 May 2026 02:38:20 +0300 Subject: [PATCH] feat(settings): forward-test (paper-trading) settings section MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Surfaces the PaperTradingWorker's config on the Settings page — Enabled toggle, min-score, flat-stake, and poll interval — so forward-testing can be switched on and tuned from the UI instead of hand-editing committed appsettings.json. Uses the established UI-mirror-options pattern (PaperTradingSettingsForm bound to the "PaperTrading" section, same as the UI WorkerOptions mirror) and writes through the existing ISettingsWriter to appsettings.Local.json. Notifications is deliberately NOT surfaced: its section holds the Telegram secret and the section-replace writer would clobber the token — that section stays Local.json-only by design. - PaperTradingSettingsForm (no secrets) + DI binding; Settings section + en/ru resx. --- src/Marathon.UI/Pages/Settings.razor | 37 +++++++++++++++++++ .../Resources/SharedResource.en.resx | 8 ++++ .../Resources/SharedResource.ru.resx | 8 ++++ .../Services/PaperTradingSettingsForm.cs | 24 ++++++++++++ .../Services/UiServicesExtensions.cs | 1 + 5 files changed, 78 insertions(+) create mode 100644 src/Marathon.UI/Services/PaperTradingSettingsForm.cs diff --git a/src/Marathon.UI/Pages/Settings.razor b/src/Marathon.UI/Pages/Settings.razor index 0dba50d..317318a 100644 --- a/src/Marathon.UI/Pages/Settings.razor +++ b/src/Marathon.UI/Pages/Settings.razor @@ -6,6 +6,7 @@ @inject IOptionsMonitor WorkerOpts @inject IOptionsMonitor StorageOpts @inject IOptionsMonitor AnomalyOpts +@inject IOptionsMonitor PaperTradingOpts @inject IOptionsMonitor LocaleOpts @inject ISettingsWriter Writer @inject IDialogService Dialogs @@ -157,6 +158,33 @@ + @* FORWARD-TEST (PAPER TRADING) *@ +
+
+

@L["Settings.Section.PaperTrading"]

+ + @L["Settings.Action.Reset"] + +
+
+ + + + + + + + + + + + + + +
+
+ @* LOCALIZATION *@
@@ -184,6 +212,7 @@ private WorkerOptions _workers = new(); private StorageOptions _storage = new(); private AnomalyOptions _anomaly = new(); + private PaperTradingSettingsForm _paperTrading = new(); private LocalizationOptions _locale = new(); private string _userAgentsRaw = string.Empty; @@ -218,6 +247,14 @@ DetectionIntervalSeconds = AnomalyOpts.CurrentValue.DetectionIntervalSeconds, }; + _paperTrading = new PaperTradingSettingsForm + { + Enabled = PaperTradingOpts.CurrentValue.Enabled, + MinScore = PaperTradingOpts.CurrentValue.MinScore, + FlatStake = PaperTradingOpts.CurrentValue.FlatStake, + PollIntervalSeconds = PaperTradingOpts.CurrentValue.PollIntervalSeconds, + }; + _locale = new LocalizationOptions { DefaultCulture = LocaleOpts.CurrentValue.DefaultCulture }; } diff --git a/src/Marathon.UI/Resources/SharedResource.en.resx b/src/Marathon.UI/Resources/SharedResource.en.resx index d50f6f0..1299e8e 100644 --- a/src/Marathon.UI/Resources/SharedResource.en.resx +++ b/src/Marathon.UI/Resources/SharedResource.en.resx @@ -97,6 +97,14 @@ Background workers Storage Anomaly detector + Forward-test (paper trading) + Enable forward-test worker + Opens a flat-stake paper bet on each live directional signal and settles it when the result lands. + Min score + Only anomalies at or above this score are paper-traded. + Flat stake + Stake placed on every paper bet. + Poll interval (sec) Localization Reset section Save diff --git a/src/Marathon.UI/Resources/SharedResource.ru.resx b/src/Marathon.UI/Resources/SharedResource.ru.resx index bf28969..3bc0177 100644 --- a/src/Marathon.UI/Resources/SharedResource.ru.resx +++ b/src/Marathon.UI/Resources/SharedResource.ru.resx @@ -101,6 +101,14 @@ Фоновые задачи Хранилище Детектор аномалий + Форвард-тест (бумажная торговля) + Включить воркер форвард-теста + Открывает ставку фиксированным стейком на каждый живой направленный сигнал и рассчитывает её по результату. + Мин. score + В форвард-тест попадают только аномалии со score не ниже указанного. + Фикс. стейк + Стейк на каждую бумажную ставку. + Интервал опроса (сек) Локализация Сбросить раздел Сохранить diff --git a/src/Marathon.UI/Services/PaperTradingSettingsForm.cs b/src/Marathon.UI/Services/PaperTradingSettingsForm.cs new file mode 100644 index 0000000..e2eca1b --- /dev/null +++ b/src/Marathon.UI/Services/PaperTradingSettingsForm.cs @@ -0,0 +1,24 @@ +namespace Marathon.UI.Services; + +/// +/// Mutable UI mirror of the host's paper-trading options, bound to the same +/// PaperTrading config section so the Settings page can edit the forward-test +/// worker's behaviour. Mirrors Marathon.Infrastructure.Configuration.PaperTradingOptions +/// (which the worker reads); keep the two in sync. Contains no secrets. +/// +public sealed class PaperTradingSettingsForm +{ + public const string SectionName = "PaperTrading"; + + /// Master switch — when false the worker idles. + public bool Enabled { get; set; } + + /// Minimum anomaly score required to open a paper bet. + public decimal MinScore { get; set; } = 0.55m; + + /// Flat stake placed on every paper bet. + public decimal FlatStake { get; set; } = 10m; + + /// Seconds between open/settle cycles. + public int PollIntervalSeconds { get; set; } = 60; +} diff --git a/src/Marathon.UI/Services/UiServicesExtensions.cs b/src/Marathon.UI/Services/UiServicesExtensions.cs index 85d1828..7b643c4 100644 --- a/src/Marathon.UI/Services/UiServicesExtensions.cs +++ b/src/Marathon.UI/Services/UiServicesExtensions.cs @@ -47,6 +47,7 @@ public static class UiServicesExtensions services.Configure(configuration.GetSection(AnomalyOptions.SectionName)); services.Configure(configuration.GetSection(StorageOptions.SectionName)); services.Configure(configuration.GetSection(ScrapingSettingsForm.SectionName)); + services.Configure(configuration.GetSection(PaperTradingSettingsForm.SectionName)); // Singletons that drive UI chrome state. services.AddSingleton();