Skip to content

Strategy Validation Properties (Exhaustive)

This is the canonical running list of properties that validation enforces for strategies.

Framework contract reference: docs/framework.md

Validation Execution Flow

flowchart LR
    A["Input strategy + date range"] --> B["Contract checks"]
    B --> C["Backtest metrics"]
    C --> D["Leakage + strict diagnostics"]
    D --> E["Threshold checks"]
    E --> F["Validation pass/fail summary"]

Validation Property Checklist

  1. [ ] Allocation span config is valid
  2. STACKSATS_ALLOCATION_SPAN_DAYS must be an integer in [90, 1460] (default 365).

  3. [ ] Strategy cannot bypass framework orchestration

  4. Custom compute_weights overrides are rejected.

  5. [ ] Strategy must implement an allowed hook path

  6. At least one is required: propose_weight(state) or build_target_profile(ctx, features_df, signals).

  7. [ ] transform_features output type is valid

  8. Must return a pandas DataFrame.

  9. [ ] build_signals output type is valid

  10. Must return dict[str, pandas.Series].

  11. [ ] Signal and profile series shape/index contract holds

  12. Each series must be a pandas Series, with no duplicate index, ascending index, exact match to window index.

  13. [ ] Signal and profile series numeric validity holds

  14. Series values must be finite numeric (no NaN, inf, or non-numeric coercion failures).

  15. [ ] propose_weight outputs are finite

  16. Every proposal must be finite numeric.

  17. [ ] Target profile mode is valid

  18. Only preference and absolute modes are allowed.

  19. [ ] Allocation index monotonicity holds for temporal counting

  20. Allocation index used for n_past must be monotonic increasing.

  21. [ ] Locked-prefix structural validity holds

  22. locked_weights must be 1D, finite, values in [0, 1], and length <= n_past.

  23. [ ] Locked-prefix budget feasibility holds

  24. Running sum of locked weights must never exceed total budget 1.0.

  25. [ ] Locked-prefix daily bounds hold on contract-length windows

  26. When window length equals configured span, locked values must be within [1e-5, 0.1].

  27. [ ] Per-day clipping obeys future feasibility constraints

  28. For contract-length windows, daily clipping enforces both day bounds and future-budget feasibility.
  29. Infeasible bounds must hard-fail.

  30. [ ] Output weight vector structure is valid

  31. Final weights must be 1D and finite.

  32. [ ] Output weight values are valid

  33. No negative weights; no values above 1.0 (within tolerance).

  34. [ ] Output weights sum exactly to budget (within tolerance)

  35. Final weight sum must be 1.0.

  36. [ ] Contract-length day bounds hold on final weights

  37. For span-length windows, each day weight must be within [1e-5, 0.1].

  38. [ ] Daily bounds are globally feasible for span length

  39. Span must satisfy feasibility: n_days * min_daily_weight <= 1.0 <= n_days * max_daily_weight.

  40. [ ] Historical lock immutability is enforced in strict checks

  41. Injected locked prefix must be preserved exactly when recomputing under perturbed future features.

  42. [ ] Forward-leakage resistance: masked-future invariance

  43. Prefix weights at probe date must match when all future features are masked to NaN.

  44. [ ] Forward-leakage resistance: perturbed-future invariance

  45. Prefix weights at probe date must match when future features are strongly perturbed.

  46. [ ] Profile-only leakage resistance is enforced

  47. For profile-hook strategies (without propose hook), prefix profile values must be invariant under masked/perturbed future inputs.

  48. [ ] Strict mode forbids in-place feature mutation

  49. Strategy must not mutate ctx.features_df during weight computation.

  50. [ ] Strict mode forbids profile-build feature mutation

  51. Strategy must not mutate ctx.features_df during transform/signal/profile build path.

  52. [ ] Strict mode determinism holds

  53. Repeated runs with identical inputs must produce exactly matching weights (within atol=1e-12).

  54. [ ] Weight constraints hold across validation windows

  55. Validation windows must not violate sum, negativity, or (when applicable) min/max day bounds.

  56. [ ] Boundary saturation stays below strict threshold

  57. In strict mode, boundary-hit rate (days at MIN or MAX) must be <= max_boundary_hit_rate (default 0.85).

  58. [ ] Cross-fold robustness minimum is met in strict mode (when fold checks run)

  59. Minimum fold win rate must be >= min_fold_win_rate (default 20.0).
  60. Fold checks are skipped when there is insufficient date range for at least two valid folds.

  61. [ ] Cross-fold instability is bounded in strict mode (when fold checks run)

  62. Fold win-rate standard deviation must be <= max_fold_win_rate_std (default 35.0).
  63. Fold checks are skipped when there is insufficient date range for at least two valid folds.

  64. [ ] Shuffled-null robustness threshold is met in strict mode (when shuffled checks run)

  65. Mean win rate on shuffled-price trials must be <= max_shuffled_win_rate (default 80.0) across shuffled_trials (default 3).
  66. Shuffled checks are skipped when PriceUSD_coinmetrics is missing, the shuffled window is empty, or shuffled_trials <= 0.

  67. [ ] Global win-rate threshold is met

  68. Validation backtest win rate must be >= min_win_rate (default 50.0).

  69. [ ] Validation date range must contain data

  70. Empty requested validation range is an automatic validation failure.

  71. [ ] Backtest path must generate windows

  72. Validation relies on backtest windows; if none are generated, validation cannot pass.