【答读者问12】如何理解backtrader的line以及对line进行操作?
作者:yunjinqi   类别:    日期:2021-12-23 17:49:14    阅读:1436 次   消耗积分:0 分    

答读者问为免费文章,不计入专栏里面。

理解line是理解backtrader的基础,backtrader是一个事件驱动的量化框架,基于元编程技术,形成了line的数据结果;在前面的文章中如何使用技术指标中,已经讲过如何理解line这种backtrader的数据结构了,但是可能还是有一部分读者对这个数据结构不太了解。

backtrader和excel表格的关系

事件驱动的核心本质是一样的,都是基于事件(数据)的更新,不断更新相关的量。backtrader本身的底层结构看起来比较抽象,但是,如果我们把backtrader和excel表格对比,对于backtrader的认识,就会瞬间提高很多。

  • backtrader的datas相当于一个文件名是datas的excel表格,每个data就相当于一个工作簿,data中的open、high、low、close等line就相当于工作簿的一个个列

  • strategy中的next每次运行相当于指向了excel表格中的下一行,用下一行代表当前行;举例说明,如果当前行是2021年6月14日,此时,data.close[0]是数据2021年6月14日的,此时,excel表格中相当于以2021年6月14日所在的行作为当前行;然后next运行一次,下个数据的日期是2021年6月15日,那么,data.close[0]就指向了2021年6月15日的bar的收盘价,excel中,当前行的index会增加1,以2021年6月15日作为当前行。

这样理解之后,会不会对backtrader的line的数据结构理解的更清晰?

backtrader的line数据结构的相关操作

如何获取line的一个值
  • 0获取的是当前的值,如close[0]是当前bar的收盘价

  • -1获取的是前一个bar的值,如close[-1]是前一个bar的收盘价

  • 1获取的是后一个bar的值,如close[1]获取的是下一个bar的收盘价,如果是最后一个bar,就会报IndexError的错误,如果使用这个,就要避免报错导致的程序中断,另外,下个bar的信息是未来数据,要慎用;在实盘的时候,是不存在下个bar的数据的,仅仅只能用于回测之中。

如何获取line的多个值
  • line是一个特殊的数据结构,获取line的多个值,和python的切片有所不同。举例说明,要想获取line里面的最近的10个值,需要使用line[-9:0],line[0]也在切片的数据中;python中line[-9:]是获取的最后的9个数值,和backtrader不一样。

  • backtrader定义了一个get的函数,用于获取过去的值,close.get(ago=0,size=10),代表获取从当前值开始的最近的10个收盘价;close.get(ago=-1,size=20)代表获取从前一个bar开始的20个收盘价。

如何获取一个line的长度

有两种不同的line的长度,一种是len,这个是backtrader已经处理过的数据的长度;一种是buflen(),这个是backtrader预先加载的数据的长度。

  • len(line):计算出backtrader已经处理(运行)的长度,如prenext,next等运行的长度

  • line.buflen()计算的是backtrader加载的line的总的数目

  • 一般情况下,是buflen大于len,如果两者想等了,可能是这个bar是最后一个bar;也有可能是某些情况下的实盘交易造成的。

line之间如何进行逻辑操作

backtrader自己集成了一些常见的操作

  • bt.And(a,b):a和b都是真的时候,才返回真值,值也是line

  • bt.Or(a,b):a和b一个是真的时候,就返回真值,值也是line

  • bt.If(cond,a,b):如果cond成立,返回a,否则,返回b,值是line

  • bt.Any、bt.All、bt.Cmp、bt.Max、bt.Min、bt.Sum和python中的any、all、cmp、max、min、sum类似

  • 这些改写的函数,可以对line进行的操作,是向量形式的操作,返回的新的结果也是line

    并且可以自己定义相应的操作方法,比如想要对一个line的每一个值取绝对值,除了可以直接用abs(line)之外,还可以继承Logic,自己实现相应的类,如

    """
    # 需要把这个类放到backtrader中的functions文件中
    class Abs(Logic):
    
        def __init__(self, a):
            super(Abs, self).__init__(a)
            self.a = self.args[0]
    
        def next(self):
            self[0] = abs(self.a[0]) 
        def once(self, start, end):
            # cache python dictionary lookups
            dst = self.array
            srca = self.a.array
            
            for i in range(start, end):
                dst[i] = abs(srca[i]) 
    """import pandas as pdimport numpy as npimport backtrader as bt 
    import datetime 
    class SmaStrategy(bt.Strategy):
        
        def log(self, txt, dt=None):
            ''' log信息的功能'''
            dt = dt or self.datas[0].datetime.date(0)
            print('%s, %s' % (dt.isoformat(), txt))
     
        def __init__(self):
            # 一般用于计算指标或者预先加载数据,定义变量使用
            self.bar_num = 0
            self.diff_price = bt.Abs(self.datas[0].close - self.datas[0].open)
            
     
        def next(self):
            self.log(f"len:{len(self.datas[0].close)},buflen:{self.datas[0].close.buflen()}")
            self.log(self.diff_price[0])
            
                           # 添加cerebrocerebro = bt.Cerebro()# 添加策略cerebro.addstrategy(SmaStrategy)# 准备数据        params = dict(
                    fromdate = datetime.datetime(2005,1,4),
                    todate = datetime.datetime(2020,8,3),
                    timeframe = bt.TimeFrame.Days,
                    compression = 1,
                    #dtformat=('%Y-%m-%d %H:%M:%S'),
                    # tmformat=('%H:%M:%S'),
                    datetime=0,
                    high=2,
                    low=3,
                    open=1,
                    close=4,
                    volume=5,
                    openinterest=6)# 数据的地址,使用自己的数据地址 data_path = '/home/yun/data/stock/index.csv'df = pd.read_csv(data_path,encoding='gbk')df.columns = ['datetime','open','high','low','close','volume','openinterest']df['datetime']=pd.to_datetime(df['datetime'])df = df.sort_values("datetime")df.index=pd.to_datetime(df['datetime'])df=df[['open','high','low','close','volume','openinterest']]feed =  bt.feeds.PandasDirectData(dataname=df,**params)# 添加合约数据cerebro.adddata(feed, name = "index")cerebro.broker.setcommission(commission=0.0005)
     # 添加资金cerebro.broker.setcash(100000.0)
     # 开始运行cerebro.run()
     # 打印相关信息cerebro.plot()

写作这篇文章,使用两个晚上,共用89分钟。


智慧、心灵、财富,总要有一个在路上,愿我们能在人生的道路上,不断成长、不断成熟~~~

感兴趣可以关注我的专栏:

my_quant_study_note:分享一些关于量化投资、量化交易相关的思考

backtrader量化投资回测与交易:本专栏免费,分享backtrader相关的内容。

量化投资神器-backtrader源码解析-从入门到精通:本专栏目前收费299元,预计更新100篇策略(更新中)+36篇backtrader讲解(已完成)+backtrader源码分析。


版权所有,转载本站文章请注明出处:云子量化, http://www.woniunote.com/article/41
上一篇:【答读者问11】backtradcer如何计算交易1手需要的现金?
下一篇:【答读者问13】backtrader实盘交易中应该注意些什么(数据篇)?