VIZANIXTrading Software Development
Research and validationValidation6 min read

Building a slippage model that does not flatter your backtest

Assuming you fill at the touch is the most common way a backtest lies. A crude but measured slippage model is worth more than a sophisticated guess.

Vizanix engineering · about the author

ARTICLE
6 minreading time
SECTION
Research and validation
PUBLISHED
2026-08-31
CHAPTERS
5
READ NEXT
3
LANGUAGE
written in English
An engineering breakdown, not a rewrite of the docs.
SLIPPAGEIMPACTDEPTHMEASUREMENT

Every backtest contains a fill model, whether or not anyone wrote one. The default — you fill at the price you asked for — is a model, and it is wrong in a direction that always favours the strategy.

The three levels of honesty

Level 0: no slippage. Fill at the touch. Fine for a first sanity check, worthless for a go-live decision. Any strategy with a small edge is entirely fictional at this level.

Level 1: a fixed haircut. Assume N basis points against you on every market order. Crude, but it puts the cost in the right direction and forces the edge to clear a bar. If you do nothing else, do this.

Level 2: depth-based. Walk the recorded order book and compute what your size would actually have consumed. This is the honest version, and it requires having recorded the book — which is why the collect phase comes first.

python
def walk_book(levels, qty):
    """What this size actually costs against recorded depth."""
    filled = cost = 0.0
    for price, size in levels:
        take = min(size, qty - filled)
        cost += take * price
        filled += take
        if filled >= qty:
            return cost / filled                     # volume-weighted fill
    return None    # not enough depth — the honest answer is 'you could not'

That None return matters. A backtest that silently fills a size the book could not support is testing a market that did not exist. Returning nothing and skipping the trade is more truthful than extrapolating.

Measure it live, then calibrate

Any model is a guess until it is compared against reality. The measurement is simple and most operations do not do it:

python
# Log on every fill. This is the only real slippage number you will ever have.
slip_bps = (fill_price - decision_mid) / decision_mid * 10_000
if side == "sell":
    slip_bps = -slip_bps
metrics.observe("slippage_bps", slip_bps,
                tags={"symbol": symbol, "order_type": order_type, "size_bucket": bucket(qty)})

After a few thousand fills you have a distribution. Compare its median and its 95th percentile against what your backtest assumed. If the backtest used one basis point and reality is four, every historical result needs re-reading.

What drives it

FactorEffect
Order size relative to depthDominant. Everything else is secondary.
Volatility at the moment of the orderStrong — the mid moves while you are in flight
UrgencyMarket orders pay; patient limits do not, but risk not filling
Time of dayThinner books in quiet hours
Whether the market is moving against youAdverse selection: worse exactly when it matters

The last row is why average slippage understates the cost. Your worst fills cluster in your worst moments, so the mean flatters and the tail is what hurts. Model the 95th percentile, not the median.

Limit orders need a different model

For a limit order the question is not price — you get your price or nothing. The question is whether it fills, and a backtest that fills every limit order whose price was touched is optimistic in a specific way: it ignores queue position.

A reasonable approximation: require the price to trade through your level, not merely touch it, before counting a fill. It is conservative and it removes the bulk of the fantasy. If you have full book data, model queue position properly.

The practical minimum

  1. Apply a fixed conservative haircut from day one. Never test at zero.
  2. Log realised slippage on every live fill, bucketed by size.
  3. Calibrate the backtest's assumption against the measured distribution quarterly.
  4. Use the 95th percentile for risk decisions and the median for expectations.
  5. Run the backtest across a slippage grid — if profitability dies between 1 and 5 basis points, you have learned something important cheaply.

This article describes engineering practice. It is not investment advice. Vizanix develops software and does not promise trading returns.

Blog

Read next

Want this running for you?

We write about what we build. If you need it built, get in touch — scoping is free.

Brief

Get a project estimate

Four questions and your contact. No deposit required to talk — if the job is not a fit, we say so straight away.

01What do you need
02Exchange
03Market
04Strategy
05Contacts

Prefer to write directly? Telegram @vx_ceo

Discuss a system