
Ths Financial Data
- 9 installs
- 33 repo stars
- Updated April 26, 2026
- bighardperson/computer-science-skills-collection
ths-financial-data is a Claude skill that fetches stock market data (real-time quotes, capital flow and daily K-line) via the thsdk library backed by the 同花顺 (THS) data interface.
About
This skill fetches stock market data using the thsdk library backed by the 同花顺 (Tonghuashun/THS) data interface, covering A-shares, Hong Kong and US stocks with real-time quotes, capital flow and daily K-line data. It auto-converts Chinese names, abbreviations and short codes into the full ths_code format and returns a candidate list when multiple stocks match. A developer uses it when building financial data lookups or stock analysis. It matters because it auto-installs thsdk and handles the code-resolution flow so the agent does not have to memorize market prefixes.
- Fetches stock market data (real-time quotes, capital flow, daily K-line) via the thsdk / 同花顺 (THS) interface
- Auto-resolves Chinese names, abbreviations and short codes into the full ths_code format
- Returns a candidate list for user selection when multiple A-shares match
Ths Financial Data by the numbers
- 9 all-time installs (skills.sh)
- Ranked #812 of 1,106 Finance & Trading skills by installs in the Skillselion catalog
- Data as of Jul 30, 2026 (Skillselion catalog sync)
ths-financial-data capabilities & compatibility
Auto-installs the free thsdk library; no API key mentioned
- Capabilities
- market data fetch · stock lookup
- Use cases
- trading · data analysis · research
- Runs
- Runs locally
- Pricing
- Free
What ths-financial-data says it does
使用thsdk库提供同花顺数据接口支持。
此skill提供基于thsdk库的股票市场数据获取功能,支持A股、港股、美股等多市场数据查询。
如果检测到 thsdk 未安装或版本低于 1.7.14,会自动执行
npx skills add https://github.com/bighardperson/computer-science-skills-collection --skill ths-financial-dataAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 9 |
|---|---|
| repo stars | ★ 33 |
| Last updated | April 26, 2026 |
| Repository | bighardperson/computer-science-skills-collection ↗ |
What it does
Fetch A-share, HK and US stock market data (quotes, capital flow, K-line) via the thsdk/THS interface.
Who is it for?
Agents that need A-share, HK or US stock quotes, capital flow or K-line data from the 同花顺 interface
Skip if: Placing trades or executing orders; it only reads market data
When should I use this skill?
The user needs stock market data, wants to analyze a stock, or is building a financial app that needs quotes or K-line data
What you get
- Structured stock data (quotes, K-line DataFrames, candidate lists)
By the numbers
- 4 supported markets (A-share, HK, US) with 4 code prefixes
- requires thsdk >= 1.7.14
Files
Stock Data Skill
概述
此skill提供基于thsdk库的股票市场数据获取功能,支持A股、港股、美股等多市场数据查询。该skill应于用户需要获取金融市场数据、进行股票分析或构建金融应用时使用。
自动安装依赖
此skill会自动处理 thsdk 库的安装,无需用户手动操作:
首次使用时:
│
▼
检查 thsdk 是否安装?
│
┌────┴────┐
YES NO
│ │
▼ ▼
检查版本 自动执行
>= 1.7.14? pip install --upgrade thsdk
│
┌────┴────┐
YES NO
│ │
▼ ▼
正常使用 自动升级如果检测到 thsdk 未安装或版本低于 1.7.14,会自动执行:
pip install --upgrade thsdk代码自动解析工作流(核心规则)
在任何需要股票代码的操作之前,必须先执行以下判断流程:
用户输入的 stock_code
│
▼
是否满足"直通"条件?
USHA + 6位数字 (如 USHA600519,上交所A股)
USZA + 6位数字 (如 USZA000001,深交所A股)
│
┌────┴────┐
YES NO(短代码/中文/缩写/其他前缀/其他任何格式)
│ │
▼ ▼
直接使用 调用 search_symbols(input) 查询候选列表
│
▼
获取完整的 ths_code
│
┌─────┴─────┐
0条 1条 多条
│ │ │
▼ ▼ ▼
返回错误 自动匹配 筛选A股
"未找到" ths_code │
┌────┴────┐
0只A股 1只A股 多只A股
│ │ │
▼ ▼ ▼
展示全部 自动选择 返回候选列表
让用户选择 等待用户选择多股票选择交互流程(重要)
当 search_symbols 匹配到多只A股时,函数会返回一个特殊结构:
{
'need_selection': True,
'candidates': [
{'ths_code': 'USHA600520', 'name': '三佳科技', 'code': '600520', 'market': '沪A'},
{'ths_code': 'USZA002796', 'name': '世嘉科技', 'code': '002796', 'market': '深A'},
# ... 更多候选
],
'display': '\n**找到 5 只A股**:\n\n 1. **三佳科技** `USHA600520` (沪A)\n 2. **世嘉科技** `USZA002796` (深A)\n ...\n\n请输入序号选择(1-5),或输入 0 取消。'
}AI 助手应该: 1. 检测返回值是否为 dict 且包含 need_selection: True 2. 将 display 内容展示给用户 3. 等待用户输入序号 4. 使用 get_candidate_by_index(candidates, index) 获取用户选择的股票 5. 使用获取到的 ths_code 继续后续操作
示例交互流程
from thsdk import THS
from stock_utils import search_stock_candidates, get_candidate_by_index, get_kline_data
with THS() as ths:
# 第一步:搜索股票
result = search_stock_candidates(ths, "sjkj")
if result['status'] == 'found':
# 唯一匹配,直接使用
ths_code = result['ths_code']
df = ths.klines(ths_code, interval="day", count=30)
elif result['status'] == 'need_selection':
# 多个候选,需要用户选择
print(result['display']) # 展示给用户
# AI 应该在这里等待用户输入序号
# 假设用户选择了 2
user_choice = 2
selected = get_candidate_by_index(result['candidates'], user_choice)
if selected:
ths_code = selected['ths_code']
df = ths.klines(ths_code, interval="day", count=30)
elif result['status'] == 'not_found':
print(result['display']) # 未找到提示---
快速开始
AI 助手使用此 Skill 时
1. 自动安装检查:首次调用时会自动检查并安装 thsdk 2. 获取 THS 实例:可使用 get_ths_instance() 或直接 from thsdk import THS 3. 调用查询函数:使用 search_stock_candidates 等函数获取数据
# 方式1:使用便捷函数(推荐)
from stock_utils import get_ths_instance, get_kline_data
ths = get_ths_instance()
if ths:
df = get_kline_data(ths, "平安银行", interval="day", count=30)
# 方式2:标准方式
from thsdk import THS
from stock_utils import search_stock_candidates, get_kline_data
with THS() as ths:
result = search_stock_candidates(ths, "平安银行")
if result['status'] == 'found':
df = ths.klines(result['ths_code'], interval="day", count=30)股票代码格式说明
thsdk 要求使用完整 ths_code,格式为市场前缀 + 代码:
| 市场 | 前缀 | 示例 |
|---|---|---|
| 深交所A股 | USZA | USZA000001 |
| 上交所A股 | USHA | USHA600519 |
| 港股 | HKHK | HKHK00700 |
| 美股 | USUS | USUSAAPL |
不需要手动记忆前缀,使用 search_stock_candidates() 自动处理一切格式。核心函数
1. ensure_thsdk() - 自动安装检查
from stock_utils import ensure_thsdk, get_ths_instance
# 确保 thsdk 已安装
if ensure_thsdk():
print("thsdk 已就绪")
# 或直接获取实例(内部会自动检查安装)
ths = get_ths_instance()2. search_stock_candidates(推荐)
搜索股票并返回结构化结果,支持优雅的用户选择流程:
from thsdk import THS
from stock_utils import search_stock_candidates
with THS() as ths:
result = search_stock_candidates(ths, "ndsd")
# result['status'] 可能的值:
# - 'found': 唯一匹配,result['ths_code'] 可直接使用
# - 'need_selection': 多个候选,需要用户选择
# - 'not_found': 未找到匹配
# result['ths_code']: 唯一匹配时的 ths_code
# result['candidates']: 候选列表
# result['display']: 格式化的展示文本(直接展示给用户)3. get_candidate_by_index
根据序号获取用户选择的股票:
from stock_utils import get_candidate_by_index
# candidates 是 search_stock_candidates 返回的候选列表
# index 是用户输入的序号(1-based)
selected = get_candidate_by_index(candidates, 2)
if selected:
print(f"用户选择: {selected['name']} ({selected['ths_code']})")4. get_kline_data
获取K线数据,支持自动解析股票代码:
from thsdk import THS
from stock_utils import get_kline_data
with THS() as ths:
result = get_kline_data(ths, "平安银行", interval="day", count=30)
# 检查是否需要用户选择
if isinstance(result, dict) and result.get('need_selection'):
print(result['display']) # 展示候选列表给用户
# 等待用户选择...
elif isinstance(result, pd.DataFrame):
print(result) # 成功获取数据
else:
print("获取失败")5. get_realtime_data
获取实时行情:
from thsdk import THS
from stock_utils import get_realtime_data
with THS() as ths:
result = get_realtime_data(ths, "000001")
if isinstance(result, dict):
if result.get('need_selection'):
print(result['display']) # 需要选择
else:
print(f"股票:{result['name']}")
print(f"最新价:{result['price']}")
print(f"涨跌幅:{result['change_pct']}%")6. get_fund_flow
获取资金流向:
from thsdk import THS
from stock_utils import get_fund_flow
with THS() as ths:
result = get_fund_flow(ths, "贵州茅台")
if isinstance(result, dict) and not result.get('need_selection'):
print(f"主力净流入:{result['main_net_inflow']}")
print(f"散户净流入:{result['retail_net_inflow']}")7. wencai_query
使用问财自然语言查询:
from thsdk import THS
from stock_utils import wencai_query
with THS() as ths:
df = wencai_query(ths, "最近热度前50的行业和涨停原因归类")
if df is not None:
print(df.head())完整使用示例
场景:用户输入模糊查询
from thsdk import THS
from stock_utils import search_stock_candidates, get_candidate_by_index, get_kline_data
with THS() as ths:
# 用户输入:sjkj
result = search_stock_candidates(ths, "sjkj")
if result['status'] == 'need_selection':
# 展示候选给用户
print(result['display'])
# 输出示例:
# **找到 5 只A股**:
#
# 1. **三佳科技** `USHA600520` (沪A)
# 2. **盛剑科技** `USHA603324` (沪A)
# 3. **世嘉科技** `USZA002796` (深A)
# 4. **仕净科技** `USZA301030` (深A)
# 5. **熵基科技** `USZA301330` (深A)
#
# 请输入序号选择(1-5),或输入 0 取消。
# 等待用户选择序号
# user_choice = int(input("请选择: ")) # 假设用户输入 3
selected = get_candidate_by_index(result['candidates'], user_choice)
if selected:
ths_code = selected['ths_code']
df = ths.klines(ths_code, interval="day", count=30)
print(f"已获取 {selected['name']} 的日K线数据")场景:唯一匹配(自动处理)
from thsdk import THS
from stock_utils import search_stock_candidates, get_kline_data
with THS() as ths:
result = search_stock_candidates(ths, "ndsd")
if result['status'] == 'found':
# 自动匹配,无需用户选择
print(result['display']) # ✅ 已自动匹配:**宁德时代** `USZA300750` (深A)
df = ths.klines(result['ths_code'], interval="day", count=30)
print(df.head())返回值说明
search_stock_candidates 返回结构
| 字段 | 类型 | 说明 |
|---|---|---|
status | str | found / need_selection / not_found |
ths_code | str | 唯一匹配时的股票代码 |
candidates | list | 候选股票列表 |
message | str | 简短提示信息 |
display | str | 格式化的展示文本(Markdown格式) |
get_candidate_by_index 返回结构
{
'ths_code': 'USZA002796',
'name': '世嘉科技',
'code': '002796',
'market': '深A'
}输出格式
所有数据以表格形式输出,使用 Markdown 表格格式:
实时行情表格示例
| 代码 | 名称 | 最新价 | 涨跌幅 | 涨跌额 | 成交量 | 成交额 |
|---|---|---|---|---|---|---|
| USZA000001 | 平安银行 | 15.20 | +1.23% | +0.18 | 12.5万 | 1.89亿 |
日K数据表格示例
| 日期 | 开盘 | 收盘 | 最高 | 最低 | 成交量 | 成交额 | 涨跌幅 |
|---|---|---|---|---|---|---|---|
| 2026-03-13 | 27.34 | 27.02 | 27.80 | 26.90 | 372.9万 | 1.02亿 | -1.75% |
注意事项
1. 自动安装:首次使用时会自动检查并安装 thsdk,无需手动操作 2. 数据延迟:数据来源于同花顺,实时数据可能存在短暂延迟 3. 请求频率:避免短时间内大量请求,每次查询间隔建议 > 100ms 4. 股票代码格式:只有 USHA/USZA + 6位数字 可以直通,其他格式都会先查询 5. 用户选择:多只A股时必须等待用户选择,不能自动选择第一只 6. 港股/美股:港股和美股代码会通过 search_symbols 查询确认
工具函数
安装检查函数
from stock_utils import check_thsdk_installed, get_thsdk_version, ensure_thsdk
# 检查是否已安装
is_installed = check_thsdk_installed() # True/False
# 获取当前版本
version = get_thsdk_version() # "1.7.14" 或 "not installed"
# 确保已安装(未安装则自动安装)
ensure_thsdk() # 返回 True/False资源文件
scripts/stock_utils.py— 核心工具函数,包含自动安装、search_stock_candidates 自动解析及所有数据获取封装references/api_reference.md— thsdk 原始 API 完整参考文档assets/stock_template.py— 含可视化的股票分析完整模板
{
"ownerId": "kn77kj9qvmvjrepkbgq9236ms182xwhb",
"slug": "ths-financial-data",
"version": "1.0.0",
"publishedAt": 1773501353464
}{
"slug": "ths-financial-data",
"name": "股票",
"version": "1.0.0",
"installedAt": 1776152366167,
"source": "skillhub"
}# Example Asset File
This placeholder represents where asset files would be stored.
Replace with actual asset files (templates, images, fonts, etc.) or delete if not needed.
Asset files are NOT intended to be loaded into context, but rather used within
the output Claude produces.
Example asset files from other skills:
- Brand guidelines: logo.png, slides_template.pptx
- Frontend builder: hello-world/ directory with HTML/React boilerplate
- Typography: custom-font.ttf, font-family.woff2
- Data: sample_data.csv, test_dataset.json
## Common Asset Types
- Templates: .pptx, .docx, boilerplate directories
- Images: .png, .jpg, .svg, .gif
- Fonts: .ttf, .otf, .woff, .woff2
- Boilerplate code: Project directories, starter files
- Icons: .ico, .svg
- Data files: .csv, .json, .xml, .yaml
Note: This is a text placeholder. Actual assets can be any file type.
#!/usr/bin/env python3
"""
股票数据分析模板 - stock_template.py
此文件提供股票数据分析的基础模板,包含常用分析功能和可视化。
"""
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from datetime import datetime, timedelta
from typing import Dict, List, Optional
import numpy as np
# 设置中文字体和图表样式
plt.rcParams['font.sans-serif'] = ['SimHei', 'Arial Unicode MS']
plt.rcParams['axes.unicode_minus'] = False
sns.set_style("whitegrid")
class StockAnalyzer:
"""股票数据分析器"""
def __init__(self, ths):
"""
初始化分析器
Args:
ths: THS连接对象
"""
self.ths = ths
def get_stock_data(self, stock_code: str, days: int = 100) -> Optional[pd.DataFrame]:
"""
获取股票数据
Args:
stock_code: 股票代码
days: 数据天数
Returns:
包含基础信息和K线数据的DataFrame
"""
# 获取基础信息
basic_response = self.ths.market_data_cn(stock_code, "基础数据")
# 获取K线数据
kline_response = self.ths.klines(stock_code, interval="day", count=days)
if basic_response.success and kline_response.success:
basic_df = basic_response.df
kline_df = kline_response.df
# 添加基础信息到K线数据
if not basic_df.empty and not kline_df.empty:
kline_df['股票名称'] = basic_df.iloc[0]['股票名称'] if '股票名称' in basic_df.columns else stock_code
kline_df['股票代码'] = stock_code
return kline_df
return None
def calculate_technical_indicators(self, df: pd.DataFrame) -> pd.DataFrame:
"""
计算技术指标
Args:
df: 包含OHLCV数据的DataFrame
Returns:
添加技术指标的DataFrame
"""
if df.empty:
return df
# 移动平均线
df['MA5'] = df['close'].rolling(window=5).mean()
df['MA10'] = df['close'].rolling(window=10).mean()
df['MA20'] = df['close'].rolling(window=20).mean()
df['MA60'] = df['close'].rolling(window=60).mean()
# RSI
delta = df['close'].diff()
gain = (delta.where(delta > 0, 0)).rolling(window=14).mean()
loss = (-delta.where(delta < 0, 0)).rolling(window=14).mean()
rs = gain / loss
df['RSI'] = 100 - (100 / (1 + rs))
# MACD
exp1 = df['close'].ewm(span=12, adjust=False).mean()
exp2 = df['close'].ewm(span=26, adjust=False).mean()
df['MACD'] = exp1 - exp2
df['MACD_Signal'] = df['MACD'].ewm(span=9, adjust=False).mean()
df['MACD_Histogram'] = df['MACD'] - df['MACD_Signal']
# 布林带
df['BB_Middle'] = df['close'].rolling(window=20).mean()
bb_std = df['close'].rolling(window=20).std()
df['BB_Upper'] = df['BB_Middle'] + (bb_std * 2)
df['BB_Lower'] = df['BB_Middle'] - (bb_std * 2)
# 成交量指标
df['Volume_MA5'] = df['volume'].rolling(window=5).mean()
df['Volume_MA10'] = df['volume'].rolling(window=10).mean()
return df
def plot_price_chart(self, df: pd.DataFrame, title: str = ""):
"""
绘制价格图表
Args:
df: 包含价格数据的DataFrame
title: 图表标题
"""
if df.empty:
print("数据为空,无法绘制图表")
return
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(12, 8),
gridspec_kw={'height_ratios': [3, 1]})
# 价格和移动平均线
ax1.plot(df.index, df['close'], label='收盘价', linewidth=1.5, color='black')
ax1.plot(df.index, df['MA5'], label='MA5', linewidth=1, alpha=0.7)
ax1.plot(df.index, df['MA10'], label='MA10', linewidth=1, alpha=0.7)
ax1.plot(df.index, df['MA20'], label='MA20', linewidth=1, alpha=0.7)
# 布林带
ax1.fill_between(df.index, df['BB_Upper'], df['BB_Lower'],
alpha=0.2, color='gray', label='布林带')
ax1.set_title(f'{df.iloc[0]["股票名称"]} ({df.iloc[0]["股票代码"]}) - 价格走势' if not title else title)
ax1.set_ylabel('价格')
ax1.legend()
ax1.grid(True, alpha=0.3)
# 成交量
colors = ['red' if row['close'] >= row['open'] else 'green'
for _, row in df.iterrows()]
ax2.bar(df.index, df['volume'], color=colors, alpha=0.7)
ax2.plot(df.index, df['Volume_MA5'], label='成交量MA5', color='blue', linewidth=1)
ax2.set_ylabel('成交量')
ax2.legend()
ax2.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
def plot_technical_indicators(self, df: pd.DataFrame):
"""
绘制技术指标图表
Args:
df: 包含技术指标的DataFrame
"""
if df.empty:
print("数据为空,无法绘制技术指标")
return
fig, axes = plt.subplots(3, 1, figsize=(12, 10))
# RSI
axes[0].plot(df.index, df['RSI'], label='RSI', linewidth=1.5)
axes[0].axhline(y=70, color='r', linestyle='--', alpha=0.7, label='超买线(70)')
axes[0].axhline(y=30, color='g', linestyle='--', alpha=0.7, label='超卖线(30)')
axes[0].set_title('RSI指标')
axes[0].set_ylabel('RSI')
axes[0].legend()
axes[0].grid(True, alpha=0.3)
# MACD
axes[1].plot(df.index, df['MACD'], label='MACD', linewidth=1.5)
axes[1].plot(df.index, df['MACD_Signal'], label='信号线', linewidth=1)
axes[1].bar(df.index, df['MACD_Histogram'],
label='MACD柱', alpha=0.5, color='gray')
axes[1].set_title('MACD指标')
axes[1].set_ylabel('MACD')
axes[1].legend()
axes[1].grid(True, alpha=0.3)
# 成交量对比
axes[2].bar(df.index, df['volume'],
alpha=0.7, label='成交量', color='lightblue')
axes[2].plot(df.index, df['Volume_MA5'],
label='5日均量', color='blue', linewidth=1.5)
axes[2].plot(df.index, df['Volume_MA10'],
label='10日均量', color='red', linewidth=1.5)
axes[2].set_title('成交量分析')
axes[2].set_ylabel('成交量')
axes[2].legend()
axes[2].grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
def generate_report(self, stock_code: str, days: int = 100):
"""
生成股票分析报告
Args:
stock_code: 股票代码
days: 分析天数
"""
df = self.get_stock_data(stock_code, days)
if df is None or df.empty:
print(f"无法获取股票 {stock_code} 的数据")
return
# 计算技术指标
df = self.calculate_technical_indicators(df)
# 打印基本信息
print("=" * 50)
print(f"股票分析报告: {df.iloc[0]['股票名称']} ({stock_code})")
print("=" * 50)
# 最新价格信息
latest = df.iloc[-1]
print(f"最新价格: {latest['close']:.2f}")
print(f"涨跌幅: {latest.get('涨跌幅', 0):.2f}%")
print(f"成交量: {latest['volume']:,.0f}")
# 技术指标状态
print("\n技术指标状态:")
print(f"RSI: {latest['RSI']:.2f} {'(超买)' if latest['RSI'] > 70 else '(超卖)' if latest['RSI'] < 30 else '(正常)'}")
print(f"MACD: {latest['MACD']:.4f}")
print(f"MACD信号线: {latest['MACD_Signal']:.4f}")
# 移动平均线关系
ma_relation = ""
if latest['close'] > latest['MA5'] > latest['MA10'] > latest['MA20']:
ma_relation = "多头排列"
elif latest['close'] < latest['MA5'] < latest['MA10'] < latest['MA20']:
ma_relation = "空头排列"
else:
ma_relation = "震荡整理"
print(f"均线状态: {ma_relation}")
# 绘制图表
self.plot_price_chart(df)
self.plot_technical_indicators(df)
def main():
"""主函数 - 示例用法"""
from thsdk import THS
# 使用示例
with THS() as ths:
analyzer = StockAnalyzer(ths)
# 分析单个股票
analyzer.generate_report("000001", days=100)
# 也可以单独获取数据进行分析
df = analyzer.get_stock_data("000001", 50)
if df is not None:
df = analyzer.calculate_technical_indicators(df)
analyzer.plot_price_chart(df)
if __name__ == "__main__":
main()thsdk API 参考文档
THS 类
初始化
from thsdk import THS
# 使用上下文管理器(推荐)
with THS() as ths:
# 执行操作
pass
# 直接实例化
ths = THS()
ths.close() # 记得关闭连接配置选项
# 账户配置
config = {
"username": "your_username",
"password": "your_password",
"mac": "your_mac_address"
}
ths = THS(config)
# 或使用环境变量
# export THS_USERNAME=your_username
# export THS_PASSWORD=your_password
# export THS_MAC=your_mac_address主要API方法
K线数据
response = ths.klines(
ths_code, # 股票代码
start_time=None, # 开始时间
end_time=None, # 结束时间
adjust="", # 复权方式:""(不复权), "forward"(前复权), "backward"(后复权)
interval="day", # 周期:1m, 5m, 15m, 30m, 60m, 120m, day, week, month, quarter, year
count=-1 # 数据条数
)市场数据
A股市场数据
response = ths.market_data_cn(
ths_code, # 股票代码
query_key # 查询类型:"基础数据", "资金流向", "财务数据", "估值指标"等
)美股市场数据
response = ths.market_data_us(
ths_code, # 股票代码(如:AAPL)
query_key # 查询类型
)港股市场数据
response = ths.market_data_hk(
ths_code, # 股票代码(如:00700)
query_key # 查询类型
)分时数据
# 当前分时数据
response = ths.intraday_data(ths_code)
# 历史分时数据
response = ths.min_snapshot(ths_code, date="2025-03-12")成交数据
# 3秒tick成交数据
response = ths.tick_level1(ths_code)
# 超级盘口数据
response = ths.tick_super_level1(ths_code, date="2025-03-12")深度数据
# 5档深度数据
response = ths.depth(ths_code)
# 买卖盘口
response = ths.order_book_ask(ths_code) # 卖方
response = ths.order_book_bid(ths_code) # 买方板块数据
# 板块数据
response = ths.block(block_id)
# 板块成分股
response = ths.block_constituents(link_code)
# 行业板块
response = ths.ths_industry()
# 概念板块
response = ths.ths_concept()证券查询
# 模糊查询证券代码
response = ths.query_securities(
pattern, # 查询模式(名称或缩写)
needmarket="" # 市场代码(空表示所有市场)
)Response对象
所有API调用返回Response对象,包含以下属性:
response.success # bool: 是否成功
response.error # str: 错误信息(失败时)
response.data # 原始响应数据
response.df # 转换为Pandas DataFrame的方法使用示例
response = ths.klines("000001", count=100)
if response.success:
# 获取DataFrame
df = response.df
print(df.head())
# 获取原始数据
data = response.data
print(data)
else:
print(f"错误: {response.error}")数据字段说明
K线数据字段
time: 时间戳open: 开盘价high: 最高价low: 最低价close: 收盘价volume: 成交量amount: 成交额
基础数据字段
股票名称: 股票名称最新价: 最新价格涨跌幅: 涨跌幅百分比成交量: 成交量成交额: 成交金额换手率: 换手率市盈率: 市盈率市净率: 市净率
资金流向字段
主力净流入: 主力资金净流入散户净流入: 散户资金净流入资金净流入: 总资金净流入净流入率: 净流入比率
错误处理
常见错误
1. 连接错误: 检查网络连接和账户配置 2. 参数错误: 验证股票代码和查询参数 3. 权限错误: 检查账户权限和有效期
错误处理示例
try:
response = ths.klines("000001")
if not response.success:
print(f"API错误: {response.error}")
# 重试或处理错误
# 检查特定错误类型
if "连接" in response.error:
print("网络连接问题")
elif "权限" in response.error:
print("账户权限问题")
except Exception as e:
print(f"异常: {e}")最佳实践
1. 使用上下文管理器: 确保连接正确关闭 2. 批量查询: 使用批量查询减少API调用次数 3. 错误重试: 实现简单的重试机制 4. 数据缓存: 对不变的数据进行缓存 5. 限流控制: 避免过于频繁的API调用
#!/usr/bin/env python3
"""
Example helper script for ths-financial-data
This is a placeholder script that can be executed directly.
Replace with actual implementation or delete if not needed.
Example real scripts from other skills:
- pdf/scripts/fill_fillable_fields.py - Fills PDF form fields
- pdf/scripts/convert_pdf_to_images.py - Converts PDF pages to images
"""
def main():
print("This is an example script for ths-financial-data")
# TODO: Add actual script logic here
# This could be data processing, file conversion, API calls, etc.
if __name__ == "__main__":
main()
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
股票数据工具函数 - stock_utils.py
核心规则(resolve_ths_code):
┌─────────────────────────────────────────────────────────────┐
│ 只有以下两种格式可以直接使用,无需查询: │
│ USHA + 6位数字 → 如 USHA600519(上交所A股) │
│ USZA + 6位数字 → 如 USZA000001(深交所A股) │
│ │
│ 其余所有输入(短代码/中文/缩写/其他前缀/混合格式等) │
│ 一律先调用 search_symbols() 查询候选列表, │
│ 获取完整的 ths_code 后再进行后续操作。 │
└─────────────────────────────────────────────────────────────┘
多条A股结果时返回候选列表,由 AI 助手展示给用户选择。
"""
import re
import sys
import subprocess
import time
import pandas as pd
from typing import Dict, List, Optional, Union
# ─────────────────────────────────────────────
# thsdk 版本要求
# ─────────────────────────────────────────────
THSDK_MIN_VERSION = "1.7.14"
def check_thsdk_installed() -> bool:
"""检查 thsdk 是否已安装"""
try:
import thsdk
return True
except ImportError:
return False
def get_thsdk_version() -> str:
"""获取当前 thsdk 版本"""
try:
import thsdk
return getattr(thsdk, '__version__', 'unknown')
except ImportError:
return 'not installed'
def install_thsdk(version: str = None) -> bool:
"""
安装或升级 thsdk 库
Args:
version: 指定版本号,如 "1.7.14"。如果为 None,则安装最新版
Returns:
bool: 安装是否成功
"""
try:
pkg = f"thsdk=={version}" if version else "thsdk"
print(f"[stock_utils] 正在安装 {pkg}...")
result = subprocess.run(
[sys.executable, "-m", "pip", "install", "--upgrade", pkg],
capture_output=True,
text=True
)
if result.returncode == 0:
print(f"[stock_utils] ✅ thsdk 安装成功")
return True
else:
print(f"[stock_utils] ❌ thsdk 安装失败: {result.stderr}")
return False
except Exception as e:
print(f"[stock_utils] ❌ thsdk 安装异常: {e}")
return False
def ensure_thsdk() -> bool:
"""
确保 thsdk 已安装且版本满足要求
如果未安装或版本过低,自动安装最新版本
Returns:
bool: 是否满足要求
"""
try:
import thsdk
# 检查版本
version = getattr(thsdk, '__version__', '0.0.0')
# 简单版本比较(假设版本号格式为 x.y.z)
try:
v_parts = [int(x) for x in version.split('.')]
min_parts = [int(x) for x in THSDK_MIN_VERSION.split('.')]
if v_parts < min_parts:
print(f"[stock_utils] thsdk 版本过低 ({version} < {THSDK_MIN_VERSION}),正在升级...")
return install_thsdk()
except:
pass # 版本比较失败,假设满足要求
return True
except ImportError:
print(f"[stock_utils] thsdk 未安装,正在安装...")
return install_thsdk()
def get_ths_instance():
"""
获取 THS 实例,自动处理 thsdk 安装
Returns:
THS 实例或 None
"""
if not ensure_thsdk():
return None
try:
from thsdk import THS
return THS()
except ImportError as e:
print(f"[stock_utils] ❌ 导入 thsdk 失败: {e}")
return None
# ─────────────────────────────────────────────
# 限频常量
# ─────────────────────────────────────────────
_SLEEP_SEARCH = 0.1 # search_symbols 查询间隔
# 合法 ths_code 直通白名单(只有这两种格式跳过查询)
_DIRECT_PATTERN = re.compile(r'^(USHA|USZA)\d{6}$', re.IGNORECASE)
# 特殊返回值:表示需要用户选择
NEED_USER_SELECTION = "NEED_USER_SELECTION"
def _is_direct_code(code: str) -> bool:
"""
判断是否满足"直通"条件:
USHA + 6位数字 或 USZA + 6位数字
满足则无需查询,直接返回大写形式。
"""
return bool(_DIRECT_PATTERN.match(code))
def _search_symbols(ths, query: str, retries: int = 3) -> List[Dict]:
"""
调用 search_symbols 搜索股票,返回候选列表。
每项格式:{'ths_code': 'USZA300750', 'name': '宁德时代', 'code': '300750', 'market': '深A'}
search_symbols 返回数据格式:
{
'MarketStr': 'USZA',
'Code': '300750',
'Name': '宁德时代',
'CodeDisplay': '300750',
'MarketDisplay': '深A',
'THSCODE': 'USZA300750'
}
"""
candidates = []
for attempt in range(retries):
time.sleep(_SLEEP_SEARCH)
try:
resp = ths.search_symbols(query)
if not resp.success or not resp.data:
continue
for item in resp.data:
ths_code = item.get('THSCODE', '')
name = item.get('Name', '')
code = item.get('Code', '')
market = item.get('MarketDisplay', '')
if not ths_code:
continue
candidates.append({
'ths_code': ths_code,
'name': name,
'code': code,
'market': market,
})
break # 成功则不重试
except Exception as e:
print(f'[stock_utils] search_symbols 异常 (尝试 {attempt + 1}/{retries}): {e}')
continue
return candidates
def _format_candidates_for_display(candidates: List[Dict], title: str = "匹配结果") -> str:
"""
将候选列表格式化为易读的字符串,供 AI 展示给用户。
"""
lines = [f"\n**{title}**:\n"]
for i, c in enumerate(candidates):
lines.append(f" {i + 1}. **{c['name']}** `{c['ths_code']}` ({c['market']})")
lines.append(f"\n请输入序号选择(1-{len(candidates)}),或输入 0 取消。")
return "\n".join(lines)
# ─────────────────────────────────────────────
# 核心公开函数
# ─────────────────────────────────────────────
def search_stock_candidates(ths, user_input: str) -> Dict:
"""
搜索股票并返回候选结果(供 AI 调用,不自动选择)。
返回格式:
{
'status': 'found' | 'not_found' | 'need_selection',
'ths_code': 'USZA300750' | None, # 唯一匹配时返回
'candidates': [...], # 多条结果时返回候选列表
'message': '...', # 给用户的提示信息
'display': '...' # 格式化的展示文本
}
"""
code = user_input.strip()
# ── 直通:USHA/USZA + 6位数字 ──────────
if _is_direct_code(code):
return {
'status': 'found',
'ths_code': code.upper(),
'candidates': [],
'message': f'直通模式,无需查询',
'display': f'股票代码:`{code.upper()}`'
}
# ── 搜索 ─────────────────────────────
candidates = _search_symbols(ths, code)
if not candidates:
return {
'status': 'not_found',
'ths_code': None,
'candidates': [],
'message': f'未找到与 "{code}" 匹配的证券',
'display': f'❌ 未找到与 "{code}" 匹配的证券,请检查输入。'
}
# 单条结果,自动匹配
if len(candidates) == 1:
c = candidates[0]
return {
'status': 'found',
'ths_code': c['ths_code'],
'candidates': [],
'message': f'已自动匹配:{c["name"]}',
'display': f'✅ 已自动匹配:**{c["name"]}** `{c["ths_code"]}` ({c["market"]})'
}
# 多条结果,筛选A股
a_stock_candidates = [c for c in candidates if c['market'] in ('深A', '沪A')]
# 只有一只A股,自动选择
if len(a_stock_candidates) == 1:
c = a_stock_candidates[0]
return {
'status': 'found',
'ths_code': c['ths_code'],
'candidates': [],
'message': f'自动选择唯一A股:{c["name"]}',
'display': f'✅ 找到唯一A股,自动选择:**{c["name"]}** `{c["ths_code"]}` ({c["market"]})'
}
# 多只A股,需要用户选择
if len(a_stock_candidates) > 1:
display = _format_candidates_for_display(a_stock_candidates, f'找到 {len(a_stock_candidates)} 只A股')
return {
'status': 'need_selection',
'ths_code': None,
'candidates': a_stock_candidates,
'message': f'找到 {len(a_stock_candidates)} 只A股,请选择',
'display': display
}
# 无A股,展示所有结果
display = _format_candidates_for_display(candidates, f'找到 {len(candidates)} 个匹配结果')
return {
'status': 'need_selection',
'ths_code': None,
'candidates': candidates,
'message': f'找到 {len(candidates)} 个匹配结果,请选择',
'display': display
}
def get_candidate_by_index(candidates: List[Dict], index: int) -> Optional[Dict]:
"""
根据用户输入的序号获取候选股票。
index: 1-based 索引
返回:
{'ths_code': '...', 'name': '...', 'code': '...', 'market': '...'} 或 None
"""
if 1 <= index <= len(candidates):
return candidates[index - 1]
return None
def resolve_ths_code(ths, user_input: str) -> Union[str, Dict, None]:
"""
将任意格式的股票标识符解析为合法的 ths_code。
返回值:
- 字符串:ths_code(唯一匹配或直通)
- Dict:{'need_selection': True, 'candidates': [...], 'display': '...'}
- None:未找到
此函数保持向后兼容,但推荐使用 search_stock_candidates() 获取更详细的结果。
"""
result = search_stock_candidates(ths, user_input)
if result['status'] == 'found':
return result['ths_code']
elif result['status'] == 'need_selection':
return {
'need_selection': True,
'candidates': result['candidates'],
'display': result['display']
}
else:
return None
# ─────────────────────────────────────────────
# 数据获取封装
# ─────────────────────────────────────────────
def get_kline_data(ths, stock_code: str, interval: str = "day",
count: int = 100, adjust: str = "") -> Union[pd.DataFrame, Dict, None]:
"""
获取K线数据。stock_code 支持任意格式,内部自动解析。
返回值:
- pd.DataFrame:成功获取数据
- Dict:{'need_selection': True, 'candidates': [...], 'display': '...'} 需要用户选择
- None:未找到或失败
Args:
interval: 1m/5m/15m/30m/60m/120m/day/week/month/quarter/year
count: 数据条数
adjust: "" 不复权 | "forward" 前复权 | "backward" 后复权
"""
ths_code = resolve_ths_code(ths, stock_code)
# 需要用户选择
if isinstance(ths_code, dict) and ths_code.get('need_selection'):
return ths_code
if not ths_code:
return None
resp = ths.klines(ths_code, interval=interval, count=count, adjust=adjust)
if resp.success:
return resp.df
print(f'[stock_utils] klines 失败: {resp.error}')
return None
def get_realtime_data(ths, stock_code: str) -> Union[Dict, None]:
"""
获取股票实时行情(最新价/涨跌幅/成交量等)。
返回值:
- Dict:成功获取数据
- Dict:{'need_selection': True, 'candidates': [...], 'display': '...'} 需要用户选择
- None:未找到或失败
"""
ths_code = resolve_ths_code(ths, stock_code)
if isinstance(ths_code, dict) and ths_code.get('need_selection'):
return ths_code
if not ths_code:
return None
resp = ths.market_data_cn(ths_code, "基础数据")
if resp.success and not resp.df.empty:
row = resp.df.iloc[0]
return {
'ths_code': ths_code,
'name': row.get('股票名称', '未知'),
'price': row.get('最新价', 0),
'change_pct': row.get('涨跌幅', 0),
'change_amt': row.get('涨跌额', 0),
'open': row.get('开盘价', 0),
'high': row.get('最高价', 0),
'low': row.get('最低价', 0),
'pre_close': row.get('昨收', 0),
'volume': row.get('成交量', 0),
'turnover': row.get('成交额', 0),
'turnover_rate': row.get('换手率', 0),
}
print(f'[stock_utils] 实时数据获取失败: {resp.error}')
return None
def get_stock_basic_info(ths, stock_code: str) -> Union[Dict, None]:
"""获取股票基础行情。支持任意格式输入。"""
return get_realtime_data(ths, stock_code)
def get_fund_flow(ths, stock_code: str) -> Union[Dict, None]:
"""
获取资金流向数据。
返回值:
- Dict:成功获取数据
- Dict:{'need_selection': True, 'candidates': [...], 'display': '...'} 需要用户选择
- None:未找到或失败
"""
ths_code = resolve_ths_code(ths, stock_code)
if isinstance(ths_code, dict) and ths_code.get('need_selection'):
return ths_code
if not ths_code:
return None
resp = ths.market_data_cn(ths_code, "资金流向")
if resp.success and not resp.df.empty:
row = resp.df.iloc[0]
return {
'ths_code': ths_code,
'main_net_inflow': row.get('主力净流入', 0),
'super_net_inflow': row.get('超大单净流入', 0),
'big_net_inflow': row.get('大单净流入', 0),
'medium_net_inflow': row.get('中单净流入', 0),
'small_net_inflow': row.get('小单净流入', 0),
'retail_net_inflow': row.get('散户净流入', 0),
'total_net_inflow': row.get('资金净流入', 0),
}
print(f'[stock_utils] 资金流向获取失败: {resp.error}')
return None
def get_intraday_data(ths, stock_code: str, date: str = None) -> Union[pd.DataFrame, Dict, None]:
"""
获取分时数据。
返回值:
- pd.DataFrame:成功获取数据
- Dict:{'need_selection': True, 'candidates': [...], 'display': '...'} 需要用户选择
- None:未找到或失败
"""
ths_code = resolve_ths_code(ths, stock_code)
if isinstance(ths_code, dict) and ths_code.get('need_selection'):
return ths_code
if not ths_code:
return None
resp = ths.min_snapshot(ths_code, date=date) if date else ths.intraday_data(ths_code)
if resp.success:
return resp.df
print(f'[stock_utils] 分时数据获取失败: {resp.error}')
return None
def get_depth_data(ths, stock_code: str) -> Union[Dict, None]:
"""
获取5档深度数据。
返回值:
- Dict:成功获取数据
- Dict:{'need_selection': True, 'candidates': [...], 'display': '...'} 需要用户选择
- None:未找到或失败
"""
ths_code = resolve_ths_code(ths, stock_code)
if isinstance(ths_code, dict) and ths_code.get('need_selection'):
return ths_code
if not ths_code:
return None
resp = ths.depth(ths_code)
if resp.success and not resp.df.empty:
df = resp.df
return {
'ths_code': ths_code,
'bid_prices': df['bid_price'].tolist() if 'bid_price' in df.columns else [],
'bid_volumes': df['bid_volume'].tolist() if 'bid_volume' in df.columns else [],
'askPrices': df['ask_price'].tolist() if 'ask_price' in df.columns else [],
'ask_volumes': df['ask_volume'].tolist() if 'ask_volume' in df.columns else [],
}
print(f'[stock_utils] 深度数据获取失败: {resp.error}')
return None
def calculate_technical_indicators(df: pd.DataFrame) -> pd.DataFrame:
"""计算 MA / RSI / MACD,原地修改并返回。"""
if df.empty or 'close' not in df.columns:
return df
df['MA5'] = df['close'].rolling(5).mean()
df['MA10'] = df['close'].rolling(10).mean()
df['MA20'] = df['close'].rolling(20).mean()
delta = df['close'].diff()
gain = delta.where(delta > 0, 0).rolling(14).mean()
loss = (-delta.where(delta < 0, 0)).rolling(14).mean()
df['RSI'] = 100 - 100 / (1 + gain / loss)
ema12 = df['close'].ewm(span=12, adjust=False).mean()
ema26 = df['close'].ewm(span=26, adjust=False).mean()
df['MACD'] = ema12 - ema26
df['MACD_Signal'] = df['MACD'].ewm(span=9, adjust=False).mean()
df['MACD_Histogram'] = df['MACD'] - df['MACD_Signal']
return df
def batch_query_stocks(ths, stock_codes: List[str], data_type: str = "basic") -> Dict:
"""
批量查询,每个代码都经过 resolve_ths_code 自动解析。
data_type: "basic" | "kline" | "flow"
"""
results = {}
for code in stock_codes:
if data_type == "basic":
results[code] = get_stock_basic_info(ths, code)
elif data_type == "kline":
results[code] = get_kline_data(ths, code)
elif data_type == "flow":
results[code] = get_fund_flow(ths, code)
return results
# ─────────────────────────────────────────────
# 便捷函数:直接获取 ths_code
# ─────────────────────────────────────────────
def query_stock_code(ths, user_input: str) -> Union[str, Dict, None]:
"""
将用户输入转换为完整的 ths_code 并返回。
这是 resolve_ths_code 的别名,便于理解。
示例:
query_stock_code(ths, "平安银行") → "USZA000001"
query_stock_code(ths, "ndsd") → "USZA300750"
query_stock_code(ths, "USHA600519") → "USHA600519" (直通)
"""
return resolve_ths_code(ths, user_input)
# ─────────────────────────────────────────────
# 问财查询
# ─────────────────────────────────────────────
def wencai_query(ths, query: str) -> Union[pd.DataFrame, None]:
"""
使用问财自然语言查询
Args:
query: 自然语言查询语句,如 "最近热度前50的行业"
Returns:
pd.DataFrame 或 None
"""
resp = ths.wencai_nlp(query)
if resp.success and resp.data:
if isinstance(resp.data, list):
return pd.DataFrame(resp.data)
return pd.DataFrame([resp.data])
print(f'[stock_utils] 问财查询失败: {resp.error}')
return None
# ─────────────────────────────────────────────
# 测试入口
# ─────────────────────────────────────────────
if __name__ == "__main__":
import logging
logging.disable(logging.CRITICAL)
# 首先检查 thsdk 安装状态
print("=" * 60)
print("thsdk 检查")
print("=" * 60)
print(f"已安装: {check_thsdk_installed()}")
print(f"版本: {get_thsdk_version()}")
print(f"最低要求: {THSDK_MIN_VERSION}")
print()
# 确保 thsdk 可用
if not ensure_thsdk():
print("❌ thsdk 安装失败,无法继续")
sys.exit(1)
from thsdk import THS
with THS() as ths:
print("=" * 60)
print("search_stock_candidates 测试")
print("=" * 60)
# 测试唯一匹配
print("\n[测试1] ndsd(预期唯一匹配)")
result = search_stock_candidates(ths, "ndsd")
print(f" status: {result['status']}")
print(f" display: {result['display']}")
# 测试多只A股
print("\n[测试2] sjkj(预期多只A股)")
result = search_stock_candidates(ths, "sjkj")
print(f" status: {result['status']}")
print(f" display: {result['display']}")
# 测试直通
print("\n[测试3] USHA600519(预期直通)")
result = search_stock_candidates(ths, "USHA600519")
print(f" status: {result['status']}")
print(f" display: {result['display']}")
Related skills
FAQ
Which markets does ths-financial-data cover?
A-shares (USHA/USZA), Hong Kong (HKHK) and US stocks (USUS), resolved from names, abbreviations or short codes into full ths_code format.
Does it install its dependency?
Yes. It auto-checks and installs or upgrades thsdk (>= 1.7.14) via pip on first use.