Same-bar decision vs a one-session lag: SPY, average session gain, 2016-2025
Answered against 22 years of US equities and 12 years of US options data and published with the query that produced it. This result is stored as of 2026-07-31, from Look-Ahead Bias: The Backtest Killer.
| year | signal_days | same_bar_avg_pct | lagged_avg_pct | gap_pp |
|---|---|---|---|---|
| 2016 | 140 | 0.447 | -0.008 | 0.455 |
| 2017 | 139 | 0.245 | 0.033 | 0.212 |
| 2018 | 127 | 0.574 | 0.007 | 0.567 |
| 2019 | 138 | 0.426 | 0.072 | 0.354 |
| 2020 | 147 | 0.742 | -0.165 | 0.907 |
| 2021 | 137 | 0.485 | 0.039 | 0.446 |
| 2022 | 127 | 0.979 | -0.028 | 1.007 |
| 2023 | 147 | 0.533 | 0.054 | 0.479 |
| 2024 | 135 | 0.422 | 0.006 | 0.416 |
| 2025 | 131 | 0.636 | -0.03 | 0.666 |
- Rows × columns
- 10 × 5
- Computed
- Completeness
- No missing values
- Source
- US exchange, SIP and OPRA market data
- Licence
- Strasmore terms · free, no signup
What each column holds
| Column | Type | Range | Notes |
|---|---|---|---|
year |
number | 2,016 to 2,025 | |
signal_days |
number | 127 to 147 | |
same_bar_avg_pct |
number | 0.245 to 0.979 | percent |
lagged_avg_pct |
number | -0.165 to 0.072 | percent |
gap_pp |
number | 0.212 to 1.007 |
Computed from Strasmore's warehouse of US exchange, SIP and OPRA market data. Equity prices are delayed; options greeks and implied volatility are end-of-day. This result is stored, not recomputed on load — it is exactly the numbers that were returned on , and the query below is what returned them.
Run it yourself
This is the exact query behind the result above. Change a ticker, a date or a column and run it against the warehouse — no account, no key. The no-signup tier is smaller than the one this page was computed on; a query that reaches past it comes back saying which plan runs it.
WITH bars AS (
SELECT date,
toFloat64(open) AS o,
toFloat64(close) AS c,
toFloat64(close) > toFloat64(open) AS up_day
FROM global_markets.stocks_daily_aggs
WHERE ticker = 'SPY'
AND date >= toDate('2015-12-01')
AND date <= toDate('2025-12-31')
),
lagged AS (
SELECT date, o, c, up_day,
any(up_day) OVER (ORDER BY date ROWS BETWEEN 1 PRECEDING AND 1 PRECEDING) AS prior_up
FROM bars
)
SELECT toYear(date) AS year,
countIf(up_day) AS signal_days,
round(100 * avgIf(c / o - 1, up_day), 3) AS same_bar_avg_pct,
round(100 * avgIf(c / o - 1, prior_up), 3) AS lagged_avg_pct,
round(100 * (avgIf(c / o - 1, up_day) - avgIf(c / o - 1, prior_up)), 3) AS gap_pp
FROM lagged
WHERE date >= toDate('2016-01-01')
GROUP BY year
ORDER BY year
Work with this data in your AI assistant
Opens ready to query, with this page's data. Free, no account.