The backtest-kit runtime is assembled from three schema registrations: one for the strategy callbacks, one for the exchange adapter, and one for the MCP feed renderer. Each registration is a single function call. The default strategy in this project uses exactly this pattern and keeps the signal-generation side completely empty — giving you a clean slate to build on.Documentation 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.
The Deliberately Empty Default Strategy
content/manual.strategy/manual.strategy.ts registers no entry logic whatsoever. The three callbacks exist only to log events to stdout. Entries happen only when the agent calls open_position; the engine owns every level, limit, and validation.
The callbacks are for logging and monitoring — they are not the place to generate entry signals. To open a position programmatically from within a strategy, call the engine’s signal API directly. For agent-driven trading the callbacks remain empty and the agent calls
open_position through the MCP tools.addStrategySchema API
addStrategySchema registers the strategy’s name and lifecycle hooks. The engine calls the appropriate callback each time a position transitions state for any symbol in the whitelist.
onOpen(symbol, signal, currentPrice)
onOpen(symbol, signal, currentPrice)
Called once when a position is confirmed open.
| Parameter | Type | Description |
|---|---|---|
symbol | string | The trading pair, e.g. "BTCUSDT" |
signal.priceOpen | number | Actual entry price recorded by the engine |
signal.priceStopLoss | number | Engine-computed stop-loss level |
signal.priceTakeProfit | number | Engine-computed take-profit level |
signal.position | "long" | "short" | Direction of the trade |
currentPrice | number | Last candle close at the time of the callback |
onClose(symbol, signal, currentPrice)
onClose(symbol, signal, currentPrice)
Called once when a position is confirmed closed (take-profit hit, stop-loss hit, or manual close via
close_position).| Parameter | Type | Description |
|---|---|---|
symbol | string | The trading pair |
signal.priceOpen | number | Original entry price |
signal.priceStopLoss | number | Stop-loss level at close time |
signal.priceTakeProfit | number | Take-profit level at close time |
signal.position | "long" | "short" | Direction of the trade |
currentPrice | number | Price at which the close was confirmed |
onActivePing(symbol, signal, currentPrice)
onActivePing(symbol, signal, currentPrice)
Called on every engine tick while a position is open. Use this for trailing-stop logic, monitoring, or external notifications — not for opening new positions.
| Parameter | Type | Description |
|---|---|---|
symbol | string | The trading pair |
signal.priceOpen | number | Original entry price |
signal.priceStopLoss | number | Current stop-loss level |
signal.priceTakeProfit | number | Current take-profit level |
signal.position | "long" | "short" | Direction of the trade |
currentPrice | number | Current candle close |
addExchangeSchema API
addExchangeSchema registers the market-data and order-execution adapter for a named exchange. The engine calls the data functions on every tick; the commit hooks are called only when a real order needs to be placed.
Paper mode
In paper mode the engine simulates fills internally —onOrderOpenCommit and onOrderCloseCommit are not needed. The paper module (modules/paper.module.ts and content/manual.strategy/modules/paper.module.ts) registers only the data side:
Live mode
In live mode,onOrderOpenCommit and onOrderCloseCommit implement the actual broker calls. The live module (modules/live.module.ts) adds a Broker.useBrokerAdapter class on top of the same data registration. See the Live Broker page for the full methodology.
addMCPSchema API
addMCPSchema registers the hook that composes what the model sees on every get_status call. In this project it is wired in packages/agent/src/config/setup.ts:
getMessages returns an array of MCP content blocks — text and image blocks. StatusControllerService composes three sources:
- Default engine messages — portfolio snapshot, open positions, unrealized PnL.
- Command history — previous
open_position/close_positioncalls and their outcomes. - Telegram feed — the last 15 posts from the configured channel as text blocks, with chart screenshots as MCP image blocks.
queued() so concurrent get_status calls line up rather than stampede the Telegram client.
Project Layout for Custom Strategies
Create a strategy folder under content/
session.txt, dump/mcp/, dump/images/, and dump/report/ all resolve relative to it.Register your schema in the strategy entry point
Import the exchange module, then call
addStrategySchema. Both registrations happen at module load time before the engine starts.How the runtime resolves modules
config/loader.config.ts imports @pro/agent and @pro/main into the CLI runtime at startup:
config/alias.config.ts maps the @pro/* aliases to the built package outputs:
npm run build after any change to packages/agent or packages/main — the CLI loads the compiled .cjs files, not the TypeScript sources.