The order lifecycle, from send to fill
Your order showed “pending”, then “partially filled”, then vanished from the open orders list without ever saying “filled”. The position is smaller than you asked for and nothing explains where the rest went.
An order is a small state machine. It has a defined set of states, a defined set of transitions between them, and every message a venue sends you is a report that one of those transitions happened. Reading the sequence correctly removes most of the confusion.
The states
Unsent. The order exists only where you composed it. Nothing has been communicated. Cancelling here is free and instant because there is nothing to cancel.
Sent, unacknowledged. The instruction has left, and no reply has come back. This is the genuinely uncertain state: you do not know whether the venue has it, whether it has already filled, or whether it never arrived. Any interface showing “pending” is usually showing this.
Accepted. The venue has validated the order — legal price increment, legal size, sufficient balance or margin — and given it an identifier. If it did not cross on arrival, it is now resting in the book. Acceptance is not a fill and does not imply one.
Rejected. Validation failed. The order never existed in the book and will never fill. Rejection is a terminal state, and it is the state people most often mistake for a system fault when it is ordinary rule enforcement.
Partially filled. Some quantity has traded; a remainder is still working. The order is in the book with reduced size, holding whatever queue position it had.
Filled. The full quantity traded. Terminal.
Cancelled. Withdrawn before completing, either by you or by the venue. Terminal, and it can be reached from partially filled — which is exactly the sequence that produces the “vanished without saying filled” experience above.
Expired. The order’s time in force ran out. Mechanically the same terminal end as cancelled, with a different cause.
Fills are events, not the order
The most useful thing to separate: an order is one object, and a fill is one of possibly many events against it. A single order for a size larger than the touch quantity generates a fill per price level it consumes, and each fill is its own record with its own price and quantity.
This is why a single order can produce several entries in a trade history, and why the price attached to the order in a summary view is an average rather than a price anything traded at. The average is a derived number; the fills are the facts.
It also means fee accounting is per fill. An order that fills in five pieces is charged five times against those pieces, and if some pieces rested and some crossed, it can be charged on both sides of a maker-taker schedule within the same order.
The mechanism
THE MECHANISM — states and transitions
· Sent, no reply yet
→ UNKNOWN state. May already be
filled, may never have arrived.
Not the same as "not filled".
· Accepted
→ identifier assigned, resting if
it did not cross. NOT a fill.
· Rejected
→ terminal. Never in the book,
will never fill. Usually a rule,
not a fault.
· Partial fill
→ some quantity traded; remainder
still working at its existing
queue position.
· Partially filled, then cancelled
→ terminal with a position smaller
than requested. Never reports
"filled".
· Cancel sent for an order that filled
→ cancel fails, correctly. The
fill happened first at the
engine.
· State names, message ordering, and
whether amends preserve identifiers
→ VENUE-SPECIFIC. Vocabulary and
granularity both differ.
The race you cannot remove
Between sending a cancel and the engine processing it, the order can fill. Between sending an amend and the engine processing it, the same. This is not a defect in any particular venue; it follows from the engine being serial and slightly ahead of your view.
The result is that a cancel has three possible outcomes, and you should expect all three:
- Cancelled. The order was still resting; it is now gone.
- Cancel rejected because already filled. The fill won the race. You hold the position.
- Cancelled after a partial fill. Part traded, the rest was withdrawn.
There is no instruction that means “cancel if it has not filled, and tell me it never filled”. The honest formulation is that a cancel is a request evaluated against a state you cannot see at the moment you make it.
Worked example
Illustrative figures, synthetic throughout. Suppose you send a limit buy for 5.0 units at 40,010, and the ask side rests as 40,004 for 1.2 and 40,010 for 2.5.
The order is accepted. It crosses, so it matches: 1.2 at 40,004, then 2.5 at 40,010. Two fills, 3.7 units total, average about 40,008.1. The remaining 1.3 does not cross anything, so it rests at 40,010 as the best bid, and the order state is partially filled.
Ten seconds later you decide against the remainder and send a cancel. If nobody sold into 40,010 in the meantime, the order goes to cancelled with 3.7 filled. Your summary shows an order for 5.0 that ended cancelled, a position of 3.7, and no line anywhere saying “filled” — which is a complete and correct account of what happened.
If instead someone sold 0.5 into your resting bid just before the cancel landed, you end with 4.2 filled, three fills, and a cancel that succeeded for the last 0.8. Same instructions, different outcome, decided by sequence.
Reduce-only, and orders the venue cancels
Some transitions are initiated by the venue rather than by you, and they are worth knowing because they arrive without warning.
Time-in-force expiry. An immediate-or-cancel order reaches its terminal state within the same processing step it arrived in. A day order ends at a session boundary the venue defines.
Self-cancellation on insufficient margin. In derivatives, if an account’s margin situation changes, resting orders that would increase risk can be cancelled by the venue to make room. Your resting order disappears and you did nothing.
Reduce-only rejection. A reduce-only order that would no longer reduce anything — because the position has already closed — is cancelled rather than left to flip you to the other side. This is the mechanism working as intended, and it means an order you set up as an exit can quietly cease to exist once the exit already happened.
Price-band rejection. An order priced outside a venue’s permitted range is refused at validation.
The failure mode
The lifecycle’s characteristic trap is treating absence of a fill message as evidence of no fill. Messages can be delayed, dropped, or delivered out of order relative to each other, and the terminal truth lives at the venue, not in the sequence of notifications that reached you.
The only reliable statements are the ones you get by asking about current state — your position and your open orders — rather than by reconstructing it from a stream of events you may have received incompletely. And an order whose state you do not know is not a stopped order; until you have a terminal state for it, it may still be working, resting, and fillable while you assume it is done.