天天看点

backtrader:终于可以集成pyfolio了

点此获取扫地僧backtrader技术教程

===============

之前,我写了一篇文章“backtrader高级专题:策略绩效评价:用不了pyfolio?还有quantstats”,提到backtrader现在不能直接集成pyfolio,但是可以集成quantstats,进行策略绩效展示。

最近,我再次研究了pyfolio,发现现在已经可以集成到backtrader了。至少我自己测试通过了。注意,pyfolio只能用于notebook里,而quantstats可用于notebook和普通.py文件里,大家各取所需吧。

下面介绍如何在backtrader里使用pyfolio。

1 安装pyfolio

必须使用如下命令安装pyfolio,这样安装的是最新版:

pip install git+https://github.com/quantopian/pyfolio

不能使用pip install pyfolio来安装。很多人集成不了pyfolio,就是因为安装方式不对。

2 在backtrader中使用pyfolio

样本代码test.ipynb如下

from datetime import datetime
import backtrader as bt
# 导入pyfolio 包
import pyfolio as pf


# 创建策略类
class SmaCross(bt.Strategy):
    # 定义参数
    params = dict(period=5)  # 移动平均期数

    # 日志函数
    def log(self, txt, dt=None):
        '''日志函数'''
        dt = dt or self.datas[0].datetime.date(0)
        print('%s, %s' % (dt.isoformat(), txt))

    def notify_order(self, order):
        if order.status in [order.Submitted, order.Accepted]:
            # 订单状态 submitted/accepted,无动作
            return
        # 订单完成
        if order.status in [order.Completed]:
            if order.isbuy():
                self.log('买单执行, %.2f' % order.executed.price)
            elif order.issell():
                self.log('卖单执行, %.2f' % order.executed.price)
        elif order.status in [order.Canceled, order.Margin, order.Rejected]:
            self.log('订单 Canceled/Margin/Rejected')

    # 记录交易收益情况(可省略,默认不输出结果)
    def notify_trade(self, trade):
        if trade.isclosed:
            print('毛收益 %0.2f, 扣佣后收益 % 0.2f, 佣金 %.2f' %
                  (trade.pnl, trade.pnlcomm, trade.commission))

    def __init__(self):
        # 移动平均线指标
        self.move_average = bt.ind.MovingAverageSimple(
            self.data, period=self.params.period)
        # 交叉信号指标
        self.crossover = bt.ind.CrossOver(self.data, self.move_average)        

    def next(self):
        if not self.position:  # 还没有仓位
            # 当日收盘价上穿5日均线,创建买单,买入100股
            if self.crossover > 0:
                self.log('创建买单')
                self.buy(size=100)
        # 有仓位,并且当日收盘价下破5日均线,创建卖单,卖出100股
        elif self.crossover < 0:
            self.log('创建卖单')
            self.sell(size=100)


##########################
# 主程序开始
#########################

# 创建大脑引擎对象
cerebro = bt.Cerebro()


# 数据文件路径
datapath = './600000.csv'

# 创建行情数据对象,加载数据
data = bt.feeds.GenericCSVData(
    dataname=datapath,
    datetime=2,  # 日期行所在列
    open=3,  # 开盘价所在列
    high=4,  # 最高价所在列
    low=5,  # 最低价所在列
    close=6,  # 收盘价价所在列
    volume=10,  # 成交量所在列
    openinterest=-1,  # 无未平仓量列
    dtformat=('%Y%m%d'),  # 日期格式
    fromdate=datetime(2019, 1, 1),  # 起始日
    todate=datetime(2020, 7, 8))  # 结束日

cerebro.adddata(data)  # 将行情数据对象注入引擎
cerebro.addstrategy(SmaCross)  # 将策略注入引擎

cerebro.broker.setcash(10000.0)  # 设置初始资金

# 加入pyfolio分析者
cerebro.addanalyzer(bt.analyzers.PyFolio, _name='pyfolio')

results=cerebro.run()  # 运行
strat = results[0]
pyfoliozer = strat.analyzers.getbyname('pyfolio')
returns, positions, transactions, gross_lev = pyfoliozer.get_pf_items()
pf.create_full_tear_sheet(returns)
           

这里pf.create_full_tear_sheet(returns)中pyfolio需要的收益率returns是日收益率。

如果backtrader原始数据不是日线数据,我估计returns, positions, transactions, gross_lev = pyfoliozer.get_pf_items()中,backtrader返回的returns应该是已经转换成日收益率了,读者可以验证一下告诉我哈。