Backtesting fees and slippage: model real trading costs
A backtest that buys and sells at a candle's ideal price is measuring a market that nobody can trade. Real orders pay fees, cross spreads, arrive late, consume liquidity, and sometimes carry funding or borrow. This guide builds a transparent cost model, works through the math in basis points, and shows how to stress the assumptions before a bot reaches live money.
The complete cost stack
Separate costs into components so each assumption can be inspected and changed. One unexplained “0.1% cost” input hides too much.
| Component | Why it occurs | How to model it |
|---|---|---|
| Commission or venue fee | Explicit charge on executed notional, shares, or contracts | Apply the correct maker/taker or broker schedule to every fill |
| Bid-ask spread | An immediate buy trades near the ask; an immediate sell near the bid | Use historical bid/ask data or a side-aware spread estimate |
| Slippage | Price moves between decision and execution | Adverse adjustment by side, volatility, order type, and delay |
| Market impact | The order consumes depth and moves its own execution price | Scale cost with size versus available depth or traded volume |
| Carry | Perpetual funding, margin interest, or stock borrow | Accrue over the actual holding intervals |
| Other charges | Exchange, regulatory, clearing, conversion, or data costs | Include when material to the venue and instrument |
Apply execution costs to both sides of a round trip. A fee quoted per trade side is paid at entry and exit. Spread and slippage are also direction-aware: increasing a long entry price is a cost, while decreasing its exit price is a cost. Short trades reverse the price directions but still suffer adverse execution.
net expectancynet return = gross strategy return
- explicit fees
- spread cost
- slippage and impact
- applicable carry and other charges
Worked round-trip example in basis points
One basis point (bp) is 0.01%. Suppose a strategy's average gross gain is 30 bps per completed trade. The assumptions—not venue quotes—are 5 bps commission per side, 3 bps spread cost per side, and 4 bps slippage per side.
| Item | Entry | Exit | Round trip |
|---|---|---|---|
| Commission | 5 bps | 5 bps | 10 bps |
| Spread | 3 bps | 3 bps | 6 bps |
| Slippage | 4 bps | 4 bps | 8 bps |
| Total | 12 bps | 12 bps | 24 bps |
The 30-bp gross edge becomes only 6 bps net before carry. On $10,000 of notional, that is $30 gross versus $24 of modeled cost, leaving $6. Across 100 round trips with the same notional, costs total $2,400 and the modeled net is $600 rather than the attractive $3,000 gross result.
Underestimating cost by just 5 bps per round trip is $500 across 100 trades at $10,000 notional. High-frequency or high-turnover strategies need a much larger gross edge than slow strategies to survive the same friction.
Choose a fill model that matches the data
A candle bar contains open, high, low, and close—not the sequence inside the bar, bid/ask spread, queue position, or available depth. The model must not claim precision that the data cannot support.
- Market order: fill from the next tradable price, cross the spread, then add adverse slippage. Filling at the signal bar's close often introduces look-ahead bias.
- Stop order: when price gaps through the stop, use the first available price after the gap rather than the stop trigger itself.
- Limit order: a bar touching the limit does not prove a fill. Conservative bar tests require price to trade through the limit; better tests use quote, trade, or queue data.
- Large order: cap size as a fraction of observed liquidity and simulate a volume-weighted walk through the book rather than filling everything at the best quote.
- Partial fill: let only available quantity execute and carry the remainder according to time-in-force. The live handling is covered in trading bot partial fills.
Do not give limit orders guaranteed maker fees. A marketable limit crosses immediately and can be treated as taker activity; a resting order may not fill at all. Model the execution condition first, then apply the fee class supported by that simulated fill.
For a dedicated round-trip worksheet and post-only tradeoffs, see maker vs taker fees for trading bots.
Run a cost frontier, not one lucky assumption
No historical estimate is exact. Test a grid from favorable to severe, using values grounded in the target market. A simple report might show:
| Scenario | Fee | Spread + slippage | Question answered |
|---|---|---|---|
| Frictionless | 0 | 0 | Does the raw signal contain any edge at all? |
| Optimistic | Best plausible tier | Quiet, liquid conditions | What is the upper bound? |
| Base | Expected account tier | Median measured execution | What is the planning case? |
| Stressed | Conservative tier | Volatile or thin conditions | Does the edge survive deterioration? |
Plot net return, profit factor, drawdown, and trade count across the grid. A robust strategy degrades gradually. If profitability exists only at zero cost or vanishes with a tiny assumption change, reject or redesign it. Also segment costs by asset, time of day, volatility regime, and order-size bucket; one global average can subsidize the worst trades with the best.
Calibrate assumptions with paper and small live fills
Record signal timestamp and price, order-send time, acknowledgement, every fill, side, quantity, fee, best bid/ask at decision, and market volatility. From that journal calculate implementation shortfall: the difference between the decision price and actual average execution, including explicit fees. Keep latency and market movement separate where the data permits.
- Start with conservative public spread and fee assumptions.
- Paper trade to validate order logic, while recognizing simulated liquidity may be generous.
- Use the smallest practical live size to observe real fill behavior.
- Group results by the factors that drive execution rather than averaging everything together.
- Update the backtest model and rerun the entire cost frontier.
- Monitor live-versus-modeled shortfall; pause scaling when it drifts beyond limits.
The site's free strategy backtester includes an adjustable fee input for a first-pass test. A production decision still needs spread, slippage, timing, and instrument-specific carry added to the broader process in how to backtest a strategy.
Frequently asked questions
What trading costs should a backtest include?
Include explicit commissions or venue fees, bid-ask spread, slippage, and market impact on entry and exit. Add funding, borrow, exchange, regulatory, data, and currency-conversion costs when they apply to the instrument and holding period.
How do I model slippage in a backtest?
Start with side-aware fills that cross the spread, then add adverse slippage based on order type, liquidity, volatility, size, and delay. Test a range rather than one optimistic constant, and calibrate assumptions against timestamped paper and small live fills.
Can a limit order backtest assume every touched price fills?
No. A bar touching a limit does not prove the bot had queue priority or enough volume traded after its order arrived. Use a conservative rule such as price trading through the limit, a volume or queue model, or report optimistic and conservative scenarios.
How can I tell if a strategy is too sensitive to costs?
Run a cost frontier across plausible fee and slippage assumptions. If a small increase turns expectancy negative or only the best-case scenario works, the edge is fragile. Compare average gross profit per trade and turnover with total round-trip cost.