analyze-stock
Analyzes stock trading data to identify significant price levels using volume and value metrics. Input a stock symbol and optional days to track volume walls and distribution patterns.
Instructions
Analyze stock data including volume and value analysis
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| days | No | Number of days to analyze (optional) | |
| symbol | Yes | Stock symbol to analyze |
Implementation Reference
- src/tools/analyze-volume-walls.ts:91-166 (handler)Main handler function that executes the 'analyze-stock' tool logic: fetches order book and trades, computes volume walls analysis, and returns structured stock data analysis.export const analyzeVolumeWalls = async (symbol: string, days?: number) => { const orderBook = await getLatestOrderBook(symbol); if (!orderBook) { throw new Error("No order book data available"); } const trades = await getRecentTrades(symbol, config.TRADES_TO_FETCH, days); const priceVolumes = analyzeVolumeAtPrice(trades, orderBook); // Sort by total value const sortedLevels = Object.entries(priceVolumes) .sort(([, a], [, b]) => b.total_value - a.total_value) .slice(0, 5); // Calculate trading summaries const buyVolume = trades .filter(t => t.side === "bu") .reduce((sum, t) => sum + t.volume, 0); const sellVolume = trades .filter(t => t.side === "sd") .reduce((sum, t) => sum + t.volume, 0); const afterHourTrades = trades.filter(t => t.side === "after-hour"); const afterHourBuy = afterHourTrades .filter(t => t.price >= orderBook.ask_1.price) .reduce((sum, t) => sum + t.volume, 0); const afterHourSell = afterHourTrades .filter(t => t.price <= orderBook.bid_1.price) .reduce((sum, t) => sum + t.volume, 0); const afterHourUnknown = afterHourTrades .filter(t => orderBook.bid_1.price < t.price && t.price < orderBook.ask_1.price) .reduce((sum, t) => sum + t.volume, 0); const totalVolume = buyVolume + sellVolume + afterHourBuy + afterHourSell + afterHourUnknown; return { timestamp: orderBook.timestamp, symbol, market_status: { current_price: orderBook.match_price, bid_price: orderBook.bid_1.price, bid_volume: orderBook.bid_1.volume, ask_price: orderBook.ask_1.price, ask_volume: orderBook.ask_1.volume, spread: orderBook.ask_1.price - orderBook.bid_1.price }, volume_analysis: { significant_levels: sortedLevels.map(([price, data]) => ({ price: Number(price), ...data })), current_bid_accumulated: priceVolumes[orderBook.bid_1.price] || {}, current_ask_accumulated: priceVolumes[orderBook.ask_1.price] || {} }, trading_summary: { period: `last ${config.TRADES_TO_FETCH} trades`, total_trades: trades.length, volume: { buy: buyVolume, sell: sellVolume, after_hour: { buy: afterHourBuy, sell: afterHourSell, unknown: afterHourUnknown, total: afterHourBuy + afterHourSell + afterHourUnknown }, total: totalVolume, buy_ratio: (buyVolume + afterHourBuy) / (buyVolume + sellVolume + afterHourBuy + afterHourSell) || 0 } } }; };
- src/services/tools.ts:34-45 (registration)Tool registration defining name, description, input schema with Zod, and execute function delegating to analyzeVolumeWalls.{ name: "analyze-stock", description: "Analyze stock data including volume and value analysis", parameters: z.object({ symbol: z.string().describe("Stock symbol to analyze"), days: z.number().optional().describe("Number of days to analyze (optional)") }), execute: async (args) => { const result = await analyzeVolumeWalls(args.symbol, args.days); return JSON.stringify(result); } }
- src/services/tools.ts:37-40 (schema)Zod schema for input parameters: symbol (required string), days (optional number).parameters: z.object({ symbol: z.string().describe("Stock symbol to analyze"), days: z.number().optional().describe("Number of days to analyze (optional)") }),
- Supporting helper function that analyzes volume and value at specific price levels from trades and order book data.export const analyzeVolumeAtPrice = ( trades: Trade[], orderBook: OrderBook ): Record<number, PriceVolumeData> => { const priceVolumes: Record<number, PriceVolumeData> = {}; for (const trade of trades.reverse()) { const price = trade.price; if (!priceVolumes[price]) { priceVolumes[price] = { buy_volume: 0, sell_volume: 0, after_hour_buy: 0, after_hour_sell: 0, after_hour_unknown: 0, buy_value: 0, sell_value: 0, after_hour_buy_value: 0, after_hour_sell_value: 0, after_hour_unknown_value: 0, total_volume: 0, total_value: 0, volume_imbalance: 0, value_imbalance: 0, total_trades: 0 }; } const data = priceVolumes[price]; const value = trade.price * trade.volume; if (trade.side === "bu") { data.buy_volume += trade.volume; data.buy_value += value; } else if (trade.side === "sd") { data.sell_volume += trade.volume; data.sell_value += value; } else { if (trade.price >= orderBook.ask_1.price) { data.after_hour_buy += trade.volume; data.after_hour_buy_value += value; } else if (trade.price <= orderBook.bid_1.price) { data.after_hour_sell += trade.volume; data.after_hour_sell_value += value; } else { data.after_hour_unknown += trade.volume; data.after_hour_unknown_value += value; } } data.total_trades += 1; data.last_trade_time = new Date(trade.time * 1000).toISOString(); } // Calculate totals and imbalances for (const data of Object.values(priceVolumes)) { data.total_volume = data.buy_volume + data.sell_volume + data.after_hour_buy + data.after_hour_sell + data.after_hour_unknown; data.total_value = data.buy_value + data.sell_value + data.after_hour_buy_value + data.after_hour_sell_value + data.after_hour_unknown_value; data.volume_imbalance = (data.buy_volume + data.after_hour_buy) - (data.sell_volume + data.after_hour_sell); data.value_imbalance = (data.buy_value + data.after_hour_buy_value) - (data.sell_value + data.after_hour_sell_value); } return priceVolumes; };