Skill: gaingush/tqsdk-query (version 1.0.0)

--- name: tqsdk-read description: 天勤量化 - 期货实时行情与历史数据接口，提供国内期货、期权的实时报价、K线序列与历史数据查询。 version: 1.0.0 author: 真圆氦狗 homepage: https://www.shinnytech.com/tqsdk/ runtime: python3 entrypoint: __init__.py:handler parameters: - name: action type: string required: true enum: - get_quote - get_kline_serial - get_kline_data description: 要执行的操作类型 - name: symbol type: string required: true description: 合约代码，格式如 "SHFE.rb2410"。多合约用逗号分隔，如 "SHFE.rb2410,DCE.m2409" - name: duration_seconds type: integer required: false default: 60 description: K线周期（秒），仅用于 get_kline_serial 或 get_kline_data - name: data_length type: integer required: false default: 200 description: K线序列长度，仅用于 get_kline_serial - name: start_dt type: string required: false description: 历史数据起始时间（ISO 8601），仅用于 get_kline_data - name: end_dt type: string required: false description: 历史数据结束时间（ISO 8601），仅用于 get_kline_data --- # 天勤量化技能 该技能提供天勤量化接口的访问，支持获取期货实时行情、K线序列及历史数据。 ## 使用示例 /tqsdk-read get_quote SHFE.rb2410 /tqsdk-read get_kline_serial SHFE.rb2410 --duration_seconds 300 --data_length 50 /tqsdk-read get_kline_data SHFE.rb2410 --duration_seconds 3600 --start_dt 2024-01-01T09:00:00 --end_dt 2024-01-31T15:00:00 ## 环境变量配置 **重要：本技能的天勤账号信息必须且只能通过环境变量配置，调用时无需也无需传入用户名和密码。** 请在使用前设置以下环境变量： - `TQ_USERNAME`：天勤用户名（注册于官网） - `TQ_PASSWORD`：天勤密码 在 ClawHub 中，可在技能设置页面或通过环境变量文件配置。 ## 注意事项 - 历史K线查询（`get_kline_data`）需要天勤**专业版账号**权限。 - 实时行情和K线序列（`get_quote`, `get_kline_serial`）基础版账号即可使用。 - 合约代码格式：交易所.合约代码，如 `SHFE.rb2410`、`DCE.m2409`、`CFFEX.IF2406`。 - 多合约操作时，`symbol` 参数用逗号分隔（仅支持 `get_quote` 和 `get_kline_serial`）。 - K线周期常用值：60（1分钟）、300（5分钟）、900（15分钟）、3600（1小时）、86400（日线）。 ## 常见问题 **Q: 提示"天勤认证失败"怎么办？** A: 请检查环境变量 `TQ_USERNAME` 和 `TQ_PASSWORD` 是否正确，并确保账户已激活。 **Q: 历史K线接口报错？** A: 确认您拥有天勤专业版账号，且时间范围有效（K线数量不超过限制）。 **Q: 调用时还需要传入用户名和密码吗？** A: 不需要。账号信息已改为通过环境变量配置，调用时只需传入 action、symbol 等业务参数。

path: __init__.py
content: import os
import json
import asyncio
from datetime import datetime
from typing import Dict, Any, List, Union

from tqsdk import TqApi, TqAuth
from .tqsdk_client import TqSdkClient  # 可选封装


def handler(params: Dict[str, Any]) -> Dict[str, Any]:
    """
    Skill 入口函数，由 Clawdbot 调用。
    params 包含用户传入的所有参数（按 SKILL.md 定义）。
    返回一个字典，包含 result 或 error。
    """
    # 从环境变量读取天勤账号
    username = os.environ.get("TQ_USERNAME")
    [REDACTED_SECRET]"TQ_PASSWORD")
    
    if not username or not [REDACTED_SECRET] {"text": "错误：未设置天勤账号。请设置环境变量 TQ_USERNAME 和 TQ_PASSWORD。"}
    
    action = params.get("action")
    symbol = params.get("symbol")
    
    # 处理多合约符号（支持逗号分隔）
    symbols = [s.strip() for s in symbol.split(",")] if symbol else []
    
    # 根据 action 调用不同逻辑
    if action == "get_quote":
        return asyncio.run(_get_quote(username, password, symbols))
    elif action == "get_kline_serial":
        duration = params.get("duration_seconds", 60)
        data_length = params.get("data_length", 200)
        return asyncio.run(_get_kline_serial(username, password, symbols, duration, data_length))
    elif action == "get_kline_data":
        duration = params.get("duration_seconds", 3600)
        start_dt = datetime.fromisoformat(params["start_dt"]) if params.get("start_dt") else None
        end_dt = datetime.fromisoformat(params["end_dt"]) if params.get("end_dt") else None
        if not start_dt or not end_dt:
            return {"text": "错误：历史数据查询需要提供 start_dt 和 end_dt 参数。"}
        return asyncio.run(_get_kline_data(username, password, symbols[0], duration, start_dt, end_dt))
    else:
        return {"text": f"未知操作: {action}。支持的操作: get_quote, get_kline_serial, get_kline_data"}


async def _get_quote(username: str, password: str, symbols: List[str]) -> Dict:
    """
    获取实时盘口数据
    """
    api = TqApi(auth=TqAuth(username, password))
    try:
        quotes = []
        for sym in symbols:
            quote = api.get_quote(sym)
            # 等待至少一次更新确保数据有效
            await api.wait_update()
            quotes.append({
                "symbol": sym,
                "last_price": quote.last_price,
                "ask_price1": quote.ask_price1,
                "ask_volume1": quote.ask_volume1,
                "bid_price1": quote.bid_price1,
                "bid_volume1": quote.bid_volume1,
                "volume": quote.volume,
                "open_interest": quote.open_interest,
                "datetime": str(quote.datetime),
                "highest": quote.highest,
                "lowest": quote.lowest,
                "open": quote.open,
                "close": quote.close,
                "pre_settlement": quote.pre_settlement,
            })
        # 构造可读文本
        text_lines = []
        for q in quotes:
            text_lines.append(
                f"{q['symbol']}: 最新价 {q['last_price']} | 买一 {q['bid_price1']}/{q['bid_volume1']} | "
                f"卖一 {q['ask_price1']}/{q['ask_volume1']} | 成交量 {q['volume']} | 时间 {q['datetime']}"
            )
        return {"text": "\n".join(text_lines), "result": quotes}
    finally:
        await api.close()


async def _get_kline_serial(username: str, password: str, symbols: List[str], duration: int, length: int) -> Dict:
    """
    获取实时K线序列（动态更新，返回最新N条）
    """
    api = TqApi(auth=TqAuth(username, password))
    try:
        # 如果 symbols 是单个，get_kline_serial 返回 DataFrame；多个时返回带后缀的 DataFrame
        if len(symbols) == 1:
            klines = api.get_kline_serial(symbols[0], duration, data_length=length)
        else:
            klines = api.get_kline_serial(symbols, duration, data_length=length)
        
        await api.wait_update()  # 确保至少获取一次数据
        
        # 将最后一条K线数据转换为字典
        last = klines.iloc[-1].to_dict()
        # 将 numpy 类型转为 Python 原生类型
        for k, v in last.items():
            if hasattr(v, 'item'):
                last[k] = v.item()
            elif isinstance(v, (int, float, str)):
                pass
            else:
                last[k] = str(v)
        # 构造可读文本
        text = f"最新{'' if len(symbols)==1 else '多合约'}K线（周期{duration}秒）：\n"
        text += f"时间 {last.get('datetime', 'N/A')} | 开 {last.get('open')} 高 {last.get('high')} "
        text += f"低 {last.get('low')} 收 {last.get('close')} | 成交量 {last.get('volume')}"
        return {"text": text, "result": {"last_kline": last, "data_length": len(klines)}}
    finally:
        await api.close()


async def _get_kline_data(username: str, password: str, symbol: str, duration: int,
                          start_dt: datetime, end_dt: datetime) -> Dict:
    """
    获取历史K线数据（静态）
    """
    api = TqApi(auth=TqAuth(username, password))
    try:
        data = api.get_kline_data_series(
            symbol=symbol,
            duration_seconds=duration,
            start_dt=start_dt,
            end_dt=end_dt
        )
        # 将 DataFrame 转换为记录列表
        records = data.to_dict(orient="records")
        # 处理时间戳
        for rec in records:
            if "datetime" in rec:
                rec["datetime"] = str(rec["datetime"])
        count = len(records)
        text = f"获取到 {count} 条 {symbol} 的{'' if count else '无'}历史K线（周期{duration}秒）"
        if count > 0:
            latest = records[-1]
            text += f"，最新一条：时间 {latest.get('datetime')} 收 {latest.get('close')}"
        return {"text": text, "result": {"count": count, "data": records}}
    except Exception as e:
        return {"text": f"获取历史K线失败: {str(e)}", "error": str(e)}
    finally:
        await api.close()

path: README.md
content: # 天勤量化 Skill

该 Skill 提供对天勤量化接口的访问，支持获取实时行情、实时K线序列和历史K线数据。

## 前置条件

- 在天勤官网注册账号并获取用户名/密码。
- 历史K线查询需要专业版账号权限。
- **重要：账号信息必须通过环境变量配置（见下文）**

## 安装

在 Clawdbot 中安装此 Skill 后，会自动安装依赖。

## 环境变量配置

本技能通过环境变量读取天勤账号，请在使用前设置：

- `TQ_USERNAME`：天勤用户名（注册于官网）
- `TQ_PASSWORD`：天勤密码

**注意：账号信息不再通过调用参数传递，必须通过环境变量配置。**

## 参数说明

| 参数名            | 类型    | 必填 | 说明                                                                 |
|-------------------|---------|------|----------------------------------------------------------------------|
| action            | string  | 是   | 操作类型：`get_quote`, `get_kline_serial`, `get_kline_data`          |
| symbol            | string  | 是   | 合约代码，多合约用逗号分隔，如 `SHFE.rb2410,DCE.m2409`               |
| duration_seconds  | integer | 否   | K线周期（秒），默认 60。仅用于 K线相关操作                           |
| data_length       | integer | 否   | K线序列长度，默认 200。仅用于 `get_kline_serial`                     |
| start_dt          | string  | 否   | 起始时间（ISO 8601），如 `2024-01-01T09:00:00`。仅用于 `get_kline_data` |
| end_dt            | string  | 否   | 结束时间（ISO 8601）。仅用于 `get_kline_data`                        |

## 示例

### 获取螺纹钢实时行情

json
{
"action": "get_quote",
"symbol": "SHFE.rb2410"
}
返回结果：
json
{
"result": [
{
"symbol": "SHFE.rb2410",
"last_price": 3825.0,
"ask_price1": 3826.0,
"bid_price1": 3824.0,
"volume": 123456,
"open_interest": 789012,
"datetime": "2025-04-15 14:30:00"
}
]
}
### 获取5分钟K线序列（最近200根）
json
{
"action": "get_kline_serial",
"symbol": "SHFE.rb2410",
"duration_seconds": 300,
"data_length": 200
}
返回结果包含最新一根K线的完整信息。

### 获取历史1小时K线
json
{
"action": "get_kline_data",
"symbol": "SHFE.rb2410",
"duration_seconds": 3600,
"start_dt": "2024-01-01T09:00:00",
"end_dt": "2024-01-31T15:00:00"
}
返回结果包含指定时间段内的所有K线数据（最多约5000条）。

## 注意事项

- 历史K线接口需要天勤专业版账号。
- 实时接口会等待第一次行情更新，可能会稍有延迟。
- 密码等敏感信息应通过环境变量配置，避免在代码或配置文件中明文存储。
- 确保在运行环境中正确设置 `TQ_USERNAME` 和 `TQ_PASSWORD` 环境变量。

path: requirements.txt
content: tqsdk>=3.0.0
pandas>=1.3.0

path: skill.yaml
content: name: tqsdk-read
description: 天勤量化 - 期货实时行情与历史数据接口，提供国内期货、期权的实时报价、K线序列与历史数据查询。
version: 1.0.0
author: 真圆氦狗
homepage: https://www.shinnytech.com/tqsdk/
runtime: python3
entrypoint: __init__.py:handler   # 指定入口函数

parameters:
  - name: action
    type: string
    required: true
    enum:
      - get_quote          # 获取实时盘口
      - get_kline_serial   # 获取实时K线序列
      - get_kline_data     # 获取历史K线数据（需专业版账号）
    description: 要执行的操作类型

  - name: symbol
    type: string
    required: true
    description: 合约代码，格式如 "SHFE.rb2410"。对于多合约操作，可用逗号分隔，如 "SHFE.rb2410,DCE.m2409"

  - name: duration_seconds
    type: integer
    required: false
    default: 60
    description: K线周期（秒），仅在 action 为 get_kline_serial 或 get_kline_data 时需要。例如 60=1分钟，300=5分钟

  - name: data_length
    type: integer
    required: false
    default: 200
    description: 返回的K线序列长度，仅在 action 为 get_kline_serial 时使用

  - name: start_dt
    type: string
    required: false
    description: 历史数据起始时间（ISO 8601格式，如 "2024-01-01T09:00:00"），仅在 action 为 get_kline_data 时使用

  - name: end_dt
    type: string
    required: false
    description: 历史数据结束时间（ISO 8601格式），仅在 action 为 get_kline_data 时使用

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