fix(anomaly): exclude non-directional kinds from grading and backtest
Review follow-up (HIGH): the three detectors fed the same evaluator/backtest, but SuspensionFreeze is non-directional (favourite unchanged) — grading it as "favourite won" polluted the hit-rate with the base favourite-win rate, and its high frozen-ness score always cleared the backtest threshold. - Add AnomalyKind.IsDirectional() (flip + steam = true, freeze = false). - AnomalyOutcomeEvaluator returns Unresolved for non-directional kinds (favourites still surfaced for display) so they don't distort calibration. - RunBacktestUseCase skips non-directional anomalies when building candidates. - Tests for the classification, the evaluator path, and the backtest skip.
This commit is contained in:
@@ -0,0 +1,24 @@
|
||||
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,
|
||||
_ => false,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user