start_grid_strategy
Calculate and place grid trading orders around current prices to automate market making strategies on supported cryptocurrency exchanges.
Instructions
Calculate and optionally place grid trading orders around the current price
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| exchange | Yes | Exchange to query. Supported: mexc, gateio, bitget, kraken | |
| symbol | Yes | Trading pair symbol (e.g., BTC/USDT, INDY/USDT) | |
| levels | No | Grid levels per side (default: 5) | |
| spacing | No | Base spacing as decimal (default: 0.02 = 2%) | |
| orderSize | No | Base order size in quote currency (default: 50) | |
| spacingModel | No | Spacing model | linear |
| spacingFactor | No | Factor for geometric spacing (default: 1.3) | |
| sizeModel | No | Size model | flat |
| dryRun | No | Preview grid without placing orders (default: true) |
Implementation Reference
- src/tools/strategy.ts:88-163 (handler)The main handler function for start_grid_strategy tool. It validates exchange and symbol parameters, fetches the current ticker price, calculates grid levels, optionally places orders based on dryRun flag, and returns a detailed response with grid configuration, calculated levels, and order results.
async ({ exchange, symbol, levels, spacing, orderSize, spacingModel, spacingFactor, sizeModel, dryRun, }) => { const validExchange = validateExchange(exchange); const validSymbol = validateSymbol(symbol); const connector = await getConnectorSafe(exchange); const ticker = await connector.getTicker(validSymbol); const centerPrice = ticker.last; const grid = calculateGridLevels( centerPrice, levels, spacing, spacingModel, spacingFactor, orderSize, sizeModel ); const placedOrders: any[] = []; if (!dryRun) { for (const level of grid) { const order = await connector.createOrder( validSymbol, 'limit', level.side, level.orderSize, level.price ); placedOrders.push(order); } } return { content: [ { type: 'text' as const, text: JSON.stringify( { status: dryRun ? 'preview' : 'active', centerPrice, config: { levels, spacing, spacingModel, spacingFactor, orderSize, sizeModel }, grid: grid.map((l) => ({ side: l.side, price: l.price, amount: l.orderSize, valueQuote: l.price * l.orderSize, })), totalOrders: grid.length, totalBuyValue: grid .filter((l) => l.side === 'buy') .reduce((s, l) => s + l.price * l.orderSize, 0), totalSellValue: grid .filter((l) => l.side === 'sell') .reduce((s, l) => s + l.price * l.orderSize, 0), ...(dryRun ? {} : { placedOrders }), exchange: validExchange, symbol: validSymbol, timestamp: new Date().toISOString(), }, null, 2 ), }, ], }; } - src/tools/strategy.ts:62-87 (schema)Zod schema definition for start_grid_strategy tool parameters. Defines validation rules for exchange, symbol, levels, spacing, orderSize, spacingModel, spacingFactor, sizeModel, and dryRun parameters with appropriate constraints and defaults.
exchange: ExchangeParam, symbol: SymbolParam, levels: z.number().min(1).max(10).default(5).describe('Grid levels per side (default: 5)'), spacing: z .number() .min(0.001) .max(0.5) .default(0.02) .describe('Base spacing as decimal (default: 0.02 = 2%)'), orderSize: z .number() .positive() .default(50) .describe('Base order size in quote currency (default: 50)'), spacingModel: z.enum(['linear', 'geometric']).default('linear').describe('Spacing model'), spacingFactor: z .number() .positive() .default(1.3) .describe('Factor for geometric spacing (default: 1.3)'), sizeModel: z.enum(['flat', 'pyramidal']).default('flat').describe('Size model'), dryRun: z .boolean() .default(true) .describe('Preview grid without placing orders (default: true)'), }, - src/tools/strategy.ts:57-164 (registration)Registration of start_grid_strategy tool with the MCP server. The registerStrategyTools function calls server.tool() with the tool name, description, schema, and handler function to register it as an available MCP tool.
export function registerStrategyTools(server: McpServer): void { server.tool( 'start_grid_strategy', 'Calculate and optionally place grid trading orders around the current price', { exchange: ExchangeParam, symbol: SymbolParam, levels: z.number().min(1).max(10).default(5).describe('Grid levels per side (default: 5)'), spacing: z .number() .min(0.001) .max(0.5) .default(0.02) .describe('Base spacing as decimal (default: 0.02 = 2%)'), orderSize: z .number() .positive() .default(50) .describe('Base order size in quote currency (default: 50)'), spacingModel: z.enum(['linear', 'geometric']).default('linear').describe('Spacing model'), spacingFactor: z .number() .positive() .default(1.3) .describe('Factor for geometric spacing (default: 1.3)'), sizeModel: z.enum(['flat', 'pyramidal']).default('flat').describe('Size model'), dryRun: z .boolean() .default(true) .describe('Preview grid without placing orders (default: true)'), }, async ({ exchange, symbol, levels, spacing, orderSize, spacingModel, spacingFactor, sizeModel, dryRun, }) => { const validExchange = validateExchange(exchange); const validSymbol = validateSymbol(symbol); const connector = await getConnectorSafe(exchange); const ticker = await connector.getTicker(validSymbol); const centerPrice = ticker.last; const grid = calculateGridLevels( centerPrice, levels, spacing, spacingModel, spacingFactor, orderSize, sizeModel ); const placedOrders: any[] = []; if (!dryRun) { for (const level of grid) { const order = await connector.createOrder( validSymbol, 'limit', level.side, level.orderSize, level.price ); placedOrders.push(order); } } return { content: [ { type: 'text' as const, text: JSON.stringify( { status: dryRun ? 'preview' : 'active', centerPrice, config: { levels, spacing, spacingModel, spacingFactor, orderSize, sizeModel }, grid: grid.map((l) => ({ side: l.side, price: l.price, amount: l.orderSize, valueQuote: l.price * l.orderSize, })), totalOrders: grid.length, totalBuyValue: grid .filter((l) => l.side === 'buy') .reduce((s, l) => s + l.price * l.orderSize, 0), totalSellValue: grid .filter((l) => l.side === 'sell') .reduce((s, l) => s + l.price * l.orderSize, 0), ...(dryRun ? {} : { placedOrders }), exchange: validExchange, symbol: validSymbol, timestamp: new Date().toISOString(), }, null, 2 ), }, ], }; } ); - src/tools/strategy.ts:12-55 (helper)Helper function calculateGridLevels that computes buy and sell grid levels around a center price. Supports linear or geometric spacing models and flat or pyramidal size models to determine order distribution.
function calculateGridLevels( centerPrice: number, levels: number, spacing: number, spacingModel: 'linear' | 'geometric', spacingFactor: number, orderSize: number, sizeModel: 'flat' | 'pyramidal' ): GridLevel[] { const spacings: number[] = []; for (let i = 1; i <= levels; i++) { if (spacingModel === 'geometric') { let cumulative = 0; for (let j = 0; j < i; j++) { cumulative += spacing * Math.pow(spacingFactor, j); } spacings.push(cumulative); } else { spacings.push(spacing * i); } } const weights: number[] = []; if (sizeModel === 'pyramidal') { const raw = Array.from({ length: levels }, (_, i) => levels - i); const sum = raw.reduce((a, b) => a + b, 0); const norm = levels / sum; raw.forEach((w) => weights.push(w * norm)); } else { for (let i = 0; i < levels; i++) weights.push(1.0); } const grid: GridLevel[] = []; for (let i = 0; i < spacings.length; i++) { const buyPrice = centerPrice * (1 - spacings[i]); const sellPrice = centerPrice * (1 + spacings[i]); const size = orderSize * weights[i]; grid.push({ price: buyPrice, side: 'buy', orderSize: size / buyPrice }); grid.push({ price: sellPrice, side: 'sell', orderSize: size / sellPrice }); } return grid; } - src/utils/validators.ts:3-7 (schema)Zod schema definitions for ExchangeParam and SymbolParam used by the start_grid_strategy tool for parameter validation.
export const ExchangeParam = z .string() .describe('Exchange to query. Supported: mexc, gateio, bitget, kraken'); export const SymbolParam = z.string().describe('Trading pair symbol (e.g., BTC/USDT, INDY/USDT)');