3. 数据源与数据加载:本地CSV数据加载、在线数据API(Yahoo/Quandl)、数据清洗与预处理

在量化回测中,数据是策略的“燃料”。Backtrader 提供了灵活的数据加载机制,支持从本地文件、在线 API 以及自定义数据源获取历史行情。本章将系统讲解三种主流数据加载方式,并重点介绍数据清洗与预处理的最佳实践,确保回测结果的准确性与可靠性。

3.1 数据源概览与选择标准

不同的数据源在覆盖范围、更新频率、历史深度和成本上存在显著差异。选择合适的数据源是回测工作的第一步。

数据源类型 典型代表 优点 缺点 适用场景
本地 CSV 自备历史数据文件 离线可用、速度快、数据完全可控 需要自行维护更新、历史深度有限 策略开发、离线回测、数据敏感场景
在线 API Yahoo Finance, Quandl 实时更新、历史数据丰富、无需本地存储 依赖网络、有请求频率限制、可能停服 快速原型验证、实时策略、研究分析
数据库/专业终端 MySQL, Wind, Bloomberg 高可靠性、数据质量高、支持高频 成本高、配置复杂、学习曲线陡 机构级回测、生产环境
建议: 初学者优先使用本地 CSV 进行策略开发,待逻辑验证通过后,再切换到在线 API 或专业数据源进行扩展测试。

3.2 本地 CSV 数据加载

CSV 是最通用的数据交换格式。Backtrader 内置了 GenericCSVData 类,可以快速加载标准格式的 CSV 文件。

3.2.1 标准 CSV 格式要求

Backtrader 默认期望 CSV 文件包含以下列(按顺序):

  • Date:日期,格式如 YYYY-MM-DD
  • Open:开盘价
  • High:最高价
  • Low:最低价
  • Close:收盘价
  • Volume:成交量
  • OpenInterest:持仓量(可选,可设为 0)

3.2.2 加载 CSV 的核心代码

import backtrader as bt

# 创建 Cerebro 引擎
cerebro = bt.Cerebro()

# 加载本地 CSV 数据
data = bt.feeds.GenericCSVData(
    dataname='./data/AAPL.csv',          # 文件路径
    dtformat='%Y-%m-%d',                 # 日期格式
    timeframe=bt.TimeFrame.Days,         # 时间周期
    compression=1,                       # 压缩倍数
    fromdate=datetime(2020, 1, 1),       # 起始日期
    todate=datetime(2023, 12, 31)        # 结束日期
)

# 将数据添加到引擎
cerebro.adddata(data)

3.2.3 自定义列映射

如果 CSV 文件的列名或顺序与默认不同,可以通过参数进行映射:

data = bt.feeds.GenericCSVData(
    dataname='./data/my_data.csv',
    datetime=0,      # 日期列索引
    open=1,          # 开盘价列索引
    high=2,          # 最高价列索引
    low=3,           # 最低价列索引
    close=4,         # 收盘价列索引
    volume=5,        # 成交量列索引
    openinterest=-1  # 无持仓量列
)
注意: 如果 CSV 文件包含表头行,Backtrader 会自动跳过。若文件无表头,需设置 header=None 参数。

3.3 在线数据 API 加载

Backtrader 通过扩展数据源支持在线 API。Yahoo Finance 和 Quandl 是最常用的两个免费数据源。

3.3.1 Yahoo Finance 数据加载

使用 YahooFinanceData 需要安装 yfinance 库:

pip install yfinance

加载示例:

import backtrader as bt

cerebro = bt.Cerebro()

# 从 Yahoo Finance 加载数据
data = bt.feeds.YahooFinanceData(
    dataname='AAPL',                     # 股票代码
    fromdate=datetime(2020, 1, 1),
    todate=datetime(2023, 12, 31),
    buffered=True                        # 启用缓冲,提高性能
)

cerebro.adddata(data)

3.3.2 Quandl 数据加载

Quandl 提供更专业的数据集,需要 API Key:

data = bt.feeds.Quandl(
    dataname='WIKI/AAPL',                # Quandl 代码
    fromdate=datetime(2020, 1, 1),
    todate=datetime(2023, 12, 31),
    apikey='YOUR_API_KEY'                # 替换为实际 Key
)
性能提示: 在线 API 受网络延迟和请求频率限制影响。建议在回测前将数据缓存到本地 CSV,避免重复请求。

3.4 数据清洗与预处理

原始数据通常包含缺失值、异常值、除权除息缺口等问题,必须进行清洗才能用于回测。

3.4.1 常见数据问题与处理方法

问题类型 表现 处理方法 Backtrader 实现
缺失值 NaN 或空行 前向填充、插值、删除 data.resample() 或预处理
除权除息缺口 价格跳空 使用复权数据 加载前使用复权 CSV
异常价格 价格超出合理范围 设置上下限、剔除 自定义过滤器
非交易日数据 周末/节假日有数据 过滤非交易日 bt.filters.SessionFilter

3.4.2 使用 Pandas 进行预处理

推荐在加载到 Backtrader 之前,使用 Pandas 完成数据清洗:

import pandas as pd

# 读取原始 CSV
df = pd.read_csv('raw_data.csv', parse_dates=['Date'], index_col='Date')

# 1. 处理缺失值:前向填充
df.fillna(method='ffill', inplace=True)

# 2. 去除异常值(例如:价格低于 0)
df = df[df['Close'] > 0]

# 3. 确保时间序列连续
df = df.asfreq('B')  # 转换为工作日频率

# 4. 保存清洗后的数据
df.to_csv('cleaned_data.csv')

3.4.3 Backtrader 内置过滤器

Backtrader 提供了一些内置过滤器,可以在数据加载时直接应用:

# 使用 SessionFilter 过滤非交易日
data.addfilter(bt.filters.SessionFilter)

# 使用 Heikin-Ashi 过滤器(平滑价格)
data.addfilter(bt.filters.HeikinAshi)

3.5 数据加载流程架构

下图展示了从原始数据到回测引擎的完整数据流:

数据加载与预处理流程架构 本地 CSV 文件 离线、可控、速度快 在线 API Yahoo / Quandl 数据库 / 专业终端 MySQL / Wind 数据清洗与预处理 缺失值处理 | 异常值过滤 | 复权调整 | 频率对齐 Pandas 预处理 / Backtrader 内置过滤器 Backtrader 数据加载 GenericCSVData / YahooFinanceData / Quandl Cerebro 回测引擎 数据流方向

3.6 多数据源混合加载

实际回测中常需要同时使用多个数据源。Backtrader 支持在同一 Cerebro 引擎中混合加载不同来源的数据:

# 混合加载示例
cerebro = bt.Cerebro()

# 从 CSV 加载股票 A
data_stock = bt.feeds.GenericCSVData(dataname='stock_A.csv')
cerebro.adddata(data_stock)

# 从 Yahoo 加载指数
data_index = bt.feeds.YahooFinanceData(dataname='^GSPC')
cerebro.adddata(data_index)

# 从 Quandl 加载期货
data_futures = bt.feeds.Quandl(dataname='CHRIS/CME_CL1')
cerebro.adddata(data_futures)
最佳实践: 将不同数据源的数据统一清洗为相同格式(列名、频率、时区),再加载到 Backtrader 中,可以大幅减少后续策略开发中的兼容性问题。

3.7 数据质量检查清单

在开始回测前,建议逐项检查数据质量:

  1. 时间范围:确认数据覆盖了策略所需的完整时间段
  2. 缺失比例:缺失值占比不应超过 5%,否则需考虑数据源替代
  3. 价格合理性:检查是否存在负价格、极端跳空等异常
  4. 成交量验证:成交量不应长期为 0(停牌期间除外)
  5. 复权一致性:确保所有品种使用相同的复权方式(前复权/后复权)
  6. 时间戳对齐:多品种数据的时间戳必须对齐到同一时区

通过系统化的数据加载与清洗流程,可以确保回测结果建立在可靠的数据基础之上,避免“垃圾进,垃圾出”的陷阱。