Fill assumptions for limit and stop orders
Lesson 12 · about 10 min
A backtest on bar data has to guess what happened inside each bar. It knows the open, high, low and close and nothing about the order in which prices were visited or how much traded at each level. Every fill in the backtest is therefore an assumption, and the assumption is different for each order type. Getting this wrong is a leading cause of systems that "fill" at prices no one could have traded.
Market orders
A market order fills at the next available price. On bar data, the honest assumption is the open of the bar after the signal, plus slippage. Filling at the close of the signal bar is look-ahead unless you can genuinely act in the last seconds with the close known.
Stop orders
A buy stop at price P fills if the bar's high reaches P. The fill price is not P; it is P plus slippage, and in a gap it is the open of the bar, which can be far above P.
| Bar open | Bar high | Stop level | Filled? | Fill price (1 tick slippage) |
|---|---|---|---|---|
| 100.0 | 101.5 | 101.0 | Yes | 101.0 + tick |
| 100.0 | 100.8 | 101.0 | No | |
| 102.0 | 103.0 | 101.0 | Yes, gapped | 102.0 + tick (not 101.0) |
Rule: fill = max(stop level, bar open) + slippage. The gap case is where naive backtests are most wrong, and it matters a great deal for stop-losses on daily bars: a stock that gaps down through your stop does not fill you at the stop.
Limit orders
A buy limit at price P is the hard case. If the bar's low is below P, the price traded through your limit, and you can be confident you filled (at P, with no slippage, and possibly at a better price if the bar opened below P). If the bar's low is exactly P, the price touched your limit and you may or may not have filled, because other orders were ahead of you in the queue.
| Assumption | Fill when low == P? | Bias |
|---|---|---|
| Optimistic | Yes | Overstates fills at the best prices; these are the trades where price bounced off your level, which are the winners |
| Conservative | No; require low < P (trade-through) | Understates fills; some real fills are missed |
| Partial | Fill a fraction | Compromise; hard to model without volume at price |
The optimistic assumption is the one that most default backtesters use, and it is systematically flattering for mean-reversion strategies. Think about which limit orders fill only at a touch: the ones where the price came down to your level and immediately reversed. Those are exactly the best trades. A backtest that counts all of them has an edge that partly consists of fills you would not have received.
Use the conservative assumption by default. If you have tick data, use the actual traded volume at your price to estimate queue position; if you do not, requiring a trade-through by one tick is the honest choice.
Key idea: A stop fills at the worse of the stop level and the bar open, plus slippage. A limit fills only if price trades through it, not merely touches it. Any backtester that assumes otherwise is giving you fills the market did not.
Same-bar stop and target
A trade opened on bar D has a stop and a target. On some later bar both levels are inside the range. Bar data cannot tell you which came first.
- Conservative convention: the stop hit first. Use this by default.
- Open-proximity heuristic: whichever level is closer to the bar's open hit first. Slightly more realistic, still a guess.
- Lower-timeframe resolution: drop to 1-minute bars for that bar and check the sequence. The only real answer, and worth doing if your platform supports it.
A worked illustration of how much this matters:
| Convention | Trades | Wins | Avg R |
|---|---|---|---|
| Stop first | 300 | 132 | +0.19 |
| Open proximity | 300 | 141 | +0.26 |
| Target first | 300 | 158 | +0.41 |
Same rules, same data, same costs; the average R doubles depending on which guess you make about 26 ambiguous bars. If your platform defaults to "target first" or does not tell you, the reported result is unreliable.
Same-bar entry and stop
A related case: you enter on a stop order at bar D+1's open or intrabar, and the same bar's low is below your stop-loss. Did you get stopped on the entry bar? Conservative: yes. Many backtesters ignore stops on the entry bar entirely, which quietly removes the worst losses from the record.
Entering at the open
If your rule is "buy at the open", note that the printed open of a daily stock bar is the opening auction price, which retail market-on-open orders do receive. For intraday bars, the "open" of a bar is the first trade in that period, which you can only match if you were already in the queue. Model a tick of slippage.
Try it: Find every trade in your backtest where the entry bar's range includes both the stop and the target. Count them and compute the result under stop-first and target-first conventions. If the difference is more than a fifth of your total profit, get lower-timeframe data before trusting the result.
Recap
- Market orders fill at the next open plus slippage, not at the signal close.
- Stops fill at max(stop level, bar open) plus slippage; gaps through the stop fill at the open.
- Limits fill only on a trade-through by default; touch fills flatter mean-reversion systems.
- When stop and target share a bar, assume the stop hit first unless lower-timeframe data says otherwise.
- Check whether your backtester honours stops on the entry bar; many do not.
See it drawn
Original diagrams for the ideas on this page. Illustrative, not real market data.