Network failures during order placement create a particularly dangerous ambiguity: you don’t know whether the request reached the exchange. If it did and the order filled, sending the same order again creates a second position the engine never asked for. If it did not, failing to retry means the signal is never acted on. The broker adapter resolves this ambiguity deterministically by querying the exchange for the previous attempt’s order before sending anything new.Documentation Index
Fetch the complete documentation index at: https://mintlify.com/backtest-kit/wallet-manager/llms.txt
Use this file to discover all available pages before exploring further.
The Reconcile Check
The engine passes anattempt counter with every call to onOrderOpenCommit. On attempt === 0 (the first try) there is nothing to reconcile. On attempt > 0, the previous attempt may have left an order on the exchange. The reconcile check queries by origClientOrderId — the clientOrderId that was stamped on the original order — and acts on what it finds:
.catch(() => null) converts a “not found” 404 response into null, which falls through to the fresh-order path below — no special handling needed for the first-attempt case on attempt > 0.
clientOrderId = signalId
The backtest-kit engine assigns every signal a stablesignalId that is preserved across retries. The broker adapter stamps that value onto every limit order as newClientOrderId:
signalId the idempotency anchor for the reconcile. On retry, origClientOrderId: signalId points back to exactly the order placed by the previous attempt — even if the network dropped the response before it arrived at the caller.
Binance Duplicate-clientOrderId Limitation
Binance enforcesclientOrderId uniqueness only among open orders. Once an order is filled or cancelled, its clientOrderId is freed and could, in theory, be reused. More importantly: if an order fills instantaneously (status goes directly to "FILLED" before any deduplication check), Binance’s own guard would not block a second order with the same clientOrderId.
This is exactly why the explicit reconcile check above is required. Rather than relying on Binance to reject the duplicate, the adapter proactively queries for the previous order and returns early if it is already filled — before the new order request is even constructed.
Note — This limitation is documented in the README: “Binance’s duplicate-clientOrderId guard only covers open orders; an instantly filled one would not be deduplicated.”
Three Outcomes
The reconcile check has exactly three possible outcomes, each leading to a different execution path:FILLED — confirm without re-sending
The previous attempt filled successfully but the response was lost in
transit. Returning without sending a new order causes the engine to record
the position as open. The position is now live exactly once.
NEW or PARTIALLY_FILLED — cancel stale order, then proceed
The previous attempt placed an order that is still resting (or partially
filled) on the book. Leaving it alive would risk a surprise fill at a stale
price. The adapter cancels it, then falls through to place a fresh order
with updated price and quantity — as if this were the first attempt.
Terminal Rejection on the Fifth Attempt
The engine’s default retry budget is five attempts (CC_ORDER_OPEN_RETRY_ATTEMPTS = 5), so attempt arrives as 0–4. When attempt === 4 (the last try) and the limit order still does not fill within the poll window, the adapter throws OrderRejectedError rather than a plain Error:
OrderRejectedError is the terminal signal to the engine: it consumes the signalId into lastPendingId, ensuring this signal is never re-issued. A plain Error on earlier attempts is transient — the engine retries with the same signalId (incremented attempt) and the reconcile check at the top of the next call handles whatever state the previous try left behind.
For the full adapter implementation including all hooks and the terminal-rejection path, see Order Open Adapter.