欢迎加入专注于财经数据与量化投研的【数据科学实战】知识星球!在这里,您将获取持续更新的《财经数据宝典》和《量化投研宝典》,这两部宝典相辅相成,为您在量化投研道路上提供明确指引。 《量化投研宝典》精选了业内持续维护且实用性强的开源工具(Backtrader、Qlib、VeighNa等),配合详细教程与代码示例,帮助您快速构建量化策略;《财经数据宝典》则汇集了多年财经数据维护经验,全面介绍从 AKShare、Tushare 到 Wind、iFind 等国内外数据源,并附有丰富的使用技巧。 无论您是量化投资新手还是经验丰富的研究者,星球社区都能帮您少走弯路,事半功倍,共同探索数据驱动的投资世界!
引言
在真实的量化交易世界中,管理多个资产的投资组合远比交易单一品种更常见。无论是为了分散风险、捕捉跨资产信号,还是实施特定的资本配置策略,多资产组合管理都是量化交易的核心。今天,我们将深入探讨如何使用 Python 的 Backtrader 框架进行多资产组合回测,从数据准备到综合分析,一步步带你掌握这项关键技能。
为什么组合回测如此重要
传统的回测往往只关注单一品种的策略表现,虽然这对初期开发很有用,但它忽略了同时管理多个头寸带来的复杂性。组合级别的回测框架能让你:
- 测试资本配置和风险管理:实施和评估不同资产间的资金分配规则
- 监控组合风险指标和权益曲线:分析整个组合的最大回撤、夏普比率等指标
-
评估跨资产相关性:了解不同资产同向或反向运动时策略的表现
第 1 步:准备和添加多个数据源
要回测多资产策略,首先需要获取每个资产的数据并添加到 Cerebro 引擎中。我们使用 yfinance 库来获取数据:
import backtrader as bt
import yfinance as yf
import pandas as pd
# 定义股票代码和日期范围
symbols = ['AAPL', 'MSFT', 'GOOG']
start_date = '2020-01-01'
end_date = '2025-01-01'
# 下载并处理所有股票数据
data_frames = {}
for symbol in symbols:
# auto_adjust=False 保留原始 OHLCV 数据
df = yf.download(symbol, start=start_date, end=end_date, auto_adjust=False)
# 扁平化多级列索引
df.columns = df.columns.droplevel(level=1)
df.index.name = 'datetime'
data_frames[symbol] = df
# 初始化 Cerebro 引擎
cerebro = bt.Cerebro()
cerebro.broker.setcash(100000.0) # 设置初始资金
# 为每个数据源添加唯一名称
for symbol, df in data_frames.items():
data = bt.feeds.PandasData(dataname=df)
cerebro.adddata(data, name=symbol)
每个资产都用唯一的名称添加,这对于在策略逻辑中引用数据至关重要。
第 2 步:在策略中访问数据源
加载多个数据源后,策略必须能够访问和区分它们:
class MultiAssetStrategy(bt.Strategy):
def __init__(self):
# 通过名称访问每个数据源
self.aapl_data = self.getdatabyname('AAPL')
self.msft_data = self.getdatabyname('MSFT')
self.goog_data = self.getdatabyname('GOOG')
# 为每个资产创建指标
self.aapl_sma = bt.indicators.SMA(self.aapl_data.close, period=20)
self.msft_rsi = bt.indicators.RSI(self.msft_data.close, period=14)
self.goog_ema = bt.indicators.EMA(self.goog_data.close, period=50)
# self.datas 包含所有数据源,可用于动态逻辑
print(f"加载的数据源数量:{len(self.datas)}")
第 3 步:编写多资产策略逻辑
个性化逻辑
在 next()
方法中,可以为每个资产应用不同的策略逻辑:
def next(self):
# AAPL 的交易逻辑
if not self.getposition(self.aapl_data):
if self.aapl_data.close[0] > self.aapl_sma[0]:
self.buy(data=self.aapl_data) # 指定数据源
elif self.aapl_data.close[0] < self.aapl_sma[0]:
self.close(data=self.aapl_data)
# MSFT 的交易逻辑
if not self.getposition(self.msft_data):
if self.msft_rsi[0] 30: # RSI 超卖
self.buy(data=self.msft_data)
elif self.msft_rsi[0] > 70: # RSI 超买
self.close(data=self.msft_data)
动态逻辑(高级用法)
对于应用相同规则到所有资产的策略,循环遍历 self.datas
更简洁:
class DynamicMultiAssetStrategy(bt.Strategy):
params = (('sma_period', 20),) # 策略参数
def __init__(self):
# 为每个数据源创建 SMA 指标
self.smas = {d._name: bt.indicators.SMA(d.close, period=self.p.sma_period)
for d in self.datas}
def next(self):
for data in self.datas:
position = self.getposition(data)
sma = self.smas[data._name]
if not position:
if data.close[0] > sma[0]: # 价格突破均线
self.buy(data=data)
else:
if data.close[0] < sma[0]: # 价格跌破均线
self.close(data=data)
第 4 步:追踪组合级别的表现
Backtrader 的经纪人(broker)模拟了跨所有数据源的统一组合,管理现金、权益价值和所有资产的持仓:
# 添加标准分析器和交易分析器
cerebro.addanalyzer(bt.analyzers.SharpeRatio, _name='sharpe')
cerebro.addanalyzer(bt.analyzers.DrawDown, _name='drawdown')
cerebro.addanalyzer(bt.analyzers.TradeAnalyzer, _name='trades')
# 运行回测并获取结果
results = cerebro.run()
# 访问组合级别的结果
sharpe_ratio = results[0].analyzers.sharpe.get_analysis()['sharperatio']
max_drawdown = results[0].analyzers.drawdown.get_analysis()['max']['drawdown']
trade_metrics = results[0].analyzers.trades.get_analysis()
print(f"组合夏普比率:{sharpe_ratio:.2f}")
print(f"组合最大回撤:{max_drawdown:.2f}%")
第 5 步:实现移动止损
移动止损是风险管理的重要组成部分。Backtrader 让你能够轻松地为多资产策略添加移动止损:
class TrailingStopStrategy(bt.Strategy):
def next(self):
# 简单示例:买入并添加 5% 移动止损
for data in self.datas:
if not self.getposition(data):
self.buy(data=data, exectype=bt.Order.Market)
# 为新开仓位添加移动止损
self.sell(data=data, exectype=bt.Order.StopTrail,
trailpercent=0.05)
第 6 步:可视化结果
使用 cerebro.plot()
函数生成综合可视化报告:
# 绘制结果,显示每个资产的指标和交易
cerebro.plot(style='candlestick', barup='green', bardown='red')
实施注意事项
- 数据同步:Backtrader 按时间戳对齐所有数据源。如果某个资产在特定日期缺少数据,
next()
方法将不会执行,除非所有数据源都对齐 - 仓位大小管理:使用
bt.sizers.PercentSizer
等仓位管理器时,会按总组合权益的百分比分配资金 - 佣金和滑点:相同的经纪人模型适用于所有资产,除非使用
cerebro.broker.setcommission
为每个品种配置特定佣金
完整示例
下面是一个完整的多资产组合回测示例:
import backtrader as bt
import yfinance as yf
import pandas as pd
class PortfolioStrategy(bt.Strategy):
params = (
('sma_period', 20),
('rsi_period', 14),
('rsi_lower', 30),
('rsi_upper', 70),
)
def __init__(self):
self.indicators = {}
# 为每个数据源创建指标
for d in self.datas:
self.indicators[d._name] = {
'sma': bt.indicators.SMA(d.close, period=self.p.sma_period),
'rsi': bt.indicators.RSI(d.close, period=self.p.rsi_period)
}
def next(self):
for data in self.datas:
pos = self.getposition(data)
indicators = self.indicators[data._name]
if not pos:
# 入场条件:价格突破 SMA 且 RSI 不在超买区
if (data.close[0] > indicators['sma'][0] and
indicators['rsi'][0] < self.p.rsi_upper):
size = self.broker.get_cash() * 0.3 / data.close[0] # 每个品种分配 30% 资金
self.buy(data=data, size=int(size))
else:
# 出场条件:价格跌破 SMA 或 RSI 超买
if (data.close[0] < indicators['sma'][0] or
indicators['rsi'][0] > self.p.rsi_upper):
self.close(data=data)
# 主程序
if
__name__ == '__main__':
# 准备数据
symbols = ['AAPL', 'MSFT', 'GOOG']
cerebro = bt.Cerebro()
cerebro.broker.setcash(100000.0)
for symbol in symbols:
df = yf.download(symbol, start='2020-01-01', end='2025-01-01', auto_adjust=False)
df.columns = df.columns.droplevel(level=1)
data = bt.feeds.PandasData(dataname=df)
cerebro.adddata(data, name=symbol)
# 添加策略和分析器
cerebro.addstrategy(PortfolioStrategy)
cerebro.addanalyzer(bt.analyzers.SharpeRatio, _name='sharpe')
cerebro.addanalyzer(bt.analyzers.Returns, _name='returns')
# 运行回测
results = cerebro.run()
# 输出结果
print(f"最终组合价值:{cerebro.broker.getvalue():.2f}")
print(f"夏普比率:{results[0].analyzers.sharpe.get_analysis()['sharperatio']:.2f}")
总结
组合级别的回测是量化策略评估不可或缺的一环。通过使用 Backtrader 模拟多资产策略,你可以严格测试整体交易方法的有效性。从使用 yfinance 正确管理数据源,到实施动态逻辑和纳入移动止损等风险管理工具,你能够深入了解分散投资的好处、资本配置的效率以及交易模型的整体稳健性。这种方法让你的研究从单一股票理论转向更实用的现实应用,为真实交易做好充分准备。
掌握多资产组合回测,不仅能让你的策略更接近实战,还能帮助你建立更稳健、更专业的量化交易系统。现在就开始尝试吧,让你的 Python 量化之路更进一步!
参考文章
加入专注于财经数据与量化投研的知识星球【数据科学实战】,获取完整研究解析、详细回测框架代码实现和完整策略逻辑实操指南。财经数据与量化投研知识社区
核心权益如下:
- 赠送《财经数据宝典》完整文档,汇集多年财经数据维护经验
- 赠送《量化投研宝典》完整文档,汇集多年量化投研领域经验
- 赠送《PyBroker-入门及实战》视频课程,手把手学习量化策略开发
星球已有丰富内容积累,包括量化投研论文、财经高频数据、 PyBroker 视频教程、定期直播、数据分享和答疑解难。适合对量化投研和财经数据分析有兴趣的学习者及从业者。欢迎加入我们!