3. 数据获取基础:从 Yahoo Finance 获取历史行情、从 CSV 文件读取数据、API 接口调用规范

数据获取是量化回测的起点。原始数据的质量直接决定回测结果的可靠性。本章聚焦三种最常用的数据获取方式:Yahoo Finance 在线接口、本地 CSV 文件读取以及通用 API 调用规范。掌握这些基础,你就能为后续清洗与回测建立稳定的数据管道。

💡 核心原则:无论使用哪种数据源,始终在获取阶段完成 字段对齐(统一列名)、类型转换(日期、数值)和 缺失标记(NaN 处理),避免将脏数据带入回测逻辑。

3.1 从 Yahoo Finance 获取历史行情

Yahoo Finance 提供免费、稳定的历史日线数据,是回测入门最常用的数据源。Python 中通过 yfinance 库即可快速获取。

3.1.1 安装与基本调用

# 安装(如未安装)
# pip install yfinance

import yfinance as yf

# 获取单只股票历史行情
ticker = "AAPL"
data = yf.download(ticker, start="2023-01-01", end="2023-12-31")
print(data.head())

3.1.2 返回数据结构

yf.download() 返回 pandas.DataFrame,包含以下标准列:

列名含义数据类型常见问题
Open开盘价float64除权后可能为 0 或负值
High最高价float64需检查是否 ≥ Open 和 Close
Low最低价float64需检查是否 ≤ Open 和 Close
Close收盘价(未复权)float64回测前通常需复权
Volume成交量int64可能为 0(停牌日)
Adj Close复权收盘价float64Yahoo 自动调整,推荐用于回测
⚠️ 常见陷阱:Yahoo Finance 数据在 拆股、分红 时,Open/High/Low/Close 不会自动调整,只有 Adj Close 是复权后的。如果直接用 Close 计算收益率,会导致严重偏差。建议始终使用 Adj Close 进行策略计算。

3.1.3 批量获取与异常处理

tickers = ["AAPL", "MSFT", "GOOGL"]
data = yf.download(tickers, start="2023-01-01", end="2023-12-31")

# 处理缺失数据(如某只股票某日停牌)
data = data.dropna(how='any')  # 删除任意列为 NaN 的行
print(data.shape)
Yahoo Finance 数据获取与清洗流程 Yahoo Finance 数据获取与清洗流程 输入参数 ticker, start, end yf.download() HTTP 请求 + 解析 原始 DataFrame 含 7 列标准字段 列名统一 小写 + 下划线 类型转换 日期、数值 缺失处理 dropna / fillna 复权检查 使用 Adj Close 清洗后 DataFrame 可直接用于回测 💡 建议:获取后立即清洗 避免脏数据扩散

3.2 从 CSV 文件读取数据

本地 CSV 文件是离线回测、历史数据备份、机构数据交换的通用格式。读取时需注意编码、分隔符、日期解析等细节。

3.2.1 标准读取方式

import pandas as pd

# 标准读取
df = pd.read_csv("historical_data.csv", 
                 parse_dates=["Date"], 
                 index_col="Date",
                 encoding="utf-8")

# 查看基本信息
print(df.info())
print(df.head())

3.2.2 常见 CSV 格式问题与解决方案

问题类型表现解决方案
编码错误UnicodeDecodeError,中文乱码指定 encoding='gbk' 或 'utf-8-sig'
分隔符不一致数据未正确分列使用 sep=';' 或 sep='\t' 匹配实际分隔符
日期格式不统一2023/01/01 与 2023-01-01 混用使用 parse_dates 参数自动推断
表头缺失第一行即为数据设置 header=None,手动指定列名
空值标记多样空字符串、"NA"、"null"、"None"使用 na_values=['', 'NA', 'null', 'None']
千位分隔符"1,234.56" 无法直接转为 float设置 thousands=','

3.2.3 读取后字段对齐

# 统一列名为小写 + 下划线
df.columns = [col.lower().replace(' ', '_') for col in df.columns]

# 确保包含必要字段
required_cols = ['open', 'high', 'low', 'close', 'volume']
for col in required_cols:
    if col not in df.columns:
        raise ValueError(f"缺少必要字段: {col}")

# 类型强制转换
df['close'] = pd.to_numeric(df['close'], errors='coerce')
📌 最佳实践:建议将 CSV 读取封装为函数,统一处理编码、列名映射、类型转换,形成可复用的数据加载模块。后续章节的清洗流程将基于此模块展开。

3.3 API 接口调用规范

除 Yahoo Finance 外,量化交易常对接专业数据服务商(如 Wind、Bloomberg、Tushare、AKShare)。统一的 API 调用规范能降低维护成本,提高代码可读性。

3.3.1 通用 API 调用模板

import requests
import time
from typing import Dict, Optional

def fetch_market_data(symbol: str, 
                      start_date: str, 
                      end_date: str,
                      api_key: str,
                      base_url: str = "https://api.example.com") -> Optional[Dict]:
    """
    通用市场数据 API 调用模板
    
    参数:
        symbol: 股票代码
        start_date: 起始日期 (YYYY-MM-DD)
        end_date: 结束日期 (YYYY-MM-DD)
        api_key: API 密钥
        base_url: API 基础地址
    
    返回:
        解析后的 JSON 数据,失败返回 None
    """
    headers = {
        "Authorization": f"Bearer {api_key}",
        "User-Agent": "QuantBacktest/1.0"
    }
    params = {
        "symbol": symbol,
        "start": start_date,
        "end": end_date,
        "format": "json"
    }
    
    try:
        response = requests.get(base_url + "/history", 
                                headers=headers, 
                                params=params,
                                timeout=10)
        response.raise_for_status()  # 触发 HTTP 错误
        return response.json()
    except requests.exceptions.RequestException as e:
        print(f"API 请求失败: {e}")
        return None
    finally:
        time.sleep(0.5)  # 限速,避免被封

3.3.2 API 调用规范清单

  • 认证方式:优先使用 API Key 放在 Header 中,避免 URL 明文传输。
  • 限速与重试:每次请求后至少等待 0.5 秒;遇到 429 状态码时指数退避重试。
  • 错误处理:区分网络错误(超时、断连)与业务错误(参数非法、无权限),分别记录日志。
  • 数据缓存:对同一参数组合的请求结果缓存到本地 CSV/Parquet,减少重复调用。
  • 字段映射:将 API 返回的字段名(如 trade_date)统一映射为内部标准名(如 date)。
API 调用规范架构 API 调用规范架构 调用层 参数组装 认证 Header 限速控制 网络层 HTTP 请求 超时设置 重试机制 处理层 JSON 解析 字段映射 本地缓存 💡 规范目标:调用层负责参数与限速,网络层负责可靠传输,处理层负责数据标准化

3.4 三种数据获取方式对比

特性Yahoo Finance (yfinance)CSV 文件读取通用 API 调用
数据实时性延迟 15-20 分钟取决于文件更新时间通常实时或 T+1
数据范围全球主要交易所仅限文件包含的数据取决于服务商覆盖
使用成本免费免费(本地存储)通常按量收费
稳定性中等(可能被限流)高(本地文件)高(商业 SLA)
清洗复杂度低(字段标准)中(需处理格式差异)中高(需字段映射)
适用场景快速原型、个人研究离线回测、数据备份生产环境、机构级回测
📌 本章小结:数据获取是回测管道的入口。Yahoo Finance 适合快速获取标准行情,CSV 读取适合离线与批量处理,通用 API 规范则保障生产环境的可靠性。无论选择哪种方式,获取后立即进行字段对齐、类型转换、缺失标记是避免脏数据扩散的关键习惯。下一章将深入讲解数据清洗的核心操作——缺失值与异常值处理。