BackTrader 中文文档(五)(4)

简介: BackTrader 中文文档(五)

BackTrader 中文文档(五)(3)https://developer.aliyun.com/article/1489262

缓解情况的方法如下:

class SimpleMovingAverage1(Indicator):
    lines = ('sma',)
    params = (('period', 20),)
    def __init__(self):
        self.addminperiod(self.params.period)
    def next(self):
        datasum = math.fsum(self.data.get(size=self.p.period))
        self.lines.sma[0] = datasum / self.p.period

addminperiod 方法告诉系统考虑该指标所需的额外周期柱到任何可能存在的最小周期。

有时这绝对不是必要的,如果所有计算都是使用已经向系统传达其周期需求的对象完成的。

带有直方图的快速MACD实现:

from backtrader.indicators import EMA
class MACD(Indicator):
    lines = ('macd', 'signal', 'histo',)
    params = (('period_me1', 12), ('period_me2', 26), ('period_signal', 9),)
    def __init__(self):
        me1 = EMA(self.data, period=self.p.period_me1)
        me2 = EMA(self.data, period=self.p.period_me2)
        self.l.macd = me1 - me2
        self.l.signal = EMA(self.l.macd, period=self.p.period_signal)
        self.l.histo = self.l.macd - self.l.signal

完成!不需要考虑最小周期。

  • EMA代表指数移动平均(一个平台内置的别名)
    这个(已经在平台上)已经说明了它需要什么
  • 指标“macd”和“signal”的命名线被分配了已经携带声明的对象(在幕后)周期的对象
  • macd 取自“me1 - me2”操作的周期,这又取自 me1 和 me2 的周期的最大值(它们都是具有不同周期的指数移动平均值)
  • signal 直接取 Exponential Moving Average 在 macd 上的周期。这个 EMA 还考虑了已经存在的 macd 周期和计算自身所需样本(period_signal)的数量
  • histo 取两个操作数“signal - macd”的最大值。一旦两者准备好了,histo 也可以生成一个值

一个完全定制的指标

让我们开发一个简单的自定义指标,用于“指示”移动平均线(可以通过参数进行修改)是否高于给定数据:

import backtrader as bt
import backtrader.indicators as btind
class OverUnderMovAv(bt.Indicator):
    lines = ('overunder',)
    params = dict(period=20, movav=btind.MovAv.Simple)
    def __init__(self):
        movav = self.p.movav(self.data, period=self.p.period)
        self.l.overunder = bt.Cmp(movav, self.data)

完成!如果平均值高于数据,则指标将具有“1”值,如果低于数据,则为“-1”。

如果数据是定期数据源,与收盘价进行比较会产生 1 和-1。

尽管在绘图部分可以看到更多内容,并且为了在绘图世界中表现良好,可以添加一些内容:

import backtrader as bt
import backtrader.indicators as btind
class OverUnderMovAv(bt.Indicator):
    lines = ('overunder',)
    params = dict(period=20, movav=bt.ind.MovAv.Simple)
    plotinfo = dict(
        # Add extra margins above and below the 1s and -1s
        plotymargin=0.15,
        # Plot a reference horizontal line at 1.0 and -1.0
        plothlines=[1.0, -1.0],
        # Simplify the y scale to 1.0 and -1.0
        plotyticks=[1.0, -1.0])
    # Plot the line "overunder" (the only one) with dash style
    # ls stands for linestyle and is directly passed to matplotlib
    plotlines = dict(overunder=dict(ls='--'))
    def _plotlabel(self):
        # This method returns a list of labels that will be displayed
        # behind the name of the indicator on the plot
        # The period must always be there
        plabels = [self.p.period]
        # Put only the moving average if it's not the default one
        plabels += [self.p.movav] * self.p.notdefault('movav')
        return plabels
    def __init__(self):
        movav = self.p.movav(self.data, period=self.p.period)
        self.l.overunder = bt.Cmp(movav, self.data)

指标中的混合时间框架

原文:www.backtrader.com/docu/mixing-timeframes/indicators-mixing-timeframes/

发布 1.3.0.92 带来了可能性,使不同时间框架的数据(来自数据源和/或指标)混合。

背景:指标是聪明的愚蠢对象。

  • 他们之所以聪明,是因为他们能进行复杂的计算。
  • 他们之所以愚蠢,是因为他们在没有了解提供计算数据的来源的情况下进行操作

就这样:

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

计算示例,在该示例中,data0 的时间框架为天,而 data1 的时间框架为

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

在这里寻找卖出信号当收盘价低于s1线时(1^(st) support

注意

PivotPoint的定义上在一个较大的时间框架内运行

这将导致以下错误:

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

出于一个很好的原因:self.data.close 提供了来自第一个瞬间的值,但是PivotPoint(因此s1线)只会在一个完整的月份过去后才会提供值,大致相当于self.data0.close的 22 个值。在这 22 个 收盘价 中还没有s1的值,并且尝试从底层数组中获取它失败。

Lines 对象支持 (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)

在这种模式下,指标和晚评估的自动 lines 对象是逐步执行而不是在紧密循环中执行。这使整个操作变慢,但这使其可能

上面断开的底部的示例脚本,现在可以运行:

$ ./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的第 1 个实例。

脚本还提供了对其他可能性的见解:耦合指标的所有线。之前我们有:

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

完整的耦合语法

对于具有多行的lines对象(例如Indicators,如PivotPoint):

  • obj(clockref=None, line=-1)
  • clockref 如果clockrefNone,则周围的对象(在示例中为Strategy)将是调整较大时间框架(例如:Months)到较小/更快时间框架(例如:Days)的参考
  • 如果需要,可以使用另一个参考
    line
* If the default `-1` is given, all *lines* are coupled.
* If another integer (for example, `0` or `1`) a single line will be
  coupled and fetched by index (from `obj.lines[x]`)
* If a string is passed, the line will be fetched by name.
  In the sample, the following could have been done:
  ```python
coupled_s1 = pp(line='s1')
```py` 

对于具有单行的lines对象(例如来自指标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()



相关文章
|
6月前
|
索引
BackTrader 中文文档(六)(2)
BackTrader 中文文档(六)
87 0
|
6月前
|
Unix 索引 Python
BackTrader 中文文档(一)(2)
BackTrader 中文文档(一)
156 0
|
6月前
|
存储 编解码 API
BackTrader 中文文档(四)(1)
BackTrader 中文文档(四)
71 1
|
6月前
|
存储 API 索引
BackTrader 中文文档(四)(3)
BackTrader 中文文档(四)
51 0
|
6月前
|
存储 安全 Unix
BackTrader 中文文档(四)(2)
BackTrader 中文文档(四)
57 0
|
6月前
|
Python
BackTrader 中文文档(一)(3)
BackTrader 中文文档(一)
75 0
|
6月前
|
数据可视化
BackTrader 中文文档(三)(3)
BackTrader 中文文档(三)
54 0
|
6月前
|
存储 编解码 网络架构
BackTrader 中文文档(二)(4)
BackTrader 中文文档(二)
107 0
|
6月前
BackTrader 中文文档(一)(4)
BackTrader 中文文档(一)
69 0
|
6月前
|
存储 C++ 索引
BackTrader 中文文档(二)(1)
BackTrader 中文文档(二)
70 0