Run: python -m data.alpaca.pipeline --steps all --timeframes 1Min,5Min --h-list 5,12
Complete 2026-08-16 00:47 UTC-4 (rc=0). All artifacts under
data/processed/alpaca/pipeline/*.json.
1. Data store (fully backfilled, verified faithful to the API feed)
Per-day spot checks against live API (2024-06-15: API 1,042 rows = store 1,042; 2025-01-10: API 1,211 = store 1,211) confirmed the backfill is lossless; the "missing" minutes are genuine feed coverage (Alpaca crypto 1Min bars are thin: ~93% have zero volume / trade_count).
| series | day-files | rows | span |
|---|---|---|---|
| ETH/USD 1Min bars | 2,054 | 2,551,785 | 2021-01-01 → 2026-08-16 |
| ETH/USD 5Min bars | 2,054 | 585,444 | 2021-01-01 → 2026-08-16 |
| SOL/USD 1Min bars | 1,636 | 1,969,483 | 2021-01-01 → 2026-08-16 |
| SOL/USD 5Min bars | 1,636 | 463,206 | 2021-01-01 → 2026-08-16 |
| ETH/USD trades | 669 | 33,330,506 | 2021-01-01 → 2026-08-16 |
| SOL/USD trades | 32 | 2,072 | 2024-10-05 → 2026-08-16 |
| ETH/USD quotes | 1,173 | 28,164,561 | 2023-06-01 → 2026-08-16 |
| SOL/USD quotes | 756 | 15,680,995 | 2023-06-01 → 2026-08-16 |
~91.2M rows total. Quotes for ETH effectively from 2023-06; SOL trades/quotes from ~Oct-2024 (feed reality). Deep book: no historical endpoint.
2. Obstacles found and fixed during this run
- Backfill hang (hung keep-alive socket, no timeout): per-request stall
watchdog (>120s aborts with a resume-safe error) +
--resumemode (restarts 3 days before the latest stored tick; 90-day coverage guard so a small live window cannot skip the historical bulk). - Empty-page paging termination (bars/ticks) — regression-tested.
- NaN feature poisoning on real data: 5 rolling features went NaN on
zero-activity bars (doji span, zero-volume windows, zero trade_count,
missing vwap) — 96.4% of quote-era rows were rejected, starving
walk-forward. Hardened with semantically neutral fills (0.5/1.0/0.0) while
preserving the warm-up NaN contract (
.maskon zero-denominator only). - OOM on 16GB box: 28M-quote re-sort allocation removed (partitions are per-day sorted; concat is already ordered), and datasets now reuse the persisted per-(sym, tf) features instead of rebuilding them per horizon.
historical reportCLI bug (--symbolsattr missing), glob missing bars-level rows in the availability report.
Full suite after all fixes: 312 passed, 2 skipped.
3. Walk-forward OOS results (5 splits, 50-bar embargo, GBR 300/3/0.05)
Only splits whose train span reaches the quote era (≥2023-06) produce models (splits 0-2 have no quote-derived features to train on — correct behavior).
| cell | rows | OOS preds | IC | Spearman | top-quintile ret (bps) |
|---|---|---|---|---|---|
| ETH 1Min h5 | 2,551,779 | 1,020,466 | +0.0122 | +0.0019 | −0.04 |
| ETH 1Min h12 | 2,551,772 | 1,020,463 | +0.0123 | −0.0078 | +0.13 |
| ETH 5Min h5 | 585,438 | 234,176 | +0.0017 | −0.0168 | +0.56 |
| ETH 5Min h12 | 585,431 | 234,173 | −0.0013 | −0.0062 | +1.24 |
| SOL 1Min h5 | 1,969,477 | 787,677 | −0.0011 | −0.0034 | +0.02 |
| SOL 1Min h12 | 1,969,470 | 787,674 | −0.0033 | −0.0013 | +0.10 |
| SOL 5Min h5 | 463,200 | 185,280 | −0.0099 | −0.0017 | +0.00 |
| SOL 5Min h12 | 463,193 | 185,278 | −0.0122 | +0.0124 | +2.02 |
IC ≈ |0.01| across all cells — statistically indistinguishable from noise; nothing survives sign consistency (ETH mildly positive, SOL mildly negative).
4. Backtests (long/flat, signal = top-decile pred, fills at next-bar
open, maker 15bps + half-spread 0.6bps per side — net includes ALL costs)
| cell | trades | net cum bps | gross cum bps | hit rate | Sharpe |
|---|---|---|---|---|---|
| ETH 1Min h5 | 498,062 | −14,911,221 | +8,285 | 6.3% | −97.9 |
| ETH 1Min h12 | 384,472 | −11,438,811 | +78,309 | 14.5% | −60.4 |
| ETH 5Min h5 | 46,898 | −1,379,001 | +25,909 | 21.5% | −39.5 |
| ETH 5Min h12 | 46,840 | −1,345,250 | +58,019 | 29.1% | −25.3 |
| SOL 1Min h5 | 390,019 | −11,703,958 | −20,975 | 8.4% | −88.5 |
| SOL 1Min h12 | 266,548 | −8,032,482 | −48,163 | 15.1% | −59.5 |
| SOL 5Min h5 | 91,715 | −2,782,518 | −35,295 | 19.0% | −45.1 |
| SOL 5Min h12 | 60,363 | −1,726,270 | +82,154 | 32.8% | −24.9 |
Verification: net ≈ gross − n × 30bps in every cell (e.g. ETH 1Min h5: 8,285 − 498,062×30 = −14,933,576 ≈ −14,911,221). The strategy loses exactly its cost floor per trade — the fee gate works as designed and rejects every cell.
5. Verdict
- No deployable long/flat signal on ETH/SOL (1Min or 5Min, h=5 or 12) over the fee-covered era. OOS IC ≈ 0; all backtests bleed exactly fees+spread per trade.
- This is an honest, complete rejection: the pipeline's economics gate (Phase-5/6/7/8) confirmed that a real edge is required to clear 30-50bps per round trip; this signal does not have one.
- Recommended state: FLAT. No live sizing/execution is justified. Do not paper-trade a noise signal expecting a different outcome.
6. What it would take to revisit
- A feature family with actual microstructure content on this feed (quote-age/spread/fill-ratio tests already carry the weight — they are the only columns with any information) — or 15Min/1Hour horizons (longer holding to amortize the cost floor).
- Calibrate a fixed
threshold_bpshurdle from OOS, then re-validate on a held-out tail (the phase-7plan_signalpath) before any paper run. - If a future signal clears the gate: wire
BarExecutor+RiskManagerinto a paper runner againstAlpacaBroker(paper=True)and monitor viadata/alpaca/monitor.py(quote staleness, missing partitions, risk halts).