Skip to content

How to Model Slippage, Fees and Market Impact in Python

Original question

How can I incorporate realistic slippage, brokerage fees, and market impact into my Python backtesting framework?
Simulate fills relative to a timestamped reference price. For an immediately marketable order, account for crossing the spread, temporary impact and any delay between decision and execution. Use the gap between the reference and the simulated fill to measure slippage. Debit explicit fees separately. Estimate the model from past fills or market data, and rerun the backtest with different liquidity and cost assumptions to see how much they affect the result.

Build the fill from a quoted midpoint

A small illustrative model uses arrival midpoint MM, absolute bid–ask spread ss, and a temporary impact fraction ii. For signed quantity qq,
Pfill=M+sign⁡(q)(s2+Mi).P_{\mathrm{fill}}=M+\operatorname{sign}(q)\left(\frac{s}{2}+Mi\right).

An order sized at a fraction ∣q∣/V|q|/V of typical daily volume can use a scenario rule i=η∣q∣/Vi=\eta\sqrt{|q|/V}. This is a modelling choice. Estimate η\eta in consistent units, segment by asset and liquidity, and avoid extrapolation far beyond observed sizes. A separate participation limit can cap the shares filled within each bar. Add market movement between decision and arrival when your reference timestamp precedes the simulated execution window.

Update cash by −qPfill−f(q)-qP_{\mathrm{fill}}-f(q), with ff set by the brokerage schedule, including per-order minimums and per-share charges if relevant. Choose whether fees apply per fill or to a parent order. For longer-horizon cost models, specify how lasting impact changes subsequent marks and fills.

Reconcile every component on a 5,000-share buy

A buy for 5,000 shares arrives at a $40.00 midpoint, with a $0.04 spread and typical volume of 500,000 shares. With η=0.004\eta=0.004, the impact fraction is 0.0040.01=0.00040.004\sqrt{0.01}=0.0004. The simulated fill is $40.036. Spread costs $100, impact costs $80, and fees of half a cent per share cost 25 dollars. The total shortfall from the arrival midpoint is $205, or 10.25 basis points of $200,000 reference notional.

On the sell side, check that the same spread and impact assumptions push the fill below the arrival midpoint. Record execution cost as signed quantity times fill price minus midpoint, with the fee added separately. If P&L already uses the fill price, spread and temporary impact have already entered it. Deducting those amounts as a second charge would count them twice. Use the price bridge to explain the result, and use explicit fees for cash deductions that the fill price does not capture.

Implement signed fills and fees

from math import copysign, sqrt def market_fill(mid, spread, shares, daily_volume, impact_scale=0.004): impact = impact_scale * sqrt(abs(shares) / daily_volume) price = mid + copysign(spread / 2 + mid * impact, shares) commission = max(1.0, 0.005 * abs(shares)) cash_change = -shares * price - commission shortfall = shares * (price - mid) + commission return price, cash_change, shortfall print(market_fill(40.0, 0.04, 5_000, 500_000))

This function prices a nonzero order assumed to fill in full. In a simulator, apply it only to the quantity the current execution window can fill.

Walk the book with different market-order sizes in the order book tool to see the price differences your fill model is approximating.

Interactive example

Find the execution cost that consumes a trading edge

A synthetic strategy earns 12 basis points per period before costs. Costs apply to the absolute change in position on each traded side.

Net edge 5.00 bps per period · break-even cost 17.14 bps per unit
Expected net return declines as execution cost rises-10010010203040Cost (bps per unit of turnover)Net edge (bps)
  • Net edge
  • Break-even

References and next steps