The data
Two clean CSVs of S&P 500 cash index price action.
- Daily OHLC + Volume covering 2020-01-02 to 2026-04-29 (1,589 trading days).
- 5-minute OHLC covering 2020-01-02 to 2026-04-02 (121,981 bars across 1,569 RTH sessions).
Daily and intraday tie out exactly: daily Open = first 5-min open; daily High/Low = max/min of intraday extremes; daily Close = last 5-min close. The 5-minute set covers the regular cash session (09:30-16:00 ET), expressed in static UTC stamps (14:35-21:00).
What was tested
Roughly 260 candidate edges across twelve families:
Day of week
O2C, C2C, overnight, range and abs-return per day. DOW × regime, DOW × gap class.
Seasonality
Per-month returns, day-of-month buckets, turn-of-month effect, OPEX week.
Gaps
Five-bucket gap classification, continuation vs. fade, gap-fill rates, gap × regime.
Regimes
Above/below 20/50/200 SMAs, combined regime score, RV20 quartiles.
Patterns & streaks
Inside / outside / NR7 / WR7, multi-day patterns, day-after-N-streaks.
Tail reversion
Decile bucketing of prior return, ±1%, ±2% threshold buckets.
Opening range
5/15/30/60-min ORB outcomes, first-break long/short strategies, OR-class continuation.
Time of day
30-min bucket means and win rates, time of high/low, FH × LH cross-tab.
Prior-range projections
PDH/PDL touches, ±0.25R/0.5R/1R extension touches, Camarilla pivots, static % bands.
Range expansion
Today / prior range ratio by decile, NR7 vs WR7 next-day behaviour.
Multi-factor
DOW × gap × regime, DOW × prior-direction, DOW × prior-close strength.
Composite scoring
5-factor score (gap dir, prev C2C, regime, close strength, DOW heuristic) → next-day return.
How edges were scored
Each candidate edge produces a conditional return distribution. For every one we record:
- n — sample size (filter: n ≥ 50 to be considered "meaningful")
- Mean and median return in %
- Win rate — % of positive returns
- Expectancy = win_rate × avg_win + loss_rate × avg_loss
- Binomial p-value against a 50/50 base rate (excluding zero-return ties)
- One-sample t-test p-value against mean = 0
- Sharpe-like = mean / std (single-period)
A composite quality score blends those terms with sample-size and effect-size thresholds. Edges with quality ≥ 9, n ≥ 50, and at least one p-value < 0.10 are included in the "significant" filter. The strongest survive both at p < 0.001.
Caveats & limitations
Recommended next steps
- Out-of-sample validation. Refit on 2020-2024, test on 2025-2026. Drop edges that don't survive.
- Bear-regime stress test. Pull pre-2020 SPX data and test the swing module against 2008, 2015-16, and 2018-Q4.
- Cost modelling. For 0DTE option implementations, pull historical SPX option chains to estimate spread/commission drag.
- Volatility overlay. Add VIX or RV20 quintile filters — many edges look likely volatility-conditional.
- Position-sizing layer. Convert edge expectancy into Kelly-fraction sizing (with realistic capping).
- Live updates. Hook the dashboard to a live data feed so the regime/gap classification updates each morning automatically.
Toolchain
Built with Python (pandas, numpy, scipy), Chart.js + Grid.js for the dashboard, matplotlib for the playbook diagrams, python-docx-equivalent (docx-js) for the report, openpyxl for the workbook, and Pine v5 for the TradingView indicators. The whole pipeline is reproducible from the two source CSVs.