# Opening gap fill on ES futures, 1-minute data - specification (RIP Backtest protocol v1.0 plus the 8 Oct 2026 rules)

Specification written and **frozen 2026-10-22 (approved by the owner the same day, draft 1 unchanged)**. No gap, signal or trade of this test has been computed. Once frozen, any change of a rule is documented and treated as a separate test; bugs may be fixed.

## Why this test, and what was looked at before
- **Chosen by the owner** on 2026-10-22 (option 1 of three proposed: opening gap fill, daily floor pivots, Crabel's NR7).
- **The idea:** when the S&P 500 future opens the regular session above or below the previous regular-session close, it often trades back to that close the same day ("the gap fills"). The trade fades the gap at the open with the previous close as the target. Write-ups disagree on the stop and on which gaps to take (small gaps are said to fill more often than large ones), so we fix three common readings and try no others after the result.
- **Looked at before (disclosed):** the Bitcoin CME gap fill (2026-10-21, buried), the weekend gap on another market. On ES the site has published the VWAP, Fibonacci scalping, noise area, intraday momentum, golden cross, Coppock and Initial Balance tests, and has tested opening range breakouts unpublished; **no opening gap rule has been computed on ES**. The ES data from 2020 has been used by all of them.

## Instrument and data
- **ES** (E-mini S&P 500 futures), `ES_1min.csv` (NinjaTrader, back-adjusted continuous contract), 1-minute bars on the New York clock, stamped at their close, 2020-01-01 to **2026-09-25**; the exchange calendar of our other futures tests (`rb_lib.js`) for the regular session (09:30 to 16:00) and early closes. $50 a point, tick 0.25.
- **Previous close:** the close of the last bar at or before the previous trading day's session close (16:00, or its early close). **Open:** the open of the bar stamped 09:31 (the first minute of the session). A day is skipped if either is missing or if the previous trading day is not the calendar's previous session (data hole).
- **Gap** = open - previous close, also as a share of the previous close. Back-adjustment shifts both prices of a gap equally inside one contract; a gap across a roll date is computed on the adjusted series, as in all our ES tests.
- **Holes (rule 3):** `data_holes.json` (ES); every gate and verdict is recomputed without days touching a known hole.

## Rules (one trade a day at most; fade the gap)
- **Entry:** at the open of the 09:31 bar, **short after a gap up, long after a gap down**, if |gap| >= 0.10% of the previous close (smaller gaps are noise against the cost).
- **Target:** the previous close (the gap filled). Distance = |gap|.
- **Three variants:**
  - **GF-1X:** every gap of at least 0.10%; stop at **one gap** beyond the entry (risk = reward).
  - **GF-SMALL:** only gaps of **0.10% to 0.50%**; stop at one gap beyond the entry.
  - **GF-NS:** every gap of at least 0.10%; **no stop**.
- **All variants:** stop and target tested on 1-minute bars from the entry bar (the stop first when one minute reaches both; a minute opening beyond a level fills at its open); a trade still open closes at the close of the last bar at or before the session close.

## Costs
- **$30.76 per round trip per contract** (commission $5.76 plus one tick, $12.50, of slippage on each fill), as in all our ES tests. Results in dollars per contract and in R (R = |gap| in points for GF-1X and GF-SMALL; for GF-NS the same |gap| as a unit).

## Periods, gates, control
- **Periods (by trade date), as in the other ES and NQ tests:** development 2020 to 2023; validation 2024-01 to 2025-03; holdout 2025-04 to 2026-09-25 (**already used**).
- **Six gates per variant** (net dollars per contract): validation profit factor >= 1.2; at least 50 trades in each period; development **t >= 2.0** (three variants of a rule not tested before on this market); above the 95th percentile of 500 runs of the matched control; positive without the 10 best trades; holdout net positive (flagged used). Fewer than 30 trades: Inconclusive.
- **Matched control (moved entries):** every real trade moved, all together, by one random circular offset of whole trading days (at least 5% of them), entered at the 09:31 open of the new day, same direction, the same target and stop distances in points, the same session-close exit and costs. 500 runs, seeds 1000 + run. Statistic: average net dollars per trade. It asks whether fading the gap beats taking the same trade on a random day.
- **Also reported (descriptive):** how many days gapped up and down by size; the share of gaps that filled by the close, by size bucket and direction; the median time to fill; long and short; by year; exits by reason.

## Engine and self-test (before the run)
New engine `gf_lib.js`, independent re-implementation `gf_ref.js`, `gf_selftest.js` that must pass before any result is printed: the previous close on a normal day and after an early close; a missing open bar; gap up and gap down; the 0.10% and 0.50% bounds; target, stop, a minute reaching both, the session-close exit; the reference matched trade by trade on the real data for all three variants; the control at offset 0 reproducing the real trades.

## Before the article
Results go to the owner first. One article, published only with the owner's agreement. Working title for search: "Gap Fill Strategy Backtest: Do ES Opening Gaps Fill? 6 Years of S&P 500 Futures".

## Reading the result
"Buried" or "Inconclusive" mean a statistically convincing edge was not demonstrated; neither is proof that none exists. One market, one data source, three readings of a rule with many versions.
