周期混合

周期混合 #

如果提供值的数据源有不同的时间框架,在 Cerebro 引擎中有不同的长度,指标将会出错。

示例计算中,data0 有天的时间框架,data1 有月的时间框架:

pivotpoint = btind.PivotPoint(self.data1)
sellsignal = self.data0.close < pivotpoint.s1

在这里,当收盘价低于 s1 线(第一个支撑)时,寻求卖出信号。

注意

PivotPoint 定义上在较大的时间框架中工作。

过去,这会导致以下错误:

return self.array[self.idx + ago]
IndexError: array index out of range

原因很简单:self.data.close 从第一个时刻提供值,但 PivotPoint(以及 s1 线)只有在整个月过去后才会提供值,这大约相当于 22 个 self.data0.close 的值。在这 22 个收盘价期间,s1 还没有值,尝试从底层数组获取它会失败。

线条对象支持 (ago) 操作符(Python 中的 __call__ 特殊方法)以提供其延迟版本:

close1 = self.data.close(-1)

在这个例子中,对象 close1(通过 [0] 访问时)始终包含由 close 提供的前一个值(-1)。此语法已被重用以适应时间框架。让我们重写上述的 pivotpoint 代码片段:

pivotpoint = btind.PivotPoint(self.data1)
sellsignal = self.data0.close < pivotpoint.s1()

请注意,() 无参数执行(在后台提供了一个 None)。正在发生以下情况:

pivotpoint.s1() 返回一个内部 LinesCoupler 对象,该对象遵循较大范围的节奏。该耦合器使用来自实际 s1 的最新提供的值填充自身(以 NaN 为默认值开始)。

但为了实现这一魔法,还需要额外的东西。Cerebro 必须这样创建:

cerebro = bt.Cerebro(runonce=False)

或这样执行:

cerebro.run(runonce=False)

在这种模式下,指标和延迟评估的自动线条对象按步执行,而不是在紧密循环中执行。这使整个操作变得更慢,但它使其成为可能。

底部的示例脚本现在可以运行:

$ ./mixing-timeframes.py

输出:

0021,0021,0001,2005-01-31,2984.75,2935.96,0.00
0022,0022,0001,2005-02-01,3008.85,2935.96,0.00
...
0073,0073,0003,2005-04-15,3013.89,3010.76,0.00
0074,0074,0003,2005-04-18,2947.79,3010.76,1.00
...

在第 74 行,第一次出现 close < s1

脚本还提供了额外的可能性:耦合一个指标的所有线条。之前是:

self.sellsignal = self.data0.close < pp.s1()

替代方法是:

pp1 = pp()
self.sellsignal = self.data0.close < pp1.s1

现在整个 PivotPoint 指标已被耦合,并且可以访问其任何线条(即 p、r1、r2、s1、s2)。脚本只对 s1 感兴趣,访问是直接的:

$ ./mixing-timeframes.py --multi

输出:

0021,0021,0001,2005-01-31,2984.75,2935.96,0.00
0022,0022,0001,2005-02-01,3008.85,2935.96,0.00
...
0073,0073,0003,2005-04-15,3013.89,3010.76,0.00
0074,0074,0003,2005-04-18,2947.79,3010.76,1.00
...

这里没有意外。与之前相同。“耦合”对象甚至可以绘制:

$ ./mixing-timeframes.py --multi --plot

完整耦合语法 #

对于具有多条线的线条对象(例如 PivotPoint 指标):

obj(clockref=None, line=-1)

clockref:如果 clockrefNone,则周围对象(例如策略)将作为参考,以适应较大时间框架(例如:月)到较小/更快的时间框架(例如:日)。如果需要,可以使用另一个参考。

line

  • 如果默认的 -1 被给定,则所有线条都被耦合。
  • 如果是另一个整数(例如 01),则单条线将被耦合,并通过索引(来自 obj.lines[x])获取。
  • 如果传递了字符串,则按名称获取线条。

在示例中,可以这样做:

coupled_s1 = pp(line='s1')

对于只有一条线的线条对象(例如来自 PivotPoint 指标的 s1 线):

obj(clockref=None)见上文的 `clockref`)

结论 #

在常规的 () 语法中,来自不同时间框架的数据源可以混合在指标中,始终考虑到 cerebro 需要使用 runonce=False 实例化或创建。

脚本代码和用法 #

可以在 backtrader 的源代码中找到示例。用法:

$ ./mixing-timeframes.py --help
usage: mixing-timeframes.py [-h] [--data DATA] [--multi] [--plot]

Sample for pivot point and cross plotting

optional arguments:
  -h, --help   show this help message and exit
  --data DATA  Data to be read in (default: ../../datas/2005-2006-day-001.txt)
  --multi      Couple all lines of the indicator (default: False)
  --plot       Plot the result (default: False)

代码:

from __future__ import (absolute_import, division, print_function,
                        unicode_literals)

import argparse

import backtrader as bt
import backtrader.feeds as btfeeds
import backtrader.indicators as btind
import backtrader.utils.flushfile


class St(bt.Strategy):
    params = dict(multi=True)

    def __init__(self):
        self.pp = pp = btind.PivotPoint(self.data1)
        pp.plotinfo.plot = False  # deactivate plotting

        if self.p.multi:
            pp1 = pp()  # couple the entire indicators
            self.sellsignal = self.data0.close < pp1.s1
        else:
            self.sellsignal = self.data0.close < pp.s1()

    def next(self):
        txt = ','.join(
            ['%04d' % len(self),
             '%04d' % len(self.data0),
             '%04d' % len(self.data1),
             self.data.datetime.date(0).isoformat(),
             '%.2f' % self.data0.close[0],
             '%.2f' % self.pp.s1[0],
             '%.2f' % self.sellsignal[0]])

        print(txt)


def runstrat():
    args = parse_args()

    cerebro = bt.Cerebro()
    data = btfeeds.BacktraderCSVData(dataname=args.data)
    cerebro.adddata(data)
    cerebro.resampledata(data, timeframe=bt.TimeFrame.Months)

    cerebro.addstrategy(St, multi=args.multi)

    cerebro.run(stdstats=False, runonce=False)
    if args.plot:
        cerebro.plot(style='bar')


def parse_args():
    parser = argparse.ArgumentParser(
        formatter_class=argparse.ArgumentDefaultsHelpFormatter,
        description='Sample for pivot point and cross plotting')

    parser.add_argument('--data', required=False,
                        default='../../datas/2005-2006-day-001.txt',
                        help='Data to be read in')

    parser.add_argument('--multi', required=False, action='store_true',
                        help='Couple all lines of the indicator')

    parser.add_argument('--plot', required=False, action='store_true

',
                        help=('Plot the result'))

    return parser.parse_args()


if __name__ == '__main__':
    runstrat()

希望这能帮助你理解如何在 backtrader 中混合不同时间框架的数据!