数据获取与清洗:数据源选择、字段定义与预处理

做量化投资,第一步就是搞数据。没有数据,再牛的策略也是空中楼阁。

我个人习惯把数据获取和清洗看作整个系统的地基。地基不稳,后面全白搭。今天咱们就聊聊这块硬骨头怎么啃。

数据源选择:三大主流方案

市面上数据源不少,但真正适合个人投资者的,我重点推荐三个:Yahoo Finance、Tushare、AKShare。每个我都用过,各有各的脾气。

数据源 特点 适用场景 我的评价
Yahoo Finance 免费、全球市场、API稳定 美股、全球指数 老牌选手,但A股数据不全
Tushare 国内专业、数据全面、需积分 A股、基金、期货 我最常用的,积分制有点烦
AKShare 开源免费、接口丰富、更新快 A股、宏观、另类数据 后起之秀,社区活跃
我的建议:新手先用AKShare入门,零成本。做A股策略,Tushare是首选。做全球配置,Yahoo Finance绕不开。

数据字段定义:别小看这一步

拿到原始数据后,第一件事不是分析,而是搞清楚每个字段的含义。我在项目中遇到过,有人把复权因子当成了价格,回测结果漂亮得不行,实盘直接亏哭。

标准字段定义如下:

  • open:开盘价,当天第一笔成交价
  • high:最高价,当天最高成交价
  • low:最低价,当天最低成交价
  • close:收盘价,当天最后一笔成交价
  • volume:成交量,当天成交的总股数
  • amount:成交额,当天成交的总金额
  • adj_factor:复权因子,用于计算复权价格
注意:不同数据源对字段命名可能不同。比如Yahoo Finance用"Adj Close"表示复权收盘价,Tushare用"adj_factor"加"close"计算。一定要先看文档。

缺失值处理:数据里的坑

现实中的数据,很少是完美的。停牌、节假日、数据源故障,都会导致缺失值。

我常用的处理方法:

  1. 向前填充(ffill):用上一个有效值填充。适合价格数据,因为停牌期间价格不变。
  2. 向后填充(bfill):用下一个有效值填充。适合某些指标数据。
  3. 插值法:线性插值或多项式插值。适合连续变化的数据。
  4. 直接删除:如果缺失比例很小,直接删掉那几行。
# 我常用的缺失值处理代码
import pandas as pd

# 向前填充
df['close'].fillna(method='ffill', inplace=True)

# 线性插值
df['volume'].interpolate(method='linear', inplace=True)

# 删除缺失行
df.dropna(subset=['open', 'high', 'low', 'close'], inplace=True)
避坑指南:我曾经在回测中用了向前填充处理成交量数据,结果停牌日成交量被填成了前一天的数值,导致策略误以为有交易。后来我改成用0填充成交量,才解决问题。

异常值检测:揪出捣乱的数据

数据里偶尔会有离谱的值。比如某只股票突然涨了1000%,或者成交量突然变成0。这些异常值会严重干扰策略。

我常用的检测方法:

  • 3σ原则:超出均值±3倍标准差的值视为异常
  • IQR方法:超出Q1-1.5*IQR或Q3+1.5*IQR的值视为异常
  • 固定阈值:比如涨跌幅超过20%视为异常
# 用IQR方法检测异常值
Q1 = df['close'].quantile(0.25)
Q3 = df['close'].quantile(0.75)
IQR = Q3 - Q1

lower_bound = Q1 - 1.5 * IQR
upper_bound = Q3 + 1.5 * IQR

anomalies = df[(df['close'] < lower_bound) | (df['close'] > upper_bound)]
print(f"发现 {len(anomalies)} 个异常值")
注意:不要机械地删除异常值。有些异常可能是真实的市场事件,比如分红、拆股。先检查原因,再决定怎么处理。

数据对齐:让不同数据步调一致

不同数据源、不同频率的数据,时间戳可能不一致。比如日线数据有的用"2024-01-01",有的用"2024/01/01"。更麻烦的是,不同股票的交易日期可能不同。

数据对齐的核心原则:

  • 统一时间格式:全部转为datetime类型
  • 统一频率:日线、周线、月线要明确
  • 对齐交易日:用所有股票的共同交易日作为基准
# 数据对齐示例
# 假设有两只股票的数据,日期不完全一致
stock_a = pd.DataFrame({'date': ['2024-01-01', '2024-01-02', '2024-01-04'],
                        'close': [100, 101, 102]})
stock_b = pd.DataFrame({'date': ['2024-01-01', '2024-01-03', '2024-01-04'],
                        'close': [200, 201, 202]})

# 合并并对齐
merged = pd.merge(stock_a, stock_b, on='date', how='inner')
print(merged)
我的经验:对齐时用inner join(内连接)还是outer join(外连接),取决于你的策略。如果策略需要连续数据,用outer join然后填充缺失值。如果策略只关心共同交易日,用inner join更干净。

知识体系总览

下面这张图,是我整理的数据获取与清洗核心流程。你想想看,每一步都环环相扣。

数据获取与清洗核心流程 数据源选择 Yahoo / Tushare / AKShare 字段定义 open/high/low/close/volume 缺失值处理 ffill / bfill / 插值 / 删除 异常值检测 3σ / IQR / 固定阈值 数据对齐 统一格式 / 统一频率 / 对齐交易日 清洗完成 可用于策略回测 关键要点 • 数据源选择:根据市场和需求选择合适的数据源 • 字段定义:理解每个字段的含义,避免误用 • 缺失值处理:根据数据特性选择合适的方法 • 异常值检测:先检查原因,再决定处理方式

嗯,到这里,数据获取与清洗的核心内容就讲完了。说白了,这一步就是给策略打好基础。数据干净了,后面的分析才能放心做。

总结一下:数据源选对,字段定义清,缺失值处理好,异常值揪出来,数据对齐准。这五步走完,你的数据就准备好了。

专注资料整理