Repository navigation
OrderRouter
Kind: global class
- constructor
- fetchRoute
- fetchHealth
- fetchReadiness
- fetchVersion
- fetchSymbols
- fetchExchangesStatus
- fetchCachedOrderBook
- watchRoute
- fetchRouteWithBalances
- loadBalances
- invalidateBalances
- marketsOf
- renderBalances
- buildExecutionPlan
- checkExecutionPlanSafety
- reconcileExecutionStep
- buildUnwindPlan
- execute
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 ()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)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)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 ()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 ()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 ()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 ()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 ()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)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)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)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?)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 ()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)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)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?)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?)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)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)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?)(If the page is not being rendered for you, you can refer to the mirror at https://docs.ccxt.com/)
- Install
- Examples
- Manual
- CCXT Pro
- Contributing
- Supported Exchanges
- Exchanges By Country
- API Spec By Method
- Order Router
- FAQ
- Changelog
- Awesome
- API Spec by Exchange
- alpaca
- apex
- aster
- backpack
- bigone
- binance
- bingx
- bit2c
- bitbank
- bitbns
- bitfinex
- bitflyer
- bitget
- bithumb
- bitopro
- bitrue
- bitso
- bitstamp
- bitteam
- bittrade
- bitvavo
- blockchaincom
- blofin
- btcbox
- btcmarkets
- btcturk
- btse
- bullish
- bybit
- bydfi
- cex
- coinbase
- coinbaseexchange
- coinbaseinternational
- coincheck
- coinmate
- coinone
- coinsph
- coinspot
- cryptocom
- cryptomus
- deepcoin
- delta
- deribit
- derive
- digifinex
- dydx
- extended
- foxbit
- gate
- gemini
- grvt
- hashkey
- hibachi
- hitbtc
- hollaex
- htx
- hyperliquid
- independentreserve
- indodax
- kraken
- krakenfutures
- kucoin
- kucoinfutures
- latoken
- lbank
- lighter
- luno
- mercado
- mexc
- modetrade
- mudrex
- nado
- ndax
- okx
- onetrading
- p2b
- pacifica
- paradex
- paymium
- phemex
- poloniex
- polymarket
- revolutx
- tokocrypto
- toobit
- upbit
- weex
- whitebit
- woo
- woofipro
- xt
- zaif
- zebpay
- API Spec by Prediction Exchange