第二章 数据基础与准备:金融数据来源与清洗

做量化研究,有一句话我特别认同:垃圾进,垃圾出。你因子逻辑再漂亮,回测框架再牛,数据源头是脏的,结果就是废的。这一章,我们就来聊聊数据那些事儿。

核心观点:因子研究80%的时间花在数据准备上,20%花在因子构建和检验上。别嫌烦,这是基本功。

2.1 金融数据来源:你该选哪个?

国内主流的数据源,我接触过三个:Wind、Tushare、聚宽。各有各的脾气。

数据源 特点 适合人群 成本
Wind 数据最全、最权威,API稳定,但贵 机构、专业团队 高(年费数万)
Tushare 开源免费,社区活跃,但数据质量参差 个人、小团队、学习 低(积分制)
聚宽 平台化,数据+回测一体,方便但封闭 策略开发、快速验证 中(有免费额度)

我个人习惯是:机构用Wind,个人用Tushare。聚宽适合快速跑通逻辑,但真要搭因子库,还是得自己拉数据。

小技巧:如果你用Tushare,记得申请token后先缓存到本地。我刚开始用的时候,每次跑脚本都重新拉,结果被限流了……后来改成每天盘后拉一次存CSV,省心多了。

2.2 数据清洗:去极值与缺失值处理

数据拉下来,第一件事不是算因子,而是洗数据。脏数据主要有两类:极值和缺失值。

2.4.1 去极值:别让异常值带偏你

什么叫极值?比如某只股票某天涨了1000%,或者市盈率突然变成负数。这些数据点会严重扭曲你的因子分布。

常用的方法有三种:

  • MAD法(中位数绝对偏差):稳健,适合非正态分布。我常用这个。
  • 百分位法:直接砍掉上下1%或5%的数据。简单粗暴。
  • 标准差法:超过3倍标准差就干掉。适合正态分布的数据。

举个例子,用MAD法去极值:

import numpy as np

def winsorize_mad(series, n=5):
    median = np.median(series)
    mad = np.median(np.abs(series - median))
    upper = median + n * mad
    lower = median - n * mad
    return np.clip(series, lower, upper)

# 使用
factor_values = [1.2, 1.5, 1.3, 100.0, 1.4, 1.1, 1.6]
cleaned = winsorize_mad(factor_values)
print(cleaned)  # 100.0 会被压缩到合理范围

注意:去极值不是删除数据,而是把极端值拉到边界。我曾经见过有人直接删掉异常值,结果导致时间序列不连续,回测时出现跳空——那叫一个惨。

2.4.2 缺失值处理:别让NaN毁了你的因子

金融数据缺失太常见了。停牌、新股上市、数据源没更新……都会产生NaN。

我的处理原则是:

  • 时间序列数据:用前向填充(ffill)或插值。比如停牌日,用前一交易日的数据。
  • 截面数据:用行业均值填充。比如某只股票的市盈率缺失,用同行业其他股票的均值补上。
  • 实在补不了的:直接删除该样本。但要注意,删除比例不能太高,超过5%就要警惕了。

代码示例:

import pandas as pd

# 前向填充
df['factor'] = df['factor'].ffill()

# 行业均值填充
df['factor'] = df.groupby('industry')['factor'].transform(
    lambda x: x.fillna(x.mean())
)

避坑指南:我曾经用ffill填充停牌数据,结果忘了处理复牌当天的跳空。因子值连续几天不变,复牌后突然变回真实值,导致因子信号出现假突破。后来我加了一个判断:如果连续填充超过5天,就标记为缺失,重新处理。

2.3 数据对齐与频率统一

因子数据、价格数据、财务数据,它们的频率可能不一样。日频、周频、月频,甚至分钟频。直接拿来用,时间戳对不上,结果就是错位。

举个例子:你要算一个基于月频财务数据的因子,但价格数据是日频的。如果不做对齐,你可能会用上个月的财务数据去预测下个月的收益——这属于未来函数,回测里看着漂亮,实盘就完蛋。

我的做法是:

  1. 统一时间戳:把所有数据都对齐到交易日历。非交易日的数据要么填充,要么删除。
  2. 频率降采样:高频数据向低频对齐。比如日频数据转周频,取每周最后一个交易日的数据。
  3. 频率升采样:低频数据向高频对齐。比如月频财务数据,在当月所有交易日重复使用。

代码示例:

# 日频数据转周频
df_weekly = df_daily.resample('W').last()

# 月频数据填充到日频
df_daily['factor'] = df_monthly.reindex(df_daily.index, method='ffill')

重要:对齐时一定要考虑滞后性。财务数据通常在财报发布后才能用,不能直接用财报截止日的数据。我一般会在财报发布日之后的下一个交易日才开始使用该数据。

2.4 本章知识体系

下面这张图,帮你理清数据准备的全流程:

数据准备流程框架图 数据准备流程框架 数据源获取 数据清洗(去极值 + 缺失值处理) 数据对齐与频率统一 干净、对齐的因子数据 常见坑点 未来函数、停牌填充、行业均值偏差 最佳实践 MAD去极值、前向填充、滞后对齐

嗯,数据准备这块,说白了就是耐心活。你想想看,因子库搭得再好,数据源头是脏的,后面所有工作都是白费。我见过太多人花几个月搭因子库,结果回测漂亮、实盘拉胯,一查原因——数据对齐没做好,用了未来数据。

所以,这一章的内容,值得你反复看、反复练。数据干净了,你的因子研究才算真正开始。