placeOrder
Execute buy or sell orders on Bitget cryptocurrency exchange, automatically handling spot and futures trading with market or limit order types.
Instructions
Place a new buy or sell order (automatically detects spot vs futures)
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| symbol | Yes | Trading pair symbol (e.g., BTCUSDT for spot, BTCUSDT_UMCBL for futures) | |
| side | Yes | Order side | |
| type | Yes | Order type | |
| quantity | Yes | Order quantity (in base currency for spot, in contracts for futures) | |
| price | No | Order price (required for limit orders) | |
| timeInForce | No | Time in force | |
| clientOrderId | No | Client order ID | |
| reduceOnly | No | Reduce only flag for futures | |
| marginMode | No | Margin mode for futures (default: crossed) | |
| marginCoin | No | Margin coin for futures (default: USDT) |
Implementation Reference
- src/server.ts:381-398 (handler)MCP tool handler for placeOrder: validates input with PlaceOrderSchema, detects spot/futures, delegates to BitgetRestClient.placeOrder, and returns result.case 'placeOrder': { const orderParams = PlaceOrderSchema.parse(args); console.error('Received placeOrder request:', JSON.stringify(orderParams, null, 2)); // Determine if this is a futures order const isFutures = orderParams.symbol.includes('_UMCBL') || orderParams.symbol.includes('_'); console.error(`Order type detected: ${isFutures ? 'futures' : 'spot'}`); const order = await this.bitgetClient.placeOrder(orderParams); return { content: [ { type: 'text', text: `Order placed successfully (${isFutures ? 'futures' : 'spot'}):\\n${JSON.stringify(order, null, 2)}`, }, ], } as CallToolResult; }
- src/types/mcp.ts:38-49 (schema)Zod schema defining input validation for placeOrder tool parameters.export const PlaceOrderSchema = z.object({ symbol: z.string().describe('Trading pair symbol'), side: z.enum(['buy', 'sell']).describe('Order side'), type: z.enum(['market', 'limit']).describe('Order type'), quantity: z.string().describe('Order quantity'), price: z.string().optional().describe('Order price (required for limit orders)'), timeInForce: z.enum(['GTC', 'IOC', 'FOK']).optional().describe('Time in force'), clientOrderId: z.string().optional().describe('Client order ID'), reduceOnly: z.boolean().optional().describe('Reduce only flag for futures'), marginMode: z.enum(['crossed', 'isolated']).optional().describe('Margin mode for futures (default: crossed)'), marginCoin: z.string().optional().describe('Margin coin for futures (default: USDT)') });
- src/server.ts:162-179 (registration)Tool registration in MCP server's listTools response, defining name, description, and input schema.name: 'placeOrder', description: 'Place a new buy or sell order (automatically detects spot vs futures)', inputSchema: { type: 'object', properties: { symbol: { type: 'string', description: 'Trading pair symbol (e.g., BTCUSDT for spot, BTCUSDT_UMCBL for futures)' }, side: { type: 'string', enum: ['buy', 'sell'], description: 'Order side' }, type: { type: 'string', enum: ['market', 'limit'], description: 'Order type' }, quantity: { type: 'string', description: 'Order quantity (in base currency for spot, in contracts for futures)' }, price: { type: 'string', description: 'Order price (required for limit orders)' }, timeInForce: { type: 'string', enum: ['GTC', 'IOC', 'FOK'], description: 'Time in force' }, clientOrderId: { type: 'string', description: 'Client order ID' }, reduceOnly: { type: 'boolean', description: 'Reduce only flag for futures' }, marginMode: { type: 'string', enum: ['crossed', 'isolated'], description: 'Margin mode for futures (default: crossed)' }, marginCoin: { type: 'string', description: 'Margin coin for futures (default: USDT)' } }, required: ['symbol', 'side', 'type', 'quantity'] },
- src/api/rest-client.ts:539-645 (helper)Core implementation of placeOrder in BitgetRestClient: dispatches to spot or futures specific order placement methods using Bitget API.async placeOrder(params: OrderParams): Promise<Order> { if (this.isFuturesSymbol(params.symbol)) { return this.placeFuturesOrder(params); } else { return this.placeSpotOrder(params); } } /** * Place a spot order */ private async placeSpotOrder(params: OrderParams): Promise<Order> { const orderData: any = { symbol: params.symbol, side: params.side, orderType: params.type, size: params.quantity, // v2 API uses 'size' instead of 'quantity' }; if (params.type === 'limit' && params.price) { orderData.price = params.price; } if (params.timeInForce) { orderData.force = params.timeInForce; // v2 API uses 'force' instead of 'timeInForceValue' } else if (params.type === 'limit') { orderData.force = 'GTC'; // Default to GTC for limit orders } if (params.clientOrderId) { orderData.clientOid = params.clientOrderId; } const response = await this.request<any>('POST', '/api/v2/spot/trade/place-order', orderData, true); return { orderId: response.data.orderId, clientOrderId: response.data.clientOid, symbol: params.symbol, side: params.side, type: params.type, quantity: params.quantity, price: params.price, status: 'open', filled: '0', remaining: params.quantity, timestamp: Date.now(), updateTime: Date.now() }; } /** * Place a futures order */ private async placeFuturesOrder(params: OrderParams): Promise<Order> { // For v1 mix API, keep the _UMCBL suffix const futuresSymbol = params.symbol.includes('_UMCBL') ? params.symbol : `${params.symbol}_UMCBL`; // Use v2 API format for futures orders const orderData: any = { symbol: futuresSymbol.replace('_UMCBL', ''), // v2 API might not need suffix productType: 'USDT-FUTURES', marginCoin: 'USDT', marginMode: 'crossed', side: params.side, orderType: params.type, size: params.quantity, // For futures, this is in contracts }; if (params.type === 'limit' && params.price) { orderData.price = params.price; } if (params.timeInForce) { orderData.timeInForceValue = params.timeInForce; // v2 API uses timeInForceValue } else if (params.type === 'limit') { orderData.timeInForceValue = 'GTC'; // v2 API uses 'GTC' } if (params.clientOrderId) { orderData.clientOid = params.clientOrderId; } if (params.reduceOnly) { orderData.reduceOnly = params.reduceOnly; } console.error('Placing futures order with data:', JSON.stringify(orderData, null, 2)); // Try v2 API endpoint const response = await this.request<any>('POST', '/api/v2/mix/order/place-order', orderData, true); return { orderId: response.data.orderId, clientOrderId: response.data.clientOid, symbol: params.symbol, // Return original symbol with suffix side: params.side, type: params.type, quantity: params.quantity, price: params.price, status: 'open', filled: '0', remaining: params.quantity, timestamp: Date.now(), updateTime: Date.now() }; }