3. 数据获取:用 Tushare 和 AkShare 拉取指数成分股与权重
好,咱们进入实战环节的第一步——拿数据。
做指数跟踪,最怕什么?最怕你算出来的偏离度,根本就不是指数的真实表现。我见过不少新手,拿着指数收盘价就去算跟踪误差,结果成分股都换了好几轮了,他还蒙在鼓里。所以,成分股列表和权重数据,是后续所有计算的基石。
3.1 为什么必须拿实时权重?
很多人以为指数权重是固定的。其实不然。沪深300、中证500这些指数,每半年调一次仓,但权重每天都在变——因为股价在波动,市值在变化。你想想看,如果某只股票今天大涨,它在指数里的权重自然就高了。你用三个月前的权重去算今天的偏离度,那结果能准吗?
我个人习惯是:每次做偏离度计算前,都重新拉一次最新的成分股和权重。哪怕只是隔了一天,我也要确认一下。
核心原则: 用最新权重,算最新偏离。别偷懒,别用缓存数据糊弄自己。
3.2 方案一:Tushare Pro(推荐,但需要积分)
Tushare 是老牌数据源了。它的 Pro 版本接口很稳定,数据质量也高。不过,获取指数成分股权重需要一定的积分权限。如果你积分够,直接用 index_weight 接口就行。
import tushare as ts
# 设置 token(你需要在 tushare.pro 注册获取)
ts.set_token('你的token')
pro = ts.pro_api()
# 获取沪深300最新成分股及权重
df_weight = pro.index_weight(index_code='000300.SH', start_date='20250101', end_date='20250301')
print(df_weight.head())
这个接口返回什么?con_code(股票代码)、weight(权重,百分比形式)。注意,权重总和可能不是100%,因为有些股票权重极小被四舍五入掉了。嗯,这里要注意:拿到数据后,最好自己归一化一下,确保总和为100%。
我的小技巧: 如果积分不够,可以只拉最近一个交易日的权重。用 trade_date 参数指定日期,能省积分。
3.3 方案二:AkShare(免费,但需要处理)
如果你不想花钱买积分,AkShare 是个好选择。它是开源的,接口丰富,但数据格式有时候需要自己清洗一下。
import akshare as ak
# 获取沪深300成分股及权重(来自东方财富)
df_weight = ak.index_stock_cons_weight_csindex(symbol="000300")
print(df_weight.head())
这个接口返回的字段包括 stock_code、stock_name、weight。注意,AkShare 的权重单位是百分比,但有时候会带百分号,需要你转成浮点数。我曾经在项目中遇到过这个问题:直接拿字符串去算偏离度,结果程序报错,排查了半天才发现是数据类型没转。
避坑指南: AkShare 的数据源来自不同网站,偶尔会有缺失值。比如某只股票停牌了,权重可能显示为0。我建议你拿到数据后,先检查一下是否有空值,用 df.isnull().sum() 看一眼。
3.4 两种方案的对比
我把两个方案的特点整理了一下,方便你选型:
| 对比项 | Tushare Pro | AkShare |
|---|---|---|
| 费用 | 需要积分(部分免费) | 完全免费 |
| 数据稳定性 | 高,接口稳定 | 中等,偶尔因网站改版失效 |
| 权重精度 | 精确到小数点后4位 | 精确到小数点后2位 |
| 数据清洗工作量 | 少,基本拿来就用 | 需要处理格式、缺失值 |
| 适合场景 | 生产环境、高频计算 | 研究、个人学习、小规模回测 |
我个人建议:如果你做的是实盘或者准实盘,用 Tushare,省心。如果只是做研究或者回测,AkShare 完全够用,还能省点钱。
3.5 数据获取后的标准化处理
不管用哪个数据源,拿到原始数据后,我通常会做三步处理:
- 权重归一化:把权重总和调整为100%。因为有时候数据源返回的权重总和是99.98%或者100.02%,直接拿来用会有微小误差。
- 股票代码统一格式:Tushare 返回的是
000001.SZ这种格式,AkShare 可能是000001。我习惯统一成000001.SZ格式,方便后续与行情数据做 join。 - 剔除权重为0的股票:有些股票虽然还在指数里,但权重极小(比如0.01%以下),对偏离度计算影响微乎其微。我一般会设一个阈值,比如0.01%,低于这个的直接剔除,减少计算量。
# 示例:权重归一化
df_weight['weight'] = df_weight['weight'] / df_weight['weight'].sum() * 100
# 示例:剔除极小权重
df_weight = df_weight[df_weight['weight'] >= 0.01]
我的经验: 剔除极小权重后,指数跟踪的误差通常不会超过0.01%。但如果你做的是高频套利,那还是保留所有成分股吧,蚊子腿也是肉。
3.6 本章核心逻辑图
下面这张图,概括了从数据获取到标准化处理的完整流程。你可以把它当作一个检查清单:
这张图看起来简单,但每一步都可能踩坑。我刚开始做的时候,就因为在数据清洗环节没处理缺失值,导致后面算出来的偏离度曲线全是锯齿——后来才发现是某只停牌股的权重字段是空的。从那以后,我每次拿到数据,第一件事就是 df.info() 看一眼。
好了,数据到手了,下一步就是用它来计算实时偏离度了。不过那是下一节的内容,咱们先把数据准备扎实。