October 6, 2026 · research

Why did my backtest trade at a price the market never showed?

Why did my backtest trade at a price the market never showed?

A backtest can report a fill at a price the market never displayed. Usually the simulator has inferred a plausible-looking execution from incomplete data: a bar’s high and low, a midpoint, or a limit price touched by one trade. That can make the trade log look precise while hiding what the market actually offered.

Start by asking which price your order could have interacted with. A last-trade bar answers what prices traded during an interval. It does not tell you the bid and ask when your order arrived, how much was available there, or whether your order could get to the front of the queue.

Why does my backtest show a fill outside the market price?

First, be precise about “outside.” A buy fill below the bar’s low or a sell above its high is an obvious accounting or timing error. A fill inside the high-low range can still be fictional: the price may have traded before the order existed, on the other side of the spread, or in a quantity too small to fill your order.

Consider a one-minute bar with an open of 100.00, a low of 99.80 and a close of 100.10. Your strategy sees the completed bar, submits a buy, and the simulator fills it at 99.80. That low might have occurred near the start of the minute, fifty seconds before the signal. The bar gives no evidence that 99.80 was available after the decision.

Data you haveWhat it establishesWhat it cannot establish
OHLCV barObserved trade-price range and volume over an intervalPrice sequence, bid and ask, or availability at order arrival
Trade printsReported executions with timestamps and pricesResting liquidity or your place in the queue
Top-of-book quotesBest displayed bid and ask at sampled timesDepth beyond the best level or whether a quote persisted between samples
Order-book eventsDisplayed depth changes and queue events, subject to feed coverageHidden liquidity, venue access, or guaranteed priority

There’s a second common cause: confusing midpoint and executable prices. If the quote is 99.99 bid and 100.01 ask, a buy at the 100.00 midpoint looks tidy in a report. A marketable buy generally pays the ask, plus any impact from its size. Calling the midpoint a fill quietly removes half the spread.

Can a limit order fill just because the market touched its price?

A touch is evidence that a trade printed at the limit price. It is not proof your resting order would have executed. If other orders were ahead of yours, the trade volume at that price may have been too small to reach your queue position. The print might also have come from another venue, while your order was resting elsewhere.

Suppose your buy limit is 50.00, and the market trades 200 shares at that price after you place it. A touch-based simulator fills all 500 shares. A more cautious model asks how much traded at or through 50.00 after arrival, then accounts for estimated queue ahead. Without order-level book data, that queue is an assumption. It should be visible in the results, not smuggled in as certainty.

For a small research system, I’d rather make that assumption explicit and test a range than pretend candle data reveals queue priority. The right range depends on venue, order size, and how often the strategy trades. A quiet stock at the open and a thin crypto contract at 03:00 UTC are different execution problems.

How should I choose a fill model for bar data?

Match the model to both the data and the strategy’s claim. A bar-based backtest can still be useful for slow strategies, but its fills should respect what the bars actually reveal.

  1. Set decision and arrival times. If a signal uses the bar close, submit after that close. Model execution from the next available interval or quote, not from the completed bar’s earlier low.
  2. Use the correct side of the spread. For marketable buys, start at the ask; for sells, at the bid. If you only have trade bars, estimate spread from a separate source or report that the model omits it.
  3. Cap fills by plausible liquidity. Apply a participation limit to observed volume and include fees and market impact. A bar’s total volume does not mean all of it was available at the price you chose.
  4. Stress the assumptions. Compare next-open fills with conservative slippage, and test whether the result survives worse execution. Don’t tune the fill model until the strategy wins.

These are modeling choices, not a recipe for recovering the one true fill from incomplete data. If the strategy depends on capturing a few basis points, bar data may not be adequate evidence for that claim.

How can I find where the impossible fill entered the backtest?

Trace one suspicious trade from signal to ledger. Keep the decision timestamp, order-submission timestamp, simulated arrival, selected market observation, fill price, fill quantity, and fee as separate fields. Then check, in order:

If you can’t answer those questions from the trade record, the backtest is missing execution evidence. Add the fields, replay a handful of trades by hand against the raw data, and check that the reported fill could have happened under the model you intended. A clean equity curve won’t catch a price that existed only inside the simulator.

backtestingmarket dataexecutiondata engineering
← All posts