get_portfolio
Retrieve your complete paper trading portfolio summary, including balance, profit/loss, win rate, trade history, and risk configuration, from Pique Signal.
Instructions
Get full paper trading portfolio summary: balance, P&L, win rate, trade history, and risk configuration.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
No arguments | |||
Implementation Reference
- src/tools.js:221-245 (registration)Registration of the 'get_portfolio' tool in the MCP server via server.tool(), with no input schema (empty {}), metadata hints, and an async handler that delegates to traderFetch('/portfolio') or paper.getPortfolio() depending on whether a remote trader is configured.
server.tool( 'get_portfolio', 'Get full paper trading portfolio summary: balance, P&L, win rate, trade history, and risk configuration.', {}, { title: 'Get Portfolio', readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false, }, async () => { try { let result; if (useRemoteTrader) { result = await traderFetch('/portfolio'); } else { result = paper.getPortfolio(); } return text(JSON.stringify(result, null, 2)); } catch (err) { return error(err.message); } } ); - src/paper-engine.js:199-222 (handler)Core handler that computes the full paper trading portfolio summary: balance, P&L percentages, realized profit/loss, open positions count, total exposure, completed trades, win rate, average win/loss percentages, uptime, recent trades, and risk configuration.
getPortfolio() { const sells = this.#tradeLog.filter(t => t.type === 'sell'); const wins = sells.filter(t => t.pnlSol > 0); const losses = sells.filter(t => t.pnlSol <= 0); const totalRealizedPnl = sells.reduce((s, t) => s + (t.pnlSol || 0), 0); return { balance: this.#round(this.#balance), startingBalance: this.#startingBalance, totalPnlPct: Math.round(((this.#balance - this.#startingBalance) / this.#startingBalance) * 10000) / 100, realizedPnlSol: this.#round(totalRealizedPnl), openPositions: this.#positions.size, totalExposureSol: this.#round(this.#totalExposure()), completedTrades: sells.length, winRate: sells.length ? Math.round((wins.length / sells.length) * 1000) / 10 + '%' : 'N/A', wins: wins.length, losses: losses.length, avgWinPct: wins.length ? Math.round(wins.reduce((s, t) => s + t.pnlPct, 0) / wins.length * 100) / 100 : 0, avgLossPct: losses.length ? Math.round(losses.reduce((s, t) => s + t.pnlPct, 0) / losses.length * 100) / 100 : 0, uptimeMin: Math.round((Date.now() - this.#startTime) / 60_000), recentTrades: this.#tradeLog.slice(-10), riskConfig: { ...this.#config }, }; } - src/tools.js:45-71 (helper)Backend factory that creates the PaperEngine instance and traderFetch helper; used by the get_portfolio tool to decide whether to call paper.getPortfolio() or traderFetch('/portfolio').
export function createBackend(apiKey, apiUrl) { const api = new PiqueSignalAPI(apiUrl, apiKey); const traderUrl = process.env.TRADER_API_URL; const traderKey = process.env.TRADER_API_KEY; const useRemoteTrader = !!(traderUrl && traderKey); const paper = useRemoteTrader ? null : new PaperEngine(); async function traderFetch(path, options = {}) { const url = traderUrl.replace(/\/+$/, '') + path; const res = await fetch(url, { ...options, headers: { 'Content-Type': 'application/json', 'x-webhook-secret': traderKey, ...(options.headers || {}), }, signal: AbortSignal.timeout(TRADER_TIMEOUT_MS), }); if (!res.ok) { const body = await res.text().catch(() => ''); throw new Error(`Trader API ${res.status}: ${body}`); } return res.json(); } return { api, paper, useRemoteTrader, traderFetch }; - src/index.js:34-34 (registration)Entry point where registerTools is called with the MCP server and backend, which registers get_portfolio among other tools.
registerTools(server, backend);