Backtrader动态指针

  |  

指针是困难的野兽。不是因为它们通常难以编码,而是主要是因为名称具有误导性,并且人们对指针是什么有不同的期望。

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

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

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

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

  • 不携带datetime时间有效负载。之所以如此,是因为输入本身可能没有要同步的datetime时间有效负载。与一般系统范围的datetime时间同步可能是不正确的,因为该指针可能使用每周时间范围内的数据,而系统时间可能以秒为单位,因为这是几个数据馈送中最低的分辨率之一。

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

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

  • 最后:指针将其输出值写入当前时刻,即:索引0 。如果不是,它将命名为Study 。一项Study将寻找模式并写入过去的输出值。

    例如,参见Backtrader社区 - ZigZag

一旦定义(在反向交易者生态系统中)明确,让我们尝试看看我们如何实际编写动态指针。看起来我们不能,因为从前面提到的设计原则来看,指针的操作过程或多或少是……不可变的。

最高的……因为……

通常启动的一个指针是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

让它充满活力

有时,我们需要指针是动态的并改变其行为以对实时条件做出反应。例如,请参阅backtrader社区中的这个问题: Highest high since position was open

我们当然不知道何时开仓/平仓,将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 ,我们将停止记录最高值

如需参考,请参阅: Backtrader文档交易

简单的!!!

使用方法

有些人会反对修改作为指针声明一部分的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)

    收集最终用户想要使用的功能

  • 如果用户未传递特定函数,则使用占位符函数的保护措施:

    # Safeguard for not set function
    self._fn = self.p.fn or lambda x, y: x
    
  • 我们使用函数(或占位符)进行计算:

    self.lines.dyn_highest[0] = self._fn(self.data[0], self.dyn_highest[-1])
    
  • 在调用我们的(现在命名的) DynamicFn指针时说明我们想要使用哪个函数…… max (这里没有意外):

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

今天所剩无几……尽情享受吧!!!

推荐阅读

相关文章

Backtrader改进代码

时不时地,带有 backtrader 代码的示例会在互联网上弹出。在我看来,有几个是中国人。最新的一个在这里: 标题是: backtrader-学习笔记2,这显然(感谢谷歌)翻译成 backtrader- 学习笔记2。

Backtrader教程:仓位

资产的头寸通常从策略中检查: position (财产)或 getposition(data=None, broker=None) 这将返回策略在默认broker状态下datas[0]的位置,由cerebro 仓位只是指示: 资产被持有size 平均价格price 它作为一种状态,

Backtrader 教程:绘图 - 同一轴

上一篇future-spot 将原始数据和稍微(随机)修改的数据绘制在同一空间上,但不在同一轴上。从该帖子中恢复第一张图片。有人能看见:图表左右两侧有不同的刻度当查看在原始数据周围振荡+- 50点的摆动红线(随机数据)时,这一点最为明显。在图表上,视觉印像是这些随机数据大多总是高于原始数据。

Backtrader同步不同市场

使用次数越多, backtrader 必须面对的想法和意外场景的混合就越多。对于每个新平台,一个挑战是要看看平台是否能够达到开发开始时设置的期望,灵活性和易用性是目标,Python被选为基石。 工单#76 提出了一个问题,即是否可以完成具有不同交易日历的同步市场。

Backtrader股票筛选

在寻找其他一些东西时,我在StackOverlow家族网站之一上遇到了一个问题:Quantitative Finance aka Quant StackExchange。问题: 它被标记为Python,因此值得一看的是 backtrader 是否能够胜任这项任务。 分析仪本身 该问题似乎适合用于简单的分析器。

Backtrader迪克森移动平均线

下面的reddit帖子以自己的作者Nathan Dickson(reddit句柄)命名了这个平均值Dickson移动平均线。 在一次对reddit Algotrading 的定期访问中,我发现了一篇关于移动平均线的帖子,该移动平均线试图模仿Jurik移动平均线(又名JMA)。

Backtrader教程:经纪商

经纪商仿真器该模拟支持不同的订单类型,根据当前现金检查提交的订单现金需求,跟踪每次反复运算的cerebro 现金和价值,并在不同数据上保持当前位置。

Backtrader 教程:Cerebro - 节省内存

版本 1.3.1.92重新设计并完全实现了以前存在的内存节省方案,尽管没有太多吹捧和较少使用。 backtrader是(并将进一步)在具有大量 RAM 的机器上开发的,再加上通过绘图的视觉反馈是一个很好的拥有并且几乎是必须拥有的事实,mde 很容易做出设计决策:保留所有内容记忆。

Backtrader多重交易

即使在相同的数据上运行,现在也可以为每笔交易添加唯一标识符。根据Tick Data and Resampling 版本backtrader的请求,支持“MultiTrades”,即:为订单分配tradeid的能力。此 id 被传递给Trades ,这使得有可能拥有不同类别的交易并同时打开它们。

Backtrader开发指针

经过 backtrader 微调(因为它已经运行了一段时间),我决定不仅通过GitHub分享它,还告诉世界它在那里,并在“Reddit”中发布它的存在。 在评论了为什么交易/算法交易平台会弹出,以及关于支持许多同时交易的即时交易的平台的私人问题之后,我得出的结论是,我自己的孩子应该拥有自己的博客。 我们来了。