0d52b7beff
Adds an interactive backtester that replays the SuspensionFlip detector over all flagged anomalies under a chosen score threshold and staking rule (flat / percent-of-bankroll / Kelly), and reports the headline numbers a user needs to judge edge: final bankroll, ROI, max drawdown (peak-to-trough), win/loss streaks, plus per-bet equity curve. Domain (pure): - StakeRule enum + BacktestStrategy params (with validation). - BacktestSimulator: deterministic function taking strategy + chronological candidates → BacktestResult. Implements Kelly with post-flip implied prob as p (skipping negative-edge bets), peak-to-trough drawdown tracking, and win/loss streak rollups. Mirrors AnomalyOutcomeEvaluator on the 2-way Draw guard so tennis data inconsistencies are refused rather than miss-counted. - Skipped counter split into SkippedByThreshold / SkippedByDataQuality / SkippedByBankroll so the UI can distinguish "strategy choice" from "data-quality" from "bankroll empty". Application: - RunBacktestUseCase: loads anomalies + events + results, parses evidence, builds candidates, hands event titles into the simulator so the UI does zero repository round-trips of its own. UI: - Pages/Anomalies/Backtest.razor: hero, strategy form (MudBlazor — conditional sub-field per staking rule), 4-card KPI strip (final bankroll / net profit / ROI / max drawdown), counters row, inline-SVG equity curve, trade-trace table with per-bet outcome pills and link-back to the source anomaly. - Nav entry under Analysis. RU + EN i18n. Tests: +20 (16 simulator math — flat / percent compounding / Kelly +/- edge / quarter-Kelly / bankroll-exceeded / out-of-order chronology / Draw favourite / multi-window drawdown / event-title pass-through + 4 use-case join). All 399 tests pass. Money rounding switched to MidpointRounding.AwayFromZero throughout the simulator output for accounting convention. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
29 lines
965 B
C#
29 lines
965 B
C#
namespace Marathon.Domain.Backtesting;
|
||
|
||
/// <summary>
|
||
/// How the simulator decides how much to stake on each bet during a backtest.
|
||
/// </summary>
|
||
public enum StakeRule
|
||
{
|
||
/// <summary>
|
||
/// Same fixed amount every bet, independent of bankroll.
|
||
/// Suitable for "flat-betting" historical analysis — the simplest baseline.
|
||
/// </summary>
|
||
Flat,
|
||
|
||
/// <summary>
|
||
/// A fixed percentage of the current bankroll every bet. Compounds: a
|
||
/// winning streak grows stake size; losses shrink it. Equivalent to
|
||
/// proportional betting.
|
||
/// </summary>
|
||
PercentOfBankroll,
|
||
|
||
/// <summary>
|
||
/// Fractional Kelly using the post-flip implied probability as the edge
|
||
/// estimate: <c>f = ((b·p) − q) / b</c>, scaled by the configured
|
||
/// <see cref="BacktestStrategy.KellyFraction"/>. Negative-expectation bets
|
||
/// stake zero (and are skipped). Half/quarter-Kelly is the usual practice.
|
||
/// </summary>
|
||
Kelly,
|
||
}
|