Order actions are requests to change the state of an order. Each such request is identified and managed by an increasing version number. The gateways will cache all requests.
If an exchange is fully FIX 4.4 compliant, it will support chaining by rewriting
OrderCancelReject messages will then include
ClOrdID which can in turn be used to correlate with the cached
However, even for exchanges offering FIX 4.4 connectivity, there are some complications that requires the use of heuristics to match with response a request
OrderCancelRejectmay not contain a unique request id because
ClOrdIDcan not be rewritten.
BusinessMessageRejectmessage is sometimes used (instead of
OrderCanceReject), typically when certain order attributes are unsupported by the exchange. This message does not even have a
ClOrdIDand the only solution is then to cache request history by message sequence number.
REST / WebSocket#
Some exchanges offer a REST service for order actions and a WebSocket service to push order updates. This design introduces an inherent race condition between the two connections.
Request matching is required when an order update arrives from WebSocket before the matching response arrives from REST.
We are in luck if the exchange supports chaining (rewriting
Otherwise the only choice is to match on order attributes:
Has the order status changed to canceled? Then it’s probably an update correlating with a cancel request.
Has the limit price or order quantity changed? Then it’s probably an update correlating with a modify request.
Any update should match if there is a create order request.
This is the situation
Having a request version or request id is the ideal situation, then we can match exactly.
For other cases, heuristics must be used to match a response or an order update to an outstanding request.
And we have these constraints
Correct time-ordering must be guaranteed, i.e.
OrderAckmust always precede
OrderAckis not be allowed.
For heuristics, the logic includes
The first matching request wins, the assumption is that the exchange will not conflate requests.
It is possible to skip request version, the assumption is that requests can be lost.
If the order status is new, the request type must be create.
If the order status is canceled, the request type must be cancel.
There can be no matching on quantity or price when the requst status rejected.
If the order status is working and the request type could be create or modify, then the quantity and price must match the request.
Response and Updates#
OrderAck message contains the version number of the requst.
OrderUpdate message contains different version numbers useful for tracking
outstanding requests as well as rejects.
max_request_versionis the version number of the last received request.
max_response_versionis the version number of the last received response (possibly matched through heuristics).
max_accepted_versionis the version number of the last received response with a positively accepted status (i.e. not rejected and not failed due to network or timeout).
max_response_versionmeans there are outstanding requests.
max_accepted_versionmeans some requests may have been rejected.
Tracking rejects is very important for chaining.
CancelOrder allows you to specify a version
CreateOrder implicitly use version 1).
The next available version number is automatically assigned if you do not specify a version number.
The validity of the version number is verified if you do specify a version number.
You can optionally specify a
This can be used by the gateway to shortcut certain scenarios:
the gateway is allowed to auto-reject this request if it has seen a reject for
The reason for having this option is to deal with a race condition and possibly
better support FIX chaining.
Some protocols will allow pipelining and implicitly expect the exchange to deal with rejects in a consistent manner.
For example, a client sends two order modification requests. The second request is sent before having received a response for the first request.
Let’s assume the first request is rejected, then the question is what has to happen with the second request?
For example, FIX expects the second request to be auto-rejected because
OrigClOrdID chaining states the the previous request
must have succeeded for this request to succeed.
This may or may not be supported by the exchange and a best-effort approach
is therefore all that can be done!
(See above comment around
conditional_on_version, for example.)
If supported, the gateway must also remember to reset
a reject is received.
It is not possible to guarantee correct FIX 4.4 chaining if the exchange does not support
Requests must be cached by FIX message sequence number, if the exchange uses the FIX
Heuristics is greedy and will try to match an update or a response to an outstanding request.
Heuristics can fail for some scenarios, e.g. trying to modify an order quantity or a limit price to the same values.