做量化分析、写复盘脚本、跟踪龙虎榜资金动向的时候,最痛苦的不是写策略,而是搞数据。早期我手动从行情软件导出Excel,格式乱七八糟还得自己清洗;后来试着写爬虫去抓网页接口,人家一改参数就全线崩盘。后来换了Tushare Pro,用Python直接拉A股行情、财务、龙虎榜数据,几行代码搞定,再也不用到处找数据了。这篇就把我实际用下来的接口选择、代码实现、坑位排查一次性讲清楚,附完整代码。
1. 为什么是Tushare Pro:数据源选型那点事
1.1 常见的A股数据获取方式,为什么最后选了Tushare
市面上获取A股数据大概这么几条路:
手动导出。通达信、同花顺、东方财富Choice都能导出日线、财务数据。适合一次性分析,但要做时间序列回测、批量拉几百只股票就完全不现实。而且导出的字段固定,想要自定义指标组合,得先在Excel里折腾半天。
爬虫抓网页接口。技术上是可行的,但痛点很明显:目标网站的前端接口经常调整,爬虫代码的生命周期可能只有几周;还要处理请求频率限制、IP封禁、动态加载参数加密等问题。投入产出比很低,尤其当你只是想拿到干净的数据做分析,而不是想研究逆向工程。
开源免费API。Baostock、AkShare、Tushare这几类是目前社区用得比较多的。AkShare侧重从公开网页聚合数据,接口数量多但字段命名和稳定性参差不齐。Baostock数据免费且不需要token,但接口功能相对基础,没有龙虎榜这类特色数据。Tushare Pro是结构化接口设计,行情、财务、龙虎榜、宏观经济等分类清晰,文档规范,字段命名统一,对需要长期稳定数据源的人来说是最省心的选择。
当然Tushare Pro也不是没有门槛,它的积分机制决定了一部分高级接口需要攒积分才能用。但基础行情和财务数据,注册后基本就能覆盖大部分需求,后面我会专门讲积分这件事怎么低成本应对。
1.2 Tushare Pro的核心设计:token、接口权限与积分机制
用过Tushare的人应该知道,它的使用流程是:注册账号 → 获取token → 调用接口。token相当于你的身份凭证,每个接口都会校验你的权限等级。这个设计的核心是积分体系:
- 120积分:注册后完成基本资料、绑定手机等操作就能获得,可调用daily(日线行情)、basic(股票列表)等基础接口。
- 2000积分:可开放财务三大报表、港股、美股等数据权限。
- 5000积分:可解锁龙虎榜、两融、期货等更细分的接口。
积分通过每日登录、社区发帖、推荐用户等方式累积,不是非得花钱充值。对我这种轻度使用者来说,最开始120积分就够把行情数据跑通了,后面慢慢攒积分逐步解锁更多接口,其实是一个很平滑的学习曲线。
从一个开发者角度看,token + 权限校验的设计比完全免费的接口更可靠,因为它在服务端做了限流和配额管理,正常频率调用很少出问题,数据质量和稳定性有保障。这个设计思路值得做技术架构的人借鉴:数据服务不怕有权限门槛,怕的是没有门槛导致被滥用,最后所有人都用不了。
2. 环境准备:从零到能跑通第一个接口
2.1 Python环境检查与tushare库安装
老规矩,先确认你的Python环境。我用的是Python 3.9以上版本,Windows和Linux都跑过,tushare的依赖只有pandas和requests,安装非常简单:
pip install tushare如果安装速度慢,换国内镜像源:
pip install tushare -i https://pypi.tuna.tsinghua.edu.cn/simple装完验证一下版本:
import tushare as ts print(ts.__version__)我当前用的是1.4.x版本,不同版本接口差异不大,但建议保持更新,有些历史版本在财务数据字段上会有细微差别。
2.2 注册、获取token与初始化连接
去Tushare Pro官网注册账号,登录后在“个人主页”里找到“接口TOKEN”,复制那串字符。这就是你调用所有接口的钥匙。
初始化方式有两种,我推荐第一种:
import tushare as ts # 方式一:全局配置token(推荐) ts.set_token('你复制的那串token') # 方式二:每次请求时手动带上token pro = ts.pro_api('你复制的那串token')set_token只需要设置一次,后续的pro_api()调用会自动携带token。注意token是敏感的认证信息,如果代码要提交到GitHub或者分享给别人,建议用环境变量或者配置文件管理,不要硬编码在脚本里。
2.3 第一个数据请求:先拿日线行情试试手
环境就绪后,写第一行数据请求代码。以平安银行(000001.SZ)为例,拉取2024年1月的日线行情:
import tushare as ts ts.set_token('你的token') pro = ts.pro_api() df = pro.daily(ts_code='000001.SZ', start_date='20240101', end_date='20240131') print(df.head())输出长这样:
ts_code trade_date open high close pre_close change pct_chg vol amount 0 000001.SZ 20240131 9.55 9.67 9.51 9.75 -0.24 -2.46 1090545.62 10368038.16 1 000001.SZ 20240130 9.69 9.75 9.75 9.70 0.05 0.52 750471.99 7314522.24 ...简单解释一下核心字段:
- ts_code:股票代码,带后缀。
.SZ代表深交所,.SH代表上交所,.BJ代表北交所。 - trade_date:交易日期,注意是字符串格式,不是Excel里的日期序列。
- open/high/low/close:开盘价、最高价、最低价、收盘价,单位是元。
- pre_close:前收盘价,用于计算涨跌幅的基准。
- change:涨跌额,等于close - pre_close。
- pct_chg:涨跌幅百分比。
- vol:成交量(手),注意这里不是股数,A股1手=100股。
- amount:成交金额(千元),不是元。
看到这里,你的第一份行情数据就到手了。这也是我最常用的一条接口,后面做策略回测、画K线图都靠它。
3. 三类核心数据的完整实操
3.1 行情数据:日线、周线与复权价格
日线接口的基本玩法
daily接口除了按ts_code单个股票拉取,还支持按trade_date拉取全市场某一天的行情:
# 获取2024年3月1日全市场行情 df = pro.daily(trade_date='20240301') print(df.shape) # 输出大概5000+行这个功能在做“全市场扫描选股”场景下非常有用。举个例子,我要找当天涨幅超过5%的所有股票,一行代码搞定:
hot_stocks = df[df['pct_chg'] > 5] print(hot_stocks[['ts_code', 'close', 'pct_chg']].head(20))周线和月线
daily接口给的是原始日频数据。要做周线、月线分析,有两种办法:一种是自己用pandas的resample聚合,另一种是直接用tushare封装好的weekly和monthly接口:
# 周线 df_w = pro.weekly(ts_code='000001.SZ', start_date='20240101', end_date='20240301') # 月线 df_m = pro.monthly(ts_code='000001.SZ', start_date='20240101', end_date='20240301')这两个接口返回的字段和daily基本一致,省去了自己聚合代码的麻烦。
复权价格:为什么不能直接用原始价格做回测
做回测的人最容易踩的一个坑,就是直接拿原始价格计算收益率。A股上市公司动不动就分红送转,比如一只股票10派5元,除息日股价会直接下跌,这不是市场下跌,而是公司把利润分配给了股东。如果直接用原始价格算收益率,会得出一个巨大的“假亏损”。
Tushare针对这个问题提供了复权工具:
# 前复权数据 df_qfq = ts.pro_bar(ts_code='000001.SZ', adj='qfq', start_date='20240101', end_date='20240301') # 后复权数据 df_hfq = ts.pro_bar(ts_code='000001.SZ', adj='hfq', start_date='20240101', end_date='20240301')简单类比一下:前复权是以当前价格为基准,把历史价格往下调整,保证价格连续,适合看最新的走势形态;后复权是以上市首日价格为基准,把后续价格往上调整,反映真实的累计涨幅,适合长期收益分析。如果做量化回测,建议用后复权数据,因为它的收益率计算不会受除权除息的影响。
3.2 财务数据:三大报表与关键财务指标
财务数据是我觉得Tushare做得比很多免费数据源更扎实的部分。它把财务数据拆成了多个接口,每个接口负责一类数据:
财务指标总览:fina_indicator
这个接口适合做快速筛选。它把ROE、毛利率、净利率、资产负债率等核心指标都聚合在一个表里:
df = pro.fina_indicator(ts_code='000001.SZ', start_date='20230101', end_date='20240301') print(df[['ts_code', 'end_date', 'roe', 'grossprofit_margin', 'debt_to_assets']])字段很多,重点看这几列:
- roe:净资产收益率,衡量股东资金的赚钱效率。
- grossprofit_margin:销售毛利率,反映产品或服务的盈利能力。
- debt_to_assets:资产负债率,衡量财务杠杆水平。
利润表、资产负债表、现金流量表
如果需要更细的三张报表科目,分别用income(利润表)、balancesheet(资产负债表)、cashflow(现金流量表):
# 利润表:营业收入、净利润等 df_income = pro.income(ts_code='000001.SZ', period='20231231') # 资产负债表:总资产、总负债、股东权益 df_balance = pro.balancesheet(ts_code='000001.SZ', period='20231231') # 现金流量表:经营/投资/筹资活动现金流 df_cashflow = pro.cashflow(ts_code='000001.SZ', period='20231231')period参数的取值非常关键,它是YYYYMMDD格式的报告期。A股财报有季报、半年报、年报,period填20231231表示2023年年报数据。如果你填20230331,拿到的就是2023年一季报数据。
这里有一个细节处理:财务数据是按单季披露还是累计披露?Tushare的income接口返回的是报告期累计值。也就是说period=20231231的利润表,营业收入是全年累计数,不是单季数。如果你要做单季分析,比如只看2023年第四季度单独的收入,需要自己用年报减三季报:
annual = pro.income(ts_code='000001.SZ', period='20231231', fields='ts_code, revenue') q3 = pro.income(ts_code='000001.SZ', period='20230930', fields='ts_code, revenue') q4_revenue = annual['revenue'] - q3['revenue']为什么同一家公司财报出来了,查询不到数据
这是财务接口最典型的问题:财报披露存在滞后性。年报最晚可以拖到次年4月底,所以你不能指望在1月份就查到上年年报数据。我通常是先拉一份公司公告列表,或者直接用fina_indicator接口查存在的报告期,确认数据披露后再去拉报表,避免白跑一次。
3.3 龙虎榜数据:每日明细、机构席位与资金动向
龙虎榜是很多短线选手盯数据的重点,Tushare把它做了接口化,比从交易所网站手动翻页方便太多了。
先搞清楚龙虎榜是什么
沪深交易所每天收盘后会公布当日满足特定条件的股票交易明细,这些股票会被列入龙虎榜,包括:
- 日涨跌幅偏离值达到±7%的前N只股票
- 连续三个交易日涨跌幅偏离值累计达到±20%
- 日换手率达到20%的股票
- 异常波动等其他情形
榜单会披露买入金额前五的营业部、卖出金额前五的营业部,以及机构专用席位的买卖情况。所以龙虎榜本质上是“异常交易公开信息披露”,对研究游资动向、机构行为很有价值。
每日明细接口:top_list
# 获取2024年3月1日全部龙虎榜股票明细 df = pro.top_list(trade_date='20240301') print(df.columns.tolist()) print(df[['ts_code', 'name', 'close', 'pct_change', 'l_buy', 'l_sell', 'net_amount', 'reason']].head())重点字段:
- l_buy:龙虎榜买入总额(元)
- l_sell:龙虎榜卖出总额(元)
- net_amount:净买入额(元)
- reason:上榜原因,比如“日涨幅偏离值达到7%”
机构席位数据:top_inst
龙虎榜里最值得深挖的是机构专用席位。普通营业部可能是游资或大户,但“机构专用”四个字通常意味着公募基金、保险等大型机构在操作:
# 获取龙虎榜机构买卖明细 df_inst = pro.top_inst(trade_date='20240301') print(df_inst[['ts_code', 'name', 'buy', 'sell', 'net_buy']].head())这个接口的数据能帮我们回答一个问题:某只股票大涨的时候,机构是在买入还是在卖出?如果股价大涨但机构席位净卖出,这个上涨的持续性就要打一个问号。
三日累计榜单:top_floating
连续涨停的股票,单日榜单往往不够看,交易所还会有三日累计榜单:
df_float = pro.top_floating(trade_date='20240301')这个接口展示的是过去三个交易日累计的买卖情况,适合跟踪连板股的游资接力链条。
一个实用的组合查询场景
我自己经常做的一件事:找出某只股票最近30天上过龙虎榜的次数,以及机构净买入额的变化:
import pandas as pd stock_code = '000001.SZ' all_days = pd.date_range('20240201', '20240301', freq='B').strftime('%Y%m%d') records = [] for day in all_days: try: tb = pro.top_list(trade_date=day) if tb is not None and not tb.empty: stock_data = tb[tb['ts_code'] == stock_code] if not stock_data.empty: records.append(stock_data) except Exception: continue if records: result = pd.concat(records) print(result[['trade_date', 'pct_change', 'net_amount', 'reason']])注意这里我用工作日序列逐个去查,是因为top_list在非交易日会返回空,遍历日期时要做好容错处理。
4. 实际项目中的坑与排查技巧
4.1 “没有权限”报错的定位与应对
刚接触时最容易碰到的报错是这样的:
抱歉,您没有访问该接口的权限这个提示的意思是:当前token对应的积分不够,请求的接口不在可用范围内。
排查思路很简单,分三步:
- 确认接口名是否在Tushare文档的“积分说明”里标明了权限门槛。比如
income、balancesheet这类财务接口一般需要2000积分,而daily只需要120积分。 - 查看自己的当前积分。在个人主页能看到实时积分值。
- 如果积分确实不够,两个选择:一是先调用同级的替代接口,二是通过每日登录、社区签到、发布内容等方式攒积分,也可以邀请朋友注册获得赠送积分。
还有一个容易忽略的点:某些接口即使权限到了,如果请求频率超限,也会返回类似的提示。Tushare对每分钟请求次数有限制,默认是每分钟500次左右,但批量循环调用时要留意,建议在循环里加个time.sleep(0.2)来控制节奏。
4.2 数据精度、日期格式与缺失值处理
数据精度
拿到的DataFrame,float类型打印出来可能会带很多位小数,这其实是浮点数存储精度问题。比如vol列精确到小数点后两位,处理前先用round处理一遍:
df['pct_chg'] = df['pct_chg'].round(2)如果是单笔金额特别大的数据,要注意float64的精度极限。通常Tushare返回的数据在既有的精度范围内是够用的,不需要额外处理,但做加总核对的时候,建议统一用Decimal或者先做整数化,避免浮点累加误差。
trade_date为什么是字符串
Tushare的日期字段设计成了字符串,格式YYYYMMDD。这个设计对接口传输效率来说是合理的,但对后续处理不友好。排序、筛选时需要显式转换:
df['trade_date'] = pd.to_datetime(df['trade_date'], format='%Y%m%d') df = df.sort_values('trade_date')缺失值
财务数据很容易出现NaN。因为不同的公司披露口径不同,某些指标只在一定条件下才会披露。不要一遇到NaN就直接dropna,可能把有用的行删没了。
我的做法是先区分缺失比例:
missing_ratio = df.isna().mean() print(missing_ratio[missing_ratio > 0.3])对于缺失比例超过30%的字段,要么去另一个接口补数据,要么放弃这个字段;低于10%的,可以用行业均值填充或者不做处理,留给后续分析模型自己处理。
4.3 批量抓取时的频率控制与缓存策略
当你需要拉取全市场5000只股票的财务数据,如果一次性循环去请求,很容易触发频率限制甚至被临时封禁。我踩过这个坑,后来形成了两个习惯:
固定频率的sleep
import time for code in stock_list: df = pro.daily(ts_code=code, start_date='20240101', end_date='20240131') time.sleep(0.3) # 控制请求频率本地缓存
对于行情、财务这种更新频率不高的数据,强烈建议在本地落一份缓存。用CSV还是SQLite,取决于数据量。我一般用SQLite,查询方便:
import sqlite3 conn = sqlite3.connect('a股数据.db') df.to_sql('daily_行情', conn, if_exists='append', index=False)下次再要同一批数据,先查本地库,命中就直接用,避免重复请求。这一步能把整个项目的请求量降低70%以上。
5. 一个完整的整合示例
5.1 把行情、财务、龙虎榜串起来做成一个小看板
前面介绍了三种核心数据接口,现在我把它们整合成一个实用的小工具:输入一个股票代码和一个日期范围,输出这只股票这段时间的行情走势、最新一期财务指标、上榜记录汇总。这个看板适合做个股快速尽调,或者复盘时统一梳理信息。
5.2 完整代码与输出效果
import tushare as ts import pandas as pd import time ts.set_token('你的token') pro = ts.pro_api() def stock_analysis_board(ts_code, start_date, end_date): print(f"===== {ts_code} 数据看板 =====") # 1. 行情数据(前复权) print("\n【行情概览】最近5个交易日") df_price = ts.pro_bar(ts_code=ts_code, adj='qfq', start_date=start_date, end_date=end_date) df_price = df_price.sort_values('trade_date') latest_5 = df_price.tail(5) print(latest_5[['trade_date', 'close', 'pct_chg', 'vol']].to_string(index=False)) # 2. 财务数据(最新报告期) print("\n【财务摘要】最新披露报告期") df_ind = pro.fina_indicator(ts_code=ts_code, limit=1) if not df_ind.empty: row = df_ind.iloc[0] print(f"报告期: {row['end_date']}") print(f"ROE: {row.get('roe', 'N/A')}") print(f"销售毛利率: {row.get('grossprofit_margin', 'N/A')}") print(f"资产负债率: {row.get('debt_to_assets', 'N/A')}") # 3. 龙虎榜记录 print("\n【龙虎榜】期间上榜记录") trade_days = pd.date_range(start_date, end_date, freq='B').strftime('%Y%m%d') top_list_all = [] for day in trade_days: try: df_top = pro.top_list(trade_date=day) if df_top is not None and not df_top.empty: stock_top = df_top[df_top['ts_code'] == ts_code] if not stock_top.empty: top_list_all.append(stock_top) except Exception: pass time.sleep(0.2) # 控制频率 if top_list_all: df_top_result = pd.concat(top_list_all) print(df_top_result[['trade_date', 'close', 'pct_change', 'net_amount', 'reason']].to_string(index=False)) else: print("期间未上榜") stock_analysis_board('000001.SZ', '20240201', '20240301')输出效果大致如下:
===== 000001.SZ 数据看板 ===== 【行情概览】最近5个交易日 trade_date close pct_chg vol 20240226 10.05 0.80 912345.55 20240227 10.12 0.70 856321.44 ... 【财务摘要】最新披露报告期 报告期: 20231231 ROE: 10.58 销售毛利率: 35.2 资产负债率: 78.3 【龙虎榜】期间上榜记录 trade_date close pct_change net_amount reason 20240229 10.35 9.98 123456789.0 日涨幅偏离值达到7%这个看板虽然简单,但已经覆盖了行情、财务、龙虎榜三类核心数据的拉取和整合逻辑。你可以在此基础上扩展:加均线指标、加财务同比环比、把多个股票循环对比,基本就把Tushare Pro的日常用法掌握了个大概。
我个人的体会是,数据接口始终是工具,真正有价值的是你怎么用这些数据去验证思路、构建策略。拿龙虎榜数据来说,单纯看机构净买入没有意义,要结合股价所处位置、成交量能、后续几天的走势一起看,才能形成有效的决策链。数据到位了,接下来就要靠你的分析逻辑了。