4. 数据准备:获取股票行情数据、财务数据

做Smart Beta组合,说白了就是「数据喂进去,策略吐出来」。但数据这步要是没弄干净,后面再牛的模型也是白搭。我见过太多人,策略回测曲线漂亮得不行,一上实盘就崩——十有八九是数据准备阶段埋了雷。

这一章,咱们就把数据准备的底裤扒干净。

4.1 行情数据怎么拿?

行情数据,就是每天的开高低收、成交量、成交额。我个人习惯用 tushare 或者 akshare,这两个库对国内A股覆盖得比较全。

举个例子,拿日线数据:

import tushare as ts
pro = ts.pro_api('你的token')

# 获取平安银行2023年日线数据
df = pro.daily(ts_code='000001.SZ', start_date='20230101', end_date='20231231')
print(df.head())

嗯,这里要注意:tushare的token要自己去官网申请,免费的额度够个人研究用。如果你在机构做,建议直接买Wind或者聚宽的接口,数据质量更稳定。

我在项目中遇到过一个问题:不同数据源对复权处理不一样。有的默认前复权,有的后复权。做Smart Beta时,我建议统一用后复权数据。为什么?因为后复权保留了真实的收益率信息,计算因子时不会失真。

我的小技巧: 拿到数据后,先画个K线图看一眼。如果某天突然跳空或者价格变成负数,八成是数据源抽风了。别偷懒,这一步能帮你筛掉很多脏数据。

4.2 财务数据怎么拿?

财务数据是Smart Beta的灵魂。市盈率、市净率、ROE、营收增速……这些因子全得靠财报算。

同样用tushare拿财务数据:

# 获取平安银行2023年一季报财务数据
fin_df = pro.fina_indicator(ts_code='000001.SZ', start_date='20230331', end_date='20230331')
print(fin_df.columns)

财务数据有个坑:财报发布日期和财报覆盖期不一样。比如4月底发布的Q1财报,覆盖的是1-3月的数据。如果你在4月15号用Q1数据做因子,那就犯了「未来函数」的错误——数据还没发布呢!

我曾经因为这个原因,回测跑出来年化20%,实盘直接亏成狗。后来学乖了:一定要用财报的实际发布日期,而不是财报覆盖期。tushare的disclosure_date字段就是干这个用的。

避坑指南: 财务数据更新有滞后性。A股规定:年报在次年4月底前发布,半年报在8月底前,季报在季度结束后1个月内。做因子时,记得给数据打上「时间戳」,别把未来的信息偷渡到过去。

4.3 数据清洗:处理停牌、ST、新股

数据拿到手,别急着算因子。先做三件事:去停牌、去ST、去新股。这三样东西,是Smart Beta组合的隐形杀手。

4.3.1 停牌处理

股票停牌期间,价格不变,成交量是0。如果你不处理,因子计算会出问题。比如波动率因子,停牌期间波动率为0,复牌后一天波动率暴增,这显然不合理。

我的做法是:停牌超过5天的股票,直接剔除。如果只是停牌1-2天,用前一天的收盘价填充。

# 标记停牌:当日成交量为0且涨跌幅为0
df['is_suspended'] = (df['vol'] == 0) & (df['pct_chg'] == 0)

# 连续停牌超过5天,剔除
df['suspend_days'] = df.groupby('ts_code')['is_suspended'].cumsum()
df = df[df['suspend_days'] <= 5]

4.3.2 ST股票处理

ST股票,说白了就是「问题股」。涨跌幅限制变成5%,流动性差,随时可能退市。Smart Beta组合里放ST股票,风险收益特征完全扭曲。

我建议:每个月调仓时,把当前处于ST状态的股票全部剔除。注意,是「当前状态」,不是历史状态。有些股票摘帽后恢复正常,可以重新纳入。

核心原则: ST股票在Smart Beta组合里没有位置。别想着「万一它翻身了呢」——那是投机,不是因子投资。

4.3.3 新股处理

新股上市头几天,经常连续涨停,波动率异常大。如果你把新股纳入组合,因子值会被严重扭曲。

我个人习惯:上市不满60个交易日的股票,直接剔除。为什么是60天?因为A股新股通常一个月左右打开涨停板,再给一个月让价格回归正常。

# 计算上市天数
df['list_days'] = (df['trade_date'] - df['list_date']).dt.days
df = df[df['list_days'] >= 60]

4.4 数据对齐:让所有股票站在同一起跑线

数据对齐,就是让不同股票的数据在时间上保持一致。比如你要算2023年1月的因子,那所有股票都得有2023年1月的数据。

对齐的步骤:

  1. 时间对齐: 把日线数据统一到同一个交易日历上。A股交易日历可以从交易所官网下载,或者用tushare的trade_cal接口。
  2. 频率对齐: 财务数据是季频,行情数据是日频。做因子时,通常把财务数据「降频」到月频——每个月用最新的财报数据。
  3. 缺失值处理: 有些股票在某个月没有财务数据(比如刚上市),直接填充为NaN,后续计算因子时自动跳过。
# 生成月度时间戳
monthly_dates = pd.date_range(start='2023-01-01', end='2023-12-31', freq='M')

# 对齐:每个月底取最新的财务数据
aligned_df = fin_df.groupby('ts_code').resample('M', on='trade_date').last()

4.5 本章知识体系

下面这张图,把数据准备的整个流程串起来了。你可以把它当成一个检查清单,每次做数据时对照着走一遍。

数据准备流程 获取行情数据 日线:开高低收、成交量 获取财务数据 季报:ROE、PE、营收增速 获取交易日历 交易所官方日历 数据清洗 剔除停牌超过5天 剔除ST股票 剔除上市不满60天 处理缺失值 数据对齐 时间对齐 → 频率对齐 → 缺失值填充 ✅ 干净、对齐的数据面板

数据准备这步,看着琐碎,但真不能省。我见过有人直接拿原始数据跑因子,结果回测收益高得离谱——仔细一查,原来是把未来数据混进去了。嗯,这种错误犯一次就够了。

数据准备好了,下一章咱们就开始算因子。记住一句话:垃圾进,垃圾出。数据干净了,策略才能站得住脚。