Wallet Manager is the canonical reference implementation for the exchange side of a backtest-kit broker adapter. It wrapsDocumentation 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.
node-binance-api in a small DI-wired service layer and demonstrates the exact order-management flows — post, poll, cancel, market fallback — that every production adapter must get right. The two hooks the adapter exposes (onOrderOpenCommit and onOrderCloseCommit) are governed by three strict rules that together guarantee the engine’s state and the exchange’s live book stay in sync even when network requests are lost, throttled, or only partially confirmed.
The Three Rules
Every safe broker adapter implementation encodes the same three invariants. Breaking any one of them leads to ghost orders, missed fills, or duplicate entries that the engine has no way to reconcile.Rule 1 — No resting orders on a transient throw
A transient throw must never leave an order resting on the exchange. Before throwing, cancel the unfilled order and market-out any partial fill. Every “will retry” that leaves a live order on the book risks that order filling on its own later — the engine will know nothing about it, and the position will be silently orphaned.
Rule 2 — Reconcile by clientOrderId on retry
payload.attempt > 0 means the previous attempt may have reached the exchange. The engine passes attempt for exactly this reason. Before posting again, look up the order by origClientOrderId = signalId. A lost response to a filled order must resolve to “already bought”, not to a second buy. Note: Binance’s duplicate-clientOrderId guard only covers open orders — an instantly filled order would not be deduplicated, so you cannot rely on the exchange to block the double-send.Rule 3 — The fifth attempt is terminal
The engine’s default retry budget is
CC_ORDER_OPEN_RETRY_ATTEMPTS = 5, so attempt arrives as 0–4 and attempt === 4 is the last try. On that attempt: cancel the order, market-sell whatever was actually bought (executedQty), and throw OrderRejectedError. The terminal rejection causes the engine to consume the signal id into lastPendingId so the signal is never re-issued. A plain Error is treated as transient and the engine keeps retrying.Key Constants
These five constants appear throughout both hooks and govern the timing and safety margins of every order lifecycle:FILL_POLL_ATTEMPTS × FILL_POLL_INTERVAL_MS gives a ~100-second window before the timeout path triggers Rule 1. CANCEL_ROUNDS applies to both the cancel sweep loop and the verify loop in onOrderCloseCommit — each runs up to 10 iterations independently. TRADE_SELL_LOWER_PERCENT nudges the limit sell price 0.1% below market so it crosses the book faster without resorting immediately to a market order.
Required Imports
Every broker adapter file starts with these three import lines.backtest-kit supplies the engine types and error class; functools-kit provides the memoize and sleep helpers used throughout the order lifecycle; node-binance-api is the Binance REST client:
Adapter Skeleton
The full adapter extendsBrokerBase, overrides the two commit hooks, and registers itself with the engine in two lines. waitForInit is the recommended place to eagerly warm the Binance client singleton and run any startup orphan sweep:
BrokerBase provides safe no-op defaults for every hook not overridden — only the two commit methods need custom logic for a minimal working adapter.
Explore the Implementation
Order Open
Full walkthrough of
onOrderOpenCommit: backtest guard, clientOrderId reconcile, limit placement, fill polling, and terminal rejection.Order Close
Full walkthrough of
onOrderCloseCommit: cancel all open orders, verify clean book, sell entire free coin balance including orphan tranches.Testing
Use the
--brokerdebug CLI flag to dry-fire any single hook against the live adapter before waiting for a real signal.clientOrderId Reconcile
Deep dive into the idempotency anchor — how
signalId as clientOrderId makes retry reconciliation safe across lost responses.