3. 汇率数据获取:使用 Yahoo Finance API (yfinance) 获取历史汇率数据,数据清洗与初步探索
做量化交易,数据就是命根子。这话我常跟团队里的人讲。
数据质量不行,后面模型再花哨也是白搭。今天咱们就聊聊怎么把汇率数据搞到手,并且把它收拾得干干净净。
3.1 为什么选 Yahoo Finance?
市面上能拿汇率数据的渠道不少,比如 Bloomberg、Reuters,还有央行官网。但说实话,对于个人学习和研究来说,Yahoo Finance 是最友好的选择。
它免费、稳定,而且通过 yfinance 这个 Python 库,几行代码就能搞定。我在做早期原型验证时,经常用它来快速获取数据。当然,如果你要上生产环境,那还是得考虑 Bloomberg 这类专业数据源。
核心优势:
- 完全免费,无需 API Key
- 覆盖主流货币对,数据历史久
- Python 接口简单,上手快
3.2 安装与导入 yfinance
先装包。这个很简单,一行命令搞定:
pip install yfinance
装完之后,在代码里导入:
import yfinance as yf
import pandas as pd
import numpy as np
from datetime import datetime
嗯,这里要注意一点。yfinance 依赖 pandas,所以最好先把 pandas 也装上。我个人习惯把 numpy 也带上,后面做数值计算方便。
3.3 获取汇率数据:以 EUR/USD 为例
汇率在 Yahoo Finance 里是用特定的代码表示的。比如欧元兑美元,代码是 EURUSD=X。记住这个格式:货币1货币2=X。
来看代码:
# 定义货币对
ticker = "EURUSD=X"
# 获取数据
data = yf.download(ticker, start="2020-01-01", end="2024-12-31")
# 看一眼
print(data.head())
跑完之后,你会得到一个 DataFrame,里面包含 Open、High、Low、Close、Volume、Adj Close 这几列。
你想想看,对于汇率来说,Volume 其实没什么意义,因为外汇市场是场外交易,没有统一的成交量数据。所以后面我们一般只用 Close 或者 Adj Close。
小技巧: 如果你只需要收盘价,可以直接用 data['Close'] 提取。这样数据更干净,也省内存。
3.4 数据清洗:把脏数据扔掉
数据拿到手,别急着用。先看看有没有坑。
我曾经有一次,模型跑出来结果特别离谱,查了半天才发现是数据里有几个空值没处理。从那以后,我养成了一个习惯:拿到数据先做清洗。
常见的清洗步骤:
- 检查缺失值
- 处理异常值
- 统一时间索引
来看代码:
# 检查缺失值
print(data.isnull().sum())
# 删除缺失值(或者用前向填充)
data_clean = data.dropna()
# 或者用前向填充
# data_clean = data.fillna(method='ffill')
# 检查索引是否连续
print(data_clean.index.is_monotonic_increasing)
这里我多说一句。对于金融时间序列,用前向填充(ffill)通常比直接删除更合理。因为市场在非交易时段没有数据,用前一个交易日的价格填充,逻辑上说得通。
注意: 如果缺失值太多(比如连续几天没有数据),那就要小心了。可能是节假日,也可能是数据源本身有问题。这时候我建议去 Yahoo Finance 网页上手动核对一下。
3.5 初步探索:数据长什么样?
数据洗干净了,接下来就是看看它到底长什么样。这一步叫 EDA(探索性数据分析)。
我一般会做三件事:
- 看统计摘要
- 画价格走势图
- 看收益率分布
先看统计摘要:
print(data_clean.describe())
这个会告诉你均值、标准差、最大最小值等。如果发现最大值异常高,那就要怀疑是不是数据有误。
然后画个走势图:
import matplotlib.pyplot as plt
data_clean['Close'].plot(figsize=(12, 6), title='EUR/USD 历史走势')
plt.xlabel('日期')
plt.ylabel('汇率')
plt.show()
走势图能让你直观地看到趋势和波动。比如 2020 年疫情初期,EUR/USD 有一波剧烈波动,这就是典型的黑天鹅事件。
最后看收益率分布:
# 计算日收益率
data_clean['Return'] = data_clean['Close'].pct_change()
# 画直方图
data_clean['Return'].hist(bins=50, figsize=(10, 6))
plt.title('EUR/USD 日收益率分布')
plt.xlabel('收益率')
plt.ylabel('频次')
plt.show()
收益率分布如果接近正态分布,那说明市场比较正常。如果出现厚尾(极端值多),那就要小心了——这往往是风险事件的前兆。
3.6 知识体系总览
下面这张图,是我自己梳理的本章知识结构。你可以把它当作一个路线图,方便回顾。
3.7 多货币对同时获取
实际项目中,我们往往需要多个货币对。比如做套利策略,可能要同时看 EUR/USD、GBP/USD、USD/JPY。
yfinance 支持一次性下载多个代码:
# 定义多个货币对
tickers = ["EURUSD=X", "GBPUSD=X", "USDJPY=X"]
# 下载数据
multi_data = yf.download(tickers, start="2020-01-01", end="2024-12-31")
# 提取收盘价
close_prices = multi_data['Close']
print(close_prices.head())
这样拿到的数据,每一列就是一个货币对的收盘价。方便做相关性分析。
小技巧: 如果你发现某个货币对的数据经常缺失,可以试试用 auto_adjust=True 参数。它会自动调整价格,有时候能解决一些数据对齐问题。
3.8 数据保存:别每次都重新下载
yfinance 下载数据虽然快,但每次跑脚本都重新下载,既浪费时间,又可能触发 Yahoo 的反爬机制。
我一般会把数据存成 CSV 文件,下次直接读取:
# 保存到 CSV
data_clean.to_csv('eur_usd_data.csv')
# 下次读取
data_loaded = pd.read_csv('eur_usd_data.csv', index_col=0, parse_dates=True)
这样既快又稳。而且 CSV 文件方便分享,团队里其他人也能直接用。
3.9 常见问题与避坑
做数据获取这么多年,踩过的坑不少。挑几个典型的说说:
- 代码失效: Yahoo Finance 偶尔会调整接口。如果发现
yf.download报错,先升级 yfinance 试试:pip install --upgrade yfinance - 时区问题: Yahoo 返回的时间是 UTC 时区。如果你在国内,记得转换成北京时间,否则日期对不上。
- 数据延迟: Yahoo 的数据不是实时的,有 15-20 分钟延迟。做回测没问题,做高频交易就别想了。
重要提醒: 如果你发现某一天的数据突然变成 0 或者 NaN,别慌。先检查那天是不是节假日。外汇市场在圣诞节、元旦等节日是休市的。
好了,数据获取和清洗这部分就聊到这儿。记住一句话:数据质量决定模型上限。花 80% 的时间在数据上,一点都不亏。