The live broker adapter inDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/theonetrade/ai-trading-mcp/llms.txt
Use this file to discover all available pages before exploring further.
modules/live.module.ts was written after a real post-mortem on a set of failure modes that a naïve ccxt wrapper exposes the moment it touches Binance spot. Every section of the module has a named cause. This page walks through the three commits that make up the methodology and explains the exact code behind each one.
The Three-Commit Methodology
Every order lifecycle is decomposed into exactly three atomic operations. Each commit solves one class of failure and the three compose cleanly — the output ofcommit_buy is the input precondition of commit_trade, and commit_cancel tears down whatever commit_trade assembled.
commit_buy
Guaranteed entry. A limit order is posted and polled. If the poll times out the order is cancelled (race condition handled) and a market top-up buys the remainder. The order never lingers on the book.
commit_trade
Atomic brackets. Take-profit and stop-loss are placed as a single OCO order — one freeze, not two independent sells. On spot, the first sell freezes the coins and the second dies with
InsufficientFunds.commit_cancel
Verified flat. A cancel sweep removes every open order for the symbol, a second verification loop confirms the book is empty, and then the entire free balance is sold. Orphan tranches are swept along.
Why Naïve Spot Adapters Fail
The table below (reproduced from the project README) maps each common adapter mistake to the exact Binance behaviour it triggers, and shows what the adapter does instead.| A naïve adapter does | What Binance actually does | This adapter |
|---|---|---|
| Places TP and SL as two independent sells | The first order freezes the coins, the second dies with InsufficientFunds — the cascade root | One OCO: TP + stop-limit SL in a single freeze |
Answers “is the position bought?” from free balance | After a successful entry the coins sit frozen inside the OCO, free ≈ 0 → it buys again (position doubling) | Checks free + used (fetchTotalQty) |
Retries the entry POST over a live NEW order | -2010 duplicate clientOrderId → terminal drop while your own order is still on the book | Cancel first (frees the id), then re-enter |
| Treats a failed cancel as a failure | The order filled between the last poll and the cancel (-2011) — that is a fill | cancelOrderSafe re-reads the order, returns "filled" |
| Market-sells the unwind qty directly | It tries to sell what its own TP order froze → the unwind itself fails, the raw error masks the verdict | Cancel-sweep → verify clean book → sell free balance; the original error always reaches the engine typed |
| Retries every error forever (or drops every error) | Network hiccups and exchange verdicts are different beasts | ccxt.NetworkError → OrderTransientError (bounded retry), ccxt.ExchangeError → OrderRejectedError (permanent) |
Guaranteed Entry (commit_buy)
The entry sequence is a limit order followed by a fill poll. If the poll times out, the order is cancelled with fill-race handling and a market order buys whatever quantity did not fill.cancelOrderSafe catches the -2011 error that Binance throws when a cancel races a fill. It re-fetches the order and returns "filled" rather than propagating an exception, so a real fill is never mistaken for a drop.buyLimitGuaranteed helper in the module wraps this loop with the FILL_POLL_INTERVAL_MS and FILL_POLL_ATTEMPTS constants. After the poll the CANCEL_SETTLE_MS pause lets the exchange settle before the filled quantity is re-read.
Idempotent Recovery
Reconciliation byclientOrderId = signalId runs unconditionally — not only on retries. This is a critical detail: after an engine revalidation, a fresh row of the same signal id can arrive with attempt = 0, and an attempt-guard would happily buy twice. For a new id the reconciliation costs exactly one call (-2013 → not found → post away).
Verified Close (commit_cancel)
The close sequence has three distinct phases executed in strict order.Cancel sweep
cancelSweepAndVerify iterates over all open orders for the symbol and cancels each one, retrying up to CANCEL_ROUNDS times. A per-order sleep(1_000) gives the exchange time to settle between individual cancels.Verify clean book
After the sweep a second loop re-fetches open orders and confirms the list is empty. Selling over a live sell order returns
InsufficientFunds — the verification loop catches this before the sell is attempted.Tuning Constants
All timing and pricing constants are declared at the top of the module so they can be adjusted without hunting through logic code.| Constant | Value | Why |
|---|---|---|
FILL_POLL_INTERVAL_MS × FILL_POLL_ATTEMPTS | 10 s × 10 | A limit entry gets ~100 s to fill before the market top-up fires |
CANCEL_SETTLE_MS | 2 s | Lets the exchange settle after a cancel before the filled quantity is re-read |
CANCEL_ROUNDS | 10 | Cancel-sweep retry budget when clearing the book on close |
STOP_LIMIT_SLIPPAGE | 0.995 | Stop-limit price parked just below the SL trigger to guarantee execution |
TRADE_SELL_LOWER_PERCENT | 0.999 | Close limit priced a hair under market to fill fast |
Error Classification
Every error that escapes a ccxt call is routed throughtoTypedError before it reaches the engine. The classification determines how the engine responds.
ccxt.NetworkError → OrderTransientError
Covers
RequestTimeout, ExchangeNotAvailable, DDoSProtection, and similar transient conditions. The engine retries with the same signalId — the idempotency logic above ensures no double-buy results.ccxt.ExchangeError → OrderRejectedError
Covers
InsufficientFunds, InvalidOrder, minimum-notional violations, and any other permanent business verdict from Binance. The engine drops the signal without retrying.Short positions are also classified as a permanent
OrderRejectedError — spot trading does not support shorts, so the adapter rejects them immediately without reaching the network.