pulse_trader_profile
Analyze any Hyperliquid trader via wallet address. Retrieve total PnL, trade count, win rate, volume, largest win/loss, and profit factor for due diligence.
Instructions
Get full profile for any Hyperliquid trader by wallet address. Returns total PnL, trade count, win rate, volume, largest win/loss, first/last trade dates, PnL tier, size tier, and profit factor. Use this for due diligence on any wallet.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| useToonFormat | No | Return data in compact toon format (default: true). Set to false for standard JSON. | |
| address | Yes | Ethereum wallet address (0x...) |
Implementation Reference
- src/index.ts:434-435 (handler)The handler function for the 'pulse_trader_profile' tool. It takes an Ethereum address and optional useToonFormat flag, then calls the backend API at '/pulse/trader/{address}' to fetch the trader's full profile including PnL, trade count, win rate, volume, largest win/loss, PnL tier, size tier, and profit factor.
async ({ useToonFormat, address }) => toolResult(await callAPI(useToonFormat, `/pulse/trader/${address}`)) ); - src/index.ts:428-433 (schema)Input schema for the pulse_trader_profile tool. Defines two parameters: useToonFormat (boolean, default true) and address (validated as an Ethereum 0x-address via regex).
description: "Get full profile for any Hyperliquid trader by wallet address. Returns total PnL, trade count, win rate, volume, largest win/loss, first/last trade dates, PnL tier, size tier, and profit factor. Use this for due diligence on any wallet.", inputSchema: { useToonFormat: useToonFormatSchema, address: ethAddressSchema, }, }, - src/index.ts:425-435 (registration)Registration of the 'pulse_trader_profile' tool on the MCP server. It is conditionally registered via shouldRegister(), meaning it requires an API key (not a free-tier tool).
if (shouldRegister("pulse_trader_profile")) server.registerTool( "pulse_trader_profile", { description: "Get full profile for any Hyperliquid trader by wallet address. Returns total PnL, trade count, win rate, volume, largest win/loss, first/last trade dates, PnL tier, size tier, and profit factor. Use this for due diligence on any wallet.", inputSchema: { useToonFormat: useToonFormatSchema, address: ethAddressSchema, }, }, async ({ useToonFormat, address }) => toolResult(await callAPI(useToonFormat, `/pulse/trader/${address}`)) ); - src/index.ts:94-166 (helper)The callAPI helper function used by the handler to make HTTP requests to the backend API with timeout, retries, and error handling. Also uses the normalizeCoin helper (line 84-91) for symbol normalization.
async function callAPI(useToon: boolean, path: string, params?: Record<string, string>): Promise<any> { const url = new URL(`${BASE}${path}`); if (params) { Object.entries(params).forEach(([key, value]) => { if (value !== undefined && value !== "") { url.searchParams.set(key, value); } }); } let lastError: Error | null = null; for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) { try { const controller = new AbortController(); const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS); const headers: Record<string, string> = {}; if (API_KEY) headers["X-API-Key"] = API_KEY; const response = await fetch(url.toString(), { headers, signal: controller.signal, }); clearTimeout(timeout); if (response.status === 429) { // Rate limited — retry after delay if (attempt < MAX_RETRIES) { await new Promise((r) => setTimeout(r, RETRY_DELAY_MS * (attempt + 1))); continue; } throw new Error("Rate limit exceeded. Please wait a moment and try again."); } if (response.status === 404) { throw new Error("Not found. The requested resource does not exist — check the address or symbol."); } if (response.status === 401) { throw new Error("Invalid API key. Check your COINVERSAA_API_KEY environment variable."); } if (!response.ok) { const body = await response.json().catch(() => null); const msg = body?.error || response.statusText; throw new Error(`Request failed (${response.status}): ${msg}`); } const data = await response.json(); return useToon ? toonEncode(data) : data; } catch (err: any) { if (err.name === "AbortError") { lastError = new Error("Request timed out after 30 seconds. The server may be under heavy load — try again."); } else if (err.cause?.code === "ECONNREFUSED" || err.cause?.code === "ENOTFOUND") { lastError = new Error("Cannot connect to the Coinversa API. Check your COINVERSAA_API_URL setting and network connection."); } else { lastError = err; } // Retry on transient network errors if (attempt < MAX_RETRIES && (err.name === "AbortError" || err.cause?.code === "ECONNRESET")) { await new Promise((r) => setTimeout(r, RETRY_DELAY_MS * (attempt + 1))); continue; } throw lastError; } } throw lastError || new Error("Request failed after retries"); }