Skip to content

动态指示器

原文: https://www.backtrader.com/blog/posts/2018-02-06-dynamic-indicator/dynamic-indicator/

指标是困难的。这并不是因为它们一般很难编码,而是因为名称具有误导性,人们对指标的含义有不同的期望。

让我们尝试至少定义一下指标反向交易者生态系统中是什么。

它是定义至少一个输出的对象,可以定义影响其行为的参数,并将一个或多个数据馈送作为输入。

为了使指标尽可能通用,选择了以下设计原则:

  • 输入数据源可以是任何看起来像数据源的东西,这带来了一个直接的优势:因为其他指标看起来像数据源,所以可以将指标作为输入传递给其他指标

  • 未携带datetime线路有效载荷。这是因为输入本身可能没有要同步的datetime有效负载。与通用系统范围的datetime同步可能不正确,因为指示器可能使用每周时间段的数据,而系统时间可能在内滴答作响,因为这是几个数据源中分辨率最低的一个。

  • 操作必须是幂等的,即:如果使用相同的输入调用两次,且参数不变,则输出必须相同。

    考虑到可以要求指示器在同一时间点以相同的输入执行多次操作。虽然这似乎不需要,但如果系统支持数据重放(即:从较小的时间段实时构建较大的时间段),则需要这样做

  • 最后,指示器将其输出值写入当前时刻,即:索引0。否则将命名为StudyStudy将查找模式并写入过去的输出值。

    例如参见反向交易者社区-之字形

一旦定义(在反向交易者生态系统中)清楚了,让我们试着看看如何实际编写动态指标。我们似乎不能,因为从上述设计原则来看,指标的操作程序或多或少是不可变的。

最高的…自从…

一个通常被启动的指标是Highest(别名MaxN),以获得给定时期内最高的某物。如

import backtrader as bt

class MyStrategy(bt.Strategy)
    def __init__(self):
        self.the_highest_high_15 = bt.ind.Highest(self.data.high, period=15)

    def next(self):
        if self.the_highest_high_15 > X:
            print('ABOUT TO DO SOMETHING') 

在这个片段中,我们实例化了Highest,以跟踪过去 15 个周期的最高点。如果最高点大于X的话,就会采取行动。

这里的陷阱是:

  • period固定在15

让它充满活力

有时,我们需要指示器是动态的,并改变其行为以对实时条件作出反应。例如参见反向交易者社区中的这个问题:自持仓以来的最高点

我们当然不知道何时打开/关闭一个位置,将period设置为像15这样的固定值是没有意义的。让我们看看怎么做,把所有的东西都放在一个指示器里

动态参数

我们将首先使用在指示器寿命期间将要更改的参数,以实现动态性。

import backtrader as bt

class DynamicHighest(bt.Indicator):
    lines = ('dyn_highest',)
    params = dict(tradeopen=False)

    def next(self):
        if self.p.tradeopen:
            self.lines.dyn_highest[0] = max(self.data[0], self.dyn_highest[-1])

class MyStrategy(bt.Strategy)
    def __init__(self):
        self.dyn_highest = DynamicHighest(self.data.high)

    def notify_trade(self, trade):
        self.dyn_highest.p.tradeopen = trade.isopen

    def next(self):
        if self.dyn_highest > X:
            print('ABOUT TO DO SOMETHING') 

瞧!我们已经做到了,到目前为止,我们还没有违反为我们的指标制定的规则。让我们看看指标

  • 它定义了一个名为dyn_highest的输出

  • 它有一个参数tradeopen=False

  • (是的,它接受数据馈送,只是因为它是Indicator的子类)

  • 如果我们总是用相同的输入调用next,它将总是返回相同的值

唯一的问题是:

  • 如果参数值改变,输出也会改变(上述规则规定,只要参数不变,输出将保持不变)

我们在notify_trade中使用它来影响我们的DynamicHighest

  • 我们使用通知的trade的值isopen作为标志,以了解是否必须记录输入数据的最高点

  • trade关闭时,isopen的值将为False,我们将停止记录最高值

参考请参见:反向交易者文件交易

容易的

使用一种方法

有些人会反对修改param,因为它是指标声明的一部分,应该只在实例化期间设置。

好的,让我们来寻找一种方法。

import backtrader as bt

class DynamicHighest(bt.Indicator):
    lines = ('dyn_highest',)

    def __init__(self):
        self._tradeopen = False

    def tradeopen(self, yesno):
        self._tradeopen = yesno

    def next(self):
        if self._tradeopen:
            self.lines.dyn_highest[0] = max(self.data[0], self.dyn_highest[-1])

class MyStrategy(bt.Strategy)
    def __init__(self):
        self.dyn_highest = DynamicHighest(self.data.high)

    def notify_trade(self, trade):
        self.dyn_highest.tradeopen(trade.isopen)

    def next(self):
        if self.dyn_highest > X:
            print('ABOUT TO DO SOMETHING') 

虽然差别不大,但现在指示器有了一些额外的样板文件,其中有__init__tradeopen(self, yesno)方法。但是我们的DynamicHighest的动力学是相同的。

奖励:让我们把它变成通用的

让我们恢复params并使指示器成为一个可以应用不同功能的指示器,而不仅仅是max

import backtrader as bt

class DynamicFn(bt.Indicator):
    lines = ('dyn_highest',)
    params = dict(fn=None)

    def __init__(self):
        self._tradeopen = False
        # Safeguard for not set function
        self._fn = self.p.fn or lambda x, y: x

    def tradeopen(self, yesno):
        self._tradeopen = yesno

    def next(self):
        if self._tradeopen:
            self.lines.dyn_highest[0] = self._fn(self.data[0], self.dyn_highest[-1])

class MyStrategy(bt.Strategy)
    def __init__(self):
        self.dyn_highest = DynamicHighest(self.data.high, fn=max)

    def notify_trade(self, trade):
        self.dyn_highest.tradeopen(trade.isopen)

    def next(self):
        if self.dyn_highest > X:
            print('ABOUT TO DO SOMETHING') 

说了又做了!我们补充说:

  • params=dict(fn=None)

    收集最终用户想要使用的函数

  • 如果用户未通过特定功能,则使用占位符功能的保护措施:

    ```py

    Safeguard for not set function

    self._fn = self.p.fn or lambda x, y: x ```

  • 我们使用函数(或占位符)进行计算:

    py self.lines.dyn_highest[0] = self._fn(self.data[0], self.dyn_highest[-1])

  • 在调用我们的(现在命名的)DynamicFn指示符时说明我们想要使用哪一个函数……max(这里没有意外):

    py self.dyn_highest = DynamicHighest(self.data.high, fn=max)

今天没剩下多少了…好好享受吧!!!


我们一直在努力

apachecn/AiLearning

【布客】中文翻译组