Same-Bar Fills: The Lookahead Bug Developers Keep Rebuilding

Daniel Ratke
Research & Engineering
Same-Bar Fills: The Lookahead Bug Developers Keep Rebuilding
A signal generated from completed bar t should normally enter no earlier than the next observable bar or quote after t. Same-bar fills often introduce lookahead.

Term map
Execution-realism vocabulary for this article
Keep bid, ask, midpoint, quote age, spread percent, last-price risk, no-bid exit, and rejected fill separate. Options execution language is where many attractive research results become fragile.
Follow the linked definitions for Quote window, Last price risk, Spread percent, No-bid exit, Side-specific fill, Stale quote, Liquidity filter, Trade print validation, Condition-aware fill, Options data API, OPRA-originating data, and OCC option symbol.
Read this article with Quotes, Trades, Backtesting Execution Realism, Options Slippage Modeling, Why Option Quotes Matter More Than Last Price, and Quote-Aware Options Backtests.
Abstract
Same-bar fills are one of the easiest ways to make an intraday strategy look better than it is. The bug is subtle: a completed bar creates a signal, but the simulator lets the strategy enter inside that same bar. The code appears realistic because the bar exists in the dataset. The decision is not realistic because the strategy did not know the full bar until it closed.
For options backtesting, this problem becomes larger because the entry then selects and prices an option using a timestamp that may already include information from the move that triggered the signal.
The Causal Rule
If a signal is generated from bar t, the earliest conservative default is entry on the next observable bar or quote after t. This rule feels strict, but it is the correct baseline for a developer who wants the simulation to survive contact with a live loop.
There are strategies that place stop or limit orders before a bar completes. Those need explicit order-state modeling. They should not be represented as "observe full bar, then fill inside it." That is not a minor implementation detail. It changes the information set.
Write The Event Timeline Down
The safest way to find same-bar leakage is to write the event timeline as data. A completed bar has an open time, close time, and publication time. A signal has an evaluation time. A contract selector has a discovery time. A quote has an exchange timestamp or feed timestamp. A simulated order has a route time and a fill policy. If those fields are missing, the simulator will eventually invent an ordering.
For a simple next-bar model, the timeline should be boring. Bar t closes, the signal evaluates after that close, contract selection runs at or after the signal time, and entry pricing uses the next quote or bar that would have been observable. If an implementation cannot express those timestamps, it cannot reliably prove that it is causal.
This is an actual implementation problem. Intraday bars often compress many market states into one row. The high, low, close, and volume of that row are only known after the row completes. Using the high to detect a breakout and the same row's low to fill a favorable option entry is a classic hindsight path.
Why It Matters More In Options
In stock-only replay, a same-bar fill can flatter the entry price. In options replay, it can also flatter the contract choice. The selected strike, DTE, spread, and quote may all reflect the completed move rather than the earlier state.
That creates a double leak: the signal sees too much, and the instrument selection sees too much. A strategy can survive the stock chart and fail once contract selection is forced back to the timestamp it actually had.
Standing Orders Are A Different Model
Some strategies really do have orders resting before the bar completes. A breakout stop, a bracket order, or a marketable limit order can be modeled before the event if the strategy defines the order state in advance. That is a valid model, but it is not the same as next-bar replay.
The difference is that a standing-order model must know the order before the outcome. It should record when the order was placed, the trigger condition, the eligible instrument, the limit rule, and the cancellation rule. It also has to model whether the selected option was known at the placement time. If the contract is chosen only after the completed bar, the model has not solved the leakage problem.
Developers should therefore avoid a vague setting such as allow_same_bar_fill=true unless the simulator also records the order-state assumptions. A boolean flag hides too much. The right question is whether the entry was a reaction after the bar closed or an order that already existed before the bar evolved.
How To Test For It
Add regression tests around signal time and entry time. A test should prove that a touch or breakout on bar t enters no earlier than bar t+1 unless the strategy explicitly modeled a standing order before the touch.
Also inspect rejected trades. If a same-bar fix suddenly creates more quote misses or spread rejects, that is useful evidence. It means the old run was using a tradable surface that did not exist at the decision time.
A Useful Regression Test Shape
A minimal regression test can use a synthetic three-bar session. Bar one creates context. Bar two crosses the threshold and closes beyond it. Bar three is the first bar eligible for a reactive entry. The test should assert that the selected entry timestamp is on bar three or later. Then add a second test for a standing order, where the order is placed before bar two and can trigger inside bar two under explicit rules.
For options, add a contract-selection assertion. The selected contract must come from the universe visible at the eligible entry time, not from a universe built after the full move. If the test only checks the underlying bar, it can miss a leak in the option layer.
The best tests also assert rejection behavior. If no quote exists after the signal, the trade should reject. It should not fall back to a prior quote or the completed bar's convenient price unless that fallback is part of a documented policy.
What Usually Changes After The Fix
Fixing same-bar fills often reduces trade count, worsens average entry, and increases rejects. That does not mean the fix harmed the strategy. It means the previous result included information the live system would not have had. The corrected result is less flattering but more useful.
Sometimes a strategy still works after the fix. That is meaningful evidence. It means the edge did not depend entirely on catching an impossible intrabar price. More often, the fix moves a branch from "promising" to "needs redesign." That is also progress, because it closes a false path before paper trading spends time on it.
Takeaway
Same-bar fill bugs are not academic. They decide whether an intraday backtest is measuring a strategy or a hindsight rule. Developers should make next-bar semantics the default, then only loosen that rule when order state is modeled explicitly.
Related workflow
For the Same-Bar Fills: The Lookahead Bug Developers Keep Rebuilding workflow, continue through Quotes, Backtesting Execution Realism, Option Quote and Trade Conditions, Options Slippage Modeling, Why Option Quotes Matter More Than Last Price, and Quote-Aware Options Backtests.
How the terminology applies
For Same-Bar Fills: The Lookahead Bug Developers Keep Rebuilding, the execution-realism workflow should treat Quote window, Last price risk, Spread percent, No-bid exit, Side-specific fill, and Stale quote as operational state rather than glossary decoration. That framing keeps the fill model honest because options execution is controlled by displayed markets, timing, liquidity, and side-specific assumptions.
A developer implementing this Backtesting idea should persist Liquidity filter, Trade print validation, Condition-aware fill, Options data API, OPRA-originating data, and OCC option symbol beside the result, instead of leaving those words in a term card. It also prevents the page from treating last price, midpoint, or a bar close as interchangeable evidence for a fill.
The review artifact for Same-Bar Fills: The Lookahead Bug Developers Keep Rebuilding becomes more useful when Bid/ask spread, Midpoint, Quote/trade condition, Quote vs trade semantics, REST snapshot, and WebSocket stream appear in the same body of evidence as the selected rows. When a modeled order is accepted, these fields should explain why the fill was plausible; when it is skipped, they should explain why.
In production notes for this execution-realism workflow, Entitlement gate, Quote freshness, Timestamp semantics, Pagination cursor, Response envelope, and Rate-limit budget define the checks that decide whether the workflow is reproducible. The result is an execution model that can be tightened without rewriting the strategy narrative.
For Same-Bar Fills: The Lookahead Bug Developers Keep Rebuilding, the practical acceptance test is simple: another developer should be able to read the body, identify the exact inputs, reproduce the request sequence, and explain the accepted and rejected rows without relying on the bottom terminology grid. If a phrase appears in the page vocabulary, it should correspond to a stored field, a validation check, a replay step, or an implementation decision in the execution-realism workflow.
This is also the reason the article should not measure success only by the final chart, table, or headline metric. The better standard is whether the data path, timing model, entitlement state, and evidence trail survive review. When those pieces are written directly into the body, the terminology becomes part of the workflow readers can implement.
Terminology
Market-data terms used in this article
These terms keep the article connected to the CuteMarkets knowledge base and to the exact API workflow behind the research.
Quote window
A bounded timestamp range used to inspect executable bid/ask markets around a modeled decision.
Last price risk
The danger of filling a strategy at a stale or isolated trade print rather than the available market.
Spread percent
Bid/ask width divided by midpoint, used as a liquidity and execution-quality filter.
No-bid exit
A contract state where the exit side has no usable bid and the backtest should reject or heavily penalize the fill.
Side-specific fill
A policy that treats buys, sells, entries, exits, stops, and profit targets differently instead of using one price rule.
Stale quote
A bid/ask record too old for the modeled decision time, especially around halts, events, reconnects, or illiquid contracts.
Liquidity filter
A pre-trade rule based on bid, ask, spread percent, volume, OI, quote age, and minimum premium.
Trade print validation
The check that a last sale supports context without replacing the executable bid/ask market.
Condition-aware fill
A fill rule that preserves quote and trade conditions before accepting, rejecting, or labeling a market-data row.
Options data API
The product surface for chains, contracts, quotes, trades, aggregates, Greeks, IV, open interest, and expirations.
OPRA-originating data
The U.S. listed-options source context behind quotes, trades, exchange participation, and consolidated option-market records.
OCC option symbol
The exact option contract identifier that preserves root, expiration, call or put side, and strike.
Bid/ask spread
The execution interval between bid and ask that determines whether a contract is realistically tradable.
Midpoint
The computed center between bid and ask, useful as a reference price but not proof that an order would fill.
Quote/trade condition
The condition-code, exchange, correction, sequence, and timestamp context that explains how a quote or trade row can be used.
Quote vs trade semantics
The distinction between executable bid/ask markets, printed transactions, and bar-level summaries.
REST snapshot
A reproducible request for current or historical market state, used for initialization, backfills, and audit logs.
WebSocket stream
A persistent live connection that needs subscription topics, reconnect tracking, freshness labels, and REST repair paths.
Entitlement gate
The product, plan, quote, live, delayed, historical, or commercial-use boundary checked before data is shown.
Quote freshness
The age, timestamp, and live or delayed state of a bid/ask record before it is used in a scanner, backtest, or UI.
Timestamp semantics
The exchange, provider, ingestion, session, and application time context attached to a market-data record.
Pagination cursor
The continuation token or next URL that keeps large chains, trades, quotes, and historical windows complete.
Response envelope
The shared status, request id, results, pagination, and error shape that keeps API wrappers and logs consistent.
Rate-limit budget
The request capacity that shapes polling cadence, scanner breadth, retries, backfills, and degraded-mode behavior.
FAQ
Related questions
Why are same-bar fills risky?
They let the strategy react to a completed bar and still fill inside that same bar, using information that was not available at entry time.

Written by
Daniel Ratke
Research & Engineering
Daniel covers the deeper research notes: options backtesting, execution realism, robustness testing, data engineering, and strategy validation.
Product links
Build the workflow with CuteMarkets
This article is part of the broader CuteMarkets product and research stack. Use the landing pages below to move from the blog into the specific API workflow you want to evaluate.
Beginner options path
Send newcomers to the beginner path for calls, puts, chains, Greeks, IV, and risk.
Options Data API
See the main options overview for real-time and historical options data.
Historical Options Data API
Inspect the historical contracts, quotes, trades, and aggregates workflow.
Options Chain API
Go straight to chain snapshots, expirations, and strike discovery.
Pricing
Review plans before you move from free evaluation into production usage.