using Marathon.Domain.Entities; using Marathon.Domain.Enums; namespace Marathon.Application.Betting; /// /// Aggregate report on the user's bet-tracking journal — totals, P&L, and /// per-bet CLV. Consumed by the Journal page; built by /// . /// /// Roll-up of stake / profit / hit rate / CLV across all bets in scope. /// /// Every bet paired with its computed CLV (null when no closing snapshot was /// available). Ordered most-recent first. /// public sealed record BetJournalReport( BetJournalStats Stats, IReadOnlyList Bets); /// /// One row in the journal — a domain plus the CLV /// computed against the closing pre-match snapshot. /// /// The domain bet exactly as persisted. /// /// Closing-line value as an implied-probability delta in roughly [-1, 1]. /// Positive means the user took a better price than the closing line; null /// when no matching bet existed in the closing snapshot. /// public sealed record BetJournalRow( PlacedBet Bet, decimal? ClvProbabilityDelta); /// /// Aggregate statistics across a set of . /// All money values share the user's currency — the domain does not encode one. /// /// Every bet in scope, regardless of outcome. /// Bets still awaiting settlement. /// Settled wins. /// Settled losses. /// Settled pushes / void grades. /// /// Turnover that contributes to ROI: sum of across /// Won and Lost bets only. Void (push) and Pending bets are excluded — a /// returned stake is not real turnover and counting it would dilute ROI. /// /// /// Sum of across the same Won + Lost subset /// that feeds . /// /// TotalReturned − TotalStaked. /// /// NetProfit / TotalStaked × 100. Null when no bets have resolved yet. /// /// /// WonCount / (WonCount + LostCount) × 100 — excludes voids and pendings. /// Null when no settled win/loss exists yet. /// /// /// Mean CLV across bets where CLV was computable. Null when no comparable /// closing snapshot was available for any bet. /// public sealed record BetJournalStats( int TotalBets, int PendingCount, int WonCount, int LostCount, int VoidCount, decimal TotalStaked, decimal TotalReturned, decimal NetProfit, decimal? RoiPercent, decimal? StrikeRatePercent, decimal? AverageClvProbabilityDelta) { /// Convenience: WonCount + LostCount + VoidCount. public int ResolvedCount => WonCount + LostCount + VoidCount; public static BetJournalStats Empty { get; } = new( TotalBets: 0, PendingCount: 0, WonCount: 0, LostCount: 0, VoidCount: 0, TotalStaked: 0m, TotalReturned: 0m, NetProfit: 0m, RoiPercent: null, StrikeRatePercent: null, AverageClvProbabilityDelta: null); }