CCXT

Order Router

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,…

OrderRouter

Kind: global class

OrderRouter

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

creates a client for the CCXT order-router service

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

ParamTypeRequiredDescription
configobjectYesclient configuration
config.apiKeystringNooptional. 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.baseUrlstringNorouter base url, defaults to https://docs.ccxt.com/router/api
config.venuesobjectNoexchangeId to a ccxt exchange instance. Routes are filtered to these, and execute sends orders to them
config.trackBalancesboolNoread 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.timeoutMsintNorequest timeout in milliseconds, defaults to 30000
config.maxNotionalUsdfloatNooptional 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

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

ParamTypeRequiredDescription
fromAssetstringYesthe asset being spent, e.g. USDT
toAssetstringYesthe asset being acquired, e.g. BTC
paramsobjectYesrequest parameters
params.amountInfloatNoexact amount of fromAsset to spend — supply this OR amountOut, never both
params.amountOutfloatNoexact amount of toAsset to acquire — supply this OR amountIn, never both
params.strategystringNobest_single, split_optimal or split_capped
params.maxVenuesintNoper-hop venue cap for split_capped
params.exchangesstring, Array<string>Novenue allowlist
params.bridgesstring, Array<string>Nointermediary assets to consider
params.balancesstringNowhat you hold, as [exchangeId.]ASSET:amount entries
params.balanceModestringNocap (default) or require
params.includeQuotesboolNoreturn the per-venue diagnostic
params.includeFeesboolNorank on fee-adjusted price, default true
params.certifiedboolNorestrict to CCXT-certified venues
params.requireFullFillboolNorefuse partial fills
params.hopPenaltyBpsfloatNohow much better a bridged route must be per extra hop
params.minLegNotionalfloatNosuppress legs below this quote notional
params.requestIdstringNoa 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.requireBalancesAppliedboolNowhen 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

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

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

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

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

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

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}

ParamTypeDescription
exchangeIdstringthe venue, e.g. binance
symbolstringthe unified symbol, e.g. BTC/USDT
OrderRouter.fetchCachedOrderBook (exchangeId, symbol)

watchRoute

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

ParamTypeDescription
fromAssetstringthe asset being spent, e.g. USDT
toAssetstringthe asset being acquired, e.g. BTC
paramsobjectthe same parameters fetchRoute accepts, EXCEPT balances and balanceMode, which this endpoint refuses — a socket outlives the holdings it was opened with
onRoutefunctioncalled 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

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

ParamTypeRequiredDescription
fromAssetstringYesthe asset being spent
toAssetstringYesthe asset being acquired
venuesobjectNoa dictionary of exchangeId to a ccxt exchange instance; defaults to the venues the router was constructed with
paramsobjectYesthe same parameters fetchRoute accepts, minus balances which this method builds
params.requireBalancesAppliedboolNothrow when the router did not echo balancesApplied, default true
OrderRouter.fetchRouteWithBalances (fromAsset, toAsset, venues?, params)

loadBalances

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

ParamTypeRequiredDescription
reloadboolNotrue re-reads the wallets even when they are already cached
OrderRouter.loadBalances (reload?)

invalidateBalances

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

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

ParamTypeDescription
venuesobjecta dictionary of exchangeId to a ccxt exchange instance
OrderRouter.marketsOf (venues)

renderBalances

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

ParamTypeDescription
valueobject, stringthe holdings, in any accepted shape
OrderRouter.renderBalances (value)

buildExecutionPlan

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

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

ParamTypeRequiredDescription
routeobjectYesa RouteResult, ideally one fetchRoute returned so the request can be checked against the answer
optionsobjectNoplan options
options.slippageBpsfloatNohow far the limit sits from the expected price, default 25
options.reconcileToleranceRatiofloatNothe shortfall ratio reconcileExecutionStep halts on, default 0.02
OrderRouter.buildExecutionPlan (route, options?)

checkExecutionPlanSafety

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

ParamTypeRequiredDescription
planobjectYesa plan from buildExecutionPlan
marketsobjectYesa dictionary of exchangeId to that exchange's markets dictionary, i.e. markets[exchangeId][symbol]
optionsobjectNocheck options
options.usdRatesobjectNoa dictionary of currency code to its USD price. USD itself is 1 implicitly; nothing else is assumed
options.maxNotionalUsdfloatNoper-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.precisionModestringNotick_size (default) or decimal_places, matching the venue's precisionMode
OrderRouter.checkExecutionPlanSafety (plan, markets, options?)

reconcileExecutionStep

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

ParamTypeDescription
planobjectthe plan, with any earlier resizes already applied to its steps
stepIndexintthe step that just completed
realisedOutfloatwhat it actually produced, in that step's output asset — base for a buy, quote for a sell
OrderRouter.reconcileExecutionStep (plan, stepIndex, realisedOut)

buildUnwindPlan

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

ParamTypeDescription
reportobjectan execution report from execute
OrderRouter.buildUnwindPlan (report)

execute

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

ParamTypeRequiredDescription
planobjectYesa 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
venuesobjectYesa dictionary of exchangeId to a ccxt exchange instance
optionsobjectNoexecution options
options.strategystringNoHOW 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.slippageBpsfloatNoonly when a route is passed: how far the limit sits from the expected price, default 25
options.reconcileToleranceRatiofloatNoonly when a route is passed: the shortfall ratio reconcileExecutionStep halts on, default 0.02
options.dryRunboolNoexactly 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.usdRatesobjectNocurrency code to USD price, required when live because the notional cap cannot be enforced without it
options.allowMarketOrdersboolNopermit a market order when the venue cannot do IOC, default false
options.maxOrdersintNohard order-count cap, required by best_effort
options.acknowledgeDispersionboolNorequired by best_effort, which can leave you holding an unintended asset mix
options.orderTimeoutMsintNohow long limit_protected leaves an order resting, default 20000
options.pollIntervalMsintNohow often limit_protected checks a resting order, default 1000
options.orderParamsobjectNoextra params merged into every createOrder call
options.idempotencyKeystringNothe 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.allowReexecutionboolNomust be exactly true to run a plan this instance has already executed live; the DEFAULT is refusal
options.retryFailedStepsintNohow 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.retryDelayMsintNohow long to wait before a retry, default 1000
options.onStepfunctionNocalled 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?)

On this page