最近在群里面有一些 backtrader 的使用者提到了如何使用 talib 计算均线的问题,想到还没有把 backtrader 如何使用指标做专题分享,今天就凑着这个周末,分享一下,如何在 backtrader 中使用技术指标(indicator)。
开始之前,再分享一下老生长谈的问题:backtrader 的 line 数据结构
backtrader 中大部分都是 line 结构,如果使用过 excel 的工作表,就特别容易理解 line 结构,也可以理解大部分的事件驱动的量化框架。
excel 中的工作表分不同的工作簿,一个工作簿中分为行和列;backtrader 中的类相当于一个工作簿,类里面包含的数据相当于一列一列的列表,每一个 line 就相当于一列数据。调取数据也和 excel 差不多,先找到是在哪个工作簿,然后找到是哪一列,然后找到是哪一行;区别在于 backtrader 找哪一行的时候是按照当前的 index 来找的,index=0,找到的是当前行的;index=-1,找到的是前一行的;index=1,找到的是下一行的。
不知道用 excel 的表格来讲 backtrader 的 line 是否够形象和易于理解,理解 backtrader 的 line 的数据结构是对 backtrader 进行深入了解的基础。
使用 backtrader 的技术指标,回测的使用,一般是在 strategy 类中的 init 中进行声明,然后在进入 next 之前,一般就已经把指标计算好了。
关于 backtrader 可以调用的技术指标,分为三种,一种是talib 上的技术指标,一种是backtrader 自带的技术指标,一种是自己创建的新的技术指标。使用具体指标的时候,尤其是 talib 的指标的时候,要认真检验一下,看是否和我们想要的结果一样,因为 talib 的代码一般比较难找到源码;我碰到过 talib 计算的和 backtrader 计算的指标不一致的情况。
-
使用方法
首先,想明白自己想要使用的指标是什么,需要哪些参数,可以在 talib 和 backtrader 自带的指标里面找,更进一步的话,也可以自己创建指标;
其次,一般是在 strategy 类中的 init 中使用 self.xxx = bt.indicators.yyy(params)或者 self.xxx = bt.talib.yyy(params),如果遇到多个数据需要计算指标,一般是使用 dict 格式,key 是数据名称,value 是计算的指标值。
最后,在 next 中调用指标值的时候,和普通的高开低收的行情数据没有差别。
-
举例说明:
参考文章:如何用 backtrader 实现双均线策略?以工商银行为例
self.short_ma = bt.indicators.SMA(self.datas[0].close,period=self.p.short_window) self.long_ma = bt.indicators.SMA(self.datas[0].close,period=self.p.long_window)
参考文章:【backtrader 股票策略】《151 trading strategies》中的三均线策略在 A 股中的测试
class xxx(bt.Strategy):
params = (('short_period',10),
("middle_period",60),
("long_period",250),
)
def __init__(self):
# 在这里面声明需要计算的公式
self.bar_num=0
# 保存均线数据
self.stock_short_ma_dict={data._name:bt.talib.SMA(data.close,timeperiod=self.p.short_period) for data in self.datas}
self.stock_middle_ma_dict={data._name:bt.talib.SMA(data.close,timeperiod=self.p.middle_period) for data in self.datas}
self.stock_long_ma_dict={data._name:bt.talib.SMA(data.close,timeperiod=self.p.long_period) for data in self.datas}
def prenext(self):
self.next()
def next(self):
# 省略很多代码之后
for data in self.datas:
# 三条均线,保存成 line 的数据结构
short_ma_info = self.stock_short_ma_dict[data._name]
middle_ma_info = self.stock_middle_ma_dict[data._name]
long_ma_info = self.stock_long_ma_dict[data._name]
# 今日向上的条件
up = short_ma_info[0]>middle_ma_info[0] and middle_ma_info[0]>long_ma_info[0]
# 今日向下的条件
down = short_ma_info[0]<=middle_ma_info[0]
# 昨日向上的条件
pre_up = short_ma_info[-1]>middle_ma_info[-1] and middle_ma_info[-1]>long_ma_info[-1]
# 昨日向下的条件
pre_down = short_ma_info[-1]<=middle_ma_info[-1] - 有一部分指标可以使用向量的方式计算,加快速度
- 把需要计算的变量计算好,可以在 next 中集中精力实现策略逻辑
直接使用 indicator 计算的变量,如果使用了 cerebro.plot()的话,是可以直接画出来的,如果是使用了中间变量,那么中间变量并不会直接画出来,需要我们声明。
举例说明,这个策略是来自官网上面
class MyStrategy(bt.Strategy):
def __init__(self):
sma1 = btind.SimpleMovingAverage(self.data)
ema1 = btind.ExponentialMovingAverage()
close_over_sma = self.data.close > sma1
close_over_ema = self.data.close > ema1
sma_ema_diff = sma1 - ema1
buy_sig = bt.And(close_over_sma, close_over_ema, sma_ema_diff > 0)
def next(self):
if buy_sig:
self.buy() 在这个策略中,sma1 和 ema1 是可以直接画出来的,但是 close_over_sma 和 close_over_ema 和 sma_ema_diff 是不会直接画出来的,需要我们使用 LinePlotterIndicator 画出来中间变量。
close_over_sma = self.data.close > self.sma
LinePlotterIndicator(close_over_sma, name='Close_over_SMA') 如果想要控制指标的位置和名称,可以在创建指标的时候,使用参数额外控制,如:
self.short_ma = bt.indicators.SMA(self.datas[0].close,period=self.p.short_window,subplot=True,plotname="short_ma") 其中,subplot 是控制显示的位置,是在 K 线图上显示(subplot=False)还是另外一幅图上显示(subplot=True),plotname 是画出来的名称.测试了一下,没问题。
在下一讲中,将会分享一下,如何创建新的技术指标以及画图的各个参数的意义。
智慧、心灵、财富,总要有一个在路上,愿我们能在人生的道路上,不断成长、不断成熟~~~
感兴趣可以关注我的专栏:
my_quant_study_note:分享一些关于量化投资、量化交易相关的思考
backtrader 量化投资回测与交易:本专栏免费,分享 backtrader 相关的内容。
量化投资神器-backtrader 源码解析-从入门到精通:本专栏目前收费 99 元,预计更新 100 篇策略+20 篇 backtrader 讲解+80 篇源代码分析。