/** * Binance Account Tools * * - binance_get_account: Get account balance and status * - binance_get_open_orders: Get all open orders * * @version 1.0.0 * @author OrbiQuant Trading Platform */ import { z } from 'zod'; import { getBinanceClient, BinanceAccount, BinanceOrder } from '../services/binance-client'; // ========================================== // binance_get_account // ========================================== /** * Tool: binance_get_account * Get account balance and status */ export const binanceGetAccountSchema = { name: 'binance_get_account', description: 'Get Binance account balance and status. Shows all assets with non-zero balance.', inputSchema: { type: 'object' as const, properties: {}, required: [] as string[], }, }; export const BinanceGetAccountInputSchema = z.object({}); export type BinanceGetAccountInput = z.infer; export interface BinanceGetAccountResult { success: boolean; data?: BinanceAccount & { totalUsdtEstimate?: number }; error?: string; } export async function binance_get_account( _params: BinanceGetAccountInput ): Promise { try { const client = getBinanceClient(); if (!client.isConfigured()) { return { success: false, error: 'Binance API keys are not configured', }; } const connected = await client.isConnected(); if (!connected) { return { success: false, error: 'Cannot connect to Binance. Please check your network.', }; } const account = await client.getAccount(); // Estimate total value in USDT let totalUsdtEstimate = 0; for (const balance of account.balances) { if (balance.asset === 'USDT' || balance.asset === 'BUSD' || balance.asset === 'USDC') { totalUsdtEstimate += balance.total; } else if (balance.total > 0) { try { const price = await client.getCurrentPrice(`${balance.asset}USDT`); totalUsdtEstimate += balance.total * price; } catch { // Skip if no USDT pair exists } } } return { success: true, data: { ...account, totalUsdtEstimate, }, }; } catch (error) { return { success: false, error: error instanceof Error ? error.message : 'Unknown error occurred', }; } } export async function handleBinanceGetAccount( params: unknown ): Promise<{ content: Array<{ type: string; text: string }> }> { const validatedParams = BinanceGetAccountInputSchema.parse(params); const result = await binance_get_account(validatedParams); if (result.success && result.data) { const d = result.data; // Sort balances by total value const sortedBalances = [...d.balances].sort((a, b) => { // USDT first, then by total if (a.asset === 'USDT') return -1; if (b.asset === 'USDT') return 1; return b.total - a.total; }); let balancesStr = sortedBalances .slice(0, 20) // Top 20 assets .map((b) => { const lockedStr = b.locked > 0 ? ` (Locked: ${b.locked.toFixed(8)})` : ''; return ` ${b.asset.padEnd(8)} Free: ${b.free.toFixed(8)}${lockedStr}`; }) .join('\n'); const formattedOutput = ` Binance Account Information ${'='.repeat(35)} Account Type: ${d.accountType} Can Trade: ${d.canTrade ? 'Yes' : 'No'} Can Withdraw: ${d.canWithdraw ? 'Yes' : 'No'} Estimated Total Value --------------------- ~$${d.totalUsdtEstimate?.toFixed(2) ?? 'N/A'} USDT Asset Balances (${d.balances.length} with balance) ${'='.repeat(35)} ${balancesStr} ${d.balances.length > 20 ? `\n ... and ${d.balances.length - 20} more assets` : ''} Last Update: ${new Date(d.updateTime).toISOString()} `.trim(); return { content: [{ type: 'text', text: formattedOutput }], }; } return { content: [{ type: 'text', text: `Error: ${result.error}` }], }; } // ========================================== // binance_get_open_orders // ========================================== /** * Tool: binance_get_open_orders * Get all open (pending) orders */ export const binanceGetOpenOrdersSchema = { name: 'binance_get_open_orders', description: 'Get all open (pending) orders. Optionally filter by symbol.', inputSchema: { type: 'object' as const, properties: { symbol: { type: 'string', description: 'Optional: Filter by trading pair symbol (e.g., BTCUSDT)', }, }, required: [] as string[], }, }; export const BinanceGetOpenOrdersInputSchema = z.object({ symbol: z.string().min(1).max(20).transform((s) => s.toUpperCase()).optional(), }); export type BinanceGetOpenOrdersInput = z.infer; export interface BinanceGetOpenOrdersResult { success: boolean; data?: { orders: BinanceOrder[]; count: number; }; error?: string; } export async function binance_get_open_orders( params: BinanceGetOpenOrdersInput ): Promise { try { const client = getBinanceClient(); if (!client.isConfigured()) { return { success: false, error: 'Binance API keys are not configured', }; } const orders = await client.getOpenOrders(params.symbol); return { success: true, data: { orders, count: orders.length, }, }; } catch (error) { return { success: false, error: error instanceof Error ? error.message : 'Unknown error occurred', }; } } export async function handleBinanceGetOpenOrders( params: unknown ): Promise<{ content: Array<{ type: string; text: string }> }> { const validatedParams = BinanceGetOpenOrdersInputSchema.parse(params); const result = await binance_get_open_orders(validatedParams); if (result.success && result.data) { const d = result.data; if (d.count === 0) { return { content: [ { type: 'text', text: `No open orders${validatedParams.symbol ? ` for ${validatedParams.symbol}` : ''}`, }, ], }; } let ordersStr = d.orders .map((o) => { const priceStr = o.price ? `$${o.price.toFixed(8)}` : 'MARKET'; const filledPct = o.amount > 0 ? ((o.filled / o.amount) * 100).toFixed(1) : '0'; return ` #${o.id} Symbol: ${o.symbol} | ${o.side.toUpperCase()} | ${o.type.toUpperCase()} Price: ${priceStr} | Amount: ${o.amount.toFixed(8)} Filled: ${o.filled.toFixed(8)} (${filledPct}%) | Remaining: ${o.remaining.toFixed(8)} Status: ${o.status} | Created: ${new Date(o.createdAt).toISOString()}`; }) .join('\n\n'); const formattedOutput = ` Open Orders${validatedParams.symbol ? ` - ${validatedParams.symbol}` : ''} ${'='.repeat(35)} Total Orders: ${d.count} ${ordersStr} `.trim(); return { content: [{ type: 'text', text: formattedOutput }], }; } return { content: [{ type: 'text', text: `Error: ${result.error}` }], }; }