- scripts/prepare_hourly.py: M1→hourly aggregation (realized_vol = sqrt(Σr²), MIN_BARS=30 threshold, no weekend rows, year-based split preserved) - tests/test_prepare_hourly.py: 5 TDD tests, all green - train.py: USE_HOURLY=True, WINDOW=240 (10-day), PATCH_LEN=24 (1-day patches); build() prefers eurusd_hourly.parquet, falls back to daily; EXPORT BLOCK updated - Taskfile.yml: data:fetch:historical, data:prepare:hourly, data:prepare:all, data:test - 98,591 hourly rows (2008-2023) covering GFC, Euro crisis, Brexit, COVID, Fed cycle Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
HEPA (Petersen et al., arXiv:2605.11130, ICML 2026 Spotlight): - CausalEncoder: non-overlapping patches + per-patch LayerNorm + causal Transformer (generate_square_subsequent_mask) → all tokens (B, N, D) - HorizonPredictor: MLP(cat(h_t, Δt)) → predicted future embedding; Δt sampled uniformly from [1, min(DELTA_T_MAX, N-1-c)] per epoch - vicreg_loss: (1-α)·L1(norm(ĥ), norm(h*)) + α·(L_var + L_cov); joint training — no stop-gradient on target encoder - Probe: last-token embedding [:, -1, :], fit on 2019-2021, eval on OOS Results (true OOS 2022-2023): val_vol_r2: -0.45 (TS-JEPA+SIGReg) → +0.243/+0.276 (HEPA) effective_rank: 58.9/64 → 122.3/128 (near-full-rank, no collapse) Phase-0 gate on val_vol_r2: PASS ✓ Tests: 6/6 green (causal masking verified with non-uniform perturbation; per-patch LayerNorm is mean-invariant so constant shifts are absorbed) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>