Skip to main content
Glama

portfolio

View cross-exchange portfolio summaries including balances, positions, and risk metrics across all connected exchanges for comprehensive trading oversight.

Instructions

Cross-exchange portfolio summary: balances, positions, and risk metrics across all exchanges

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault

No arguments

Implementation Reference

  • The MCP tool "portfolio" is implemented directly in `src/mcp-server.ts`. It fetches balance, positions, and open orders from all supported exchanges ("pacifica", "hyperliquid", "lighter"), calculates aggregated portfolio risk metrics, and returns a JSON summary.
      "portfolio",
      "Cross-exchange portfolio summary: balances, positions, and risk metrics across all exchanges",
      {},
      async () => {
        const EXCHANGES = ["pacifica", "hyperliquid", "lighter"] as const;
    
        interface ExchangeSnapshot {
          exchange: string;
          connected: boolean;
          balance: { equity: string; available: string; marginUsed: string; unrealizedPnl: string } | null;
          positions: Awaited<ReturnType<ExchangeAdapter["getPositions"]>>;
          openOrders: number;
          error?: string;
        }
    
        const snapshots: ExchangeSnapshot[] = await Promise.all(
          EXCHANGES.map(async (name) => {
            try {
              const adapter = await getOrCreateAdapter(name);
              const [balance, positions, orders] = await Promise.all([
                adapter.getBalance(),
                adapter.getPositions(),
                adapter.getOpenOrders(),
              ]);
              return { exchange: name, connected: true, balance, positions, openOrders: orders.length };
            } catch (e) {
              return {
                exchange: name,
                connected: false,
                balance: null,
                positions: [],
                openOrders: 0,
                error: e instanceof Error ? e.message : String(e),
              };
            }
          }),
        );
    
        let totalEquity = 0;
        let totalAvailable = 0;
        let totalMarginUsed = 0;
        let totalUnrealizedPnl = 0;
        let totalPositions = 0;
        let totalOpenOrders = 0;
        const allPositions: (Awaited<ReturnType<ExchangeAdapter["getPositions"]>>[number] & { exchange: string })[] = [];
    
        for (const snap of snapshots) {
          if (snap.balance) {
            totalEquity += Number(snap.balance.equity);
            totalAvailable += Number(snap.balance.available);
            totalMarginUsed += Number(snap.balance.marginUsed);
            totalUnrealizedPnl += Number(snap.balance.unrealizedPnl);
          }
          totalPositions += snap.positions.length;
          totalOpenOrders += snap.openOrders;
          for (const pos of snap.positions) {
            allPositions.push({ ...pos, exchange: snap.exchange });
          }
        }
    
        const marginUtilization = totalEquity > 0 ? (totalMarginUsed / totalEquity) * 100 : 0;
    
        let largestPosition: { symbol: string; exchange: string; notional: number } | null = null;
        for (const pos of allPositions) {
          const notional = Math.abs(Number(pos.size) * Number(pos.markPrice));
          if (!largestPosition || notional > largestPosition.notional) {
            largestPosition = { symbol: pos.symbol, exchange: pos.exchange, notional };
          }
        }
    
        const exchangeConcentration = snapshots
          .filter(s => s.balance && Number(s.balance.equity) > 0)
          .map(s => ({
            exchange: s.exchange,
            pct: totalEquity > 0 ? (Number(s.balance!.equity) / totalEquity) * 100 : 0,
          }))
          .sort((a, b) => b.pct - a.pct);
    
        const summary = {
          totalEquity,
          totalAvailable,
          totalMarginUsed,
          totalUnrealizedPnl,
          totalPositions,
          totalOpenOrders,
          exchanges: snapshots,
          positions: allPositions,
          riskMetrics: { marginUtilization, largestPosition, exchangeConcentration },
        };
    
        return { content: [{ type: "text", text: ok(summary) }] };
      },
    );

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/hypurrquant/perp-cli'

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