4、数据获取与预处理:从零开始搭建你的数据管道
做统计套利,说白了就是跟数据打交道。你策略再牛,模型再花哨,数据一塌糊涂,结果就是白忙活。我见过太多人一上来就调参、跑回测,结果发现数据里全是坑——缺失值、异常点、时间戳对不齐……嗯,今天我们就从最基础的数据获取和预处理讲起。
4.1 用 yfinance 获取历史数据
我个人习惯用 yfinance 来拉数据。它免费、轻量,而且接口设计得很人性化。你想想看,几行代码就能拿到股票、ETF 甚至加密货币的历史行情,多方便。
先装包:
pip install yfinance
然后拉数据:
import yfinance as yf
# 获取两只股票的历史数据
tickers = ["AAPL", "MSFT"]
data = yf.download(tickers, start="2020-01-01", end="2023-12-31")
print(data.head())
这里有个细节要注意:yf.download() 返回的是 MultiIndex DataFrame,列名是 (Price, Ticker) 的形式。比如 ("Close", "AAPL") 表示苹果的收盘价。我个人习惯把它拆成单层索引,方便后续操作:
# 提取收盘价
close_prices = data["Close"]
print(close_prices.head())
yf.download(tickers, start="...", end="...", auto_adjust=True),这样会自动调整复权价格,省去手动计算的麻烦。
4.2 数据清洗:缺失值与异常值处理
数据到手后,第一件事就是检查有没有缺失值。我在项目中遇到过好几次,因为某只股票停牌或者数据源问题,导致某几天的价格是 NaN。如果不处理,后面计算收益率、协方差矩阵时就会报错。
先看看缺失情况:
# 检查缺失值
print(close_prices.isnull().sum())
# 删除包含缺失值的行
clean_data = close_prices.dropna()
# 或者用前向填充(适合停牌情况)
filled_data = close_prices.fillna(method='ffill')
异常值处理更考验经验。我记得有一次,某只股票突然出现一个 -9999 的价格,明显是数据录入错误。怎么发现?用 Z-score 或者 IQR 方法:
import numpy as np
# 用 Z-score 检测异常值
z_scores = np.abs((clean_data - clean_data.mean()) / clean_data.std())
outliers = (z_scores > 3).any(axis=1)
print(f"发现 {outliers.sum()} 个异常日期")
4.3 重采样与对齐
做配对交易,两只股票的时间戳必须完全对齐。你想想看,如果 A 股票有 2023-01-01 的数据,而 B 股票没有,那这一天就没法用。更麻烦的是,不同交易所的节假日不同,比如美股和港股,休市日期不一样。
重采样可以解决频率不一致的问题:
# 将日数据重采样为周数据
weekly_data = clean_data.resample('W').last()
# 对齐:只保留两只股票都有的日期
aligned_data = clean_data.dropna()
这里有个坑:resample('W') 默认以周日为结束,但实际交易周是周一到周五。我建议用 resample('W-FRI') 来对齐到周五:
weekly_data = clean_data.resample('W-FRI').last()
4.4 数据可视化基础
光看数字不够直观。我习惯先画个图,看看两只股票的价格走势是否相似,有没有明显的背离。用 matplotlib 几行代码搞定:
import matplotlib.pyplot as plt
# 绘制价格走势
plt.figure(figsize=(12, 6))
plt.plot(aligned_data.index, aligned_data["AAPL"], label="AAPL")
plt.plot(aligned_data.index, aligned_data["MSFT"], label="MSFT")
plt.title("AAPL vs MSFT 价格走势")
plt.xlabel("日期")
plt.ylabel("价格")
plt.legend()
plt.grid(True)
plt.show()
还可以画价差图,看看两者是否长期保持稳定关系:
# 计算价差(假设已经做过标准化)
spread = aligned_data["AAPL"] - aligned_data["MSFT"]
plt.figure(figsize=(12, 4))
plt.plot(spread.index, spread, color='blue')
plt.axhline(y=spread.mean(), color='red', linestyle='--', label='均值')
plt.title("价差序列")
plt.legend()
plt.show()
4.5 本章知识体系
下面这张图帮你理清数据预处理的完整流程:
嗯,数据预处理这块就讲到这里。记住,干净的、对齐的数据是配对交易成功的基石。别急着跑策略,先把数据管道搭好。
公众号:蓝海数据掘金营,微信 deep3321