fund_data
Retrieve comprehensive public fund data including listings, managers, net values, dividends, and holdings to support investment analysis and portfolio management decisions.
Instructions
获取公募基金全面数据,包括基金列表、基金经理、基金净值、基金分红、基金持仓等数据。
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| ts_code | Yes | 基金代码,如'150018.SZ'表示银华深证100分级,'001753.OF'表示场外基金。注意:查询基金列表(basic)时必须提供此参数 | |
| data_type | Yes | 数据类型,可选值:basic(基金列表)、manager(基金经理)、nav(基金净值)、dividend(基金分红)、portfolio(基金持仓)、all(全部数据) | |
| start_date | No | 起始日期,格式为YYYYMMDD,如'20230101'。重要:对于基金持仓(portfolio)数据和基金净值(nav)数据,如果不指定时间参数,将返回所有历史数据,可能数据量很大。建议指定时间范围或使用period参数 | |
| end_date | No | 结束日期,格式为YYYYMMDD,如'20231231'。配合start_date使用可限制数据范围 | |
| period | No | 特定报告期,格式为YYYYMMDD。例如:'20231231'表示2023年年报,'20240630'表示2024年中报,'20220630'表示2022年三季报,'20240331'表示2024年一季报。指定此参数时将忽略start_date和end_date |
Implementation Reference
- build/tools/fundData.js:32-96 (handler)The primary handler function for the 'fund_data' tool. It processes input arguments, fetches fund data (basic, manager, nav, dividend, portfolio) from Tushare API, handles multiple data types including 'all', applies date filtering, merges share data for NAV, formats output as markdown tables/text, and returns MCP-compatible content.async run(args) { try { console.log('基金数据查询参数:', args); const TUSHARE_API_KEY = TUSHARE_CONFIG.API_TOKEN; const TUSHARE_API_URL = TUSHARE_CONFIG.API_URL; if (!TUSHARE_API_KEY) { throw new Error('请配置TUSHARE_TOKEN环境变量'); } // 默认日期设置 const today = new Date(); const currentYear = today.getFullYear(); const defaultEndDate = `${currentYear}1231`; const defaultStartDate = `${currentYear - 1}0101`; const results = []; // 根据data_type决定要查询的API const dataTypes = args.data_type === 'all' ? ['basic', 'manager', 'nav', 'dividend', 'portfolio'] : [args.data_type]; for (const dataType of dataTypes) { try { // 基金列表(basic)模块必须提供基金代码,否则跳过 if (dataType === 'basic' && !args.ts_code) { console.warn('基金列表查询需要提供基金代码,跳过basic模块'); results.push({ type: dataType, error: '基金列表查询需要提供基金代码(ts_code)参数,否则数据量过大' }); continue; } const result = await fetchFundData(dataType, args.ts_code, args.period, args.start_date || defaultStartDate, args.end_date || defaultEndDate, TUSHARE_API_KEY, TUSHARE_API_URL); if (result.data && result.data.length > 0) { results.push({ type: dataType, data: result.data, fields: result.fields }); } } catch (error) { console.warn(`获取${dataType}数据失败:`, error); results.push({ type: dataType, error: error instanceof Error ? error.message : '未知错误' }); } } if (results.length === 0) { throw new Error(`未找到相关基金数据`); } // 格式化输出 const formattedOutput = formatFundData(results, args.ts_code); return { content: [{ type: "text", text: formattedOutput }] }; } catch (error) { console.error('基金数据查询错误:', error); return { content: [{ type: "text", text: `查询基金数据时发生错误: ${error instanceof Error ? error.message : '未知错误'}` }] }; } }
- build/tools/fundData.js:5-30 (schema)JSON Schema defining the input parameters for the fund_data tool, including required fields and enums for data_type.parameters: { type: "object", properties: { ts_code: { type: "string", description: "基金代码,如'150018.SZ'表示银华深证100分级,'001753.OF'表示场外基金。注意:查询基金列表(basic)时必须提供此参数" }, data_type: { type: "string", description: "数据类型,可选值:basic(基金列表)、manager(基金经理)、nav(基金净值)、dividend(基金分红)、portfolio(基金持仓)、all(全部数据)", enum: ["basic", "manager", "nav", "dividend", "portfolio", "all"] }, start_date: { type: "string", description: "起始日期,格式为YYYYMMDD,如'20230101'。重要:对于基金持仓(portfolio)数据和基金净值(nav)数据,如果不指定时间参数,将返回所有历史数据,可能数据量很大。建议指定时间范围或使用period参数" }, end_date: { type: "string", description: "结束日期,格式为YYYYMMDD,如'20231231'。配合start_date使用可限制数据范围" }, period: { type: "string", description: "特定报告期,格式为YYYYMMDD。例如:'20231231'表示2023年年报,'20240630'表示2024年中报,'20220630'表示2022年三季报,'20240331'表示2024年一季报。指定此参数时将忽略start_date和end_date" } }, required: ["data_type", "ts_code"]
- build/index.js:290-296 (registration)Registration and dispatch of the fund_data tool in the MCP stdio server's CallToolRequest handler switch statement.case "fund_data": { const ts_code = request.params.arguments?.ts_code ? String(request.params.arguments.ts_code) : undefined; const data_type = String(request.params.arguments?.data_type); const start_date = request.params.arguments?.start_date ? String(request.params.arguments.start_date) : undefined; const end_date = request.params.arguments?.end_date ? String(request.params.arguments.end_date) : undefined; const period = request.params.arguments?.period ? String(request.params.arguments.period) : undefined; return normalizeResult(await fundData.run({ ts_code, data_type, start_date, end_date, period }));
- build/httpServer.js:314-321 (registration)Tool dispatch case for fund_data in the HTTP server's MCP tools/call handler.case 'fund_data': return await fundData.run({ ts_code: args?.ts_code ? String(args.ts_code) : undefined, data_type: String(args?.data_type), start_date: args?.start_date ? String(args.start_date) : undefined, end_date: args?.end_date ? String(args.end_date) : undefined, period: args?.period ? String(args.period) : undefined, });
- build/tools/fundData.js:99-247 (helper)Key helper function that performs the actual API call to Tushare for specific fund data types, handles response parsing, date filtering, and data merging (e.g., NAV with shares). Called from the main run handler.async function fetchFundData(dataType, tsCode, period, startDate, endDate, apiKey, apiUrl) { const apiConfigs = { basic: { api_name: "fund_basic", default_fields: "ts_code,name,management,custodian,fund_type,found_date,due_date,list_date,issue_date,delist_date,issue_amount,m_fee,c_fee,duration_year,p_value,min_amount,exp_return,benchmark,status,invest_type,type,trustee,purc_startdate,redm_startdate,market" }, manager: { api_name: "fund_manager", default_fields: "ts_code,ann_date,name,gender,birth_year,edu,nationality,begin_date,end_date,resume" }, nav: { api_name: "fund_nav", default_fields: "ts_code,ann_date,nav_date,unit_nav,accum_nav,accum_div,net_asset,total_netasset,adj_nav" }, dividend: { api_name: "fund_div", default_fields: "ts_code,ann_date,imp_anndate,base_date,div_proc,record_date,ex_date,pay_date,earpay_date,net_ex_date,div_cash,base_unit,ear_distr,ear_amount,account_date,base_year" }, portfolio: { api_name: "fund_portfolio", default_fields: "ts_code,ann_date,end_date,symbol,mkv,amount,stk_mkv_ratio,stk_float_ratio" } }; const config = apiConfigs[dataType]; if (!config) { throw new Error(`不支持的数据类型: ${dataType}`); } // 构建请求参数 const params = { api_name: config.api_name, token: apiKey, params: {}, fields: config.default_fields }; // 根据不同的API添加特定参数 if (dataType === 'basic') { if (tsCode) params.params.ts_code = tsCode; } else if (dataType === 'manager') { if (tsCode) params.params.ts_code = tsCode; } else if (dataType === 'nav') { if (tsCode) params.params.ts_code = tsCode; if (period) { params.params.nav_date = period; } else { if (startDate) params.params.start_date = startDate; if (endDate) params.params.end_date = endDate; } } else if (dataType === 'dividend') { if (tsCode) params.params.ts_code = tsCode; } else if (dataType === 'portfolio') { if (tsCode) params.params.ts_code = tsCode; if (period) { params.params.period = period; } else { if (startDate) params.params.start_date = startDate; if (endDate) params.params.end_date = endDate; } } console.log(`调用${config.api_name} API,参数:`, JSON.stringify(params, null, 2)); // 设置请求超时 const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), TUSHARE_CONFIG.TIMEOUT); try { const response = await fetch(apiUrl || 'https://api.tushare.pro', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(params), signal: controller.signal }); clearTimeout(timeoutId); if (!response.ok) { throw new Error(`API请求失败: ${response.status} ${response.statusText}`); } const result = await response.json(); if (result.code !== 0) { throw new Error(`API返回错误: ${result.msg || '未知错误'}`); } if (!result.data || !result.data.items) { return { data: [], fields: result.data?.fields || [] }; } // 转换数据格式 const formattedData = result.data.items.map((item) => { const obj = {}; result.data.fields.forEach((field, index) => { obj[field] = item[index]; }); return obj; }); // 对某些数据类型进行日期范围过滤 let filteredData = formattedData; if (['dividend'].includes(dataType) && startDate && endDate && !period) { filteredData = formattedData.filter((item) => { const annDate = item.ann_date; if (!annDate) return true; return annDate >= startDate && annDate <= endDate; }); console.log(`日期范围过滤后剩余${filteredData.length}条${dataType}记录`); } console.log(`成功获取到${filteredData.length}条${dataType}数据记录`); // 如果是净值数据且有基金代码,尝试获取基金份额数据并合并 if (dataType === 'nav' && tsCode && filteredData.length > 0) { try { const shareResult = await fetchFundShareData(tsCode, startDate, endDate, period, apiKey, apiUrl); if (shareResult.data && shareResult.data.length > 0) { // 创建份额数据的映射表,以交易日期为键 const shareMap = new Map(); shareResult.data.forEach((shareItem) => { shareMap.set(shareItem.trade_date, shareItem.fd_share); }); // 将份额数据合并到净值数据中 filteredData.forEach((navItem) => { const tradeDate = navItem.nav_date || navItem.ann_date; navItem.fd_share = shareMap.get(tradeDate) || null; }); console.log(`成功合并${shareResult.data.length}条基金份额数据`); } } catch (error) { console.warn('获取基金份额数据失败,将继续返回净值数据:', error); } } return { data: filteredData, fields: result.data.fields }; } catch (error) { clearTimeout(timeoutId); throw error; } }