BackTrader 中文文档(二)(2)

简介: BackTrader 中文文档(二)

BackTrader 中文文档(二)(1)https://developer.aliyun.com/article/1489214

运算符,使用自然构造

为了实现“易用性”目标,该平台允许(在 Python 的约束条件下)使用运算符。为了进一步增强这一目标,运算符的使用已分为两个阶段。

第 1 阶段 - 运算符创建对象

即使没有明确指定,示例已经展示了这一点。在像指标和策略这样的对象的初始化阶段(__init__方法)中,运算符创建可以进行操作、分配或保留作为后续在策略逻辑评估阶段使用的对象。

再次展示了一个简单移动平均的潜在实现,进一步分解为步骤。

简单移动平均指标__init__中的代码可能如下所示:

def __init__(self):
    # Sum N period values - datasum is now a *Lines* object
    # that when queried with the operator [] and index 0
    # returns the current sum
    datasum = btind.SumN(self.data, period=self.params.period)
    # datasum (being *Lines* object although single line) can be
    # naturally divided by an int/float as in this case. It could
    # actually be divided by anothr *Lines* object.
    # The operation returns an object assigned to "av" which again
    # returns the current average at the current instant in time
    # when queried with [0]
    av = datasum / self.params.period
    # The av *Lines* object can be naturally assigned to the named
    # line this indicator delivers. Other objects using this
    # indicator will have direct access to the calculation
    self.line.sma = av

在策略初始化期间展示了一个更完整的用例:

class MyStrategy(bt.Strategy):
    def __init__(self):
        sma = btind.SimpleMovinAverage(self.data, period=20)
        close_over_sma = self.data.close > sma
        sma_dist_to_high = self.data.high - sma
        sma_dist_small = sma_dist_to_high < 3.5
        # Unfortunately "and" cannot be overridden in Python being
        # a language construct and not an operator and thus a
        # function has to be provided by the platform to emulate it
        sell_sig = bt.And(close_over_sma, sma_dist_small)

在上述操作完成后,sell_sig是一个Lines对象,可以在策略的逻辑中稍后使用,指示条件是否满足。

第二阶段 - 自然的运算符

让我们首先记住,策略有一个next方法,系统处理每个柱状图时都会调用该方法。这就是运算符实际处于第 2 阶段模式的地方。在前面的示例基础上构建:

class MyStrategy(bt.Strategy):
    def __init__(self):
        self.sma = sma = btind.SimpleMovinAverage(self.data, period=20)
        close_over_sma = self.data.close > sma
        self.sma_dist_to_high = self.data.high - sma
        sma_dist_small = sma_dist_to_high < 3.5
        # Unfortunately "and" cannot be overridden in Python being
        # a language construct and not an operator and thus a
        # function has to be provided by the platform to emulate it
        self.sell_sig = bt.And(close_over_sma, sma_dist_small)
    def next(self):
        # Although this does not seem like an "operator" it actually is
        # in the sense that the object is being tested for a True/False
        # response
        if self.sma > 30.0:
            print('sma is greater than 30.0')
        if self.sma > self.data.close:
            print('sma is above the close price')
        if self.sell_sig:  # if sell_sig == True: would also be valid
            print('sell sig is True')
        else:
            print('sell sig is False')
        if self.sma_dist_to_high > 5.0:
            print('distance from sma to hig is greater than 5.0')

不是一个非常有用的策略,只是一个例子。在第 2 阶段,运算符返回预期的值(如果测试真实性则返回布尔值,如果与浮点数比较则返回浮点数),算术运算也是如此。

注意

请注意,比较实际上并没有使用[]运算符。这是为了进一步简化事情。

if self.sma > 30.0: … 比较self.sma[0]30.0(第 1 行和当前值)

if self.sma > self.data.close: … 比较self.sma[0]self.data.close[0]

一些未被覆盖的运算符/函数

Python 不允许覆盖所有内容,因此提供了一些函数来处理这些情况。

注意

仅在阶段 1 中使用,以创建稍后提供值的对象。

运算符:

  • and -> And
  • or -> Or

逻辑控制:

  • if -> If

函数:

  • any -> Any
  • all -> All
  • cmp -> Cmp
  • max -> Max
  • min -> Min
  • sum -> Sum
    Sum实际上使用math.fsum作为底层操作,因为平台使用浮点数,并且应用常规的sum可能会影响精度。
  • reduce -> Reduce

这些实用运算符/函数操作可迭代对象。可迭代对象中的元素可以是常规的 Python 数值类型(整数,浮点数,…)也可以是具有Lines的对象。

一个生成非常愚蠢买入信号的例子:

class MyStrategy(bt.Strategy):
    def __init__(self):
        sma1 = btind.SMA(self.data.close, period=15)
        self.buysig = bt.And(sma1 > self.data.close, sma1 > self.data.high)
    def next(self):
        if self.buysig[0]:
            pass  # do something here

很明显,如果sma1高于最高价,那么它必须高于收盘价。但重点是说明bt.And的用法。

使用bt.If

class MyStrategy(bt.Strategy):
    def __init__(self):
        sma1 = btind.SMA(self.data.close, period=15)
        high_or_low = bt.If(sma1 > self.data.close, self.data.low, self.data.high)
        sma2 = btind.SMA(high_or_low, period=15)

分解:

  • data.close上生成一个SMA,周期为15
  • 然后
  • bt.If如果sma的值大于close,则返回low,否则返回high
  • 请记住,当调用bt.If时并不会返回实际值。它返回一个Lines对象,就像一个SimpleMovingAverage一样。
    值将在系统运行时计算
  • 生成的bt.If Lines对象然后被传递给第 2 个SMA,有时会使用low价格,有时会使用high价格进行计算

这些函数也接受数值。同样的例子,稍作修改:

class MyStrategy(bt.Strategy):
    def __init__(self):
        sma1 = btind.SMA(self.data.close, period=15)
        high_or_30 = bt.If(sma1 > self.data.close, 30.0, self.data.high)
        sma2 = btind.SMA(high_or_30, period=15)

现在第 2 个移动平均值使用30.0high价格执行计算,取决于smaclose的逻辑状态

注意

30在内部转换为一个伪可迭代对象,始终返回30

操作平台

原文:www.backtrader.com/docu/operating/

线迭代器

为了参与操作,平台使用线迭代器的概念。它们松散地模仿了 Python 的迭代器,但实际上与它们毫不相关。

策略和指标都是线迭代器。

线迭代器的概念试图描述以下内容:

  • 一条线迭代器踢动从属线迭代器,告诉它们迭代
  • 然后,线迭代器遍历其自己声明的命名行并设置值

迭代的关键,就像普通的 Python 迭代器一样,是:

  • next 方法
    它将被每次迭代调用。 线迭代器具有的并作为逻辑/计算基础的datas数组已经被平台移动到下一个索引(除了数据重播)
    在满足线迭代器的最小周期时调用。稍后将详细介绍。

但因为它们不是常规迭代器,所以还存在两种额外的方法:

  • prenext
    在满足最小周期的条件之前调用线迭代器
  • nextstart
    当满足最小周期的条件时仅调用一次线迭代器。
    默认行为是将调用转发给next,但如果需要的话当然可以重写。

指标的额外方法

为了加快操作速度,指标支持一种称为 runonce 的批处理操作模式。这不是严格必需的(一个next方法就足够了),但它极大地减少了时间。

runonce 方法规则使得与索引 0 的点的获取/设置无效,并依赖于直接访问保存数据的底层数组,并为每个状态传递正确的索引。

定义的方法遵循 next 系列的命名:

  • once(self, start, end)
    在满足最小周期的条件时调用。必须在从内部数组的起始位置为零开始的 start 和 end 之间处理内部数组
  • preonce(self, start, end)
    在满足最小周期之前调用。
  • oncestart(self, start, end)
    当满足最小周期的条件时仅调用一次
    默认行为是将调用转发给once,但如果需要的话当然可以重写。

最小周期

一张图值千言,而在这种情况下可能还有一个例子。一个简单移动平均能够解释它:

class SimpleMovingAverage(Indicator):
    lines = ('sma',)
    params = dict(period=20)
    def __init__(self):
        ...  # Not relevant for the explanation
    def prenext(self):
        print('prenext:: current period:', len(self))
    def nextstart(self):
        print('nextstart:: current period:', len(self))
        # emulate default behavior ... call next
        self.next()
    def next(self):
        print('next:: current period:', len(self))

实例化可能如下所示:

sma = btind.SimpleMovingAverage(self.data, period=25)

简要解释:

  • 假设传递给移动平均的数据是标准数据源,默认周期为1,即数据源生成一个没有初始延迟的条形图。
  • 然后,**“period=25”**实例化的移动平均将按以下方式调用其方法:
  • prenext 24 次
  • nextstart 1 次(依次调用next
  • next 再次直到数据源耗尽

让我们来看一个致命的指标:另一个简单移动平均值a SimpleMovingAverage。实例化可能如下所示:

sma1 = btind.SimpleMovingAverage(self.data, period=25)
sma2 = btind.SimpleMovingAverage(sma1, period=20)

现在发生的情况是:

  • 对于sma1也是如上所述
  • sma2正在接收一个数据源,其最小周期为 25,这是我们的sma1,因此
  • sma2方法的调用方式如下:
  • prenext首次调用 25 + 18 次,总共 43 次
  • 25 次让sma1产生其第 1 个合理值。
  • 18 次累积额外的sma1
  • 总共 19 个值(在 25 次调用后再加 1 次,然后再加 18 次)
  • nextstart然后调用 1 次(轮流调用next
  • next另外调用 n 次,直到数据源耗尽

当系统已经处理了 44 个柱状时,平台会调用next

最小周期已自动调整为传入数据。

策略和指标遵循这种行为:

  • 只有当自动计算的最小周期已达到时,才会调用next(除了对nextstart的初始钩子调用)

注意。

相同的规则适用于runonce批量操作模式的preonceoncestartonce

注意。

最小周期行为可以被操纵,尽管不建议这样做。如果希望使用,在策略或指标中使用setminperiod(minperiod)方法

已启动并运行。

启动和运行至少涉及 3 个Lines对象:

  • 一个数据源
  • 一个策略(实际上是从策略派生的类)
  • 一个 Cerebro(西班牙语中的“大脑”)。

数据源

这些对象显然提供将通过应用计算(直接和/或带有指标)进行回测的数据。

该平台提供了几个数据源:

  • 几种 CSV 格式和一个通用的 CSV 阅读器
  • 雅虎在线获取器
  • 支持接收Pandas DataFramesblaze对象
  • Interacive BrokersVisual ChartOanda一起的实时数据源。

该平台不对数据源的内容(如时间段和压缩)做任何假设。这些值,连同名称,可以供信息用途和高级操作(例如数据源重采样,将例如 5 分钟数据源转换为每日数据源)。

设置 Yahoo Finance 数据源的示例:

import backtrader as bt
import backtrader.feeds as btfeeds
...
datapath = 'path/to/your/yahoo/data.csv'
data = btfeeds.YahooFinanceCSVData(
    dataname=datapath,
    reversed=True)

显示了雅虎的可选reversed参数,因为直接从雅虎下载的 CSV 文件从最新日期开始,而不是从最旧日期开始。

如果您的数据跨越了大的时间范围,则实际加载的数据可以限制如下:

data = btfeeds.YahooFinanceCSVData(
    dataname=datapath,
    reversed=True
    fromdate=datetime.datetime(2014, 1, 1),
    todate=datetime.datetime(2014, 12, 31))

如果存在,fromdatetodate都将被包含在数据源中。

如已提及的时间段、压缩和名称可添加:

data = btfeeds.YahooFinanceCSVData(
    dataname=datapath,
    reversed=True
    fromdate=datetime.datetime(2014, 1, 1),
    todate=datetime.datetime(2014, 12, 31)
    timeframe=bt.TimeFrame.Days,
    compression=1,
    name='Yahoo'
   )

如果数据已绘制,则将使用这些值。

一个策略(派生)类

注意。

在继续之前,并且为了更简化的方法,请检查文档的Signals部分,如果不希望子类化策略。

使用该平台的任何人的目标都是对数据进行回测,这是在策略(派生类)内完成的。

至少有 2 种方法需要定制:

  • __init__
  • next

在初始化过程中,对数据和其他计算进行了创建和准备,以后将应用逻辑。

稍后将调用next方法来应用每个数据条的逻辑。

注意

如果传递了不同时间框架(因此具有不同的条形计数)的数据源,则将调用next方法以获取主数据(传递给 cerebro 的第一个数据,见下文),它必须是具有较小时间框架的数据

注意

如果使用数据重播功能,则将为相同的条形进行多次调用next方法,因为条形的发展正在重播。

一个基本的派生自类的策略:

class MyStrategy(bt.Strategy):
    def __init__(self):
        self.sma = btind.SimpleMovingAverage(self.data, period=20)
    def next(self):
        if self.sma > self.data.close:
            self.buy()
        elif self.sma < self.data.close:
            self.sell()

策略具有其他方法(或挂钩点)可以重写:

class MyStrategy(bt.Strategy):
    def __init__(self):
        self.sma = btind.SimpleMovingAverage(self.data, period=20)
    def next(self):
        if self.sma > self.data.close:
            submitted_order = self.buy()
        elif self.sma < self.data.close:
            submitted_order = self.sell()
    def start(self):
        print('Backtesting is about to start')
    def stop(self):
        print('Backtesting is finished')
    def notify_order(self, order):
        print('An order new/changed/executed/canceled has been received')

startstop方法应该是不言而喻的。与预期的一样,并且遵循打印函数中的文本,当策略需要通知时,将调用notify_order方法。用例:

  • 请求购买或出售(如下所示)
    购买/出售将返回一个order,该订单将提交给经纪人。保留对此已提交订单的引用由调用者自行决定。
    例如,可以用它来确保如果订单仍未处理,则不会提交新订单。
  • 如果订单被接受/执行/取消/更改,则经纪人将通过 notify 方法将状态更改(例如执行大小)通知回策略

快速入门指南在notify_order方法中有一个完整而实用的订单管理示例。

还可以使用其他策略类做更多事情:

  • buy/sell/close
    使用底层的brokersizer向经纪人发送购买/出售订单
    也可以通过手动创建订单并将其传递给经纪人来完成相同的操作。但是该平台旨在使使用它的人更容易。
    close将获取当前的市场持仓并立即关闭它。
  • getposition(或属性“position”)
    返回当前的市场持仓
  • setsizer/getsizer(或属性“sizer”)
    这些允许设置/获取底层的 Stake Sizer。可以对提供相同情况的不同 Stake 的 Sizer 检查相同的逻辑(固定大小,与资本成比例,指数)
    有很多文献,但 Van K. Tharp 在这个领域有出色的书籍。

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

相关文章
|
6月前
|
索引
BackTrader 中文文档(六)(2)
BackTrader 中文文档(六)
87 0
|
6月前
|
Unix 索引 Python
BackTrader 中文文档(一)(2)
BackTrader 中文文档(一)
145 0
|
6月前
|
存储 编解码 API
BackTrader 中文文档(四)(1)
BackTrader 中文文档(四)
70 1
|
6月前
|
索引 Python
BackTrader 中文文档(五)(3)
BackTrader 中文文档(五)
69 0
|
6月前
|
存储 DataX Python
BackTrader 中文文档(五)(1)
BackTrader 中文文档(五)
110 0
|
6月前
|
存储 算法 索引
BackTrader 中文文档(三)(1)
BackTrader 中文文档(三)
123 0
|
6月前
|
存储 编解码 网络架构
BackTrader 中文文档(二)(4)
BackTrader 中文文档(二)
106 0
|
6月前
|
存储 数据库连接 数据库
BackTrader 中文文档(三)(2)
BackTrader 中文文档(三)
107 0
|
6月前
|
存储 C++ 索引
BackTrader 中文文档(二)(1)
BackTrader 中文文档(二)
69 0
|
6月前
|
Python
BackTrader 中文文档(六)(3)
BackTrader 中文文档(六)
84 0