1. 为什么选择Tushare获取A股数据?
在金融量化分析领域,获取准确、完整的市场数据是开展一切研究的基础。Tushare作为国内领先的金融数据接口,已经成为众多量化研究者和个人投资者的首选工具。我最初接触Tushare是在2018年,当时正在做一个基于技术指标的选股策略,试用了多个数据源后,最终被Tushare的稳定性和数据质量所折服。
相比其他数据获取方式,Tushare有几个不可替代的优势:
- 数据更新及时:A股行情数据通常在交易日结束后1小时内完成更新
- 接口稳定:采用HTTP协议,响应速度快,平均查询时间在300-500ms
- 历史数据完整:包含从1990年A股开市至今的全部日线数据
- 免费额度充足:基础版每天可调用500次,完全能满足个人研究需求
提示:虽然Tushare提供免费接口,但对于高频交易策略开发者,建议购买Pro版获取更稳定的服务
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. Tushare环境配置与认证
2.1 安装与基础配置
在Python环境中安装Tushare非常简单,只需执行标准pip命令:
bash复制pip install tushare
但要想正常使用API,还需要完成关键的一步 - 获取并设置token。这个token相当于你的身份凭证,所有API调用都需要携带。注册流程如下:
- 访问Tushare官网注册账号
- 在个人中心找到"接口TOKEN"
- 复制这串由字母数字组成的密钥
设置token有两种方式,我推荐使用环境变量法,既安全又方便多项目共享:
python复制import tushare as ts
ts.set_token('你的token') # 替换为实际获取的token
pro = ts.pro_api() # 初始化接口
2.2 接口版本选择
Tushare目前有两个主要版本接口:
- 老版接口(ts.get_hist_data):已停止维护,不推荐使用
- 新版接口(pro.daily):功能更全,数据更规范
对于历史行情获取,我们主要使用以下几个API端点:
- pro.daily:获取日线行情
- pro.weekly:获取周线行情
- pro.monthly:获取月线行情
- pro.daily_basic:获取每日指标数据
3. 获取A股历史行情数据实战
3.1 单只股票历史数据获取
以获取贵州茅台(600519.SH)的日线数据为例,完整代码如下:
python复制import tushare as ts
import pandas as pd
# 设置token(如果已通过环境变量设置可跳过)
ts.set_token('你的token')
pro = ts.pro_api()
# 获取贵州茅台日线数据
df = pro.daily(ts_code='600519.SH',
start_date='20100101',
end_date='20231231',
fields='trade_date,open,high,low,close,vol,amount')
# 转换日期格式并设为索引
df['trade_date'] = pd.to_datetime(df['trade_date'])
df.set_index('trade_date', inplace=True)
# 按时间升序排列
df.sort_index(inplace=True)
这段代码会返回包含以下字段的DataFrame:
- open:开盘价
- high:最高价
- low:最低价
- close:收盘价
- vol:成交量(手)
- amount:成交金额(千元)
注意:Tushare的股票代码格式为"代码.SH/.SZ",SH表示沪市,SZ表示深市
3.2 多只股票批量获取
实际研究中,我们往往需要获取多只股票的数据。直接循环调用虽然可行,但效率较低。更高效的做法是:
python复制stock_list = ['600519.SH', '000858.SZ', '600036.SH']
all_data = {}
for stock in stock_list:
data = pro.daily(ts_code=stock,
start_date='20230101',
end_date='20231231')
all_data[stock] = data
对于更大规模的股票池(如全市场股票),建议:
- 先获取股票列表:pro.stock_basic()
- 分批查询(每次50-100只)
- 使用多线程加速
4. 数据清洗与规整
4.1 处理异常值和缺失值
原始数据中可能存在以下问题需要处理:
- 停牌日数据缺失
- 早期数据字段不全
- 价格异常波动
我的标准清洗流程:
python复制# 1. 处理停牌日(成交量为0)
df = df[df['vol'] > 0]
# 2. 前复权处理
df['adj_close'] = df['close'] # 实际应用中需要使用复权因子计算
# 3. 填充可能的缺失值
df.fillna(method='ffill', inplace=True)
# 4. 计算收益率
df['return'] = df['close'].pct_change()
4.2 数据存储方案
对于长期积累的数据,建议采用以下存储方案:
-
本地存储:
- CSV:适合小规模数据
- SQLite:轻量级数据库
- Parquet:列式存储,节省空间
-
数据库方案:
- MySQL:关系型数据库
- MongoDB:文档型数据库,适合非结构化数据
我个人的习惯是将原始数据按股票代码分文件存储为Parquet格式,既节省空间又便于快速读取:
python复制df.to_parquet(f'data/{stock_code.replace(".", "_")}.parquet')
5. 高级应用与性能优化
5.1 配合Backtrader进行回测
Tushare获取的数据可以无缝对接Backtrader等回测框架。关键步骤:
- 创建数据加载函数:
python复制def get_data_from_tushare(stock_code, start, end):
data = pro.daily(ts_code=stock_code,
start_date=start,
end_date=end)
return data
- 转换为Backtrader数据格式:
python复制import backtrader as bt
data = bt.feeds.PandasData(dataname=df,
datetime=None,
open=0, high=1, low=2, close=3,
volume=4, openinterest=-1)
5.2 性能优化技巧
- 缓存机制:对频繁查询的数据建立本地缓存
- 批量查询:使用pro.batch接口批量获取数据
- 异步请求:使用aiohttp等库实现并发查询
- 增量更新:只获取最新数据,与本地存储合并
示例代码(异步请求):
python复制import aiohttp
import asyncio
async def fetch_data(session, url):
async with session.get(url) as response:
return await response.json()
async def main():
async with aiohttp.ClientSession() as session:
tasks = []
for stock in stock_list:
url = f"http://api.tushare.pro?token=YOUR_TOKEN&api_name=daily¶ms={stock}"
tasks.append(fetch_data(session, url))
results = await asyncio.gather(*tasks)
6. 常见问题与解决方案
6.1 接口限流与配额管理
Tushare免费版有以下限制:
- 每分钟最多调用500次
- 每天最多调用500次(基础接口)
- 部分高级接口需要积分
应对策略:
- 在代码中添加延时:
python复制import time
time.sleep(0.1) # 每次请求后暂停0.1秒
- 监控调用次数:
python复制from tushare.util import get_call_count
print(get_call_count()) # 查看当日剩余调用次数
6.2 数据不一致问题
有时会发现不同时间获取的同一时期数据有细微差异,这是因为:
- Tushare会不定期修正历史数据
- 复权因子可能调整
解决方案:
- 定期全量更新数据
- 建立数据版本管理(如按获取日期存储多份副本)
6.3 停牌股票处理
对于长期停牌的股票,建议:
- 在回测中剔除这些股票
- 或者用行业指数填充缺失数据
识别长期停牌股票:
python复制# 找出过去20个交易日成交量都为0的股票
suspend_stocks = [code for code, df in all_data.items()
if df['vol'][-20:].sum() == 0]
7. 数据质量验证与交叉核对
7.1 基础验证方法
获取数据后,建议进行以下检查:
- 时间连续性验证:
python复制date_diff = df.index.to_series().diff().dt.days
gap_dates = date_diff[date_diff > 1] # 找出间隔大于1天的日期
- 价格合理性检查:
python复制abnormal = df[(df['high'] < df['low']) |
(df['close'] > df['high']) |
(df['close'] < df['low'])]
7.2 与其他数据源交叉验证
我通常会对比以下数据源:
- 交易所官网数据
- 同花顺/东方财富等行情软件
- Wind/Choice等专业金融终端
对比脚本示例:
python复制def compare_with_eastmoney(tushare_df, eastmoney_df):
merged = pd.merge(tushare_df, eastmoney_df,
left_index=True, right_index=True,
suffixes=('_ts', 'em'))
discrepancy = merged[abs(merged['close_ts'] - merged['close_em']) > 0.01]
return discrepancy
8. 实际应用案例分享
8.1 构建本地A股数据库
我的本地数据库结构如下:
code复制A股数据库/
├── daily/ # 日线数据
│ ├── SH/ # 沪市
│ └── SZ/ # 深市
├── basic/ # 基本面数据
├── index/ # 指数数据
└── update.log # 更新记录
自动更新脚本的关键部分:
python复制def update_daily_data():
last_update = read_last_update() # 读取上次更新日期
today = datetime.now().strftime('%Y%m%d')
if last_update != today:
new_data = pro.daily(trade_date=today)
save_to_database(new_data)
write_update_log(today)
8.2 量化策略研究实例
以简单的双均线策略为例:
python复制# 使用Tushare数据计算均线
df['ma5'] = df['close'].rolling(5).mean()
df['ma20'] = df['close'].rolling(20).mean()
# 生成交易信号
df['signal'] = 0
df.loc[df['ma5'] > df['ma20'], 'signal'] = 1
df.loc[df['ma5'] <= df['ma20'], 'signal'] = -1
# 计算策略收益
df['strategy_return'] = df['signal'].shift(1) * df['return']
这个简单策略虽然不够完善,但展示了如何将Tushare数据应用于实际策略开发。在实际操作中,我发现以下几个改进点能显著提升表现:
- 增加交易成本考量
- 结合成交量过滤假突破
- 不同参数组合的优化
