Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/backtest-kit/ai-trading-mcp/llms.txt

Use this file to discover all available pages before exploring further.

Live mode runs the same engine, the same MCP tools, and the same Telegram feed as paper mode — the only difference is that modules/live.module.ts replaces the paper broker with a hardened Binance spot adapter that places real orders. Every open_position call routes to a real Binance account; fills, brackets, and closes all settle on-exchange.
Live mode places real orders with real money. Test your full setup — including at least one complete open/close cycle — in paper mode before switching. The engine cannot distinguish a bad signal from a good one; that judgement belongs to the agent and, ultimately, to you.
This adapter is spot-only. Futures, margin, and cross-margin are not supported. Attempting to open a short position will be rejected with a permanent OrderRejectedError at the broker level — spot has no native short mechanism.

Prerequisites

Set your Binance API credentials as environment variables before starting the process:
export BINANCE_API_KEY=your_key_here
export BINANCE_API_SECRET=your_secret_here
The live module reads these at startup via process.env. The authenticated spot client (getSpotExchange) is initialised lazily on the first order attempt — if the credentials are missing or invalid, the ccxt call will fail and the error will be typed and surfaced to the engine.

Launch Command

export BINANCE_API_KEY=your_key_here
export BINANCE_API_SECRET=your_secret_here
npm start -- --live --entry ./content/manual.strategy/manual.strategy.ts --ui
Flags work identically to paper mode: --live activates the spot broker adapter, --entry points to the strategy file, and --ui serves the dashboard on port 60050. The MCP HTTP bridge starts on 127.0.0.1:60051 as usual.

What Changes vs Paper Mode

ComponentPaperLive
Exchange modulemodules/paper.module.tsmodules/live.module.ts
Market data clientPublic ccxt Binance (no auth)Public ccxt Binance (no auth)
Order execution clientNone — fills simulatedAuthenticated ccxt Binance spot
Broker adapterEngine-internal simulationBroker.useBrokerAdapter(...)
API credentials neededNoYes
Real money at riskNoYes
The engine, the MCP tools, the Telegram scraper, the audit trail, and the dashboard are unchanged.

Exchange Setup in the Live Module

The live module registers the same ccxt-exchange schema for market data as paper mode — a public client for candles, order book, and price formatting:
const getExchange = singleshot(async () => {
  const exchange = new ccxt.binance({
    options: {
      defaultType: "spot",
      adjustForTimeDifference: true,
      recvWindow: 60000,
    },
    enableRateLimit: true,
  });
  await exchange.loadMarkets();
  return exchange;
});
A second, authenticated getSpotExchange client — initialized with BINANCE_API_KEY and BINANCE_API_SECRET — handles all order operations exclusively inside the broker adapter. Market data and order execution are intentionally separate clients.

The Spot Broker Adapter

The live module installs a battle-tested spot broker via Broker.useBrokerAdapter(). It was written after a real incident post-mortem and addresses the failure modes that naive spot adapters trip over on Binance.
1

commit_buy — Guaranteed Entry

A limit buy is posted with clientOrderId = signalId. The adapter polls up to 10 × 10 seconds for a fill. If the order hasn’t filled at the deadline, it cancels (handling the fill-at-cancel-time race correctly) and tops up any unfilled remainder with a market order. The entry is guaranteed to complete; no resting order is ever left on the book.
const order = await exchange.createOrder(symbol, "limit", "buy", qty, price, { clientOrderId: signalId });
// poll up to 10 × 10 s …
if (last.status !== "closed") {
  if (await cancelOrderSafe(exchange, order.id, symbol) === "filled") return;
  const final = await exchange.fetchOrder(order.id, symbol);
  const remainder = truncateQty(exchange, symbol, qty - (final.filled ?? 0));
  if (remainder > 0) await exchange.createOrder(symbol, "market", "buy", remainder);
}
2

commit_trade — OCO Brackets

Take-profit and stop-loss are placed as a single OCO order (privatePostOrderOco), not as two independent sell orders. Two independent sells against the same coin balance on Binance spot is the root cause of InsufficientFunds cascade failures — the first sell freezes the coins, the second dies. One OCO = one freeze, both levels atomically guarded.
3

Idempotent Recovery via clientOrderId

Before every entry attempt, the adapter queries Binance by origClientOrderId = signalId. If a prior POST already executed (crash before brackets, lost network response), the adapter checks free + used balance (not just free — coins inside an OCO freeze show free ≈ 0) and skips the buy entirely if the position is confirmed. If a prior order is still NEW or PARTIALLY_FILLED, it cancels first (freeing the clientOrderId) before re-entering.
const prior = await fetchEntryByClientId(exchange, symbol, signalId);
if (prior && prior.executedQty > 0) {
  const totalQty = await fetchTotalQty(exchange, symbol); // free + used!
  if (totalQty * openPrice >= minNotional) {
    if (!(await exchange.fetchOpenOrders(symbol)).length) await confirmWithBrackets();
    return; // entry confirmed — do NOT buy again
  }
}
4

commit_cancel — Verified Close

On close, the adapter runs a cancel sweep across all open orders for the symbol (up to 10 rounds, 1 s between each cancel). It then runs a second verification loop that proves the book is empty before selling — selling over a live sell order causes InsufficientFunds. Finally it sells the entire free balance of the base asset, sweeping any orphaned tranches along. Dust below minNotional is treated as a confirmed close.

Adapter Tuning Constants

ConstantValueMeaning
FILL_POLL_INTERVAL_MS × FILL_POLL_ATTEMPTS10 s × 10Limit entry gets ~100 s to fill before the market top-up fires
CANCEL_SETTLE_MS2 sWait after cancel before re-reading filled quantity
CANCEL_ROUNDS10Cancel-sweep retries when clearing the book on close
STOP_LIMIT_SLIPPAGE0.995Stop-limit price parked 0.5 % below the SL trigger
TRADE_SELL_LOWER_PERCENT0.999Close limit priced 0.1 % under market to fill fast

Error Classification

The adapter maps ccxt exceptions to engine-typed errors so the engine can decide retry policy:
  • ccxt.NetworkErrorOrderTransientError — bounded retry with the same signalId
  • ccxt.ExchangeErrorOrderRejectedError — permanent drop, no retry

What the Agent Does Not Control

Even in live mode, Claude’s vocabulary is exactly three tools. The following are engine-computed and cannot be overridden by the model, the prompt, or anything in the Telegram feed:
  • Position size — computed from engine-side cost configuration and available USDT balance (capped at 98 % of free USDT to leave room for fees)
  • Take-profit price — engine-computed at signal creation
  • Stop-loss price — engine-computed at signal creation
  • Symbol eligibility — enforced by CC_SYMBOL_LIST; any symbol outside the whitelist is rejected before the broker is ever called
For full details on the broker adapter internals, see the modules/live.module.ts source file.

Build docs developers (and LLMs) love