Files
foxhunt/scripts/generate_sweep_variants.py
jgrusewski 0d9fbc16b0 refactor(per-horizon): N_HORIZONS 5→3 — sweep configs + generator script
5 sweep YAMLs updated to reference the new checkpoint filename:
- config/ml/sweep_smoke.yaml: trunk_best_h6000.bin → trunk_best_h1000.bin
- config/ml/sweep_perhoriz_diag.yaml: same
- config/ml/sweep_threshold_tuning.yaml: same
- config/ml/sweep_deployability.yaml: same
- config/ml/sweep_smoke_perhoriz_cfc.yaml: same + 3 comment updates
  (WIN-gate criteria, header doc, best-checkpoint annotation)

scripts/generate_sweep_variants.py:61 updated atomically — without this
the next regeneration of sweep_deployability.yaml would silently
re-introduce trunk_best_h6000.bin.

Argo workflow templates (alpha-perception, alpha-cv, lob-backtest-sweep)
did NOT need text changes — they're already horizon-agnostic:
- They forward CLI flags via {{workflow.parameters.*}} to binaries
- Don't grep alpha_train_summary.json inline
- Don't reference per-horizon field names
- early-stop-metric default is "mean_auc" (horizon-agnostic)

Intentionally left:
- alpha-cv-template.yaml stacker-horizon: "6000" (unrelated TFT lookback)
- alpha-cv-template.yaml horizon: "1200" (DQN execution horizon in bars)
- lob-backtest-sweep-template.yaml ci-training-h100 (GPU pool name)

NOTE: kubectl apply of workflow templates is deferred to Task 10 (push
+ dispatch). Verified all 5 sweep YAMLs parse with python3 yaml.safe_load.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 01:40:13 +02:00

76 lines
3.4 KiB
Python
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
"""P6 helper: emit the 140 sim_variants for the deployability sweep.
Cross-product: 7 costs × 4 latencies × 5 thresholds = 140 variants.
Threshold values are placeholders — the actual values come from
config/ml/v2_prod_thresholds.json after the threshold-tuning step.
Re-run this script post-tuning to refresh sweep_deployability.yaml with
calibrated thresholds.
Usage:
scripts/generate_sweep_variants.py > config/ml/sweep_deployability.yaml
"""
from __future__ import annotations
import json, sys
from pathlib import Path
# 7 costs (price-units / lot / side). 0.125 = 1 tick (ES), 0.0625 = 0.5 tick (best-case),
# stepping through realistic retail (0.25, 0.375 = 2-3 ticks), and worst-case (1.0 = 8 ticks).
COSTS = [0.0625, 0.125, 0.1875, 0.25, 0.375, 0.5, 1.0]
# 4 latencies (ns). 100M = 100ms (best), 200M = realistic anchor, 300M = degraded,
# 400M = stress anchor.
LATENCIES_NS = [100_000_000, 200_000_000, 300_000_000, 400_000_000]
# 5 thresholds — REPLACE THESE WITH THE OUTPUT OF THE THRESHOLD-TUNING PASS.
# Read from config/ml/v2_prod_thresholds.json if it exists; otherwise use
# the canonical p60-p95 placeholder (5 steps spanning the range).
THRESH_JSON = Path(__file__).resolve().parent.parent / "config" / "ml" / "v2_prod_thresholds.json"
if THRESH_JSON.exists():
blob = json.loads(THRESH_JSON.read_text())
THRESHOLDS = blob["thresholds_absolute"] # e.g. {"p60": 0.42, "p70": 0.55, ...}
THRESHOLD_NAMES = list(THRESHOLDS.keys())
THRESHOLD_VALUES = list(THRESHOLDS.values())
assert len(THRESHOLD_VALUES) == 5, f"expected 5 thresholds; got {len(THRESHOLD_VALUES)}"
else:
print("# WARNING: v2_prod_thresholds.json missing — using p60-p95 placeholder thresholds",
file=sys.stderr)
THRESHOLD_NAMES = ["p60", "p70", "p80", "p90", "p95"]
THRESHOLD_VALUES = [0.40, 0.55, 0.70, 0.85, 0.95]
assert len(COSTS) == 7
assert len(LATENCIES_NS) == 4
print("# P6 deployability sweep — 4 windows × 140 sim_variants (7 cost × 4 latency × 5 threshold).")
print("# Generated by scripts/generate_sweep_variants.py — do NOT hand-edit.")
print("# Re-run after threshold-tuning to refresh threshold absolute values.")
print()
print("base:")
print(" data_template: /mnt/training-data/futures-baseline-mbp10/ES.FUT/ES.FUT_{window}.dbn.zst")
print(" predecoded_dir: /feature-cache/predecoded")
print(" n_parallel: 1 # batched flow overrides with variants.len()=140")
print(" decision_stride: 4")
print(" latency_ns: 200000000 # default (overridden per variant)")
print(" target_annual_vol_units: 50.0")
print(" annualisation_factor: 825.0")
print(" max_lots: 5")
print(" max_events: 0")
print(" seed: 12648430")
print(" # __SHA__ replaced by submitter with post-trunk-grows training short-SHA.")
print(" checkpoint: /feature-cache/alpha-perception-runs/__SHA__/trunk_best_h1000.bin")
print(" sim_variants:")
for ci, cost in enumerate(COSTS):
for li, latency in enumerate(LATENCIES_NS):
for ti, (tname, tval) in enumerate(zip(THRESHOLD_NAMES, THRESHOLD_VALUES)):
name = f"c{ci}_l{li}_{tname}"
print(f" - {{ name: {name}, threshold: {tval}, cost_per_lot_per_side: {cost}, latency_ns: {latency} }}")
print()
print("cells:")
print(" - { name: W1, window: 2025-Q2 }")
print(" - { name: W2, window: 2025-Q3 }")
print(" - { name: W3, window: 2025-Q4 }")
print(" - { name: W4, window: 2026-Q1 }")