Skip to main content
Glama

analyzeTradingPerformance

Evaluate trading performance for a specified account on over 100 cryptocurrency exchanges. Filter by symbol or period to assess profitability and refine strategies.

Instructions

Analyze trading performance for a configured account

Input Schema

NameRequiredDescriptionDefault
accountNameYesAccount name defined in the configuration file (e.g., 'bybit_main')
periodNoAnalysis period: '7d', '30d', '90d', or 'all'30d
symbolNoOptional trading symbol (e.g., 'BTC/USDT') to filter trades

Input Schema (JSON Schema)

{ "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "accountName": { "description": "Account name defined in the configuration file (e.g., 'bybit_main')", "type": "string" }, "period": { "default": "30d", "description": "Analysis period: '7d', '30d', '90d', or 'all'", "enum": [ "7d", "30d", "90d", "all" ], "type": "string" }, "symbol": { "description": "Optional trading symbol (e.g., 'BTC/USDT') to filter trades", "type": "string" } }, "required": [ "accountName" ], "type": "object" }

Implementation Reference

  • The core handler function for the 'analyzeTradingPerformance' tool. Fetches personal trades from the specified CCXT exchange account using fetchMyTrades, calculates 'since' timestamp based on period, invokes analyzeTradeData helper for metrics computation, and returns formatted JSON analysis or error response.
    async ({ accountName, symbol, period }) => { try { const exchange = ccxtServer.getExchangeInstance(accountName); // fetchMyTrades 메서드가 지원되는지 확인 if (!exchange.has["fetchMyTrades"]) { return { content: [ { type: "text", text: `Account '${accountName}' (Exchange: ${exchange.id}) does not support fetching personal trades for analysis`, }, ], isError: true, }; } // 기간에 따른 since 값 계산 const now = Date.now(); let since; switch (period) { case "7d": since = now - 7 * 24 * 60 * 60 * 1000; // 7일 break; case "30d": since = now - 30 * 24 * 60 * 60 * 1000; // 30일 break; case "90d": since = now - 90 * 24 * 60 * 60 * 1000; // 90일 break; case "all": since = undefined; // 전체 데이터 break; } // 거래 데이터 가져오기 const trades = await exchange.fetchMyTrades(symbol, since, undefined); // 기본 분석 지표 계산 const analysis = analyzeTradeData(trades, period); return { content: [ { type: "text", text: JSON.stringify(analysis, null, 2), }, ], }; } catch (error) { return { content: [ { type: "text", text: `Error analyzing trading performance for account '${accountName}': ${ (error as Error).message }`, }, ], isError: true, }; } }
  • Zod input schema defining parameters for analyzeTradingPerformance: required accountName, optional symbol filter, period enum (7d/30d/90d/all, default 30d).
    accountName: z .string() .describe( "Account name defined in the configuration file (e.g., 'bybit_main')" ), symbol: z .string() .optional() .describe("Optional trading symbol (e.g., 'BTC/USDT') to filter trades"), period: z .enum(["7d", "30d", "90d", "all"]) .default("30d") .describe("Analysis period: '7d', '30d', '90d', or 'all'"), },
  • Direct MCP server.tool registration within registerAnalysisTools function, specifying name, description, input schema, and handler for the analyzeTradingPerformance tool.
    "analyzeTradingPerformance", "Analyze trading performance for a configured account", { accountName: z .string() .describe( "Account name defined in the configuration file (e.g., 'bybit_main')" ), symbol: z .string() .optional() .describe("Optional trading symbol (e.g., 'BTC/USDT') to filter trades"), period: z .enum(["7d", "30d", "90d", "all"]) .default("30d") .describe("Analysis period: '7d', '30d', '90d', or 'all'"), }, async ({ accountName, symbol, period }) => { try { const exchange = ccxtServer.getExchangeInstance(accountName); // fetchMyTrades 메서드가 지원되는지 확인 if (!exchange.has["fetchMyTrades"]) { return { content: [ { type: "text", text: `Account '${accountName}' (Exchange: ${exchange.id}) does not support fetching personal trades for analysis`, }, ], isError: true, }; } // 기간에 따른 since 값 계산 const now = Date.now(); let since; switch (period) { case "7d": since = now - 7 * 24 * 60 * 60 * 1000; // 7일 break; case "30d": since = now - 30 * 24 * 60 * 60 * 1000; // 30일 break; case "90d": since = now - 90 * 24 * 60 * 60 * 1000; // 90일 break; case "all": since = undefined; // 전체 데이터 break; } // 거래 데이터 가져오기 const trades = await exchange.fetchMyTrades(symbol, since, undefined); // 기본 분석 지표 계산 const analysis = analyzeTradeData(trades, period); return { content: [ { type: "text", text: JSON.stringify(analysis, null, 2), }, ], }; } catch (error) { return { content: [ { type: "text", text: `Error analyzing trading performance for account '${accountName}': ${ (error as Error).message }`, }, ], isError: true, }; } } );
  • src/server.ts:375-375 (registration)
    Top-level call to registerAnalysisTools in CcxtMcpServer.registerTools() method, which registers the analyzeTradingPerformance tool (among others) to the MCP server.
    registerAnalysisTools(this.server, this);
  • Supporting helper function analyzeTradeData that processes raw trades array to compute comprehensive performance metrics including win rate, net profit, profit factor, largest win/loss, total volume, and trading period statistics. Called by the main handler.
    function analyzeTradeData(trades: any[], period: string) { if (!trades || trades.length === 0) { return { period, totalTrades: 0, message: "No trades found for the specified period.", }; } // 거래 데이터 정렬 (시간순) trades.sort((a, b) => a.timestamp - b.timestamp); // 기본 지표 계산 let totalProfit = 0; let totalLoss = 0; let winCount = 0; let lossCount = 0; let totalFees = 0; let largestWin = 0; let largestLoss = 0; let totalVolume = 0; // 거래별 분석 trades.forEach((trade) => { // 수수료 계산 const fee = trade.fee?.cost || 0; totalFees += fee; // 거래량 계산 totalVolume += trade.amount * trade.price; // 손익 계산 (단순화된 버전 - 실제로는 포지션 추적 필요) const cost = trade.amount * trade.price; const profit = trade.side === "buy" ? -cost : cost; // 매우 단순화된 계산 if (profit > 0) { totalProfit += profit; winCount++; largestWin = Math.max(largestWin, profit); } else if (profit < 0) { totalLoss += Math.abs(profit); lossCount++; largestLoss = Math.max(largestLoss, Math.abs(profit)); } }); const totalTrades = trades.length; const winRate = totalTrades > 0 ? (winCount / totalTrades) * 100 : 0; const netProfit = totalProfit - totalLoss - totalFees; const profitFactor = totalLoss > 0 ? totalProfit / totalLoss : totalProfit > 0 ? Infinity : 0; // 거래 패턴 분석 const firstTradeDate = new Date(trades[0].timestamp); const lastTradeDate = new Date(trades[trades.length - 1].timestamp); const tradingDurationDays = (lastTradeDate.getTime() - firstTradeDate.getTime()) / (1000 * 60 * 60 * 24); const tradesPerDay = tradingDurationDays > 0 ? totalTrades / tradingDurationDays : totalTrades; return { period, totalTrades, winCount, lossCount, winRate: winRate.toFixed(2) + "%", totalProfit: totalProfit.toFixed(8), totalLoss: totalLoss.toFixed(8), netProfit: netProfit.toFixed(8), totalFees: totalFees.toFixed(8), profitFactor: profitFactor.toFixed(2), largestWin: largestWin.toFixed(8), largestLoss: largestLoss.toFixed(8), totalVolume: totalVolume.toFixed(2), tradingPeriod: { firstTrade: firstTradeDate.toISOString(), lastTrade: lastTradeDate.toISOString(), durationDays: tradingDurationDays.toFixed(1), tradesPerDay: tradesPerDay.toFixed(1), } }; }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/lazy-dinosaur/ccxt-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server