量化投资之工具篇一:Backtrader从入门到精通(1)-手把手教你零基础实现一个策略案例

本文逐步讲解如何使用Backtrader进行量化投资,包括安装、基本操作、策略开发、参数传递及指标添加,最终实现策略执行和可视化。通过实例演示,读者将学会如何构建并优化自己的量化投资系统。
该文章已生成可运行项目,

量化投资是一个非常大的课题,从这边文章开始,我会从如下几个方面构建量化投资的这个框架:

1、工欲善其事,必先利其器。我们先学习一个量化投资回测利器-backtrader,通过这个工具,我们可以将量化策略在经过回测之后,付诸实用。

2、我们学习一些常用的以及大师们实用量化策略,了解它的原理,选择合适的标的资产,为己所用。

3、开发自己的策略。老实说,公开的策略使用的人众多,往往会失效,那么如果构造开发自己的策略显得尤其重要。这一块,我们会介绍投资、数据挖掘,预测等关键技术,及其如何应用在构建自己投资策略上。

4、最后我们会构造一个完整的实用系统,该系统上,可以查看关键投资指标、定制量化策略。

下面我们开始介绍Backtrader,内容主要基于Backtrader的网站指导文档以及示例。

目录

1、简介

2、安装

3、手把手教你实现一个例子

3.1、首先需要理解的几个关键概念

3.2、从0到100:一步一步实现一个例子

创建第一个程序

给空白的大脑加载数据

给大脑第一个策略

加入买的逻辑到Strategy中

不仅要买,还要卖

券商说,俺的钱呢?

如何给策略Strategy传递参数

加一个指标(indicator)

可视化-画图

再来点优化

3.3总结


1、简介

Backtrader的特点,就是两点:

1、易于使用;

2、参见第1条。

那么如何使用Backtrader呢?比把大象装进冰箱复杂点,一共4步:

创建一个Cerebro引擎:

  1.     加入一个Strategy。

  2.     加载数据。

  3.     执行:cerebro.run()。

  4.     对执行结果可视化。

就是这么简单!

这么简单如何执行那么多复杂的量化策略,关键就是Backtrader作为一个平台,具有极高的可配置性,也就是可以根据需要进行不同的配置,完成不同的量化策略回测,后续将进行详细描述。

2、安装

一般是通过Python安装:

pip install backtrader

特别注意的是,和backtrader适配的matplotlib版本不能太高,测试可用的版本是3.2.2。如果高于此版本,可以通过如下命令降级:

pip uninstall matplotlib
pip install matplotlib==3.2.2

3、手把手教你实现一个例子

3.1、首先需要理解的几个关键概念

1、Line:Line在Backtrader系统中,是最重要的对象。

Line的本意就是一连串可以连接在一起的点,所有可以在坐标上形成一条线的数据,就称为Line。在量化投资的领域,这个Line通常指的是证券的open(开盘价)、high(最高价)、low(最低价)、close(收盘价)、volume(成交量)。例如如下我们下载的某股票的数据:

image.png

Excle中画个图:

image.png

可以看出,每一列均可形成一个Line,这个Line就是需要进行处理的数据,对于证券数据,我们通常对close(收盘价)进行处理。

除了数据本身可以形成Line之外,对数据进行处理后形成的数据也可以作为Line,比如计算close列的移动平均线,也可以形成一个Line。

2、Index为0的含义

Backtrader系统中,对Line的数据是逐行处理的,如下:

系统处理顺序从上至下,当处理到26.5的时候,对应的Index为0.如果要访问之前的数据,就是-1,-2.之后的数据,就是1,2.

特别值得注意的是-1在python中用于访问一个列表的最后一个数据,而在backtrader中,-1指的是最后已经处理过得数据,在当前处理数据之前 ,值会随着系统的处理而不断变化。

如果系统在创建Strategy的时候,系统初始化了一个移动平均线:

self.sma = SimpleMovingAverage(.....)

访问移动平均线当前值的简单易用的方法是:

av = self.sma[0]

这种方法的好处就是无需知道已经处理了多少行(在Backtrader中,统一将行称之为Bar),也无需知道还有多少Bar需要处理,因为0唯一确定了系统正在处理的数据(Bar)。

3.2、从0到100:一步一步实现一个例子

掌握一项技术最好的方法就是亲手写一个程序,下面采用不断迭代的方法,一步一步,从简单到复杂实现咱们的第一个量化回测程序。

创建第一个程序

from __future__ import (absolute_import, division, print_function,
                        unicode_literals)
import backtrader as bt

if __name__ == '__main__':
    cerebro = bt.Cerebro()
    print('Starting Portfolio Value: %.2f' % cerebro.broker.getvalue())
    cerebro.run()
    print('Final Portfolio Value: %.2f' % cerebro.broker.getvalue())

执行下,看看啥结果:

Starting Portfolio Value: 10000.00
Final Portfolio Value: 10000.00

这个程序做了啥?

  • 将Backtrader引入到咱们程序中,命名为bt。

  • 创建了一个机器人大脑(Cerebro),同时隐含创建了一个borker(券商)。

  • 让机器人大脑开始运行。

  • 显示了机器人在券商那里存有多少钱。

等等,为啥只有10000元,失败啊,太少了,没事,咱可以多存点钱到券商。

cerebro = bt.Cerebro()
cerebro.broker.setcash(100000.0)#加到100000元,咱们也富裕了。

再执行看看,果然富裕了:

Starting Portfolio Value: 100000.00
Final Portfolio Value: 100000.00

不对,为啥钱没变啊,这个机器人没给我挣钱啊。因为这个机器人大脑只是初始化,还没发育好,脑子一片空白,啥也做不了,自然挣不了钱。咱们先给机器人点股票数据看看,让他先看看股票数据,说不定能学习点啥。

给空白的大脑加载数据

import backtrader as bt
import pandas as pd
from datetime import datetime
if __name__ == '__main__':
    cerebro = bt.Cerebro()
    #获取数据
    stock_hfq_df = pd.read_excel("./data/sh600000.xlsx",index_col='date',parse_dates=True)
    start_date = datetime(2010, 9, 30)  # 回测开始时间
    end_date = datetime(2021, 9, 30)  # 回测结束时间
    data = bt.feeds.PandasData(dataname=stock_hfq_df, fromdate=start_date, todate=end_date)  # 加载数据
    cerebro.adddata(data)  # 将数据传入回测系统
    
    cerebro.broker.setcash(100000.0)
    print('Starting Portfolio Value: %.2f' % cerebro.broker.getvalue())
    cerebro.run()
    print('Final Portfolio Value: %.2f' % cerebro.broker.getvalue())

再执行看看:

Starting Portfolio Value: 100000.00
Final Portfolio Value: 100000.00

大脑开始发育了,起码做到了:

  • 能接受股票的数据了。(这里提供的是下载浦发银行(sh6000000)的历史数据作为示例,如何获取数据后续专门讨论)

  • 也能对datetime进行处理,根据需要看具体特定时期的数据了。

但是咱们钱还是没增加了,大脑大脑快快成长吧,快快给俺挣钱啊

给大脑第一个策略

钱有了(在broker券商),股票数据也有了,似乎马上就可以进行有风险的投资了。要投资,就得有一个有投资策略。而投资策略,针对的通常是数据的收盘价(close),也就是根据收盘价决定如何投资。

毕竟股市太凶险,机器人新加的策略是先看看股票的收盘价。

import backtrader as bt
import pandas as pd
from datetime import datetime

# Create a Stratey
class TestStrategy(bt.Strategy):

    def log(self, txt, dt=None):
        ''' 提供记录功能'''
        dt = dt or self.datas[0].datetime.date(0)
        print('%s, %s' % (dt.isoformat(), txt))

    def __init__(self):
        # 引用到输入数据的close价格
        self.dataclose = self.datas[0].close

    def next(self):
        # 目前的策略就是简单显示下收盘价。
        self.log('Close, %.2f' % self.dataclose[0])

if __name__ == '__main__':
    cerebro = bt.Cerebro()
    
    # 增加一个策略
    cerebro.addstrategy(TestStrategy)
    
    #获取数据
    stock_hfq_df = pd.read_excel("./data/sh600000.xlsx",index_col='date',parse_dates=True)
    start_date = datetime(2010, 9, 30)  # 回测开始时间
    end_date = datetime(2021, 9, 30)  # 回测结束时间
    data = bt.feeds.PandasData(dataname=stock_hfq_df, fromdate=start_date, todate=end_date)  # 加载数据
    cerebro.adddata(data)  # 将数据传入回测系统
       
    cerebro.broker.setcash(100000.0)
    print('Starting Portfolio Value: %.2f' % cerebro.broker.getvalue())

    cerebro.run()

    print('Final Portfolio Value: %.2f' % cerebro.broker.getvalue())

执行后结果:

Starting Portfolio Value: 100000.00
2020-09-30, Close, 125.97
...(省略n行)
2021-09-27, Close, 127.11
2021-09-28, Close, 127.26
2021-09-29, Close, 127.11
2021-09-30, Close, 126.83
Final Portfolio Value: 100000.00

看起来还好,没赔钱,股票市场似乎没那么凶险。

关于这个策略(Strategy),需要重点关注:

  • Strategy初始化的时候,将大脑加载的数据更新到dataclose属性中(注意,这是一个列表,保存股票回测开始时间到结束时间的所有close数据)。 self.datas[0]指向的是大脑通过cerebro.adddata函数加载的第一个数据,本例中指加载浦发银行的股票数据。

  • self.dataclose = self.datas[0].close指向的是close (收盘价)line

  •  strategy 的next方法针对self.dataclose(也就是收盘价Line)的每一行(也就是Bar)进行处理。在本例中,只是打印了下close的值。next方法是Strategy最重要的的方法,具体策略的实现都在这个函数中,后续还会详细介绍。

这个策略还是没能挣钱,没买卖咋挣钱?大胆点,咱们开始买!

加入买的逻辑到Strategy中

没买卖就没收入,咱们开始买,啥时候买?妈妈说,买东西要便宜,那就如果价格连续降2天,咱就买入,试试看!

import backtrader as bt
import pandas as pd
from datetime import datetime

# 创建一个测试策略
class TestStrategy(bt.Strategy):

    def log(self, txt, dt=None):
        ''' 记录策略信息'''
        dt = dt or self.datas[0].datetime.date(0)
        print('%s, %s' % (dt.isoformat(), txt))

    def __init__(self):
        # 应用第一个数据源的收盘价
        self.dataclose = self.datas[0].close

    def next(self):
        # Simply log the closing price of the series from the reference
        self.log('Close, %.2f' % self.dataclose[0])

        if self.dataclose[0] < self.dataclose[-1]:
            # 当前的价格比上一次价格(也就是昨天的价格低)

            if self.dataclose[-1] < self.dataclose[-2]:
                # 上一次的价格(昨天)比上上一次的价格(前天的价格)低

                # 开始买!!
                self.log('BUY CREATE, %.2f' % self.dataclose[0])
                self.buy()

执行结果如下:

Starting Portfolio Value: 100000.00
...(省略n行)
2021-09-09, Close, 131.06
2021-09-10, Close, 132.61
2021-09-13, Close, 132.33
2021-09-14, Close, 129.79
2021-09-14, BUY CREATE, 129.79
2021-09-15, Close, 129.51
2021-09-15, BUY CREATE, 129.51
2021-09-16, Close, 128.52
2021-09-16, BUY CREATE, 128.52
2021-09-17, Close, 128.38
2021-09-17, BUY CREATE, 128.38
2021-09-22, Close, 127.26
2021-09-22, BUY CREATE, 127.26
2021-09-23, Close, 127.26
2021-09-24, Close, 127.11
2021-09-27, Close, 127.11
2021-09-28, Close, 127.26
2021-09-29, Close, 127.11
2021-09-30, Close, 126.83
2021-09-30, BUY CREATE, 126.83
Final Portfolio Value: 110441.06

挣钱了耶,居然挣了1万多块钱。从打印可以看出,在收盘价连续2天价格下跌的时候,strategy就执行买入。虽然咱们挣了钱,订单(order)好像创建了,但是不知道是否执行了以及何时以什么价格执行了。后面我们会展示如何监听订单执行的状态。

也许你要问了,咱们买了多少股票(称之为资产asset)?买了啥股票?订单是咋执行的?后续会回答这些问题,在当前示例中:

  • self.datas[0] 就是我们购买了的股票。本例中没有输入其他数据,如果输入了其他数据,购买的股票就不一定是啥了,这个要看具体的策略执行情况。

  • 买了多少股本(stake)的股票?这个通过机器人大脑的position sizer属性

本文章已经生成可运行项目
评论 45
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值