get_price_history
Retrieve OHLCV candle history for any Buda market. Choose period (5m to 1d) and adjust trade count for depth.
Instructions
IMPORTANT: Candles are aggregated client-side from raw trades (Buda has no native candlestick endpoint) — fetching more trades via the 'limit' parameter gives deeper history but slower responses. Returns OHLCV candles (open/high/low/close as floats in quote currency; volume as float in base currency) for periods 5m, 15m, 30m, 1h, 4h, or 1d. Candle timestamps are UTC bucket boundaries. Example: 'Show me the hourly BTC-CLP price chart for the past 24 hours.'
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| market_id | Yes | Market ID (e.g. 'BTC-CLP', 'ETH-BTC'). | |
| period | No | Candle period: '5m', '15m', '30m', '1h', '4h', or '1d'. Default: '1h'. | 1h |
| limit | No | Raw trades to fetch before aggregation (default: 100, max: 1000). More trades = deeper history but slower response. |
Implementation Reference
- src/tools/price_history.ts:39-117 (handler)Handler function that registers the get_price_history tool. Fetches raw trades from Buda API (/markets/{id}/trades), then aggregates them client-side into OHLCV candles using aggregateTradesToCandles(). Validates market_id, accepts optional period (default 1h) and limit (default 100, max 1000).
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')."), period: z .enum(["5m", "15m", "30m", "1h", "4h", "1d"]) .default("1h") .describe("Candle period: '5m', '15m', '30m', '1h', '4h', or '1d'. Default: '1h'."), limit: z .number() .int() .min(1) .max(1000) .optional() .describe( "Raw trades to fetch before aggregation (default: 100, max: 1000). " + "More trades = deeper history but slower response.", ), }, async ({ market_id, period, limit }) => { try { const validationError = validateMarketId(market_id); if (validationError) { return { content: [{ type: "text", text: JSON.stringify({ error: validationError, code: "INVALID_MARKET_ID" }) }], isError: true, }; } const id = market_id.toLowerCase(); const tradesLimit = limit ?? 100; const data = await client.get<TradesResponse>( `/markets/${id}/trades`, { limit: tradesLimit }, ); const entries = data.trades.entries; if (entries.length === 0) { return { content: [ { type: "text", text: JSON.stringify({ market_id: market_id.toUpperCase(), period, candles: [] }), }, ], }; } const candles = aggregateTradesToCandles(entries, period); const result = { market_id: market_id.toUpperCase(), period, candle_count: candles.length, trades_fetched: entries.length, note: "Candles derived from raw trade history. Candle timestamps are UTC bucket boundaries. " + "Increase 'limit' (max 1000) for deeper history.", candles, }; 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/price_history.ts:9-37 (schema)Schema definition for get_price_history tool: name, description, and JSON Schema input with market_id (required string), period (optional string), and limit (optional number).
export const toolSchema = { name: "get_price_history", description: "IMPORTANT: Candles are aggregated client-side from raw trades (Buda has no native candlestick " + "endpoint) — fetching more trades via the 'limit' parameter gives deeper history but slower " + "responses. Returns OHLCV candles (open/high/low/close as floats in quote currency; volume as float " + "in base currency) for periods 5m, 15m, 30m, 1h, 4h, or 1d. Candle timestamps are UTC bucket boundaries. " + "Example: 'Show me the hourly BTC-CLP price chart for the past 24 hours.'", inputSchema: { type: "object" as const, properties: { market_id: { type: "string", description: "Market ID (e.g. 'BTC-CLP', 'ETH-BTC').", }, period: { type: "string", description: "Candle period: '5m', '15m', '30m', '1h', '4h', or '1d'. Default: '1h'.", }, limit: { type: "number", description: "Raw trades to fetch before aggregation (default: 100, max: 1000). " + "More trades = deeper history but slower response.", }, }, required: ["market_id"], }, }; - src/index.ts:43-43 (registration)Registration of the get_price_history tool in the main entrypoint (stdio server).
priceHistory.register(server, client, cache); - src/http.ts:88-88 (registration)Registration of the get_price_history tool in the HTTP/Express server entrypoint.
priceHistory.register(server, client, reqCache); - src/utils.ts:61-100 (helper)Helper function that aggregates raw trade entries into OHLCV candles for a given period. Sorts trades, buckets by period boundaries, and computes open/high/low/close/volume per bucket.
export function aggregateTradesToCandles( entries: [string, string, string, string][], period: string, ): OhlcvCandle[] { const periodMs = PERIOD_MS[period]; if (!periodMs) throw new Error(`Unknown period: ${period}`); const sorted = [...entries].sort(([a], [b]) => parseInt(a, 10) - parseInt(b, 10)); const buckets = new Map<number, OhlcvCandle>(); for (const [tsMs, amount, price] of sorted) { const ts = parseInt(tsMs, 10); const bucketStart = Math.floor(ts / periodMs) * periodMs; const p = parseFloat(price); const v = parseFloat(amount); if (!buckets.has(bucketStart)) { buckets.set(bucketStart, { time: new Date(bucketStart).toISOString(), open: p, high: p, low: p, close: p, volume: v, trade_count: 1, }); } else { const candle = buckets.get(bucketStart)!; if (p > candle.high) candle.high = p; if (p < candle.low) candle.low = p; candle.close = p; candle.volume = parseFloat((candle.volume + v).toFixed(8)); candle.trade_count++; } } return Array.from(buckets.entries()) .sort(([a], [b]) => a - b) .map(([, candle]) => candle); }