Current Blog
How to Model Partial Fills in a Trading Backtest
A partial-fill backtest records each incremental execution, keeps the unfilled remainder live, preserves venue sequence, and computes position and cost from the actual fill ledger.
This article was prepared with AI assistance and checked through automated editorial and source review. No named human review is recorded.
A partial-fill backtest should never turn the first eligible execution into a fill for the entire order. It should append one execution event at a time, reduce the live remainder by the executed quantity, and leave that remainder exposed until another execution, cancellation, replacement, expiry, or rejection ends it.
Keep the order ledger and fill ledger separate. The order record describes instructions and live quantity. Each fill record stores venue time, local receipt time, executed shares, price, match identifier, liquidity classification when available, and fees. Position and cash change from fills, not from order acceptance.
Use incremental execution messages
The Nasdaq OUCH 5.0 specification says an Executed message can represent all or part of an order. Its quantity is the incremental number of shares just executed, and its price is the execution price. The message also carries a match number.
Update remaining quantity with a simple invariant: new remainder equals prior remainder minus the incremental execution. Reject any event that would make the remainder negative. Do not treat the execution quantity as cumulative unless the venue protocol says it is cumulative.
Reconstruct fills in venue sequence
The Nasdaq TotalView-ITCH specification says an order can receive several Order Executed messages when it executes in parts. The effects of those messages are cumulative, while each message supplies the shares for that execution. Process them in venue sequence against the matching order reference number.
Market-data execution messages describe changes to the book. They do not prove that a simulated strategy order received the same allocation. Combine them with the queue-position model, the venue rule, and the evidence available at that timestamp. Keep a range when cancellations or hidden interest make exact priority unknowable.
Work a share-by-share example
Assume a synthetic buy limit order for 1,000 shares at $50.02. At venue acceptance, the model has 1,500 displayed shares ahead at the same price. Assume strict price-time priority, no cancellations, no hidden quantity, and complete order-level events for this example.
Three sell executions arrive for 600, 700, and 500 shares. The first two consume 1,300 shares ahead, leaving 200 ahead. The third consumes those 200 and fills 300 shares of the simulated order. The order now has 700 shares remaining. A later 450-share execution fills another 450, leaving 250 live.
This is illustrative arithmetic, not a claim about an observed Nasdaq order. If the evidence only shows aggregated trades, publish an optimistic and conservative allocation range instead of selecting one exact fill.
Calculate price and cost per fill
Suppose the first 300 shares execute at $50.02 and the next 450 receive price improvement to $50.01. The filled quantity is 750 shares. The volume-weighted fill price is ((300 × $50.02) + (450 × $50.01)) ÷ 750, or $50.014 per share.
Apply commissions, exchange fees, rebates, taxes, and slippage to each fill using the rules and units valid at that time. Do not charge a full-order fee on every partial execution unless the fee schedule actually works that way. Reuse the price constraints from the limit-order model.
Keep the remainder live through latency
A strategy may receive an acknowledgment after another execution has already occurred. Store venue event time separately from local receipt time, as described in the latency model. The simulator updates venue state in venue sequence, while the strategy can react only after the relevant message reaches its local clock.
Cancel and replacement requests do not erase fills already completed. Continue exposing the remainder until the venue confirms the new state. If a replacement is accepted, carry cumulative executions into the chain accounting described in the replacement model.
Reverse broken trades precisely
OUCH states that a Broken Trade message follows an earlier execution for the same match number. Reverse the exact fill identified by that match number. Restore its shares to the position and cash ledgers, reverse its fees according to the applicable rules, and record the break as a new event rather than deleting history.
Whether the original order quantity becomes live again is venue-specific and must come from the protocol or an explicit research assumption. A trade break is not permission to reconstruct an order state that the evidence does not support.
Every fill quantity is positive and no greater than the prior live remainder.
Cumulative fills plus live remainder plus canceled quantity reconcile to accepted quantity.
Fill prices respect the order instructions and venue rules.
Each match identifier is applied once unless a documented correction reverses it.
Position, cash, costs, and order state reconcile after every event.
Test full fills, several partial fills, price improvement, cancellation after a partial fill, replacement while a remainder is live, duplicate messages, out-of-order local arrival, and broken trades. Report uncertainty when the historical feed cannot identify allocation precisely.




