Py学习  »  Python

Python 量化交易:用 Backtrader 轻松实现多资产组合回测

数据科学实战 • 3 周前 • 111 次点击  

欢迎加入专注于财经数据与量化投研的【数据科学实战】知识星球!在这里,您将获取持续更新的《财经数据宝典》和《量化投研宝典》,这两部宝典相辅相成,为您在量化投研道路上提供明确指引。 《量化投研宝典》精选了业内持续维护且实用性强的开源工具(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'][0and 
                    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'][0or 
                    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 量化之路更进一步!

参考文章

加入专注于财经数据与量化投研的知识星球【数据科学实战】,获取完整研究解析、详细回测框架代码实现和完整策略逻辑实操指南。

财经数据与量化投研知识社区

核心权益如下:

  1. 赠送《财经数据宝典》完整文档,汇集多年财经数据维护经验
  2. 赠送《量化投研宝典》完整文档,汇集多年量化投研领域经验
  3. 赠送《PyBroker-入门及实战》视频课程,手把手学习量化策略开发
  4. 每日分享高质量量化投研文章、代码和相关资料
  5. 定期更新高频财经数据
  6. 参与年度不少于 10 次专属直播与录播课程
  7. 与核心开发者直接交流,解决实际问题
  8. 获取专业微信群交流机会和课程折扣

星球已有丰富内容积累,包括量化投研论文、财经高频数据、 PyBroker 视频教程、定期直播、数据分享和答疑解难。适合对量化投研和财经数据分析有兴趣的学习者及从业者。欢迎加入我们!

好文推荐

1. 用 Python 打造股票预测系统:Transformer 模型教程(一)

2. 用 Python 打造股票预测系统:Transformer 模型教程(二)

3. 用 Python 打造股票预测系统:Transformer 模型教程(三)

4. 用 Python 打造股票预测系统:Transformer 模型教程(完结)

5. 揭秘隐马尔可夫模型:因子投资的制胜武器

6. YOLO 也能预测股市涨跌?计算机视觉在股票市场预测中的应用

7. 金融 AI 助手:FinGPT 让你轻松掌握市场分析

8. 量化交易秘籍:为什么专业交易员都在用对数收益率?

9. Python 量化投资利器:Ridge、Lasso 和 Elastic Net 回归详解

10. 掌握金融波动率模型:完整 Python 实现指南

好书推荐

《Python编程:从入门到实践(第3版)》是一本广受欢迎的 Python 入门经典教材,由经验丰富的程序员 Eric Matthes 编写。该书采用循序渐进的教学方式,从基础语法讲解到实战项目开发,内容编排合理,实例丰富,语言通俗易懂。全书配有大量练习题和完整项目实战,包括数据可视化、网络爬虫、Web 应用开发等,让读者在实践中掌握编程技巧。第3版还增加了 f-string、海龟绘图等最新的 Python 特性内容。这本书不仅适合零基础读者入门学习,也非常适合想系统掌握 Python 的编程爱好者以及数据分析、人工智能等领域的学习者。它不仅教授编程知识,更注重培养读者的编程思维,是一本非常值得投资的 Python 学习指南。


Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/185348
 
111 次点击