在做量化回测时,Backtrader 依然是目前最流行、生态最成熟的 Python 回测框架之一。但用过的人都知道,Backtrader 最大的痛点之一就是“喂数”(Data Feed)[1]。如果数据源的格式不规范、时间戳混乱或复权有问题,光是写数据清洗和格式转换的代码就能让人抓狂[2][3]。
本文将分享如何通过 quantdash-python-sdk 统一获取多市场(A股/港美股)的标准 K 线数据,并优雅地封装成 Backtrader 可直接读取的 PandasData 格式,快速跑通一个双均线策略[3][4]。
1. 为什么选择 QuantDash 作为 Backtrader 的数据源?
格式高度统一:无论是 A 股、美股还是港股,返回的 DataFrame 字段完全一致(date, open, high, low, close, volume 等),免去了针对不同市场写不同清洗脚本的麻烦[3][5]。
原生支持前/后复权:回测最忌讳使用未复权的价格计算技术指标。QuantDash 在服务端直接计算好前复权数据,客户端一行参数即可获取,避免了回测时的“未来函数”和价格跳空 Bug[3]。
2. 核心对接代码实现
我们首先定义一个符合 Backtrader 规范的自定义数据类,然后通过 QuantDash 抓取数据并加载。
import backtrader as bt import pandas as pd from quantdash import QuantDash # 1. 实例化 QuantDash 客户端 # 填入你自己的 API Key qd = QuantDash(api_key="your_quantdash_api_key") class QuantDashBacktraderData(bt.feeds.PandasData): """ 自定义 Backtrader PandasData 类,对接 QuantDash 返回的 DataFrame """ # 显式指出 QuantDash DataFrame 中的列名与 Backtrader 属性的对应关系 lines = ('openinterest',) params = ( ('datetime', 'date'), # 时间列 ('open', 'open'), # 开盘价 ('high', 'high'), # 最高价 ('low', 'low'), # 最低价 ('close', 'close'), # 收盘价 ('volume', 'volume'), # 成交量 ('openinterest', -1), # 如果无持仓量字段,传 -1 ) def get_bt_feed(symbol: str, start_date: str, end_date: str): """ 获取 QuantDash 数据并包装为 Backtrader 数据源 """ # 调用 SDK 获取前复权历史 K 线 df = qd.stock.get_kline( symbol=symbol, start_date=start_date, end_date=end_date, adjust="forward" # 使用前复权,保证回测指标真实性 ) # 确保时间列转化为 datetime 格式,并作为 DataFrame 的索引 df['date'] = pd.to_datetime(df['date']) df.set_index('date', inplace=True) df.sort_index(ascending=True, inplace=True) # 将标准 DataFrame 喂给自定义 Data 类 return QuantDashBacktraderData(dataname=df)3. 编写一个简单的双均线回测策略
下面我们把这个数据源塞进 Backtrader 的 Cerebro 引擎里,以腾讯控股(00700.HK)为例进行回测[3]。
class SmaCross(bt.Strategy): params = ( ('pfast', 10), # 快速均线周期 ('pslow', 30), # 慢速均线周期 ) def __init__(self): # 计算两条均线 self.fast_ma = bt.indicators.SimpleMovingAverage( self.data.close, period=self.p_pfast) self.slow_ma = bt.indicators.SimpleMovingAverage( self.data.close, period=self.p_pslow) # 产生金叉/死叉信号 self.crossover = bt.indicators.CrossOver(self.fast_ma, self.slow_ma) def next(self): # 如果当前无持仓,且发生金叉,买入 if not self.position: if self.crossover > 0: self.buy() # 如果有持仓,且发生死叉,清仓 elif self.crossover < 0: self.close() if __name__ == '__main__': # 初始化回测引擎 cerebro = bt.Cerebro() cerebro.addstrategy(SmaCross) # 获取 QuantDash 的港股数据并加载到引擎中 # 示例拉取 2025 年整年的日 K 线数据 data_feed = get_bt_feed( symbol="00700.HK", start_date="2025-01-01", end_date="2025-12-31" ) cerebro.adddata(data_feed) # 设置初始资金和佣金 cerebro.broker.setcash(100000.0) cerebro.broker.setcommission(commission=0.001) # 万分之十佣金 print(f'回测前初始资金: {cerebro.broker.getvalue():.2f}') cerebro.run() print(f'回测后最终资产: {cerebro.broker.getvalue():.2f}')4. 工程实践避坑提示
时区与日期格式:QuantDash 默认返回的标准 K 线时间戳格式能被 Pandas 极快地解析。在接入 Backtrader 时,请确保执行了 pd.to_datetime 并设为 Index,否则 Backtrader 在推进时间轴时会报错。
多市场兼容:如果你想回测美股(如 AAPL.US)或 A 股(如 600519.SH),上面的 get_bt_feed 函数一行代码都不需要修改,直接更换 symbol 参数即可,这就是多市场标准化数据接口带来的开发红利[3][6]。
相关链接:
QuantDash 官方:QuantDash
Python SDK 快速开始:快速开始 - QuantDash