The stream is not a record
Updates are delivered at most once, and nothing is queued for a socket that is not open. There is no backlog and no replay on reconnect: an update sent while you were disconnected is gone.get_order is what tells you where an order stands.
A push carries no requestId: that is how you tell it from a reply. Two order_updated frames for one order can arrive close together; occurredAt, the broker’s time for the change, orders them. order_updated leaves out orderType, timeInForce, limitPrice, fills, mints, burns, fees and feeTotal; get_order returns them.
After a disconnect
- Reconnect with backoff and open a new session.
- For every order you hold as not finished, send
get_orderbyorderId. - Update your state from
statusandleavesQuantity. - For orders that filled while you were away, read their CETs: each
get_orderanswer carriesmintsandburns, or askget_mintsandget_burnsbyregulatoryId.
When an order is UNKNOWN
Anack with status: UNKNOWN means the broker never acknowledged the order. Before answering, the service already looked for it by your reference for a few seconds, and answers ACCEPTED if it turns up. What reaches you as UNKNOWN either does not exist or took longer to appear. You have no orderId, so look it up by externalRef:
Do the same after an
error with UPSTREAM_UNAVAILABLE: the broker could not be reached and the order’s fate is unknown.
get_order takes exactly one of orderId or externalRef; both, or neither, is refused. An order on another account answers ORDER_NOT_FOUND, like one that does not exist.
Cancel an order
cancel_order is a request, not a deletion: it can arrive after the order has filled. The ack says whether the request was taken; the outcome arrives as order_updated.
leavesQuantity of zero means nothing is left to cancel. In sandbox every order fills at once, so every cancellation answers ORDER_NOT_CANCELLABLE.
Executions
executedQuantity says how much filled, not in how many pieces, at what prices or when. Ask for the executions with include:
- Ask only when you need them. A large order can have a hundred executions. Without
includethe field is absent, which is not the same as an empty list: an empty list means you asked and nothing has executed yet. sequencestarts at 2, not 1. Nothing is missing: the broker numbers an order’s first execution 2, and the number is part ofexecutionId.- A busted execution stays in the list with
effective: falseand the broker’s word intype. The effective executions sum toexecutedQuantity; keep the others for the audit trail. Branch oneffective, not ontype. priceis what one execution filled at; the order’sexecutedPriceis the average across all of them.
Trades
trade_updated is the same executions seen from the broker’s ledger, where fees and settlement live.
- Deduplicate on
tradeId. Treat it as an opaque string: it is not a dense sequence, so a gap in it does not mean a missing trade. - Join to the order on
orderRegulatoryId= the order’sregulatoryId. It is absent on a ledger row that carries no order reference. - Order by
executedAt, never by arrival oroccurredAt. Executions of one order arrive out of order, and the broker records an order’s executions in one batch with the sameoccurredAt. priceis the broker’s figure, notgrossAmountdivided byquantity. Amounts carry the ledger’s signs, which do not follow the trade’s direction:sidesays which way it went.- A correction is a new frame with
brokerStatusC, not a change to the first one. - Settlement is never pushed.
settledisfalseon arrival and no frame updates it. UsesettleDate, and read cash on or after that date.
When the quantities do not add up
Every quantity is the broker’s arithmetic, passed through unchanged. Ifquantity, executedQuantity and leavesQuantity do not reconcile (for example, more executed than ordered), do not act on the order: treat it as a fault, stop, and contact Securitize with the traceId.