Skip to content

过滤器

原文: https://www.backtrader.com/docu/filters/

此功能是对backtrader的较新添加,必须安装到现有内部。这使得它不是如所希望的那样灵活和 100%功能齐全,但在许多情况下它仍然可以达到目的。

尽管该实现试图允许即插即用过滤器链接,但现有的内部结构使其难以确保始终能够实现。因此,一些过滤器可能被链接,而另一些过滤器可能没有链接。

意图

  • 转换数据馈送提供的值,以传递不同的数据馈送

开始实现是为了简化两个明显过滤器的实现,这两个过滤器可以通过大脑API 直接使用。这些是:

  • 重采样cerebro.resampledata

    这里,过滤器转换传入的数据馈送timeframecompression。例如:

    py (Seconds, 1) -> (Days, 1)

    这意味着原始数据馈送是分辨率为1 秒的传送条。重采样过滤器截取数据并对其进行缓冲,直到它能够发送1 天条。当看到第二天的1 秒条时,就会发生这种情况。

  • 回放cerebro.replaydata

    对于与上述相同的时间段,过滤器将使用1 秒分辨率条重建1 天条。

    这意味着1 天条的发送次数与1 秒条的发送次数相同,更新后包含最新信息。

    例如,这模拟了实际交易日的发展过程。

    笔记

    只要没有改变,数据的长度len(data)和策略的长度就保持不变。

过滤器在工作

给定现有数据源/数据源,您使用数据源的addfilter方法:

data = MyDataFeed(dataname=myname)
data.addfilter(filter, *args, **kwargs)
cerebro.addata(data) 

即使它恰好与重采样/重放过滤器兼容,也可以执行以下操作:

data = MyDataFeed(dataname=myname)
data.addfilter(filter, *args, **kwargs)
cerebro.replaydata(data) 

过滤器接口

filter必须符合给定的接口,即:

  • 接受此签名的可调用函数:

    py callable(data, *args, **kwargs)

  • 一个可以实例化的类,称为

    • 实例化时,__init__方法必须支持签名:

    py def __init__(self, data, *args, **kwargs)

    • __call__方法具有以下签名:

    py def __call__(self, data, *args, **kwargs)

    对于来自数据馈送的每个新传入值,都将调用该实例。\*args\*kwargs传递给__init__的内容相同

    返回值

    ``py *True`: the inner data fetching loop of the data feed must retry fetching data from the feed, becaue the length of the stream was manipulated

    • False even if data may have been edited (example: changed close price), the length of the stream has remain untouched ```

    对于基于类的过滤器,可以实现 2 个附加方法

    • last签字如下:

    py def last(self, data, *args, **kwargs)

    数据馈送结束时,将调用此函数,允许筛选器传递其可能具有的数据,例如缓冲数据。典型的情况是重采样,因为在看到下一个时间段的数据之前,会缓冲一个条。当数据馈送结束时,没有新数据将缓冲数据推出。

    last提供了将缓冲数据推出的机会。

笔记

很明显,如果过滤器完全不支持参数,并且添加时不支持任何参数,那么签名可以简化为:

def __init__(self, data, *args, **kwargs) -> def __init__(self, data) 

样品过滤器

非常快速的过滤器实现:

class SessionFilter(object):
    def __init__(self, data):
        pass

    def __call__(self, data):
        if data.p.sessionstart <= data.datetime.time() <= data.p.sessionend:
            # bar is in the session
            return False  # tell outer data loop the bar can be processed

        # bar outside of the regular session times
        data.backwards()  # remove bar from data stack
        return True  # tell outer data loop to fetch a new bar 

此筛选器:

  • 使用data.p.sessionstartdata.p.sessionend(标准数据馈送参数)确定某个条是否在会话中。

  • 如果会话中的返回值为False,表示没有做任何事情,当前条的处理可以继续

  • 如果不在会话中,则从流中删除该条,True返回,表示必须提取新条。

    笔记

    data.backwards()使用LineBuffer接口。这深入挖掘了反向交易者的内部。

此过滤器的使用:

  • 一些数据源包含超出正常交易时间的数据,交易员可能对此不感兴趣。使用此过滤器时,只考虑会话中的条。

用于过滤器的数据伪 API

在上面的示例中,已经展示了过滤器如何调用data.backwards()从流中删除当前条。来自数据馈送对象的有用调用是作为过滤器的伪 API 的:

  • data.backwards(size=1, force=False):通过向后移动逻辑指针,从数据流中删除大小条(默认为1)。如果为force=True,则物理存储也会被移除。

    移除物理存储是一项微妙的操作,只意味着对内部操作的攻击。

  • data.forward(value=float('NaN'), size=1):向前移动大小栏位,根据需要增加物理存储量,并填充value

  • data._addtostack(bar, stash=False):将bar添加到堆栈中,以便后续处理。bar是一个 iterable,包含的值与lines的数据馈送值一样多。

    如果stash=False添加到堆栈中的条将在下一次迭代开始时立即被系统消耗。

    如果stash=True条将经历整个循环处理,包括可能被过滤器重新解析

  • data._save2stack(erase=False, force=False):将当前数据条保存到堆栈中,以便以后处理。如果是erase=True,则调用data.backwards并接收参数force

  • data._updatebar(bar, forward=False, ago=0):使用 iterablebar中的值覆盖数据流ago位置中的值。默认情况下ago=0将更新当前栏。使用-1,前一个。

另一个例子:粉红鱼过滤器

这是一个可以链接到另一个过滤器(即重播过滤器)的过滤器示例。粉红鱼的名字来自图书馆,它在主页上描述了这一想法:使用每日数据执行操作,而这只能通过日内数据实现。

要达到这一效果:

  • 一根每日棒将被分成两部分:OHLC

  • 这两个片段通过重播链接,在流中发生以下事件:

    py With Len X -> OHL With Len X -> OHLC With Len X + 1 -> OHL With Len X + 1 -> OHLC With Len X + 2 -> OHL With Len X + 2 -> OHLC ...

逻辑:

  • 当收到一个OHLC条时,它被复制到一个互动表中,并被分解成:

    • 酒吧。因为这个概念实际上并不存在,收盘价开盘价取代,真正形成一个OHLO条。

    • 一个C酒吧也不存在。事实是,它将像滴答声一样发出CCCC

    • 如果在两个部分之间分配,则为体积

    • 当前条将从流中删除

    • OHLO部件被放在堆栈上以便立即处理

    • CCCC部分放入仓库,以便下一轮加工

    • 因为堆栈具有即时处理功能,所以过滤器可以返回False来指示它。

此过滤器与以下部件一起工作:

  • 重播过滤器,将OHLOCCCC部分组合在一起,最终交付OHLC条。

用例:

  • 如果今天的最大值是过去 20 个交易日中的最高值,则会发出一个Close指令,该指令会在第 2个勾号的情况下执行。

守则:

class DaySplitter_Close(bt.with_metaclass(bt.MetaParams, object)):
    '''
 Splits a daily bar in two parts simulating 2 ticks which will be used to
 replay the data:

 - First tick: ``OHLX``

 The ``Close`` will be replaced by the *average* of ``Open``, ``High``
 and ``Low``

 The session opening time is used for this tick

 and

 - Second tick: ``CCCC``

 The ``Close`` price will be used for the four components of the price

 The session closing time is used for this tick

 The volume will be split amongst the 2 ticks using the parameters:

 - ``closevol`` (default: ``0.5``) The value indicate which percentage, in
 absolute terms from 0.0 to 1.0, has to be assigned to the *closing*
 tick. The rest will be assigned to the ``OHLX`` tick.

 **This filter is meant to be used together with** ``cerebro.replaydata``

 '''
    params = (
        ('closevol', 0.5),  # 0 -> 1 amount of volume to keep for close
    )

    # replaying = True

    def __init__(self, data):
        self.lastdt = None

    def __call__(self, data):
        # Make a copy of the new bar and remove it from stream
        datadt = data.datetime.date()  # keep the date

        if self.lastdt == datadt:
            return False  # skip bars that come again in the filter

        self.lastdt = datadt  # keep ref to last seen bar

        # Make a copy of current data for ohlbar
        ohlbar = [data.lines[i][0] for i in range(data.size())]
        closebar = ohlbar[:]  # Make a copy for the close

        # replace close price with o-h-l average
        ohlprice = ohlbar[data.Open] + ohlbar[data.High] + ohlbar[data.Low]
        ohlbar[data.Close] = ohlprice / 3.0

        vol = ohlbar[data.Volume]  # adjust volume
        ohlbar[data.Volume] = vohl = int(vol * (1.0 - self.p.closevol))

        oi = ohlbar[data.OpenInterest]  # adjust open interst
        ohlbar[data.OpenInterest] = 0

        # Adjust times
        dt = datetime.datetime.combine(datadt, data.p.sessionstart)
        ohlbar[data.DateTime] = data.date2num(dt)

        # Ajust closebar to generate a single tick -> close price
        closebar[data.Open] = cprice = closebar[data.Close]
        closebar[data.High] = cprice
        closebar[data.Low] = cprice
        closebar[data.Volume] = vol - vohl
        ohlbar[data.OpenInterest] = oi

        # Adjust times
        dt = datetime.datetime.combine(datadt, data.p.sessionend)
        closebar[data.DateTime] = data.date2num(dt)

        # Update stream
        data.backwards(force=True)  # remove the copied bar from stream
        data._add2stack(ohlbar)  # add ohlbar to stack
        # Add 2nd part to stash to delay processing to next round
        data._add2stack(closebar, stash=True)

        return False  # initial tick can be further processed from stack 

我们一直在努力

apachecn/AiLearning

【布客】中文翻译组