BackTrader 中文文档(二)(4)

简介: BackTrader 中文文档(二)

BackTrader 中文文档(二)(3)https://developer.aliyun.com/article/1489218

addtz(tz)

这也可以通过参数tz完成

为策略添加全局时区。参数tz可以是

  • None:在这种情况下,策略显示的日期时间将为 UTC,这一直是标准行为
  • pytz实例。将按此使用它将 UTC 时间转换为所选时区
  • string。将尝试实例化一个pytz实例。
  • integer。对于策略,使用与self.datas可迭代对象中相应data相同的时区(0将使用来自data0的时区)
add_timer(when, offset=datetime.timedelta(0), repeat=datetime.timedelta(0), weekdays=[], weekcarry=False, monthdays=[], monthcarry=True, allow=None, tzdata=None, strats=False, cheat=False, *args, **kwargs)

安排定时器以调用notify_timer

  • 参数when(-) – 可以是
  • datetime.time实例(见下文tzdata
  • bt.timer.SESSION_START表示会话开始
  • bt.timer.SESSION_END表示会话结束
  • 必须是datetime.timedelta实例的offset
  • 用于偏移值when。与SESSION_STARTSESSION_END结合使用时,它具有有意义的用途,用于指示诸如在会话开始后15 分钟调用定时器之类的事情。
  • 必须是datetime.timedelta实例的repeat
    指示如果在第 1 次调用后,后续调用将在同一会话中按计划的repeat增量中安排
    一旦定时器超过会话结束,它将被重置为when的原始值
  • weekdays:一个排序的可迭代对象,其中的整数表示可以实际调用定时器的日期(ISO 代码,星期一为 1,星期日为 7)
    如果未指定,定时器将在所有日期上都处于活动状态。
  • weekcarry(默认值:False)。如果为True且周几未见(例如:交易假期),则定时器将在下一天执行(即使在新的一周中)
  • monthdays:一个排序的可迭代对象,其中的整数表示定时器必须执行的月份中的哪一天。例如,每个月的第15天始终执行
    如果未指定,定时器将在所有日期上都处于活动状态
  • monthcarry(默认值:True)。如果当天没有看到(周末、交易假期),则定时器将在下一个可用日期执行。
  • allow(默认值:None)。一个回调函数,接收一个datetime.date实例,并返回True如果该日期允许定时器,否则返回False
  • tzdata可以是None(默认值),一个pytz实例或一个data feed实例。
    Nonewhen按面值解释(即使它不是 UTC,也会处理它)
    pytz实例:when将被解释为时区实例指定的本地时间。
    data feed实例:when将被解释为数据源实例的tz参数指定的本地时间。
    注意
    如果whenSESSION_STARTSESSION_ENDtzdataNone,则系统中的第 1 个数据源(也称为self.data0)将用作查找会话时间的参考。
  • strats(默认值:False)还会调用策略的notify_timer
  • cheat(默认为 False)如果为 True,则会在经纪人有机会评估订单之前调用计时器。例如,在交易会话开始之前,可以根据开盘价下订单。
  • *args: 任何额外的参数都将传递给 notify_timer
  • **kwargs: 任何额外的关键字参数都将传递给 notify_timer

返回值:

  • 创建的计时器
notify_timer(timer, when, *args, **kwargs)

接收计时器通知,其中 timer 是由 add_timer 返回的计时器,when 是调用时间。argskwargs 是传递给 add_timer 的任何额外参数。

实际的 when 时间可能会晚一些,但系统可能无法在之前调用计时器。该值是计时器值,而不是系统时间。

add_order_history(orders, notify=True)

将订单历史记录添加到经纪人中,以供性能评估直接执行

  • orders: 是一个可迭代对象(例如列表、元组、迭代器、生成器),其中每个元素也将是一个具有以下子元素的可迭代对象(有 2 种格式)[datetime, size, price][datetime, size, price, data]注意必须按照日期时间升序排序(或生成排序的元素)。其中:
  • datetime 是一个 python date/datetime 实例,或者是一个格式为 YYYY-MM-DD[THH:MM:SS[.us]] 的字符串,方括号中的元素是可选的。
  • size 是一个整数(买入为正,卖出为负)
  • price 是一个浮点数/整数
  • 如果存在data,则可以采用以下任何值
  • None - 将使用第 1 个数据源作为目标。
  • integer - 将使用该索引对应的数据(在Cerebro中的插入顺序)。
  • string - 该名称的数据,例如通过 cerebro.addata(data, name=value) 分配,将作为目标。
  • notify(默认值:True
    如果设为 True,则会通知系统中插入的第 1 个策略,其会根据每个订单中的信息创建人工订单。

注意

隐含在描述中的是需要添加一个数据源,该数据源是订单的目标。例如,分析器需要追踪回报率。

节省内存

www.backtrader.com/docu/memory-savings/memory-savings/

发布版本 1.3.1.92已经重新设计并完全实现了先前存在的节省内存方案,尽管没有受到太多宣传并且使用较少。

backtrader曾经(并将继续)在内存较大的机器上开发,并且与通过绘图提供的视觉反馈是一个必需的美好事物相结合,使得设计决策变得容易:将所有内容保存在内存中。

这个决定有一些缺点:

  • 用于数据存储的array.array在超过某些限制时必须分配和移动数据。
  • RAM 较少的机器可能会受到影响。
  • 连接到可以在线运行数周/数月、提供数千秒/分钟分辨率 ticks 的实时数据源

后者比第一点更加重要,因为另一个设计决定是为了 backtrader

  • 必须是纯 Python,以便在需要时在嵌入式系统中运行。
    将来的一个场景可能是 backtrader 连接到第二台机器,该机器提供实时数据源,而 backtrader 本身运行在类似 Raspberry Pi 或甚至更有限的设备上,如 ADSL 路由器(AVM Frit!Box 7490,带有 Freetz 映像)

因此需要 backtrader 支持动态内存方案。现在 Cerebro 可以使用以下语义进行实例化或run

  • exactbars(默认值:False)默认值为False,每个存储在一行中的值都会保存在内存中。可能的值:
  • True1:所有“lines”对象将内存使用量减少到自动计算的最小周期。如果简单移动平均值的周期为 30,底层数据将始终具有 30 个条形图的运行缓冲区,以允许计算简单移动平均值
  • 此设置将停用preloadrunonce
  • 使用此设置还会停用plotting
  • -1:在策略级别,数据和指标/操作将保留所有数据在内存中。例如:RSI在内部使用指标UpDay进行计算。此子指标将不会将所有数据保存在内存中。
  • 这允许保持plottingpreloading处于活动状态。
  • runonce将被停用。
  • -2:作为策略属性保留的数据和指标将在内存中保存所有数据。例如:RSI在内部使用指标UpDay进行计算。此子指标将不会将所有数据保存在内存中。如果在__init__中定义了类似a = self.data.close - self.data.high这样的内容,则a将不会将所有数据保存在内存中。
  • 这允许保持plottingpreloading处于活动状态。
  • runonce将被停用。

一如既往,一个例子胜过千言万语。一个示例脚本显示了差异。它针对 1996 年至 2015 年的 Yahoo 每日数据运行,总共 4965 天。

注意

这只是一个小样本。每天交易 14 小时的 EuroStoxx50 期货,在仅 1 个月的交易中将产生大约 18000 个 1 分钟的 K 线。

执行脚本 1^(st)以查看在不请求内存节省时使用了多少内存位置:

$ ./memory-savings.py --save 0
Total memory cells used: 506430

对于 1 级(总储蓄):

$ ./memory-savings.py --save 1
Total memory cells used: 2041

天啊!!!从五十万跌至2041。确实。系统中的每个lines对象都使用collections.deque作为缓冲区(而不是array.array),并且长度被限制在绝对需要的最小值以进行请求的操作。例如:

  • 在数据源上使用期间为30SimpleMovingAverage策略。

在这种情况下,将进行以下调整:

  • 数据源将具有30个位置的缓冲区,这是SimpleMovingAverage产生下一个值所需的数量
  • SimpleMovingAverage将有一个1位置的缓冲区,因为除非其他指标需要(这些指标将依赖于移动平均线),否则不需要保留较大的缓冲区。

注意

这种模式最吸引人且可能最重要的功能是,所使用的内存量在脚本的整个生命周期内保持不变。

无论数据源的大小如何。

如果例如连接到长时间的实时数据源,则这将非常有用。

但请注意:

  1. 绘图不可用
  2. 还有其他的内存消耗来源,随着时间的推移会积累,比如策略生成的orders
  3. 此模式只能在cerebro中的runonce=False时使用。对于实时数据源,这也是强制性的,但在简单回测的情况下,这比runonce=True慢。
    肯定有一个权衡点,从而内存管理比逐步执行回测更昂贵,但这只能由平台的最终用户在每个案例中进行判断。

现在是负级别。这些级别旨在在仍然节省相当数量的内存的同时保持绘图可用。第一级别-1

$ ./memory-savings.py --save -1
Total memory cells used: 184623

在这种情况下,指标的第 1 级别(在策略中声明的那些)保持其完整长度的缓冲区。但是如果这些指标依赖于其他指标(这就是情况),则子对象将被长度限制。在这种情况下,我们已经从:

  • 506430个内存位置到-> 184623

超过 50%的节省。

注意

当然,array.array对象已被collections.deque所取代,这在内存方面更昂贵,尽管在操作方面更快。但是collections.deque对象相当小,并且节省了大致计算的内存位置的使用。

现在是级别-2,这也是为了节省在策略级别上声明的指标的内存,这些指标已被标记为不需要绘制:

$ ./memory-savings.py --save -2
Total memory cells used: 174695

现在没有保存太多。这是因为一个单独的指标已被标记为不需要绘制:TestInd().plotinfo.plot = False

让我们看看来自最后一个示例的绘图:

$ ./memory-savings.py --save -2 --plot
Total memory cells used: 174695

对于感兴趣的读者,示例脚本可以生成对指标层次结构中遍历的每个对象的详细分析。运行时启用绘图(保存在-1):

$ ./memory-savings.py --save -1 --lendetails
-- Evaluating Datas
---- Data 0 Total Cells 34755 - Cells per Line 4965
-- Evaluating Indicators
---- Indicator 1.0 Average Total Cells 30 - Cells per line 30
---- SubIndicators Total Cells 1
---- Indicator 1.1 _LineDelay Total Cells 1 - Cells per line 1
---- SubIndicators Total Cells 1
...
---- Indicator 0.5 TestInd Total Cells 9930 - Cells per line 4965
---- SubIndicators Total Cells 0
-- Evaluating Observers
---- Observer 0 Total Cells 9930 - Cells per Line 4965
---- Observer 1 Total Cells 9930 - Cells per Line 4965
---- Observer 2 Total Cells 9930 - Cells per Line 4965
Total memory cells used: 184623

同样的,但启用了最大节省(1):

$ ./memory-savings.py --save 1 --lendetails
-- Evaluating Datas
---- Data 0 Total Cells 266 - Cells per Line 38
-- Evaluating Indicators
---- Indicator 1.0 Average Total Cells 30 - Cells per line 30
---- SubIndicators Total Cells 1
...
---- Indicator 0.5 TestInd Total Cells 2 - Cells per line 1
---- SubIndicators Total Cells 0
-- Evaluating Observers
---- Observer 0 Total Cells 2 - Cells per Line 1
---- Observer 1 Total Cells 2 - Cells per Line 1
---- Observer 2 Total Cells 2 - Cells per Line 1

第二个输出立即显示了数据源中的行数被限制为38个内存位置,而不是完整数据源长度4965

并且指标观察者在可能的情况下被限制为1,如输出的最后几行所示。

脚本代码和用法

backtrader的源代码中可作为示例使用。用法:

$ ./memory-savings.py --help
usage: memory-savings.py [-h] [--data DATA] [--save SAVE] [--datalines]
                         [--lendetails] [--plot]
Check Memory Savings
optional arguments:
  -h, --help    show this help message and exit
  --data DATA   Data to be read in (default: ../../datas/yhoo-1996-2015.txt)
  --save SAVE   Memory saving level [1, 0, -1, -2] (default: 0)
  --datalines   Print data lines (default: False)
  --lendetails  Print individual items memory usage (default: False)
  --plot        Plot the result (default: False)

代码:

from __future__ import (absolute_import, division, print_function,
                        unicode_literals)
import argparse
import sys
import backtrader as bt
import backtrader.feeds as btfeeds
import backtrader.indicators as btind
import backtrader.utils.flushfile
class TestInd(bt.Indicator):
    lines = ('a', 'b')
    def __init__(self):
        self.lines.a = b = self.data.close - self.data.high
        self.lines.b = btind.SMA(b, period=20)
class St(bt.Strategy):
    params = (
        ('datalines', False),
        ('lendetails', False),
    )
    def __init__(self):
        btind.SMA()
        btind.Stochastic()
        btind.RSI()
        btind.MACD()
        btind.CCI()
        TestInd().plotinfo.plot = False
    def next(self):
        if self.p.datalines:
            txt = ','.join(
                ['%04d' % len(self),
                 '%04d' % len(self.data0),
                 self.data.datetime.date(0).isoformat()]
            )
            print(txt)
    def loglendetails(self, msg):
        if self.p.lendetails:
            print(msg)
    def stop(self):
        super(St, self).stop()
        tlen = 0
        self.loglendetails('-- Evaluating Datas')
        for i, data in enumerate(self.datas):
            tdata = 0
            for line in data.lines:
                tdata += len(line.array)
                tline = len(line.array)
            tlen += tdata
            logtxt = '---- Data {} Total Cells {} - Cells per Line {}'
            self.loglendetails(logtxt.format(i, tdata, tline))
        self.loglendetails('-- Evaluating Indicators')
        for i, ind in enumerate(self.getindicators()):
            tlen += self.rindicator(ind, i, 0)
        self.loglendetails('-- Evaluating Observers')
        for i, obs in enumerate(self.getobservers()):
            tobs = 0
            for line in obs.lines:
                tobs += len(line.array)
                tline = len(line.array)
            tlen += tdata
            logtxt = '---- Observer {} Total Cells {} - Cells per Line {}'
            self.loglendetails(logtxt.format(i, tobs, tline))
        print('Total memory cells used: {}'.format(tlen))
    def rindicator(self, ind, i, deep):
        tind = 0
        for line in ind.lines:
            tind += len(line.array)
            tline = len(line.array)
        thisind = tind
        tsub = 0
        for j, sind in enumerate(ind.getindicators()):
            tsub += self.rindicator(sind, j, deep + 1)
        iname = ind.__class__.__name__.split('.')[-1]
        logtxt = '---- Indicator {}.{}  {} Total Cells {} - Cells per line {}'
        self.loglendetails(logtxt.format(deep, i, iname, tind, tline))
        logtxt = '---- SubIndicators Total Cells {}'
        self.loglendetails(logtxt.format(deep, i, iname, tsub))
        return tind + tsub
def runstrat():
    args = parse_args()
    cerebro = bt.Cerebro()
    data = btfeeds.YahooFinanceCSVData(dataname=args.data)
    cerebro.adddata(data)
    cerebro.addstrategy(
        St, datalines=args.datalines, lendetails=args.lendetails)
    cerebro.run(runonce=False, exactbars=args.save)
    if args.plot:
        cerebro.plot(style='bar')
def parse_args():
    parser = argparse.ArgumentParser(
        formatter_class=argparse.ArgumentDefaultsHelpFormatter,
        description='Check Memory Savings')
    parser.add_argument('--data', required=False,
                        default='../../datas/yhoo-1996-2015.txt',
                        help='Data to be read in')
    parser.add_argument('--save', required=False, type=int, default=0,
                        help=('Memory saving level [1, 0, -1, -2]'))
    parser.add_argument('--datalines', required=False, action='store_true',
                        help=('Print data lines'))
    parser.add_argument('--lendetails', required=False, action='store_true',
                        help=('Print individual items memory usage'))
    parser.add_argument('--plot', required=False, action='store_true',
                        help=('Plot the result'))
    return parser.parse_args()
if __name__ == '__main__':
    runstrat()


相关文章
|
9月前
|
索引
BackTrader 中文文档(六)(2)
BackTrader 中文文档(六)
106 0
|
9月前
|
Unix 索引 Python
BackTrader 中文文档(一)(2)
BackTrader 中文文档(一)
241 0
|
9月前
|
存储 编解码 API
BackTrader 中文文档(四)(1)
BackTrader 中文文档(四)
99 1
|
9月前
|
存储 数据库连接 数据库
BackTrader 中文文档(三)(2)
BackTrader 中文文档(三)
166 0
|
9月前
|
存储 安全 Unix
BackTrader 中文文档(四)(2)
BackTrader 中文文档(四)
78 0
|
9月前
|
Python
BackTrader 中文文档(六)(4)
BackTrader 中文文档(六)
105 0
|
9月前
|
存储 C++ 索引
BackTrader 中文文档(二)(1)
BackTrader 中文文档(二)
103 0
|
9月前
|
存储 API 索引
BackTrader 中文文档(四)(3)
BackTrader 中文文档(四)
71 0
|
9月前
|
测试技术 索引 Python
BackTrader 中文文档(二)(2)
BackTrader 中文文档(二)
101 0
|
9月前
|
数据可视化
BackTrader 中文文档(三)(3)
BackTrader 中文文档(三)
77 0

热门文章

最新文章