# Internal Bar Strength (IBS) reversal on NQ futures, daily regular-session bars built from 1-minute data - specification (RIP Backtest protocol v1.0 plus the 8 Oct 2026 rules)

Specification written and **frozen 2026-11-03 by Claude**, at the owner's request ("Hai fă tu o strategie pe NQ. Una bună."): the owner chose the market (NQ) and asked Claude to choose one idea and test it honestly. **No IBS value, signal, trade or result of this test had been computed when this file was frozen.** Once frozen, any change of a rule is documented and treated as a separate test; bugs may be fixed and are logged at the end. This is a research test for the owner, **not an article**: nothing goes on the site unless the owner asks.

## Why this idea, and what could make it fail
- **The idea.** The Internal Bar Strength of a day is IBS = (close - low) / (high - low): 0 when the session closes on its low, 1 when it closes on its high. Alexander Pagonidis ("The IBS Effect: Mean Reversion in Equity ETFs", 2013) reported that in US index ETFs, QQQ among them, a close near the day's low (IBS < 0.2) was followed by above-average next-day returns and a close near the high (IBS > 0.8) by below-average ones. We found no reliable out-of-sample check of it on QQQ or NQ after 2020 (only vendor articles), so this is a real test of a documented effect on years it was not found in.
- **Why it could have an edge (session structure).** A lot of volume at the US close is not information: leveraged and inverse ETFs must rebalance in the direction of the day's move (the Nasdaq-100 has one of the largest of these complexes, TQQQ and SQQQ), volatility-target and risk-parity funds cut exposure after down days, and market-on-close orders cluster at 16:00. If that pressure pushes the close away from fair value, whoever takes the other side should be paid by a partial reversal the next session. A close near the low or the high is a simple sign of such pressure.
- **Why it might not work (written before the run).** Boyarchenko, Larsen and Whelan ("The Overnight Drift", Review of Financial Studies, 2023) found that sell-off closes were followed by positive overnight returns in E-mini futures from 1998 to 2020. In "The Disappearing Overnight Drift" (Liberty Street Economics, 1 July 2026) the same authors report that from 2021 to 2025 the 2:00-3:00 a.m. drift was flat in ES, and that the same holds in NQ and YM, and that the link between closing order imbalance and the overnight return "has broken down" as extreme closing imbalances became rarer. IBS rests on the same kind of closing pressure and our data are 2020 to 2026. We considered testing the overnight drift itself and dropped it for this reason.
- **Related tests already published (disclosed).** Buying short-term weakness in an equity index on 60-minute ES bars: the RSI(2) Dip Buyer (Buried, Fragile), the Bollinger band reversal (Buried, Fragile), RSI divergence (Buried); also the ES opening gap fill (Buried, Costs). None used daily bars, the close location or NQ. Because this family has been tried in more than four variants on the site, the development t bar is **2.5**, as in our Initial Balance test for the opening-range family.
- **Considered and not chosen.** The overnight drift (above). More intraday momentum on NQ (the noise area breakout already passes and is in a forward test; ORB, Initial Balance, first-to-last half-hour, EMA ribbon, 9 EMA, MACD + RSI were all tested). Turn of the month and pre-FOMC drift (too few trades for the gates in 2020 to 2026).
- **Expectation before the run (for the record, not a gate):** the long side should be positive before costs; whether it clears the gates is open. The short side of IBS-LS is likely to lose in a market that roughly tripled over the sample.

## Instrument and data
- **NQ** (E-mini Nasdaq-100 futures), `NQ_1min.csv` (NinjaTrader, back-adjusted continuous contract, merge back-adjusted), 1-minute bars on the New York clock stamped at their close, from 2020-01-01 to the frozen end used by every test, **2026-09-25 17:00 New York**. Bars after it are not used (they stay fresh). $20 a point, tick 0.25. The minutes of 9-22 October 2026 that are missing in NinjaTrader are after the end and play no part.
- **Sessions = New York Stock Exchange trading days.** A weekday is a session unless the NYSE is closed: the days our exchange calendar (`rb_lib.js`) gives a 13:00 CME close (Martin Luther King, Presidents, Memorial, Juneteenth from 2022, Independence Day observed, Labor Day, Thanksgiving), 9 January 2025, Good Friday, New Year's Day observed (none when 1 January is a Saturday) and Christmas observed. Early-close days (the calendar's 13:15 CME close: the day after Thanksgiving, 24 December, 3 July) are sessions whose cash market closes at 13:00. The session list comes from the calendar, never from the data, so a data hole is never taken for a holiday.
- **Daily bar of a session:** the 1-minute bars stamped 09:31 to 16:00 (09:31 to 13:00 on early-close days). Open = first bar's open, high and low = highest high and lowest low, close = close of the bar stamped 16:00 (13:00).
- **Usable session (needed for a signal):** its first bar is stamped 09:35 or earlier, a bar is stamped exactly at its close, and at least 90% of its minutes have a bar. Trading halts (March 2020) are not holes.

## Rules
- **IBS** = (close - low) / (high - low) of the session's daily bar; no signal if high = low.
- **Two variants, fixed now:**
  - **IBS-L** (long only): IBS **< 0.20** at the close of a usable session -> buy one contract.
  - **IBS-LS** (long and short): as IBS-L, and IBS **> 0.80** -> sell one contract short.
  - The inequalities are strict (0.20 and 0.80 exactly give no signal).
- **Entry:** at the open of the first 1-minute bar after the session's close (the bar stamped 16:01, or 13:01 on early-close days), i.e. the next 1-minute open after the signal, as the protocol requires.
- **Exit:** at the close of the **next session** by the calendar, with the same convention: the open of the first 1-minute bar after that session's close. Holidays and weekends in between are held through. If the data has no bar at that time (a hole), the exit is the open of the first bar after it. No trade if the exit would fall after the end of the data (the last possible entry is the close of 2026-09-24).
- **One trade per signal.** A new signal at the exit close starts a new trade: the backtest closes and reopens and charges both (a real trader would simply hold, so this is conservative). The exit and the next entry happen at the same minute, so there is never more than one position.
- **No stop, no target, no trailing stop**: the documented rule is a one-session hold. The worst loss open inside a trade is reported.
- **Size:** one NQ contract per trade for every gate. MNQ ($2 a point) is reported as a conversion only.
- **Hours:** signals only at the regular-session close; positions are held overnight and over weekends and holidays.

## Costs
- **NQ: $15.76 per round trip per contract** (commission $5.76 plus one tick of slippage on each fill), as in all our NQ tests.
- **Contract roll:** the back-adjusted file switches to the next contract at the start of the session of the second Thursday of March, June, September and December (Wednesday 18:00 New York). A trade open across that moment pays one more $15.76.
- **MNQ (conversion only):** $2.52 per round trip ($1.52 commission and fees plus one tick, $0.50, of slippage per fill), the same again per roll. An assumption, stated as such.
- Gross results are shown only to explain a result.

## Periods, gates, control
- **Periods (by entry date), as in the other NQ tests:** development 2020-01-01 to 2023-12-31; validation 2024-01-01 to 2025-03-31; holdout 2025-04-01 to 2026-09-25 (**already used** by other NQ tests, never by this rule; flagged).
- **Six gates per variant** (net dollars per contract): (1) validation profit factor >= 1.2; (2) at least 50 trades in each period; (3) development **t >= 2.5**; (4) average net dollars per trade above the 95th percentile of 500 runs of the matched control; (5) positive without the 10 best trades; (6) holdout net positive (flagged used). Fewer than 30 trades in total: Inconclusive.
- **Rule 3 (data holes):** trades open across a known NQ hole (`data_holes.json`) are removed and the gates recomputed; if the verdict changes, the result is Inconclusive.
- **Matched control (moved signal days):** all real signal days moved together by one random circular offset of whole usable sessions (at least 5% of them), each keeping its direction, with the same one-session hold (entry after that day's close, exit after the next session's close), the same costs and roll rule. 500 runs, seeds 1000 + run. Statistic: average net dollars per trade. This keeps the minute of entry, the hold, the number of trades, the mix of longs and shorts and their clustering in time, and removes only the IBS condition.

## Also reported (descriptive, after the gates; nothing here can change a rule or a verdict)
- Next-session result by IBS decile over all usable sessions (the dose-response check).
- **Neighbouring thresholds:** long below 0.10, 0.15, 0.25, 0.30 and short above 0.70, 0.75, 0.85, 0.90, with the same periods, gates and control.
- Year by year; longs and shorts separately; without the 10 and the 20 best trades; without 2020.
- Each trade split into its overnight part (entry to the next session's 09:30 open) and its day part (09:30 to the exit).
- Win rate with its Wilson interval; worst open loss inside a trade; drawdown on closed trades and approximately including open losses; the MNQ conversion; trades held through a roll.

## Engine and self-test (before the run)
New engine `ibs_lib.js` (the existing minute loader, the exchange calendar of `rb_lib.js`, the shared statistics and control helpers), an independent re-implementation `ibs_ref.js` (its own CSV reading and holiday rules), and `ibs_selftest.js`, which must pass before any result is printed: hand-built days (IBS below 0.2, above 0.8, exactly 0.2 and 0.8, high = low, an early-close day, a holiday and a weekend inside the hold, a missing exit bar, an unusable day, a roll inside the hold, the end of the data); the engine equal to the reference trade by trade on the real data for both variants; the control at offset 0 reproducing the real trades. `ibs_run.js` refuses to run unless the self-test passed on the current code.

## If it passes / if it fails
Results go to the owner first (in Romanian), with every gate. If a variant survives: a proposal for a paper forward test with a NinjaTrader 8 strategy or indicator in a new file, to be started only with the owner's agreement. If not: the verdict as it is, with no new thresholds, filters or exits tried to rescue it.

## Reading the result
"Buried" or "Inconclusive" mean a statistically convincing edge was not demonstrated; neither is proof that none exists. One market, two variants of one rule.

## Log
- 2026-11-03: frozen (draft 1). Nothing computed. SHA-256 of the frozen text (before this log grew): 00d01803a621b0f37749866836dbaa8ce268e59142e82876e5d7a005bdf251e8.
- 2026-11-03, before any result: `ibs_selftest.js` passed on its first run (hand-built days, calendar 2020-2026, engine = reference on 1,692 sessions and 317 / 870 real trades, control at offset 0). Counts only: IBS-L 317 trades (development 210, validation 59, holdout **48**), IBS-LS 870 (561 / 154 / 155; 317 long, 553 short); 1,687 usable sessions (not usable: 2020-10-23, 2023-04-05, 2025-08-29, 2026-01-23, 2026-06-11, all data holes). **IBS-L therefore fails gate 2 (fewer than 50 trades in the holdout) whatever its results**; noted here before any result, and no rule is changed because of it.
- 2026-11-03, the run (`node ibs_run.js`, once, outputs in `ibs_out/`): **IBS-L Buried, 3 of 6** (fails validation PF 1.09, holdout count 48, development t 2.24; passes the control at the 98.4th percentile, without the 10 best +$70,233, holdout +$87,703). **IBS-LS Buried, 1 of 6** (the shorts lost in validation and holdout). Rule 3 changes neither verdict. The neighbouring thresholds were looked at only after the gates, as written above; the long threshold 0.25 passed 5 of 6 there, which is a post-hoc reading and **not** a pass. Nothing was rerun or changed.
- 2026-11-04: the owner asked for an article ("Da, scrie-l"). Published from the outputs of the single run of 3 Nov, unchanged; no rule, threshold or result was changed for it.
