feat(settings): forward-test (paper-trading) settings section
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.
This commit is contained in:
@@ -6,6 +6,7 @@
|
||||
@inject IOptionsMonitor<WorkerOptions> WorkerOpts
|
||||
@inject IOptionsMonitor<StorageOptions> StorageOpts
|
||||
@inject IOptionsMonitor<AnomalyOptions> AnomalyOpts
|
||||
@inject IOptionsMonitor<PaperTradingSettingsForm> PaperTradingOpts
|
||||
@inject IOptionsMonitor<Marathon.UI.Services.LocalizationOptions> LocaleOpts
|
||||
@inject ISettingsWriter Writer
|
||||
@inject IDialogService Dialogs
|
||||
@@ -157,6 +158,33 @@
|
||||
</div>
|
||||
</article>
|
||||
|
||||
@* FORWARD-TEST (PAPER TRADING) *@
|
||||
<article class="m-section m-rise m-rise-5">
|
||||
<header class="m-section__head">
|
||||
<h2>@L["Settings.Section.PaperTrading"]</h2>
|
||||
<MudButton Variant="Variant.Text" Size="Size.Small"
|
||||
OnClick="@(() => ResetSectionAsync(PaperTradingSettingsForm.SectionName))">
|
||||
@L["Settings.Action.Reset"]
|
||||
</MudButton>
|
||||
</header>
|
||||
<div class="m-section__body">
|
||||
<Field Label="@L["Settings.PaperTrading.Enabled"]" Hint="@L["Settings.PaperTrading.Enabled.Hint"]">
|
||||
<MudSwitch T="bool" @bind-Value="_paperTrading.Enabled" Color="Color.Primary" />
|
||||
</Field>
|
||||
<Field Label="@L["Settings.PaperTrading.MinScore"]" Hint="@L["Settings.PaperTrading.MinScore.Hint"]">
|
||||
<MudNumericField T="decimal" @bind-Value="_paperTrading.MinScore" Min="0m" Max="1m" Step="0.05m" Variant="Variant.Outlined" />
|
||||
</Field>
|
||||
<Field Label="@L["Settings.PaperTrading.FlatStake"]" Hint="@L["Settings.PaperTrading.FlatStake.Hint"]">
|
||||
<MudNumericField T="decimal" @bind-Value="_paperTrading.FlatStake" Min="0.01m" Step="5m" Variant="Variant.Outlined" />
|
||||
</Field>
|
||||
<Field Label="@L["Settings.PaperTrading.PollIntervalSeconds"]">
|
||||
<MudNumericField T="int" @bind-Value="_paperTrading.PollIntervalSeconds" Min="5" Max="3600" Variant="Variant.Outlined" />
|
||||
</Field>
|
||||
|
||||
<SectionFooter OnSave="@(() => SaveSectionAsync(PaperTradingSettingsForm.SectionName, _paperTrading))" />
|
||||
</div>
|
||||
</article>
|
||||
|
||||
@* LOCALIZATION *@
|
||||
<article class="m-section m-rise m-rise-5">
|
||||
<header class="m-section__head">
|
||||
@@ -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 };
|
||||
}
|
||||
|
||||
|
||||
@@ -97,6 +97,14 @@
|
||||
<data name="Settings.Section.Workers"><value>Background workers</value></data>
|
||||
<data name="Settings.Section.Storage"><value>Storage</value></data>
|
||||
<data name="Settings.Section.Anomaly"><value>Anomaly detector</value></data>
|
||||
<data name="Settings.Section.PaperTrading"><value>Forward-test (paper trading)</value></data>
|
||||
<data name="Settings.PaperTrading.Enabled"><value>Enable forward-test worker</value></data>
|
||||
<data name="Settings.PaperTrading.Enabled.Hint"><value>Opens a flat-stake paper bet on each live directional signal and settles it when the result lands.</value></data>
|
||||
<data name="Settings.PaperTrading.MinScore"><value>Min score</value></data>
|
||||
<data name="Settings.PaperTrading.MinScore.Hint"><value>Only anomalies at or above this score are paper-traded.</value></data>
|
||||
<data name="Settings.PaperTrading.FlatStake"><value>Flat stake</value></data>
|
||||
<data name="Settings.PaperTrading.FlatStake.Hint"><value>Stake placed on every paper bet.</value></data>
|
||||
<data name="Settings.PaperTrading.PollIntervalSeconds"><value>Poll interval (sec)</value></data>
|
||||
<data name="Settings.Section.Localization"><value>Localization</value></data>
|
||||
<data name="Settings.Action.Reset"><value>Reset section</value></data>
|
||||
<data name="Settings.Action.Save"><value>Save</value></data>
|
||||
|
||||
@@ -101,6 +101,14 @@
|
||||
<data name="Settings.Section.Workers"><value>Фоновые задачи</value></data>
|
||||
<data name="Settings.Section.Storage"><value>Хранилище</value></data>
|
||||
<data name="Settings.Section.Anomaly"><value>Детектор аномалий</value></data>
|
||||
<data name="Settings.Section.PaperTrading"><value>Форвард-тест (бумажная торговля)</value></data>
|
||||
<data name="Settings.PaperTrading.Enabled"><value>Включить воркер форвард-теста</value></data>
|
||||
<data name="Settings.PaperTrading.Enabled.Hint"><value>Открывает ставку фиксированным стейком на каждый живой направленный сигнал и рассчитывает её по результату.</value></data>
|
||||
<data name="Settings.PaperTrading.MinScore"><value>Мин. score</value></data>
|
||||
<data name="Settings.PaperTrading.MinScore.Hint"><value>В форвард-тест попадают только аномалии со score не ниже указанного.</value></data>
|
||||
<data name="Settings.PaperTrading.FlatStake"><value>Фикс. стейк</value></data>
|
||||
<data name="Settings.PaperTrading.FlatStake.Hint"><value>Стейк на каждую бумажную ставку.</value></data>
|
||||
<data name="Settings.PaperTrading.PollIntervalSeconds"><value>Интервал опроса (сек)</value></data>
|
||||
<data name="Settings.Section.Localization"><value>Локализация</value></data>
|
||||
<data name="Settings.Action.Reset"><value>Сбросить раздел</value></data>
|
||||
<data name="Settings.Action.Save"><value>Сохранить</value></data>
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
namespace Marathon.UI.Services;
|
||||
|
||||
/// <summary>
|
||||
/// Mutable UI mirror of the host's paper-trading options, bound to the same
|
||||
/// <c>PaperTrading</c> config section so the Settings page can edit the forward-test
|
||||
/// worker's behaviour. Mirrors <c>Marathon.Infrastructure.Configuration.PaperTradingOptions</c>
|
||||
/// (which the worker reads); keep the two in sync. Contains no secrets.
|
||||
/// </summary>
|
||||
public sealed class PaperTradingSettingsForm
|
||||
{
|
||||
public const string SectionName = "PaperTrading";
|
||||
|
||||
/// <summary>Master switch — when false the worker idles.</summary>
|
||||
public bool Enabled { get; set; }
|
||||
|
||||
/// <summary>Minimum anomaly score required to open a paper bet.</summary>
|
||||
public decimal MinScore { get; set; } = 0.55m;
|
||||
|
||||
/// <summary>Flat stake placed on every paper bet.</summary>
|
||||
public decimal FlatStake { get; set; } = 10m;
|
||||
|
||||
/// <summary>Seconds between open/settle cycles.</summary>
|
||||
public int PollIntervalSeconds { get; set; } = 60;
|
||||
}
|
||||
@@ -47,6 +47,7 @@ public static class UiServicesExtensions
|
||||
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>();
|
||||
|
||||
Reference in New Issue
Block a user