第三章:金融数据获取——数据源选择、清洗与预处理

做量化交易,第一道坎就是数据。

我见过太多人,策略写得天花乱坠,结果数据源选错了,回测跑出来全是幻觉。说白了,数据质量决定了策略的生死。今天咱们就聊聊,怎么搞定金融数据获取这件事。

3.1 数据源选择:三个主流方案

我个人习惯把数据源分成三类:免费API、付费API、本地文件。每个都有它的适用场景,别盲目追求高大上。

3.1.1 Yahoo Finance

这是入门首选。免费、易用、覆盖全球市场。我在项目中经常用它做快速原型验证。

优点: 免费、无需API Key、支持历史数据和实时数据

缺点: 数据偶尔延迟、部分市场覆盖不全、有请求频率限制

# 使用 yfinance 库获取数据
import yfinance as yf

# 获取苹果公司股票数据
aapl = yf.download('AAPL', start='2023-01-01', end='2023-12-31')
print(aapl.head())

我的经验: Yahoo Finance 适合做日频数据。如果你需要分钟级数据,它就不太靠谱了。我曾经用它做日内策略回测,结果发现数据有大量缺失,后来果断换了方案。

3.1.2 Alpha Vantage

这个API比Yahoo Finance更专业一些。它提供20多种技术指标,还有外汇、加密货币数据。

# Alpha Vantage 示例
import requests

API_KEY = 'your_api_key_here'
symbol = 'IBM'
url = f'https://www.alphavantage.co/query?function=TIME_SERIES_DAILY&symbol={symbol}&apikey={API_KEY}'
response = requests.get(url)
data = response.json()

注意: Alpha Vantage 免费版每分钟只能请求5次。我刚开始用的时候没注意,结果策略跑着跑着就报错了。建议加个请求间隔控制。

3.1.3 本地CSV文件

这是最稳妥的方式。数据在自己手里,想怎么处理都行。我一般会把从各个渠道获取的数据统一存成CSV格式,方便后续处理。

# 读取本地CSV
import pandas as pd

df = pd.read_csv('stock_data.csv', parse_dates=['Date'], index_col='Date')
print(df.info())

3.2 数据清洗与预处理

拿到原始数据后,千万别直接拿去跑策略。你想想看,数据里可能藏着各种坑:空值、异常值、格式错误……

3.2.1 数据格式统一

不同数据源的格式可能不一样。我习惯把所有数据统一成标准格式:日期作为索引,列名统一为Open、High、Low、Close、Volume。

# 统一数据格式
def standardize_data(df):
    df.columns = [col.capitalize() for col in df.columns]
    df.index = pd.to_datetime(df.index)
    return df.sort_index()

3.2.2 缺失值处理

缺失值是个大问题。我遇到过最夸张的情况,某只股票连续三天没有交易数据,结果策略直接崩了。

常用处理方法:

  • 向前填充: 用上一个有效值填充,适合非交易日的缺失
  • 向后填充: 用下一个有效值填充,适合数据延迟的情况
  • 插值法: 线性插值或多项式插值,适合短期缺失
  • 直接删除: 缺失比例小于5%时可以考虑
# 缺失值处理示例
# 向前填充
df.fillna(method='ffill', inplace=True)

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

# 检查缺失值
print(df.isnull().sum())

3.2.3 异常值检测

异常值比缺失值更隐蔽。我记得有一次回测收益特别高,结果发现是数据里混了一个价格异常点——某天股价突然涨了1000倍,显然是数据录入错误。

我的检测方法:

  • Z-score方法: 超过3个标准差视为异常
  • IQR方法: 低于Q1-1.5*IQR或高于Q3+1.5*IQR视为异常
  • 百分比变化法: 日收益率超过±20%需要警惕
# 异常值检测示例
import numpy as np

# 计算日收益率
df['Return'] = df['Close'].pct_change()

# 标记异常值(超过3个标准差)
mean_return = df['Return'].mean()
std_return = df['Return'].std()
df['Anomaly'] = np.abs(df['Return'] - mean_return) > 3 * std_return

# 查看异常值
print(df[df['Anomaly'] == True])

3.3 数据预处理流程

嗯,这里要注意。数据预处理不是一次性工作,而是个迭代过程。我一般按这个流程走:

  1. 数据加载: 从数据源读取原始数据
  2. 格式检查: 确认日期格式、列名、数据类型
  3. 缺失值处理: 根据缺失比例选择合适方法
  4. 异常值检测: 标记并处理异常点
  5. 数据对齐: 多只股票数据按日期对齐
  6. 数据保存: 清洗后的数据存为本地文件

避坑指南: 我曾经犯过一个错误——先做异常值处理再做缺失值填充。结果异常值被填充掩盖了,导致策略在真实交易中频繁出错。正确的顺序应该是:先检测异常值,再处理缺失值。

3.4 知识体系图

金融数据获取与处理知识体系 数据源选择 数据清洗 数据预处理 Yahoo Finance Alpha Vantage 本地CSV文件 缺失值处理 异常值检测 格式统一 数据对齐 标准化处理 数据保存 数据获取 → 清洗 → 预处理 → 存储 核心原则:数据质量决定策略上限 建议:建立数据版本管理,每次清洗都保留原始数据备份

3.5 实战建议

最后,分享几个我在实战中总结的经验:

  • 数据备份: 每次清洗前都保留原始数据副本。我吃过这个亏,清洗错了数据,想恢复都来不及。
  • 自动化脚本: 把数据获取和清洗流程写成脚本,每天定时运行。手动操作太容易出错了。
  • 数据验证: 清洗完成后,做个简单的统计验证。比如检查价格是否为正数、成交量是否合理。
  • 版本控制: 用Git管理数据清洗脚本,方便回溯和协作。

一个小技巧: 我习惯在数据清洗脚本里加个日志功能,记录每次清洗的改动。这样出了问题,能快速定位是哪个环节导致的。

数据获取和清洗,听起来枯燥,但这是量化交易的地基。地基不稳,楼盖得再高也是白搭。希望这些经验能帮你少走些弯路。

蓝海数据掘金营,专注资料整理