Slippage and Fill Quality: Measure Prices and Reconcile Replacements
TECH INSIGHT / EXPLAINED
Execution quality needs a benchmark and a timeline. Measure the difference between the decision price and the quantity-weighted fills, then account for fees and unfilled quantity separately.
The same 500-share example, with a stated benchmark
Assume a buy fills 300 shares at 10,000 and 200 at 10,005. The weighted average is 10,002. Relative to a 10,000 decision benchmark, the adverse difference is 0.02%, or 2 basis points, excluding fees. This synthetic book is an arithmetic example, not an executable quote.
from decimal import Decimal as D
fills = [(D('10000'), D('300')), (D('10005'), D('200'))]
qty = sum(q for _, q in fills)
average = sum(p*q for p, q in fills) / qty
slippage_bps = (average / D('10000') - 1) * 10000
assert average == D('10002')
assert slippage_bps == D('2')Choose constraints, not a guaranteed outcome
A market order prioritizes execution but does not cap the execution price. A buy limit caps the acceptable price but may remain partly or wholly unfilled. Trading halts, unavailable liquidity and venue protection rules can interfere with execution. Order-type codes such as 00 and 01 are API-specific, not a universal vocabulary.
Visible top-of-book size is only a snapshot. Other participants may trade or cancel before your order arrives, so fitting inside that size does not imply zero slippage. Splitting a trade can reduce instantaneous size while increasing exposure to later price movement.
Cancel, reconcile, then replace
Suppose the target is 500 and 300 are filled when cancellation starts. Another 50 may fill before cancellation is confirmed. Replacing with 200 would overshoot; the remaining target is now 150.
Wait for a terminal cancellation result or query the order’s final state, reconcile unique execution records, and only then calculate remaining quantity. If state is unknown, stop automatic replacement and reconcile. Blindly switching to a full-size market order after a timeout can duplicate exposure.
What to keep in an execution journal
Record side, benchmark price and time, quote age, requested and filled quantity, average fill, fees, rejection reason and cancel outcome. Use a consistent sign convention: buys are worse above the benchmark; sells are worse below it. Backtest/live differences can also reflect look-ahead, data quality or model overfitting; slippage is one measurable contributor, not a universal explanation.
Unfilled quantity can hide behind a good average price
Suppose a hypothetical instruction targets 1,000 units at a decision benchmark of 100, but only 400 fill at 100.05 and 200 at 100.20. The 600 filled units average 100.10, an adverse difference of 10 basis points. That statistic omits the 40% of the instruction still unfilled. A system reporting only completed fills can appear better simply by leaving difficult orders unfinished.
Set an observation horizon in advance and suppose the price there is 101. Relative to a hypothetical full purchase at the decision price, the unfilled quantity has an opportunity-cost component of 400 × (101 − 100) = 400. This is a counterfactual comparison, not cash debited from the account. If the horizon price falls, that component can become favorable; do not force it to be a loss or truncate negative values.
Use a shared denominator for the complete instruction
The 600 executed units cost 60 more than the decision-price benchmark. An assumed fee of 0.05% on their actual notional of 60,060 is 30.03. Total shortfall against buying the complete instruction at the benchmark is therefore 60 + 400 + 30.03 = 490.03, or 49.003 basis points on planned notional of 100,000. No sale is assumed at the observation horizon, so a separate liquidation fee is not included.
Dividing by executed notional instead answers a different question. Fix and display intended quantity, filled quantity, denominator and evaluation horizon. The Investor.gov explanation of order types distinguishes a limit order's price condition from whether it executes. That tradeoff is why average fill price alone is an incomplete ranking criterion.
Divide the timeline without claiming causation
If the decision benchmark is 100, the benchmark at arrival is 100.04 and the average fill is 100.10, the difference can be split into two intervals. Using 100 as the denominator for both gives 4 basis points before arrival and 6 afterward, totaling 10. Dividing only the later component by 100.04 and then adding it is not the same decomposition.
This accounts for changes across time; it does not prove that network delay caused the first 4 basis points. Market movement, the order's own impact and benchmark selection can all contribute. If exchange receipt time is unavailable, label a local send-time proxy explicitly. Subtracting timestamps from unsynchronized computers does not produce a reliable measured latency.
Keep the full set of attempted instructions
Include complete fills, partial fills, rejections and expirations in the comparison population, then separate order side and size bands. Do not choose the evaluation horizon after seeing which price is most favorable. Distinguish a simple mean of order-level basis points from a notional-weighted mean, since many tiny orders can dominate the former. The average-price and shortfall calculations above were verified locally with Python Decimal. They are synthetic accounting examples, not estimates of actual market impact or recommendations for a particular order type.
Sources and further reading
Investor.gov order types · Order-book companion
Content and examples reviewed: 2026-10-01
댓글
댓글 쓰기