Skill: gaingush/tushare-stocks (version 1.0.0)

# Tushare 股票数据技能详细文档 ## 技能概述 本技能是一个**接口明确的** Tushare Pro 股票数据获取工具。与通用调用器不同，它**有明确的边界**，支持文档中描述的 **23 个股票数据接口**。这确保了技能能力的透明度和可预测性，用户无需猜测其功能范围。 ## 核心特性：明确的接口支持 本技能的核心价值在于**明确性**。您不需要猜测它能做什么，所有功能都已预先定义： ### 完整接口支持表 | 分类 | 接口数量 | 接口名称 (api_name) | 主要功能 | | :--- | :--- | :--- | :--- | | 行情数据 | 13 | `daily`, `rt_k`, `stk_mins`, `rt_min`, `weekly`, `monthly`, `stk_weekly_monthly`, `stk_week_month_adj`, `adj_factor`, `daily_basic`, `stk_limit`, `suspend_d`, `hsgt_top10` | 日线、实时K线、分钟线、周月线、复权因子、基础行情、涨跌停、停牌、沪深港通 | | 基础信息 | 10 | `stock_basic`, `trade_cal`, `stock_st`, `stock_hsgt`, `namechange`, `stock_company`, `stk_managers`, `stk_rewards`, `bse_mapping`, `new_share`, `bak_basic` | 股票列表、交易日历、ST股、沪深港通、更名、公司信息、管理层、分红、BSE映射、新股、备用基础信息 | ## 调用前必读：核心参数说明 大部分接口都依赖以下核心参数，请务必了解其格式： | 参数名 | 含义 | 格式/示例 | 如何获取/注意事项 | | :--- | :--- | :--- | :--- | | **`api_name`** | 接口名称 | 必须是支持的23个接口之一，如 `"daily"` | 详见上方“完整接口支持表” | | **`ts_code`** | 股票代码 | `股票代码.交易所`<br>例如：`000001.SZ` (平安银行)<br>`600000.SH` (浦发银行)<br>支持通配符：`6*.SH` (所有沪市6开头股票) | 使用 `stock_basic` 接口查询有效代码 | | **`trade_date`** | 单个交易日 | `YYYYMMDD`<br>例如：`20240115` | 查询单日数据时使用，需为交易日 | | **`start_date`** /<br>**`end_date`** | 开始/结束日期 | 日线/周月线：`YYYYMMDD`<br>分钟线：`YYYY-MM-DD HH:MM:SS`<br>示例：<br>日线范围：`20240101` 到 `20240110`<br>分钟线：`2024-01-15 09:00:00` 到 `2024-01-15 15:00:00` | 查询日期范围时使用 | | **`freq`** | 分钟线频率 | `1min`, `5min`, `15min`, `30min`, `60min` | 仅 `stk_mins` 接口需要 | | **`token`** | Tushare Token | 您的Tushare API Token字符串 | 可在每次调用时传入，或通过环境变量`TUSHARE_TOKEN`设置 | | **`exchange`** | 交易所代码 | `SSE` (上交所), `SZSE` (深交所)<br>`BSE` (北交所) | 部分接口如`stock_basic`可用，非必需 | **重要提示**： 1. **代码格式**：股票代码必须包含交易所后缀（`.SH`/`.SZ`/`.BJ`） 2. **日期格式**：日线接口使用`YYYYMMDD`（无短横线），分钟线接口使用`YYYY-MM-DD HH:MM:SS`（必须包含短横线和空格） 3. **交易日**：查询日线数据时，请确保日期为交易日，可通过`trade_cal`接口验证 4. **通配符**：`rt_k`接口支持通配符查询，如`6*.SH`查询所有沪市6开头股票 5. **必填参数**：每个接口的必填参数不同，不传必填参数会报错 ## 接口详细说明（精选） ### 1. 日线行情 (`daily`) * **描述**: 获取股票日线行情数据，包含开盘、最高、最低、收盘、成交量、成交额、涨跌幅等核心指标 * **必填参数**: `ts_code` 或 `trade_date` 二选一 * **常用参数**: `ts_code`（单只股票）, `trade_date`（单个交易日）, `start_date` + `end_date`（日期范围） * **输出示例**: json { "api_name": "daily", "ts_code": "000001.SZ", "start_date": "20240101", "end_date": "20240110" } * **典型用途**: 获取股票历史价格、计算技术指标、回测分析 ### 2. 基础信息 (`stock_basic`) * **描述**: 获取股票列表基本信息，包括代码、名称、上市日期、退市日期、所属板块等 * **必填参数**: 无 * **常用参数**: `exchange`（交易所）, `list_status`（上市状态：L上市 D退市 P暂停上市）, `fields`（指定字段） * **输出示例**: json { "api_name": "stock_basic", "exchange": "SSE", "list_status": "L" } * **典型用途**: 获取全市场股票列表、筛选特定交易所股票、验证股票代码有效性 ### 3. 分钟行情 (`stk_mins`) * **描述**: 获取A股历史分钟数据，支持1、5、15、30、60分钟频率 * **必填参数**: `ts_code`, `freq`, `start_date`, `end_date` * **重要参数**: `freq`（频率）, `start_date`（精确到秒）, `end_date`（精确到秒） * **输出示例**: json { "api_name": "stk_mins", "ts_code": "600000.SH", "freq": "5min", "start_date": "2024-01-15 09:00:00", "end_date": "2024-01-15 15:00:00" } * **注意**: 分钟线的起止时间格式必须包含秒，且为`YYYY-MM-DD HH:MM:SS` ### 4. 复权因子 (`adj_factor`) * **描述**: 获取股票复权因子，用于计算前复权、后复权价格 * **必填参数**: `ts_code` 或 `trade_date` 二选一 * **常用参数**: `ts_code`（单只股票）, `trade_date`（单个交易日）, `start_date` + `end_date`（日期范围） * **输出示例**: json { "api_name": "adj_factor", "ts_code": "000001.SZ", "start_date": "20230101", "end_date": "20231231" } * **典型用途**: 配合日线数据计算复权价格，进行准确的收益率计算 ## 快速开始示例 ### 示例1：获取单只股票近期日线行情 json { "api_name": "daily", "ts_code": "000001.SZ", "start_date": "20240101", "end_date": "20240131" } ### 示例2：获取多只股票实时行情（使用通配符） json { "api_name": "rt_k", "ts_code": "6*.SH" } ### 示例3：获取上证所所有上市股票列表 json { "api_name": "stock_basic", "exchange": "SSE", "list_status": "L" } ### 示例4：获取交易日历 json { "api_name": "trade_cal", "start_date": "20240101", "end_date": "20241231" } ## 如何获取完整接口详情 虽然本技能文档列出了所有支持的接口及其基本信息，但每个接口的**完整参数列表、所有输出字段的详细说明、数据更新频率、以及所需的Tushare积分要求**等，均需以 **[Tushare Pro 官方文档](https://tushare.pro/document/2)** 为准。调用前强烈建议查阅。 ## 返回数据格式 本技能始终返回一个结构化的JSON对象： **成功响应**： json { "success": true, "data": [...], // 数据数组 "msg": "查询成功", "api": "daily" } **失败响应**： json { "success": false, "error": "错误信息详情", "api": "daily" } ## 开发说明 ### 接口增删原则 本技能的接口列表已基于明确的需求文档固化。如需增加或删减接口，需要按顺序完成以下步骤： 1. **确认接口**：确认目标接口在 [Tushare 官方文档](https://tushare.pro/document/2) 中存在且可用。 2. **更新代码**：修改 `__init__.py` 文件中的 `SUPPORTED_APIS` 字典。 3. **更新文档**：同步更新 `README.md` 和本文件 (`SKILL.md`) 中的接口列表和描述。 4. **更新版本**：在 `metadata.json` 中更新技能版本号，以区分不同发布。 ### 代码与文件结构 本技能作为一个标准的 **ClawHub 纯 Python 技能**，由以下核心文件构成： - `__init__.py`：技能的主逻辑文件，包含 `SUPPORTED_APIS` 字典、`handler` 主函数以及从标准输入读取参数的标准入口。 - `metadata.json`：**技能的核心配置文件**，定义了技能在 ClawHub 平台上的元数据，包括名称、版本、依赖和运行环境要求 (`python3`)。 - `requirements.txt`：Python 第三方依赖包列表 (`tushare`, `pandas`)。 - `README.md`：面向最终用户的快速使用指南和完整接口列表。 - `SKILL.md`：本文件，即面向开发者和高级用户的详细技术文档。 ## 常见问题 **Q: 这个技能和通用的 Tushare 调用器有什么区别？** **A**: 主要区别在于**接口的明确性**。通用调用器可能声称支持“所有”Tushare接口，但用户无法确知其具体支持哪些。本技能明确列出了所支持的 **23 个股票接口**，让用户对其能力边界一目了然，避免了猜测和试错。 **Q: 我想用的某个 Tushare 接口不在这 23 个列表中怎么办？** **A**: 本技能的设计初衷是提供确定性的功能集，因此仅支持文档中明确的接口。如果您需要其他接口，有两个选择：1) 根据上述“开发说明”自行修改代码添加；2) 使用功能更宽泛的通用 Tushare 调用器。 **Q: 如何知道某个接口具体需要哪些参数？** **A**: 虽然本技能文档提供了核心参数说明，但最权威和完整的参数信息来源于 [Tushare 官方文档](https://tushare.pro/document/2)。调用时若参数错误，Tushare API 本身也会返回具体的错误信息。 **Q: 如何区分沪市、深市、北交所股票代码？** **A**: 通过代码后缀区分： - `.SH`：上海证券交易所（主板688开头为科创板） - `.SZ`：深圳证券交易所（000/001/002/003开头为主板，300开头为创业板） - `.BJ`：北京证券交易所 **Q: 通过此技能获取的数据是实时的吗？** **A**: 数据的实时性取决于您的 **Tushare 账户权限和积分**。免费账号或基础积分账号获取的行情数据通常有 **15分钟** 的延迟。实时数据接口（如 `rt_min`、`rt_k`）通常需要更高的积分或单独的数据权限。 **Q: 复权因子 (`adj_factor`) 怎么用？** **A**: 复权因子用于计算复权价格。以`adj_factor`为基准： - 后复权价格 = 当日收盘价 × 当日复权因子 - 前复权价格 = 当日收盘价 × (当日复权因子 / 最新复权因子) 通常结合`daily`接口的收盘价进行计算。 **Q: Token 应该如何配置？** **A**: 您可以通过两种方式配置 Tushare Token (按优先级): 1. **调用参数传入**：在每次调用的 JSON 参数中传入 `"token": "您的token"`。 2. **环境变量**：设置系统环境变量 `TUSHARE_TOKEN` 为您的 token。 如果以上均未提供，技能初始化将失败并提示错误。 **Q: 返回的数据格式是什么？** **A**: 技能始终返回一个结构化的 JSON 对象。成功的调用会包含 `"success": true`、`"data"` (数据列表) 等字段；失败的调用会包含 `"success": false` 和 `"error"` (错误信息) 字段。

path: requirements.txt
content: tushare>=1.2.89
pandas>=1.5.0

path: README.md
content: # Tushare 股票数据技能

本技能封装了 **Tushare Pro 数据接口**，基于用户提供的详细接口文档，明确了所支持的**全部23个接口**。与通用调用器不同，本技能有明确的接口边界，方便用户了解其完整能力。

## 特性
- ✅ **接口明确**: 支持 23 个具体接口，涵盖行情、基础信息、基本面、特色数据。
- 📋 **列表可查**: 通过 `api_name: list` 可获取完整的支持接口列表。
- 🎯 **分类清晰**: 接口按“行情数据”和“基础信息”分类。
- 🔧 **即装即用**: 包含完整依赖和配置。

## 快速开始

### 1. 列出所有支持的接口
调用本技能，并将 `api_name` 参数设为 `list`：
json
{
"api_name": "list"
}
返回结果将包含所有支持的接口名称、中文名、描述和分类。

### 2. 调用具体接口
例如，获取平安银行日线数据：
json
{
"api_name": "daily",
"ts_code": "000001.SZ",
"start_date": "20240101",
"end_date": "20240110"
}
### 3. 配置Token (必做)
**本技能不自带有效Token，您必须使用自己在[Tushare Pro官网](https://tushare.pro)注册获取的Token。**

有两种方式设置Tushare Token（按优先级）：
1.  **调用参数传入**: 在每次调用的JSON参数中传入 `"token": "你的token"`。
2.  **环境变量**: 设置系统环境变量 `TUSHARE_TOKEN` 为你的token。

如果以上均未提供，技能将初始化失败并返回错误。

## 完整接口支持表
| 分类 | 接口数量 | 接口名称 (api_name) |
|------|----------|-------------------|
| 行情数据 | 13 | `daily`, `rt_k`, `stk_mins`, `rt_min`, `weekly`, `monthly`, `stk_weekly_monthly`, `stk_week_month_adj`, `adj_factor`, `daily_basic`, `stk_limit`, `suspend_d`, `hsgt_top10` |
| 基础信息 | 10 | `stock_basic`, `trade_cal`, `stock_st`, `stock_hsgt`, `namechange`, `stock_company`, `stk_managers`, `stk_rewards`, `bse_mapping`, `new_share`, `bak_basic` |

## 核心参数说明
调用本技能时，可传递以下参数。其中 `api_name` 为必填项，其他参数是否必需取决于具体接口。

| 参数名 | 必填 | 类型 | 说明与示例 |
| :--- | :--- | :--- | :--- |
| `api_name` | 是 | String | 要调用的接口名称。例如：`"daily"`, `"stock_basic"`。特殊值`"list"`用于查询接口列表。 |
| `token` | 否 | String | 您的Tushare Token。若不在此传入，则必须设置`TUSHARE_TOKEN`环境变量。 |
| `ts_code` | 否 | String | 股票代码。格式：`代码.交易所`。单/多个：`"000001.SZ"` 或 `"000001.SZ,600000.SH"`。 |
| `trade_date` | 否 | String | 指定交易日。格式：`YYYYMMDD`。示例：`"20240115"`。 |
| `start_date` | 否 | String | 开始日期。日线：`YYYYMMDD`；分钟线：`YYYY-MM-DD HH:MM:SS`。需与`end_date`配对使用。 |
| `end_date` | 否 | String | 结束日期。格式同 `start_date`。 |
| `fields` | 否 | String | 指定返回字段，英文逗号分隔，无空格。示例：`"ts_code,trade_date,open,close,vol"`。 |
| `extra_params` | 否 | String | 其他接口特定参数，需为**合法的JSON字符串**。示例：`"{\"freq\": \"5min\"}"`。 |

## 典型调用示例

### 获取实时日K线（支持通配符）
json
{
"api_name": "rt_k",
"ts_code": "6*.SH"
}
### 获取5分钟K线数据
json
{
"api_name": "stk_mins",
"ts_code": "600000.SH",
"freq": "5min",
"start_date": "2024-01-15 09:00:00",
"end_date": "2024-01-15 15:00:00"
}
### 获取股票列表
json
{
"api_name": "stock_basic",
"list_status": "L",
"fields": "ts_code,symbol,name,area,industry,list_date"
}
### 使用额外参数
json
{
"api_name": "stock_hsgt",
"trade_date": "20240115",
"extra_params": "{"type": "HK_SZ"}"
}
## 安装依赖
bash
pip install tushare pandas
## 重要注意事项
1.  **积分与权限**: 不同接口需要不同的Tushare积分。基础行情接口通常需2000积分，实时数据等高级接口需要更高积分或单独申请权限。
2.  **数据延迟**: 免费账号获取的数据可能有**15分钟**的延迟。
3.  **股票代码**: 格式为 `代码.交易所`，如 `000001.SZ` (深交所), `600000.SH` (上交所)。
4.  **日期格式**: 请严格区分**日线接口** (`YYYYMMDD`) 和**分钟线接口** (`YYYY-MM-DD HH:MM:SS`) 的日期时间格式。
5.  **官方文档**: 完整参数和字段说明，请参考 [Tushare官方文档](https://tushare.pro/document/2)。
6.  **错误排查**: 如调用失败，请按序检查：① Token是否有效且已配置；② 参数名称和格式是否正确；③ 账号积分是否支持该接口。


path: metadata.json
content: {
  "name": "tushare-stock-data",
  "version": "1.0.0",
  "description": "Tushare 股票数据接口集合 - 提供行情、基础信息、基本面、特色数据等23个明确的数据接口。",
  "author": "真圆氦狗",
  "tags": [
    "股票",
    "行情",
    "A股",
    "tushare",
    "量化",
    "金融数据",
    "明确接口"
  ],
  "repository": "",
  "license": "MIT",
  "dependencies": {
    "python": ">=3.8",
    "packages": [
      "tushare>=1.2.89",
      "pandas>=1.5.0"
    ]
  },
  "openclaw": {
    "requires": {
      "bins": [
        "python3"
      ],
      "env": [
        "TUSHARE_TOKEN"
      ]
    }
  },
  "environment_variables": ["TUSHARE_TOKEN"],
  "runtime": {
    "type": "python3",
    "entrypoint": "handler"
  }
}



path: __init__.py
content: #!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Tushare 股票数据技能 (完整接口版)
基于用户提供的详细接口文档实现。
支持 23 个核心接口。
"""
import json
import os
import sys
import pandas as pd
import traceback
from datetime import datetime

# 添加当前目录到Python路径
sys.path.append(os.path.dirname(os.path.abspath(__file__)))

# 尝试导入tushare
try:
    import tushare as ts
    TUSHARE_AVAILABLE = True
except ImportError:
    TUSHARE_AVAILABLE = False
    print("警告: tushare库未安装，请运行: pip install tushare")

# ========== 【核心】本技能支持的全部接口列表 ==========
SUPPORTED_APIS = {
    # ===== 行情数据类 =====
    "daily": {
        "name": "日线行情",
        "description": "获取股票日线行情数据，包含开盘、最高、最低、收盘、成交量等。交易日每天15点～16点之间入库。本接口是未复权行情，停牌期间不提供数据。",
        "category": "行情数据"
    },
    "rt_k": {
        "name": "实时日K线",
        "description": "获取实时日k线行情，支持按股票代码及股票代码通配符一次性提取全部股票实时日k线行情。单次最大可提取6000条数据。",
        "category": "行情数据"
    },
    "stk_mins": {
        "name": "分钟行情",
        "description": "获取A股分钟数据，支持1min/5min/15min/30min/60min行情。单次最大8000行数据，可提供超过10年历史分钟数据。",
        "category": "行情数据"
    },
    "rt_min": {
        "name": "全A实时分钟数据",
        "description": "获取全A股票实时分钟数据，包括1~60min。单次最大1000行数据。",
        "category": "行情数据"
    },
    "weekly": {
        "name": "周线行情",
        "description": "获取A股周线行情，本接口每周最后一个交易日更新。单次最大6000行。",
        "category": "行情数据"
    },
    "monthly": {
        "name": "月线行情",
        "description": "获取A股月线数据。单次最大4500行。",
        "category": "行情数据"
    },
    "stk_weekly_monthly": {
        "name": "股票周/月线行情(每日更新)",
        "description": "股票周/月线行情(每日更新)。单次最大6000行。",
        "category": "行情数据"
    },
    "stk_week_month_adj": {
        "name": "股票周/月线行情(复权--每日更新)",
        "description": "股票周/月线行情(复权--每日更新)。单次最大6000行。",
        "category": "行情数据"
    },
    "adj_factor": {
        "name": "复权因子",
        "description": "获取股票复权因子，可提取单只股票全部历史复权因子，也可以提取单日全部股票的复权因子。盘前9点15~20分完成当日复权因子入库。",
        "category": "行情数据"
    },
    "daily_basic": {
        "name": "每日指标",
        "description": "获取全部股票每日重要的基本面指标，可用于选股分析、报表展示等。交易日每日15点～17点之间更新。单次请求最大返回6000条数据。",
        "category": "行情数据"
    },
    "stk_limit": {
        "name": "涨跌停价格",
        "description": "获取全市场（包含A/B股和基金）每日涨跌停价格，包括涨停价格，跌停价格等，每个交易日8点40左右更新当日股票涨跌停价格。单次最多提取5800条记录。",
        "category": "行情数据"
    },
    "suspend_d": {
        "name": "每日停复牌信息",
        "description": "按日期方式获取股票每日停复牌信息。",
        "category": "行情数据"
    },
    "hsgt_top10": {
        "name": "沪深港通十大成交股",
        "description": "获取沪股通、深股通每日前十大成交详细数据，每天18~20点之间完成当日更新。",
        "category": "行情数据"
    },
    # ===== 基础信息类 =====
    "stock_basic": {
        "name": "股票列表",
        "description": "获取基础信息数据，包括股票代码、名称、上市日期、退市日期等。每次最多返回6000行数据。此接口是基础信息，调取一次就可以拉取完，建议保存到本地存储后使用。",
        "category": "基础信息"
    },
    "trade_cal": {
        "name": "交易日历",
        "description": "获取各大交易所交易日历数据，默认提取的是上交所。",
        "category": "基础信息"
    },
    "stock_st": {
        "name": "ST股票列表",
        "description": "获取ST股票列表，可根据交易日期获取历史上每天的ST列表。每天上午9:20更新，单次请求最大返回1000行数据。本接口数据从20160101开始。",
        "category": "基础信息"
    },
    "stock_hsgt": {
        "name": "沪深港通股票列表",
        "description": "获取沪深港通股票列表。每天上午9:20更新，单次请求最大返回2000行数据。本接口数据从20250812开始。",
        "category": "基础信息"
    },
    "namechange": {
        "name": "历史名称变更记录",
        "description": "获取股票历史名称变更记录。",
        "category": "基础信息"
    },
    "stock_company": {
        "name": "上市公司基础信息",
        "description": "获取上市公司基础信息，单次提取4500条，可以根据交易所分批提取。",
        "category": "基础信息"
    },
    "stk_managers": {
        "name": "上市公司管理层",
        "description": "获取上市公司管理层信息。",
        "category": "基础信息"
    },
    "stk_rewards": {
        "name": "管理层薪酬和持股",
        "description": "获取上市公司管理层薪酬和持股信息。",
        "category": "基础信息"
    },
    "bse_mapping": {
        "name": "北交所新旧代码对照表",
        "description": "获取北交所股票代码变更后新旧代码映射表数据。单次最大1000条。",
        "category": "基础信息"
    },
    "new_share": {
        "name": "IPO新股列表",
        "description": "获取新股上市列表数据。单次最大2000条。",
        "category": "基础信息"
    },
    "bak_basic": {
        "name": "股票历史列表（备用基础列表）",
        "description": "获取备用基础列表，数据从2016年开始。单次最大7000条。",
        "category": "基础信息"
    }
}

class TushareClient:
    """Tushare API客户端"""
    
    def __init__(self, token: str = None):
        # 【关键修正】移除默认Token，强制用户提供
        self.token = token or os.environ.get("TUSHARE_TOKEN", "")
        if not self.token:
            raise ValueError(
                "未检测到有效的 Tushare Token。\n"
                "请通过以下任一方式配置：\n"
                "  1. 在调用参数中传入：{'token': '你的token'}\n"
                "  2. 设置系统环境变量：export TUSHARE_TOKEN='你的token'\n"
                "Token需在Tushare官网(https://tushare.pro)注册获取。"
            )
        self.pro = None
        self._init_pro()
    
    def _init_pro(self):
        try:
            self.pro = ts.pro_api(self.token)
        except Exception as e:
            raise Exception(f"Tushare初始化失败: {str(e)}")
    
    def call_api(self, api_name: str, **kwargs):
        if not self.pro:
            self._init_pro()
        
        if not hasattr(self.pro, api_name):
            raise Exception(f"Tushare接口 '{api_name}' 不存在。请检查接口名称。")
        
        try:
            api_method = getattr(self.pro, api_name)
            result = api_method(**kwargs)
            
            if result is None:
                return {"success": False, "error": "API返回空结果", "data": None}
            
            if isinstance(result, pd.DataFrame):
                if result.empty:
                    return {"success": True, "message": "查询成功，但无数据", "data": [], "count": 0}
                df = result.where(pd.notnull(result), None)
                return {
                    "success": True,
                    "message": "查询成功",
                    "data": df.to_dict('records'),
                    "count": len(df),
                    "columns": list(df.columns)
                }
            else:
                return {"success": True, "message": "查询成功", "data": result, "count": 1}
        except Exception as e:
            return {"success": False, "error": f"API调用失败: {str(e)}"}

def handler(params: dict) -> dict:
    if not TUSHARE_AVAILABLE:
        return {"success": False, "error": "tushare库未安装。请运行: pip install tushare pandas"}
    
    api_name = params.get("api_name", "").strip()
    [REDACTED_SECRET]"token", "").strip()
    ts_code = params.get("ts_code", "").strip()
    trade_date = params.get("trade_date", "").strip()
    start_date = params.get("start_date", "").strip()
    end_date = params.get("end_date", "").strip()
    fields = params.get("fields", "").strip()
    extra_params_str = params.get("extra_params", "{}").strip()
    
    # 处理 list 命令
    if api_name.lower() in ["list", "help", "?", "接口列表"]:
        result_list = []
        for api_key, info in SUPPORTED_APIS.items():
            result_list.append({
                "api_name": api_key,
                "name": info["name"],
                "category": info["category"],
                "description": info["description"][:100] + "..." if len(info["description"]) > 100 else info["description"]
            })
        return {
            "success": True,
            "message": f"本技能共支持 {len(SUPPORTED_APIS)} 个Tushare股票接口",
            "apis": result_list
        }
    
    # 验证必需参数
    if not api_name:
        return {"success": False, "error": "参数 'api_name' 为必填项。输入 'list' 查看全部接口。"}
    if api_name not in SUPPORTED_APIS:
        return {"success": False, "error": f"接口 '{api_name}' 不在支持列表中。输入 'list' 查看全部接口。"}
    
    # 构建API参数
    api_params = {}
    for key in ["ts_code", "trade_date", "start_date", "end_date", "fields"]:
        if value := params.get(key, "").strip():
            api_params[key] = value
    
    if extra_params_str:
        try:
            extra_params = json.loads(extra_params_str)
            if isinstance(extra_params, dict):
                api_params.update(extra_params)
        except json.JSONDecodeError:
            return {"success": False, "error": "参数 'extra_params' 必须是有效的JSON字符串。"}
    
    api_params = {k: v for k, v in api_params.items() if v not in ["", None]}
    
    # 调用API
    try:
        client = TushareClient(token=token if token else None)
        result = client.call_api(api_name, **api_params)
        if result.get("success"):
            result["request_info"] = {"api_name": api_name, "params": api_params, "called_at": datetime.now().isoformat()}
        return result
    except ValueError as e:
        return {"success": False, "error": str(e)}
    except Exception as e:
        return {"success": False, "error": f"处理请求时出错: {str(e)}"}

if __name__ == "__main__":
    import sys
    import json

    # 从标准输入读取调用参数
    input_str = sys.stdin.read()
    if not input_str.strip():
        # 如果输入为空，默认执行列出接口的命令
        params = {"api_name": "list"}
    else:
        try:
            params = json.loads(input_str)
        except json.JSONDecodeError as e:
            # 如果输入不是合法JSON，返回错误
            error_result = {"success": False, "error": f"Invalid JSON input: {e}"}
            print(json.dumps(error_result, ensure_ascii=False))
            sys.exit(1)

    # 调用主处理函数
    try:
        result = handler(params)
        # 将结果以JSON格式打印到标准输出，供平台捕获
        print(json.dumps(result, ensure_ascii=False))
    except Exception as e:
        # 捕获处理过程中的未预期异常
        error_result = {"success": False, "error": f"Handler execution failed: {str(e)}"}
        print(json.dumps(error_result, ensure_ascii=False))
        sys.exit(1)

Security scan verdicts — ClawScan: clean | static analysis: clean | VirusTotal: clean | SkillSpector: clean (LOW)