Skip to content

OrderRouter

github-actions[bot] edited this page Sep 21, 2026 · 1 revision

OrderRouter{docsify-ignore}

Kind: global class

OrderRouter{docsify-ignore}

a client for the ccxt order-routing service and a multi-venue execution engine for plans you build yourself. NOT an exchange: it does not extend Exchange, has no unified methods, and is constructed directly. The whole pipeline is two calls — fetchRoute, then execute

OrderRouter.OrderRouter ()

constructor{docsify-ignore}

creates a client for the CCXT order-router service

Kind: instance method of OrderRouter
Returns: OrderRouter - a router client

Param Type Required Description
config object Yes client configuration
config.apiKey string No optional. The router service is public and rate-limits by IP, so no key is needed; one supplied here is still sent as the x-api-key header, which a keyless server ignores
config.baseUrl string No router base url, defaults to https://docs.ccxt.com/router/api
config.venues object No exchangeId to a ccxt exchange instance. Routes are filtered to these, and execute sends orders to them
config.trackBalances bool No read those venues' wallets and route on what you can actually fund, default false. Off, fetchRoute never touches a venue and stays a single HTTP request
config.timeoutMs int No request timeout in milliseconds, defaults to 30000
config.maxNotionalUsd float No optional per-trade USD notional guardrail. Omitted or 0 means NO cap and no notional check at all; any positive value is honoured exactly, never clamped
OrderRouter.constructor (config)

fetchRoute{docsify-ignore}

asks the router how to convert one asset into another, over the venues and bridges it has live books for

Kind: instance method of OrderRouter
Returns: object - a RouteResult — an unroutable pair comes back as a RouteResult with an unroutableReason, not as an exception

See: https://docs.ccxt.com/router/api

Param Type Required Description
fromAsset string Yes the asset being spent, e.g. USDT
toAsset string Yes the asset being acquired, e.g. BTC
params object Yes request parameters
params.amountIn float No exact amount of fromAsset to spend — supply this OR amountOut, never both
params.amountOut float No exact amount of toAsset to acquire — supply this OR amountIn, never both
params.strategy string No best_single, split_optimal or split_capped
params.maxVenues int No per-hop venue cap for split_capped
params.exchanges string, Array<string> No venue allowlist
params.bridges string, Array<string> No intermediary assets to consider
params.balances string No what you hold, as [exchangeId.]ASSET:amount entries
params.balanceMode string No cap (default) or require
params.includeQuotes bool No return the per-venue diagnostic
params.includeFees bool No rank on fee-adjusted price, default true
params.certified bool No restrict to CCXT-certified venues
params.requireFullFill bool No refuse partial fills
params.hopPenaltyBps float No how much better a bridged route must be per extra hop
params.minLegNotional float No suppress legs below this quote notional
params.requestId string No a caller-chosen audit id, sent as the x-request-id header so your log and the router's decision log can be joined. The service mints one when this is absent, and caps it at 200 characters
params.requireBalancesApplied bool No when balances are sent, throw unless the router echoed that it read them. Default true — a server that predates the feature IGNORES balances and answers byte-identically to one that never received any
OrderRouter.fetchRoute (fromAsset, toAsset, params)

fetchHealth{docsify-ignore}

liveness only — answers 200 from the first millisecond of boot, before a single venue has connected. Use fetchReadiness to decide whether the router can actually price anything

Kind: instance method of OrderRouter
Returns: object - status and uptimeSec

See: https://docs.ccxt.com/router/openapi.yaml // GET /health

OrderRouter.fetchHealth ()

fetchReadiness{docsify-ignore}

whether the router has enough fresh books to rank on, measured with the same staleness cutoff /route uses. NOT_READY IS A NORMAL ANSWER: the service replies 503 with the same body it returns on 200, and this method returns it rather than throwing, because a caller asking "are you ready" needs the counts that say why not

Kind: instance method of OrderRouter
Returns: object - status (ready or not_ready), bookCount, freshCount, staleCount, minFreshBooksForReady and staleBookMs

See: https://docs.ccxt.com/router/openapi.yaml // GET /ready

OrderRouter.fetchReadiness ()

fetchVersion{docsify-ignore}

build provenance of the running process. This is what a deploy pipeline asserts against — health answers 200 from the OLD process just as happily when a deploy silently no-ops, and commit is the only field that tells the two apart

Kind: instance method of OrderRouter
Returns: object - version, commit, commitShort, builtAt, builtBy, startedAt and uptimeSec

See: https://docs.ccxt.com/router/openapi.yaml // GET /version

OrderRouter.fetchVersion ()

fetchSymbols{docsify-ignore}

the unified symbols the router currently holds a cached book for. A pair absent from this list cannot be routed no matter how it is spelled

Kind: instance method of OrderRouter
Returns: Array<string> - the cached symbols

See: https://docs.ccxt.com/router/openapi.yaml // GET /symbols

OrderRouter.fetchSymbols ()

fetchExchangesStatus{docsify-ignore}

per-venue connection health. A venue can hold an open socket while its subscription is silently dead, so read the per-venue update age and not only the connected flag

Kind: instance method of OrderRouter
Returns: Array<object> - one health record per venue

See: https://docs.ccxt.com/router/openapi.yaml // GET /exchanges/status

OrderRouter.fetchExchangesStatus ()

fetchCachedOrderBook{docsify-ignore}

the router's own cached L2 book for one venue and symbol — the exact depth a route was ranked on, which is what makes a surprising route auditable

Kind: instance method of OrderRouter
Returns: object - the cached book

See: https://docs.ccxt.com/router/openapi.yaml // GET /orderbook/{exchange}/{symbol}

Param Type Description
exchangeId string the venue, e.g. binance
symbol string the unified symbol, e.g. BTC/USDT
OrderRouter.fetchCachedOrderBook (exchangeId, symbol)

watchRoute{docsify-ignore}

the same route as fetchRoute, pushed over a websocket whenever any market it depends on moves. Every leg of every candidate path is watched, so a bridged route does not miss half the price changes that alter its answer. BLOCKS until the stream ends: the hook is how you read it

Kind: instance method of OrderRouter
Returns: object - the last route seen, or an empty dict if the stream ended before any frame

See: https://docs.ccxt.com/router/openapi.yaml // GET /stream/route

Param Type Description
fromAsset string the asset being spent, e.g. USDT
toAsset string the asset being acquired, e.g. BTC
params object the same parameters fetchRoute accepts, EXCEPT balances and balanceMode, which this endpoint refuses — a socket outlives the holdings it was opened with
onRoute function called with each RouteResult as it arrives, stamped with the client-side keys fetchRoute stamps. Return 'stop' to close the socket cleanly and return; any other value keeps watching. It runs between frames, so do no slow work in it — the service pushes up to ten times a second
OrderRouter.watchRoute (fromAsset, toAsset, params, onRoute)

fetchRouteWithBalances{docsify-ignore}

reads the live balances of the supplied venues, sends them to the router, and returns a route you can actually fund

Kind: instance method of OrderRouter
Returns: object - the RouteResult, with the client-side keys balancesUsed and balancesDropped added

Param Type Required Description
fromAsset string Yes the asset being spent
toAsset string Yes the asset being acquired
venues object No a dictionary of exchangeId to a ccxt exchange instance; defaults to the venues the router was constructed with
params object Yes the same parameters fetchRoute accepts, minus balances which this method builds
params.requireBalancesApplied bool No throw when the router did not echo balancesApplied, default true
OrderRouter.fetchRouteWithBalances (fromAsset, toAsset, venues?, params)

loadBalances{docsify-ignore}

reads the venues' wallets once and caches the result, so a quote stays a single HTTP request. Called for you by fetchRoute; call it yourself to prime the cache at start-up, or with reload to refresh it

Kind: instance method of OrderRouter
Returns: string - the rendered balances string, empty when the router holds no venues

Param Type Required Description
reload bool No true re-reads the wallets even when they are already cached
OrderRouter.loadBalances (reload?)

invalidateBalances{docsify-ignore}

drops the cached balances, so the next quote re-reads the wallets. Called for you after any run that reached a venue

Kind: instance method of OrderRouter

OrderRouter.invalidateBalances ()

marketsOf{docsify-ignore}

loads each venue's markets and keys them by exchange id, which is the shape checkExecutionPlanSafety wants. execute does this for you; this is for calling the check yourself

Kind: instance method of OrderRouter
Returns: object - exchangeId to that venue's markets

Param Type Description
venues object a dictionary of exchangeId to a ccxt exchange instance
OrderRouter.marketsOf (venues)

renderBalances{docsify-ignore}

turns whatever a caller wrote for balances into the router's wire form. Accepts the rendered string itself, a list of entries, a per-venue wallet ({ mexc: { USDT: 100 } }) and a flat single-venue wallet ({ USDT: 100 })

Kind: instance method of OrderRouter
Returns: string - the [exchangeId.]ASSET:amount string the service reads

Param Type Description
value object, string the holdings, in any accepted shape
OrderRouter.renderBalances (value)

buildExecutionPlan{docsify-ignore}

turns a RouteResult into an ordered list of concrete orders. PURE — no I/O

Kind: instance method of OrderRouter
Returns: object - an execution plan

Param Type Required Description
route object Yes a RouteResult, ideally one fetchRoute returned so the request can be checked against the answer
options object No plan options
options.slippageBps float No how far the limit sits from the expected price, default 25
options.reconcileToleranceRatio float No the shortfall ratio reconcileExecutionStep halts on, default 0.02
OrderRouter.buildExecutionPlan (route, options?)

checkExecutionPlanSafety{docsify-ignore}

checks a plan against per-venue market rules and the hard per-trade USD notional cap. PURE — no I/O. A step that cannot be valued in USD BLOCKS; it is never skipped, because a cap that silently disappears when a rate is missing is not a cap

Kind: instance method of OrderRouter
Returns: Array<object> - the violations, each with stepIndex, code, blocking, actual, limit and a constant message. An empty array means the plan passed

Param Type Required Description
plan object Yes a plan from buildExecutionPlan
markets object Yes a dictionary of exchangeId to that exchange's markets dictionary, i.e. markets[exchangeId][symbol]
options object No check options
options.usdRates object No a dictionary of currency code to its USD price. USD itself is 1 implicitly; nothing else is assumed
options.maxNotionalUsd float No per-trade cap for this call, overriding the client's own in either direction. Omitted falls back to the client's; 0 or absent on both means no cap and no notional check
options.precisionMode string No tick_size (default) or decimal_places, matching the venue's precisionMode
OrderRouter.checkExecutionPlanSafety (plan, markets, options?)

reconcileExecutionStep{docsify-ignore}

compares what a step actually produced against what the route predicted, resizes every downstream hop, and returns the proceed-or-halt verdict. PURE — no I/O. The halt decision lives here rather than in the execution loop because it is a money decision, and six separate loops is six chances to omit it

Kind: instance method of OrderRouter
Returns: object - the verdict, with expectedOut, realisedOut, shortfall, shortfallRatio, scale, verdict, reason and resizedSteps

Param Type Description
plan object the plan, with any earlier resizes already applied to its steps
stepIndex int the step that just completed
realisedOut float what it actually produced, in that step's output asset — base for a buy, quote for a sell
OrderRouter.reconcileExecutionStep (plan, stepIndex, realisedOut)

buildUnwindPlan{docsify-ignore}

given a halted execution report, computes the reverse orders that sell each stranded residual back toward the original from-asset, on the venue that actually holds it. PURE — no I/O. NEVER automatic: the result carries requiresConfirmation and nothing in this class executes it

Kind: instance method of OrderRouter
Returns: object - the unwind plan, with steps[] in reverse execution order and unresolved[] for residuals that cannot be reversed

Param Type Description
report object an execution report from execute
OrderRouter.buildUnwindPlan (report)

execute{docsify-ignore}

executes a plan against live exchange instances. THE ONLY IMPURE METHOD, and IT PLACES ORDERS: calling it is the instruction, there is no permission flag beside it. Pass options.dryRun true to rehearse instead, which makes not one call against a venue

Kind: instance method of OrderRouter
Returns: object - an execution report with per-step results, openOrders, errors and the halt verdict

Param Type Required Description
plan object Yes a RouteResult from fetchRoute, a plan from buildExecutionPlan, or a caller-assembled plan of the same shape — this method never assumes it came from the routing service. A route is turned into a plan here, so the simple path is fetchRoute then execute; build the plan yourself when you want to inspect or change it first
venues object Yes a dictionary of exchangeId to a ccxt exchange instance
options object No execution options
options.strategy string No HOW the orders go out: sequential (the default), parallel_within_hop, limit_protected, best_effort or atomic_ish. Whether they go out at all is options.dryRun
options.slippageBps float No only when a route is passed: how far the limit sits from the expected price, default 25
options.reconcileToleranceRatio float No only when a route is passed: the shortfall ratio reconcileExecutionStep halts on, default 0.02
options.dryRun bool No exactly true rehearses: the plan is built, checked and reported on, and not one call is made against a venue. Anything else, including absent, PLACES ORDERS
options.usdRates object No currency code to USD price, required when live because the notional cap cannot be enforced without it
options.allowMarketOrders bool No permit a market order when the venue cannot do IOC, default false
options.maxOrders int No hard order-count cap, required by best_effort
options.acknowledgeDispersion bool No required by best_effort, which can leave you holding an unintended asset mix
options.orderTimeoutMs int No how long limit_protected leaves an order resting, default 20000
options.pollIntervalMs int No how often limit_protected checks a resting order, default 1000
options.orderParams object No extra params merged into every createOrder call
options.idempotencyKey string No the identity of this execution, required when the plan carries no requestId; it keys the re-execution guard, and OVERRIDES the plan's requestId when both are given
options.allowReexecution bool No must be exactly true to run a plan this instance has already executed live; the DEFAULT is refusal
options.retryFailedSteps int No how many times to re-place a step the venue DEFINITIVELY REJECTED, default 0. An outcome_unknown step is never retried at any setting: it may already be a live position, and re-placing it is the double-fill this class exists to prevent. The router sets no client order id, so a retry is a fresh order to the venue
options.retryDelayMs int No how long to wait before a retry, default 1000
options.onStep function No called after each step completes and reconciles, never mid-order, with one event object describing that step. Return 'halt' to stop the route cleanly (haltReason becomes halted_by_on_step); any other value continues. It can only STOP a route, never resume one already halted. Do NO network I/O here — it sits between orders on the money path. A hook that throws is recorded as on_step_hook_failed and the run continues, because losing the report would destroy the only account of orders that are already live
OrderRouter.execute (plan, venues, options?)

Clone this wiki locally