get-stock-history
Retrieve historical stock price data including daily, weekly, and monthly candlestick charts to analyze past performance trends.
Instructions
获取单个股票的历史数据、过去价格、K线数据,支持日K、周K、月K线,用于分析股票过去的表现
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| stock_code | Yes | 股票代码或名称 (例如: 600519 或 贵州茅台) | |
| period | No | 时间周期: 1d=日K线, 1w=周K线, 1m=月K线 | 1d |
| days | No | 获取天数 (1-500天) |
Implementation Reference
- src/index.ts:50-110 (registration)Registration of the 'get-stock-history' tool via server.tool(), including input schema (Zod) and inline async handler function that orchestrates data fetching and formatting.server.tool( "get-stock-history", "获取单个股票的历史数据、过去价格、K线数据,支持日K、周K、月K线,用于分析股票过去的表现", { stock_code: z .string() .describe("股票代码或名称 (例如: 600519 或 贵州茅台)"), period: z .enum(["1d", "1w", "1m"]) .default("1d") .describe("时间周期: 1d=日K线, 1w=周K线, 1m=月K线"), days: z .number() .min(1) .max(500) .default(30) .describe("获取天数 (1-500天)"), }, async ({ stock_code, period, days }) => { // Convert period to API format const periodMap = { "1d": "101", "1w": "102", "1m": "103" }; const apiPeriod = periodMap[period]; const historyData = await fetchStockHistory(stock_code, apiPeriod, days); if (!historyData || historyData.length === 0) { return { content: [ { type: "text", text: `无法获取股票 ${stock_code} 的历史数据。请检查输入是否正确。`, }, ], }; } // Get stock name for display let stockName = stock_code; if (!stock_code.match(/^\d{6}$/)) { const searchResult = await searchStock(stock_code); if (searchResult) { stockName = `${searchResult[1]}(${searchResult[0]})`; } } else { // Try to get name from current data const currentData = await fetchStockData(stock_code); if (currentData) { stockName = `${currentData.name}(${currentData.code})`; } } return { content: [ { type: "text", text: formatHistoryData(historyData, stockName), }, ], }; } );
- src/index.ts:68-109 (handler)Inline handler function for 'get-stock-history' tool: validates inputs, maps period, calls fetchStockHistory, handles stock name resolution, and returns formatted content.async ({ stock_code, period, days }) => { // Convert period to API format const periodMap = { "1d": "101", "1w": "102", "1m": "103" }; const apiPeriod = periodMap[period]; const historyData = await fetchStockHistory(stock_code, apiPeriod, days); if (!historyData || historyData.length === 0) { return { content: [ { type: "text", text: `无法获取股票 ${stock_code} 的历史数据。请检查输入是否正确。`, }, ], }; } // Get stock name for display let stockName = stock_code; if (!stock_code.match(/^\d{6}$/)) { const searchResult = await searchStock(stock_code); if (searchResult) { stockName = `${searchResult[1]}(${searchResult[0]})`; } } else { // Try to get name from current data const currentData = await fetchStockData(stock_code); if (currentData) { stockName = `${currentData.name}(${currentData.code})`; } } return { content: [ { type: "text", text: formatHistoryData(historyData, stockName), }, ], }; }
- src/index.ts:53-67 (schema)Zod input schema for 'get-stock-history': stock_code (string), period (enum 1d/1w/1m), days (number 1-500).{ stock_code: z .string() .describe("股票代码或名称 (例如: 600519 或 贵州茅台)"), period: z .enum(["1d", "1w", "1m"]) .default("1d") .describe("时间周期: 1d=日K线, 1w=周K线, 1m=月K线"), days: z .number() .min(1) .max(500) .default(30) .describe("获取天数 (1-500天)"), },
- src/api.ts:65-121 (helper)fetchStockHistory helper: resolves stock code, constructs API params, fetches K-line data from HISTORY_API, parses response into HistoryDataPoint array.export async function fetchStockHistory( stockInput: string, period: string = "101", days: number = 30 ): Promise<HistoryDataPoint[] | null> { try { let stockCode = stockInput; if (!stockInput.match(/^\d{6}$/)) { const searchResult = await searchStock(stockInput); if (!searchResult) { console.error(`未找到股票:${stockInput}`); return null; } [stockCode] = searchResult; } const [market, fullCode] = getStockMarket(stockCode); const params = { secid: fullCode, klt: period, fqt: "1", lmt: days.toString(), end: "20500101", iscca: "1", fields1: "f1,f2,f3,f4,f5,f6", fields2: "f51,f52,f53,f54,f55,f56,f57,f58,f59,f60,f61", }; const response = await makeRequest(HISTORY_API, params); const data = (await response.json()) as HistoryResponse; if (data.rc !== 0 || !data.data || !data.data.klines) { throw new Error(data.msg || "获取历史数据失败"); } const historyData: HistoryDataPoint[] = data.data.klines.map((kline) => { const parts = kline.split(","); return { date: parts[0], open: parseFloat(parts[1]), close: parseFloat(parts[2]), high: parseFloat(parts[3]), low: parseFloat(parts[4]), volume: parseInt(parts[5]) / 100, amount: parseFloat(parts[6]) / 10000, changePercent: parseFloat(parts[8]), }; }); return historyData.reverse(); } catch (error) { console.error("Error fetching stock history:", error); return null; } }
- src/formatters.ts:11-41 (helper)formatHistoryData helper: converts history data array and stock name into formatted markdown text with table, stats (high/low/avg/total vol).export function formatHistoryData(data: HistoryDataPoint[], stockName: string): string { let result = ` 📈 ${stockName} 历史数据 (最近${data.length}个交易日) `; const recentData = data.slice(0, Math.min(10, data.length)); result += "日期 开盘 收盘 最高 最低 成交量(手) 涨跌幅\n"; result += "─".repeat(65) + "\n"; for (const point of recentData) { const changeColor = point.changePercent >= 0 ? "📈" : "📉"; result += `${point.date} ${formatPrice(point.open).padStart(6)} ${formatPrice(point.close).padStart(6)} ${formatPrice(point.high).padStart(6)} ${formatPrice(point.low).padStart(6)} ${formatVolume(point.volume).padStart(8)} ${changeColor}${point.changePercent.toFixed(2)}%\n`; } const prices = data.map(d => d.close); const maxPrice = Math.max(...prices); const minPrice = Math.min(...prices); const avgPrice = prices.reduce((a, b) => a + b, 0) / prices.length; const totalVolume = data.reduce((sum, d) => sum + d.volume, 0); result += `\n📊 统计信息: 最高价: ${formatPrice(maxPrice)} 最低价: ${formatPrice(minPrice)} 平均价: ${formatPrice(avgPrice)} 总成交量: ${formatVolume(totalVolume)}手 `; return result; }