Files
maraphon-app/src/Marathon.Application/Abstractions/IPaperBetRepository.cs
T
alexei.dolgolyov f622dadf95 feat(paper-trading): forward-test ledger engine
Adds a background forward-test engine that records flat-stake "paper" bets
for directional anomalies as they fire and settles them when results arrive,
measuring the detector's live, out-of-sample edge — the antidote to backtest
overfitting. The results UI is a follow-up.

- Domain: PaperBet entity (Rate>1 / Stake>0 invariants, Open factory,
  SettleAgainst — Won pays stake x rate, else Lost) + AnomalyEvidenceSide.RateFor.
- Application: OpenPaperBetsUseCase (directional + score gate, dedups by
  AnomalyId, picks the post-flip favourite and its locked-in rate) and
  SettlePaperBetsUseCase (Won when pick == winner else Lost; ungraded events
  stay open; batched result lookup).
- Infrastructure: PaperBetEntity + config (TEXT decimals, unique AnomalyId index,
  Outcome index), repository, mapping, additive AddPaperBets migration, and
  PaperTradingWorker (config-gated, baseline since-marker, open+settle per cycle).
- Config: PaperTradingOptions / appsettings PaperTrading (Enabled:false default).
- 25 tests: domain settlement, both use cases, and a real-SQLite round-trip
  incl. the unique-AnomalyId double-open backstop.
2026-05-29 02:25:54 +03:00

25 lines
961 B
C#

using Marathon.Domain.Entities;
using Marathon.Domain.Enums;
namespace Marathon.Application.Abstractions;
/// <summary>
/// Repository for <see cref="PaperBet"/> entities — the forward-test ledger written
/// by the paper-trading worker.
/// </summary>
public interface IPaperBetRepository : IRepository<Guid, PaperBet>
{
/// <summary>
/// Paper bets in a given settlement state — <see cref="BetOutcome.Pending"/> is
/// the open set the settler scans each cycle.
/// </summary>
Task<IReadOnlyList<PaperBet>> ListByOutcomeAsync(BetOutcome outcome, CancellationToken ct = default);
/// <summary>
/// The subset of <paramref name="anomalyIds"/> that already have a paper bet —
/// lets the opener skip anomalies it has already forward-tested (one bet per anomaly).
/// </summary>
Task<IReadOnlySet<Guid>> GetExistingAnomalyIdsAsync(
IReadOnlyCollection<Guid> anomalyIds, CancellationToken ct = default);
}