Backtest Slippage and the Realistic Fill Model: The Sixth Lie That Fakes Your Returns
Everyone quotes the five lies of backtesting. There is a sixth, and it is the most expensive: the fill. A backtest books trades at prices the market would never give you, so it corrupts the return series itself before any metric runs. Here is the cost re-gate I use to tell a real edge from fictional fills.
Everyone in this corner of the internet can recite the five lies of a backtest: wrong units, survivor math, peeking at the future, features normalised on data that had not happened yet, and no error bars. I named those five myself, in an earlier chapter, and I stand by them. But there is a sixth lie, and it is the one that has cost me the most, because the other five corrupt the measurement of a return series that did happen, while the sixth corrupts the return series itself, before any Sharpe or Calmar or ruin number is ever computed on it. It is the fill.
Here is the whole of it in one sentence: the fill you assumed is not the fill you would get. The backtest booked a trade at a price the market would never have handed you, so every downstream metric is faithfully measuring an edge that lived in the fills, not in the signal. And unlike the other five, this one does not read as a bug. It reads as the absence of a decision. The backtest fills at the mid, instantly, for free, because nobody told it not to, and that silence is worth more phantom alpha than any .shift() you ever forgot.
I run a real multi-strategy system, live, through a retail broker. I call it Titan throughout these notes. Titan has shipped every one of the five lies at least once. But the incident that made me build a whole layer of the system was the sixth: a slow cross-asset sleeve whose entire edge, it turned out, was a gift from an execution model that did not exist.
The four faces of the fill
The sixth lie is not one mistake. It is four, and a defensible backtest has an explicit, stated answer to each of them, the same way it states its annualisation factor rather than leaving it to a default.
Figure
The four faces of the fill
Every one flatters you in the same direction: a cost the backtest forgot to charge lands as invented profit.
Bar timing
same-bar close vs next-bar open
Filling at the close the signal was computed on is the close cousin of look-ahead. Real signals fire on a closing bar and fill on the next one.
The half-spread
you never fill at the mid
A buy lifts the offer, a sell hits the bid. You cross half the spread each side, every round trip. A mid-price backtest touches a level no aggressive order gets.
Stops fill past the trigger
1R designed, ~1.5R paid
A stop trades once price reaches a level; on a gap the next print is materially worse. A backtest that fills at the trigger models a discipline the market does not provide.
Impact grows with size
small is nearly free
A large clip fills in pieces at worse prices, and slippage scales with participation. The term that turns a capacity question into a hard ceiling.
The only honest Sharpe is the one that has already paid to trade.
Bar timing. Did the trade fill at the same bar's close the signal was computed on, or at the next bar's open? Same-bar-close is the close cousin of look-ahead. You are filling at the exact price that printed at the instant your signal crystallised, with zero latency between deciding and executing. No real signal does that. It fires on a closing bar and fills on the next one, and the gap between those two prices is pure, free alpha the backtest invents out of nothing. The honest default is next-bar-open, and if you have never checked which one your harness uses, assume it is cheating.
The half-spread. Your fill is not the mid. A buy lifts the offer, a sell hits the bid. You cross half the quoted spread on the way in and half on the way out, every single round trip, no exceptions. A backtest priced at the mid is pricing at a level no aggressive order ever touches. For a fast strategy on a wide instrument, that half-spread, doubled across entry and exit, can be the whole margin.
Stops fill past the trigger, not at it. This is the one that gets people killed. A stop is a promise to trade once price reaches a level. On a gap or a fast tape, the next available print is materially worse than that level. A position you designed to lose 1R loses 1.5R, sometimes more. A backtest that fills every stop exactly at its trigger is modelling a discipline the market simply does not provide, and a risk-of-ruin gate fed that fiction is certifying a strategy that does not exist.
Impact grows with size. A large clip does not fill at one price. It fills in pieces at progressively worse prices, and the slippage scales with how much of the available volume you are demanding. A small order in a liquid name is nearly free. The same edge at ten times the size pays several times the per-unit impact, and sometimes the order does not fully fill at all. This is the term that quietly converts a capacity question into a hard ceiling.
Notice the common thread. Every one of the four flatters you in the same direction. None of them is a price you would ever get on the wrong side of by accident. They are all costs the backtest forgot to charge, and forgotten costs always land as invented profit.
The war story: an edge that was the cost it never paid
The sleeve that taught me this was a slow cross-asset strategy, the patient sort that rebalances on a daily signal and holds for a while. It passed every gate I had at the time. Positive gross Sharpe, a bootstrap confidence interval whose lower bound sat comfortably above zero, a clean plateau in parameter space rather than a spike. By the standards of the five lies, it was clean. I sent it to paper trading feeling good about it.
Then I re-ran its costs honestly, and the edge evaporated.
Three things had been quietly free in the backtest and were not free in life. First, the sleeve signalled on a US line but traded a wider UCITS substitute, because the US instrument was blocked to me under European rules, and that substitute costs roughly an order of magnitude more per round trip. Second, it carried a ballast leg overnight, and overnight financing is charged per day held, not per trade, so a strategy that "never trades" was bleeding rent the backtest never booked. Third, the per-side commission floor mattered on a modest clip in a way it never does at size. Charge all three, on the right events, and the net lower bound crossed below zero. The entire gross edge was a multiple of the cost the backtest had omitted.
The sleeve had not been wrong about its signal. It had been wrong about being free. And here is the part that still bothers me: nothing about the equity curve looked suspicious. The optimism was not visible on the chart. It only appeared when I put the assumed cost and the honest cost side by side.
The portable artefact: the cost re-gate
If you take one thing from this piece, take this, because it fits in an afternoon and it is brutally hard to fool. I am not going to hand you my constructed cost model; the exact component breakdown, the per-class spread and slippage presets, the impact coefficient and the stop-fill stress live in the book. But the test you wrap around whatever cost model you build is universal, and it is this:
Re-run the strategy's edge at 0x, 1x, and 2x your modelled cost, and read the shape.
The 0x run is the gross fantasy, the number the naive backtest reports. The 1x run charges your honest, constructed estimate of what it costs to trade: the half-spread each side, the slippage, the commission floor, the financing and roll on the legs that carry, all charged on the transitions and the calendar, not on the bars held. The 2x run is your margin of safety against having under-modelled the friction, which you almost certainly have.
Now judge the pattern, and judge it on the lower bound of a bootstrap Sharpe interval, never the point estimate:
Chart
The edge collapses as you charge realistic cost
Net Sharpe (bootstrap lower bound) for one illustrative strategy re-run at three cost levels. An edge that is gone by 1x was never real; the 0x-to-1x drop is the size of the fictional fills. Illustrative and sanitised.
- A real edge survives 1x realistic cost with its lower bound still above zero, and degrades gracefully toward 2x. It bends; it does not break.
- An edge that is handsome at 0x and gone by 1x was never an edge. It was the friction you forgot to charge, wearing a Sharpe ratio as a disguise. Reject it. It does not matter how stable it looked, how clean the plateau was, or how much you want it to be real.
And here is the diagnostic buried in the same three runs, the one I find most useful of all. The drop from 0x to 1x is a direct measurement of how much of your edge was fictional fills. If gross Sharpe is 1.4 and net-at-1x is 1.2, the fills were a rounding error and you have a genuine signal. If gross is 1.4 and net-at-1x is 0.1, then almost the entire thing was execution fantasy, and you got extraordinarily lucky that you ran this test before funding it. That single number, the 0x-to-1x collapse, is the honest size of the sixth lie in your particular strategy.
Wire it into the promotion path so no strategy reaches capital without clearing net-at-1x, exactly as you already gate on the gross lower bound. The only honest Sharpe is the one that has already paid to trade.
Why this is the most expensive lie
The five lies I named before are failures of measurement. You had a real return series and you described it wrongly: you annualised with the wrong factor, you counted only the survivors, you let a statistic peek. Fix the measurement and the truth is still sitting there in the data, waiting to be read correctly.
The sixth lie is different in kind, because there is no true return series underneath it to recover. The returns themselves are counterfeit. Every buy printed a little too cheap, every sell a little too dear, every stop honoured a level the market would have blown straight through. By the time a metric runs, it is computing an impeccable statistic on fabricated inputs, and no amount of statistical care downstream can undo a fabrication upstream. That is why it corrupts more thoroughly than the other five combined, and why I now treat the cost model not as a footnote to a strategy but as part of the strategy. For a small-edge sleeve, whether you charge the real spread on the leg you actually trade, the real financing on the days you carry, and the real commission floor on the clip you actually send, is the entire difference between a deploy and a reject.
There is a whole layer behind this that I have kept for the book: how to construct a defensible cost model instead of asserting a round-number haircut, how to charge each component on its own event so you never double-count a held position or let a carried one trade for free, how the stop-fill stress feeds the ruin gate, and how to reconcile the cost you assumed against the bps you actually paid once the strategy is live, so the estimate cannot rot. The full chapter on the execution layer, order policy, the fill model, and the constructed cost model, is in Building a Production Quant Trading System, a living digital copy on Leanpub and a print paperback on Amazon. A sanitised, Apache-2.0 companion framework lives on GitHub if you want to see the shape of it in code. But you do not need any of that to start. You need three runs and the discipline to believe the worst one.
So carry this out of here: your backtest's fills are fiction until you have charged for them, and the cheapest way to find out how much of your edge is fiction is to re-run it at 0x, 1x, and 2x cost and watch what dies. If it dies at 1x, it was never yours. It was the broker's, and you just had not paid them yet.
This is an engineering essay, not investment advice, and it contains no tradable strategy. All figures are illustrative and sanitised, and the war-stories are about bugs and costs, not profits.
Chart
The edge collapses as you charge realistic cost
Net Sharpe (bootstrap lower bound) for one illustrative strategy re-run at three cost levels. An edge that is gone by 1x was never real; the 0x-to-1x drop is the size of the fictional fills. Illustrative and sanitised.
Figure
The four faces of the fill
Every one flatters you in the same direction: a cost the backtest forgot to charge lands as invented profit.
Bar timing
same-bar close vs next-bar open
Filling at the close the signal was computed on is the close cousin of look-ahead. Real signals fire on a closing bar and fill on the next one.
The half-spread
you never fill at the mid
A buy lifts the offer, a sell hits the bid. You cross half the spread each side, every round trip. A mid-price backtest touches a level no aggressive order gets.
Stops fill past the trigger
1R designed, ~1.5R paid
A stop trades once price reaches a level; on a gap the next print is materially worse. A backtest that fills at the trigger models a discipline the market does not provide.
Impact grows with size
small is nearly free
A large clip fills in pieces at worse prices, and slippage scales with participation. The term that turns a capacity question into a hard ceiling.
The only honest Sharpe is the one that has already paid to trade.
Further reading
- Capacity and Crowding: Why a Real Edge Still Decays at Size
The impact term of the sixth lie is the same square-root cost that sets a strategy's capacity ceiling.
- Suspicion Over Celebration: Inside "Building a Production Quant Trading System"
The constructed cost model, the fill model and the order policy are in the book.
Related posts
Live Trading Does Not Match the Backtest: The Code-Level Causes Nobody Names
When your live P&L drifts from the backtest you validated, the culprit is almost never psychology. It is code: the same metric computed two subtly different ways in research and in the live sizing path. Here is the parity oracle I now gate on, and the deeper rule behind it: live and research must call the same code, not two copies of it.
Fail Closed Data Validation: Why a Trading Bot Should Refuse to Boot on Bad Data
A data-quality gate that crash-loops on corrupt, stale or all-NaN data is not broken, it is working: the alternative is fail open, trading on garbage with silent defaults. Here is the war-story from both sides, the honest flip where an over-eager gate locked me out of a market, and the one portable rule: on bad data, refuse to trade and alert loudly, never proceed with a default that looks like data.
Bar Timestamp Convention: The Open vs Close Stamp That Leaks a Full Bar of Look-Ahead
A bar carries one timestamp, but that stamp is ambiguous: is a bar labelled 09:00 the open of the coming interval or the close of the last one? Vendors disagree, and reading the wrong edge is a clean one-bar look-ahead that sails through review. Here is the war-story, why the leak is invisible, and the ingest rule I now enforce on every feed.