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_codestock_nameweight。注意,AkShare 的权重单位是百分比,但有时候会带百分号,需要你转成浮点数。我曾经在项目中遇到过这个问题:直接拿字符串去算偏离度,结果程序报错,排查了半天才发现是数据类型没转。

避坑指南: AkShare 的数据源来自不同网站,偶尔会有缺失值。比如某只股票停牌了,权重可能显示为0。我建议你拿到数据后,先检查一下是否有空值,用 df.isnull().sum() 看一眼。

3.4 两种方案的对比

我把两个方案的特点整理了一下,方便你选型:

对比项 Tushare Pro AkShare
费用 需要积分(部分免费) 完全免费
数据稳定性 高,接口稳定 中等,偶尔因网站改版失效
权重精度 精确到小数点后4位 精确到小数点后2位
数据清洗工作量 少,基本拿来就用 需要处理格式、缺失值
适合场景 生产环境、高频计算 研究、个人学习、小规模回测

我个人建议:如果你做的是实盘或者准实盘,用 Tushare,省心。如果只是做研究或者回测,AkShare 完全够用,还能省点钱。

3.5 数据获取后的标准化处理

不管用哪个数据源,拿到原始数据后,我通常会做三步处理:

  1. 权重归一化:把权重总和调整为100%。因为有时候数据源返回的权重总和是99.98%或者100.02%,直接拿来用会有微小误差。
  2. 股票代码统一格式:Tushare 返回的是 000001.SZ 这种格式,AkShare 可能是 000001。我习惯统一成 000001.SZ 格式,方便后续与行情数据做 join。
  3. 剔除权重为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 本章核心逻辑图

下面这张图,概括了从数据获取到标准化处理的完整流程。你可以把它当作一个检查清单:

指数成分股与权重数据获取流程 选择数据源 Tushare Pro / AkShare 调用接口获取数据 index_weight / index_stock_cons_weight 数据清洗与检查 检查缺失值 | 转换数据类型 | 统一代码格式 权重标准化处理 归一化至100% | 剔除极小权重(阈值0.01%) 输出:标准化权重DataFrame

这张图看起来简单,但每一步都可能踩坑。我刚开始做的时候,就因为在数据清洗环节没处理缺失值,导致后面算出来的偏离度曲线全是锯齿——后来才发现是某只停牌股的权重字段是空的。从那以后,我每次拿到数据,第一件事就是 df.info() 看一眼。

好了,数据到手了,下一步就是用它来计算实时偏离度了。不过那是下一节的内容,咱们先把数据准备扎实。