simulate_order
Simulate a buy or sell order on Buda.com using live ticker data to estimate fill price, fees, total cost, and slippage. No real order is placed.
Instructions
[DEPRECATED: prefer get_real_quotation for server-side accurate quotes] Simulates a buy or sell order on Buda.com using live ticker data — no order is placed. Returns estimated fill price, fee, total cost, and slippage vs mid-price. Omit 'price' for a market order simulation; supply 'price' for a limit order simulation. All outputs are labelled simulation: true — this tool never places a real order. Example: 'How much would it cost to buy 0.01 BTC on BTC-CLP right now?'
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| market_id | Yes | Market ID (e.g. 'BTC-CLP', 'ETH-BTC'). | |
| side | Yes | 'buy' or 'sell'. | |
| amount | Yes | Order size in base currency (e.g. BTC for BTC-CLP). | |
| price | No | Limit price in quote currency. Omit for a market order simulation. |
Implementation Reference
- src/tools/simulate_order.ts:49-155 (handler)Main handler function 'handleSimulateOrder' that executes the order simulation logic. Fetches ticker and market data via cache, computes estimated fill price, fee, total cost, and slippage vs mid-price. Supports both market (no price) and limit (with price) order simulation.
export async function handleSimulateOrder( args: SimulateOrderArgs, client: BudaClient, cache: MemoryCache, ): Promise<{ content: Array<{ type: "text"; text: string }>; isError?: boolean }> { const { market_id, side, amount, price } = args; const validationError = validateMarketId(market_id); if (validationError) { return { content: [{ type: "text", text: JSON.stringify({ error: validationError, code: "INVALID_MARKET_ID" }) }], isError: true, }; } try { const id = market_id.toLowerCase(); const [tickerData, marketData] = await Promise.all([ cache.getOrFetch<TickerResponse>( `ticker:${id}`, CACHE_TTL.TICKER, () => client.get<TickerResponse>(`/markets/${id}/ticker`), ), cache.getOrFetch<MarketResponse>( `market:${id}`, CACHE_TTL.MARKETS, () => client.get<MarketResponse>(`/markets/${id}`), ), ]); const ticker = tickerData.ticker; const market = marketData.market; const minAsk = parseFloat(ticker.min_ask[0]); const maxBid = parseFloat(ticker.max_bid[0]); const quoteCurrency = ticker.min_ask[1]; if (isNaN(minAsk) || isNaN(maxBid) || minAsk <= 0 || maxBid <= 0) { return { content: [ { type: "text", text: JSON.stringify({ error: "Unable to simulate: invalid or zero bid/ask values in ticker.", code: "INVALID_TICKER", }), }, ], isError: true, }; } const mid = (minAsk + maxBid) / 2; const takerFeeRate = parseFloat(market.taker_fee) / 100; const orderTypeAssumed = price !== undefined ? "limit" : "market"; let estimatedFillPrice: number; if (orderTypeAssumed === "market") { estimatedFillPrice = side === "buy" ? minAsk : maxBid; } else { // Limit order: fill at provided price if it crosses the spread, otherwise at limit price if (side === "buy") { estimatedFillPrice = price! >= minAsk ? minAsk : price!; } else { estimatedFillPrice = price! <= maxBid ? maxBid : price!; } } const grossValue = amount * estimatedFillPrice; const feeAmount = parseFloat((grossValue * takerFeeRate).toFixed(8)); const totalCost = side === "buy" ? parseFloat((grossValue + feeAmount).toFixed(8)) : parseFloat((grossValue - feeAmount).toFixed(8)); const slippageVsMidPct = parseFloat( (((estimatedFillPrice - mid) / mid) * 100).toFixed(4), ); const result = { simulation: true, market_id: ticker.market_id, side, amount, order_type_assumed: orderTypeAssumed, estimated_fill_price: parseFloat(estimatedFillPrice.toFixed(2)), price_currency: quoteCurrency, fee_amount: feeAmount, fee_currency: quoteCurrency, fee_rate_pct: parseFloat((takerFeeRate * 100).toFixed(3)), total_cost: totalCost, slippage_vs_mid_pct: slippageVsMidPct, mid_price: parseFloat(mid.toFixed(2)), }; return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }], }; } catch (err) { const msg = formatApiError(err); return { content: [{ type: "text", text: JSON.stringify(msg) }], isError: true, }; } } - src/tools/simulate_order.ts:42-47 (schema)TypeScript type 'SimulateOrderArgs' defining the input arguments: market_id, side (buy/sell), amount, and optional price.
type SimulateOrderArgs = { market_id: string; side: "buy" | "sell"; amount: number; price?: number; }; - src/tools/simulate_order.ts:8-40 (schema)Exported 'toolSchema' object containing the tool name ('simulate_order'), description (marking it deprecated in favor of get_real_quotation), and JSON Schema input definition.
export const toolSchema = { name: "simulate_order", description: "[DEPRECATED: prefer get_real_quotation for server-side accurate quotes] " + "Simulates a buy or sell order on Buda.com using live ticker data — no order is placed. " + "Returns estimated fill price, fee, total cost, and slippage vs mid-price. " + "Omit 'price' for a market order simulation; supply 'price' for a limit order simulation. " + "All outputs are labelled simulation: true — this tool never places a real order. " + "Example: 'How much would it cost to buy 0.01 BTC on BTC-CLP right now?'", inputSchema: { type: "object" as const, properties: { market_id: { type: "string", description: "Market ID (e.g. 'BTC-CLP', 'ETH-BTC').", }, side: { type: "string", description: "'buy' or 'sell'.", }, amount: { type: "number", description: "Order size in base currency (e.g. BTC for BTC-CLP).", }, price: { type: "number", description: "Limit price in quote currency. Omit for a market order simulation.", }, }, required: ["market_id", "side", "amount"], }, }; - src/tools/simulate_order.ts:157-180 (registration)Registration function that calls server.tool() with the schema, Zod-validated args, and the handler callback.
export function register(server: McpServer, client: BudaClient, cache: MemoryCache): void { server.tool( toolSchema.name, toolSchema.description, { market_id: z .string() .describe("Market ID (e.g. 'BTC-CLP', 'ETH-BTC')."), side: z .enum(["buy", "sell"]) .describe("'buy' or 'sell'."), amount: z .number() .positive() .describe("Order size in base currency (e.g. BTC for BTC-CLP)."), price: z .number() .positive() .optional() .describe("Limit price in quote currency. Omit for a market order simulation."), }, (args) => handleSimulateOrder(args, client, cache), ); } - src/validation.ts:7-16 (helper)Helper function 'validateMarketId' used by the handler to validate the market_id format (BASE-QUOTE with 2-10 alphanumeric chars per part).
export function validateMarketId(id: string): string | null { if (!MARKET_ID_RE.test(id)) { return ( `Invalid market ID. ` + `Expected format: BASE-QUOTE with 2–10 alphanumeric characters per part ` + `(e.g. "BTC-CLP", "ETH-BTC").` ); } return null; }