第三章:数据获取——用yfinance搞定纳斯达克历史数据
做量化交易,第一步就是拿数据。没有数据,再牛的策略也是空中楼阁。
我个人习惯用yfinance来获取纳斯达克的历史数据。为什么选它?因为简单、免费、够用。你想想看,一个pip install就能搞定的事,何必折腾复杂的API?
3.1 安装与初始化
先装包,这步没什么好说的:
pip install yfinance pandas numpy
嗯,这里要注意。yfinance依赖pandas,所以一起装上。我建议用虚拟环境,别污染全局包。
导入的时候,我习惯这样写:
import yfinance as yf
import pandas as pd
import numpy as np
from datetime import datetime, timedelta
为什么要导入datetime?因为后面要算时间范围。你总不想每次都手动输入起止日期吧?
3.2 获取纳斯达克指数数据
纳斯达克指数的代码是^IXIC。注意那个脱字符,这是雅虎财经的特殊标记。
# 获取纳斯达克近5年数据
nasdaq = yf.download('^IXIC', start='2019-01-01', end='2024-01-01')
# 看一眼数据长什么样
print(nasdaq.head())
print(nasdaq.info())
跑完这段代码,你会看到类似这样的输出:
| Date | Open | High | Low | Close | Volume | Adj Close |
|---|---|---|---|---|---|---|
| 2019-01-02 | 6635.27 | 6665.95 | 6569.80 | 6635.27 | 0 | 6635.27 |
看到Volume那一列了吗?全是0。这是雅虎财经的老毛病了。指数数据不提供成交量,但没关系,我们做策略分析主要用价格。
3.3 获取个股数据
光有指数不够,我们还得拿个股数据。比如苹果、微软、谷歌这些纳斯达克权重股。
# 定义股票列表
tickers = ['AAPL', 'MSFT', 'GOOGL', 'AMZN', 'META']
# 批量下载
data = yf.download(tickers, start='2019-01-01', end='2024-01-01')
# 看看数据结构
print(data.columns.names)
print(data.head())
这里有个小技巧。yf.download返回的是MultiIndex DataFrame。列名是两层:第一层是字段(Open, Close...),第二层是股票代码。我个人习惯把它展平:
# 展平列名
data.columns = ['_'.join(col).strip() for col in data.columns.values]
print(data.head())
展平之后,列名就变成了'AAPL_Open'、'MSFT_Close'这种格式。操作起来方便多了。
3.4 数据清洗与预处理
数据拿到手,别急着用。先洗一洗。我见过太多人直接拿原始数据跑策略,结果回测漂亮,实盘一塌糊涂。
清洗步骤其实就三件事:
- 处理缺失值——检查有没有NaN
- 处理异常值——比如某天价格突然跳空100%
- 对齐时间轴——确保所有股票日期一致
# 检查缺失值
print(data.isnull().sum())
# 前向填充(用前一天的数据填充缺失)
data.fillna(method='ffill', inplace=True)
# 再检查一遍
print(data.isnull().sum().sum())
异常值怎么处理?我一般用Z-score方法:
from scipy import stats
# 计算每只股票的Z-score
z_scores = np.abs(stats.zscore(data['AAPL_Close']))
threshold = 3
# 标记异常值
outliers = np.where(z_scores > threshold)
print(f'发现 {len(outliers[0])} 个异常值')
# 用中位数替换异常值
median_val = data['AAPL_Close'].median()
data.loc[data['AAPL_Close'].index[outliers], 'AAPL_Close'] = median_val
阈值设3倍标准差,这是统计学上的常用做法。当然,你也可以根据实际情况调整。
3.5 数据存储
清洗完的数据,得存起来。下次用的时候直接读,不用再跑一遍下载。
我提供两种存储方式:CSV和HDF5。
3.5.1 CSV存储
CSV是最通用的格式,任何工具都能打开。但缺点也很明显——大文件读写慢,而且不支持数据类型保留。
# 保存为CSV
data.to_csv('nasdaq_data.csv')
# 读取CSV
df_csv = pd.read_csv('nasdaq_data.csv', index_col=0, parse_dates=True)
注意那个parse_dates=True。如果不加,日期列会被当成字符串读进来。到时候你还要手动转格式,多麻烦。
3.5.2 HDF5存储
HDF5是我个人更推荐的格式。读写速度快,支持压缩,还能保留数据类型。对于量化交易这种高频读写场景,HDF5是首选。
# 保存为HDF5
data.to_hdf('nasdaq_data.h5', key='nasdaq', mode='w')
# 读取HDF5
df_h5 = pd.read_hdf('nasdaq_data.h5', key='nasdaq')
HDF5还有一个好处——可以存多个数据集。比如你可以把指数数据、个股数据、因子数据都放在同一个文件里,用不同的key区分:
# 存储多个数据集
with pd.HDFStore('quant_data.h5') as store:
store['nasdaq_index'] = nasdaq
store['stocks'] = data
store['factors'] = factor_data
3.6 本章知识体系
下面这张图,是我梳理的本章核心逻辑。你看一眼就能明白整个数据获取流程:
这张图把整个流程串起来了。从yfinance获取原始数据,到清洗预处理,最后落地存储。每一步都有坑,但每一步也都有解法。
好了,数据获取这块就讲到这里。记住一个原则:数据质量决定策略质量。花80%的时间在数据上,20%的时间在策略上,这才是量化交易的正确姿势。
公众号:蓝海资料掘金营,微信deep3321