getTokenPriceHistory
Retrieve historical token price data on Ethereum by specifying the token address, time range, and resolution. Analyze price trends for informed decision-making.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| address | Yes | ||
| days | No | Number of days of history | |
| networkId | No | Network ID (1 for Ethereum, 101 for Solana) | |
| resolution | No | Time resolution (e.g. 1D, 1H, 60) | 1D |
Implementation Reference
- tools/token-analysis.js:51-77 (handler)The main handler function that implements the tool logic: calculates the time range based on days, fetches historical price chart data using fetchChartData helper, formats it using formatChartDataResponse, and returns a formatted text response or error.async ({ address, networkId, days, resolution }) => { try { // Calculate time range const to = Math.floor(Date.now() / 1000); const from = to - (60 * 60 * 24 * days); // Get chart data from Codex API const chartData = await fetchChartData(address, networkId, resolution, from, to); if (!chartData || chartData.length === 0) { return { content: [{ type: "text", text: `No price history found for ${address} on network ${networkId}` }] }; } // Format the chart data for display const response = formatChartDataResponse(chartData); return { content: [{ type: "text", text: response }] }; } catch (error) { return { content: [{ type: "text", text: `Error fetching token price history: ${error.message}` }] }; } }
- tools/token-analysis.js:45-50 (schema)Zod input schema defining parameters for the getTokenPriceHistory tool: token address (required), network ID (default 1), days of history (default 7), time resolution (default '1D').{ address: z.string().min(1, "Token address is required"), networkId: z.number().int().positive().default(1).describe("Network ID (1 for Ethereum, 101 for Solana)"), days: z.number().int().positive().default(7).describe("Number of days of history"), resolution: z.string().default("1D").describe("Time resolution (e.g. 1D, 1H, 60)") },
- tools/token-analysis.js:44-78 (registration)Registration of the getTokenPriceHistory tool using server.tool(), specifying the name, input schema, and inline handler function.server.tool("getTokenPriceHistory", { address: z.string().min(1, "Token address is required"), networkId: z.number().int().positive().default(1).describe("Network ID (1 for Ethereum, 101 for Solana)"), days: z.number().int().positive().default(7).describe("Number of days of history"), resolution: z.string().default("1D").describe("Time resolution (e.g. 1D, 1H, 60)") }, async ({ address, networkId, days, resolution }) => { try { // Calculate time range const to = Math.floor(Date.now() / 1000); const from = to - (60 * 60 * 24 * days); // Get chart data from Codex API const chartData = await fetchChartData(address, networkId, resolution, from, to); if (!chartData || chartData.length === 0) { return { content: [{ type: "text", text: `No price history found for ${address} on network ${networkId}` }] }; } // Format the chart data for display const response = formatChartDataResponse(chartData); return { content: [{ type: "text", text: response }] }; } catch (error) { return { content: [{ type: "text", text: `Error fetching token price history: ${error.message}` }] }; } } );
- tools/token-analysis.js:165-269 (helper)Supporting helper that queries the Codex GraphQL API for OHLCV price bars (historical data) given token address, network, resolution, and time range; restructures response data into array of bar objects with volume, transactions, buy/sell metrics.async function fetchChartData(address, networkId, resolution = '1D', from, to) { try { // Use API key from environment variable const apiKey = process.env.CODEX_API_KEY; if (!apiKey) { throw new Error("CODEX_API_KEY environment variable is not set"); } const response = await axios({ url: API_URL, method: 'post', headers: { 'Content-Type': 'application/json', 'Authorization': apiKey }, data: { query: `{ getBars( symbol: "${address}:${networkId}" from: ${from} to: ${to} resolution: "${resolution}" removeEmptyBars: true ) { t o h l c v volume transactions buyers sellers traders liquidity buyVolume sellVolume buys sells volumeNativeToken } }` } }); if (response.data && response.data.data && response.data.data.getBars) { const bars = response.data.data.getBars; // Process bars data if (Array.isArray(bars.t)) { // Multiple bars - restructure into an array of bar objects const result = []; for (let i = 0; i < bars.t.length; i++) { result.push({ t: bars.t[i], o: bars.o[i], h: bars.h[i], l: bars.l[i], c: bars.c[i], v: bars.v ? bars.v[i] : null, volume: bars.volume ? bars.volume[i] : null, transactions: bars.transactions ? bars.transactions[i] : null, buyers: bars.buyers ? bars.buyers[i] : null, sellers: bars.sellers ? bars.sellers[i] : null, traders: bars.traders ? bars.traders[i] : null, liquidity: bars.liquidity ? bars.liquidity[i] : null, buyVolume: bars.buyVolume ? bars.buyVolume[i] : null, sellVolume: bars.sellVolume ? bars.sellVolume[i] : null, buys: bars.buys ? bars.buys[i] : null, sells: bars.sells ? bars.sells[i] : null, volumeNativeToken: bars.volumeNativeToken ? bars.volumeNativeToken[i] : null }); } return result; } else if (typeof bars.t === 'number') { // Single bar return [{ t: bars.t, o: bars.o, h: bars.h, l: bars.l, c: bars.c, v: bars.v, volume: bars.volume, transactions: bars.transactions, buyers: bars.buyers, sellers: bars.sellers, traders: bars.traders, liquidity: bars.liquidity, buyVolume: bars.buyVolume, sellVolume: bars.sellVolume, buys: bars.buys, sells: bars.sells, volumeNativeToken: bars.volumeNativeToken }]; } } return []; } catch (error) { console.error('Error fetching chart data:', error.response?.data || error.message); throw new Error(`API error: ${error.response?.data?.errors?.[0]?.message || error.message}`); } }
- tools/token-analysis.js:295-326 (helper)Supporting utility that converts raw chart data into a human-readable text table with price history, change summary, and aggregated trading stats.function formatChartDataResponse(data) { let response = `=== Price History ===\n`; response += `Date | Open | High | Low | Close | Volume\n`; response += `-----------|----------|----------|----------|----------|------------\n`; data.forEach(bar => { // Make sure all fields are present to avoid errors if (bar.t && bar.o !== undefined && bar.h !== undefined && bar.l !== undefined && bar.c !== undefined) { response += `${formatDate(bar.t)} | $${bar.o.toFixed(4).padEnd(8)} | $${bar.h.toFixed(4).padEnd(8)} | $${bar.l.toFixed(4).padEnd(8)} | $${bar.c.toFixed(4).padEnd(8)} | $${formatNumber(bar.volume || bar.v)}\n`; } }); // Display price change if (data.length > 1) { const firstPrice = data[0].o; const lastPrice = data[data.length - 1].c; const priceChange = ((lastPrice - firstPrice) / firstPrice) * 100; response += `\nPrice change over period: ${priceChange.toFixed(2)}%\n`; // Show basic trading activity response += '\n=== Recent Trading Activity ===\n'; const totalTransactions = data.reduce((sum, bar) => sum + (bar.transactions || 0), 0); const totalTraders = data.reduce((sum, bar) => sum + (bar.traders || 0), 0); response += `Total Transactions: ${totalTransactions}\n`; response += `Total Unique Traders: ${totalTraders}\n`; } return response; }