Files
maraphon-app/src/Marathon.Domain/Enums/AnomalyKindExtensions.cs
T
alexei.dolgolyov 115872aad0 feat(anomaly): overround-compression detector
Adds the 4th IAnomalyDetector: flags a sharp drop in the bookmaker's
overround (raw implied-probability sum / margin) over a continuous live
window. Informational/non-directional — excluded from outcome grading
and backtest staking via AnomalyKind.IsDirectional().

- OverroundCompressionDetector: sliding-window scan mirroring SteamMove,
  score = min(1, compression / 0.10 reference), suspension-gap aware.
- MatchWinEvidence.Probabilities gains Overround (pre-normalisation
  margin); evidence JSON shape unchanged.
- Wired into DetectAnomaliesUseCase fan-out; AnomalyOptions + appsettings
  (window 120s, threshold 0.02); en/ru resx + KindLabel arms.
- 11 detector tests incl. score saturation/scaling, inclusive threshold
  boundary, and a three-way (draw-leg) overround case.
2026-05-29 01:46:56 +03:00

26 lines
1.1 KiB
C#

namespace Marathon.Domain.Enums;
/// <summary>Semantic classification of anomaly kinds.</summary>
public static class AnomalyKindExtensions
{
/// <summary>
/// Whether the kind makes a <i>directional</i> prediction — a specific side/favourite
/// expected to win — that can be graded against the result and bet on in a backtest.
/// </summary>
/// <remarks>
/// <see cref="AnomalyKind.SuspensionFlip"/> and <see cref="AnomalyKind.SteamMove"/> are
/// directional (they point at a favourite). <see cref="AnomalyKind.SuspensionFreeze"/> is
/// informational — the line did NOT move — so "predicting" the unchanged favourite would
/// merely measure the base favourite-win rate; it is excluded from outcome grading and
/// from backtest staking so it does not distort detector calibration.
/// </remarks>
public static bool IsDirectional(this AnomalyKind kind) => kind switch
{
AnomalyKind.SuspensionFlip => true,
AnomalyKind.SteamMove => true,
AnomalyKind.SuspensionFreeze => false,
AnomalyKind.OverroundCompression => false,
_ => false,
};
}