Backtrader 教程:佣金计划 - 自定义计划

  |  

将 CommInfo 对象改造成实际涉及的最重要的部分:

  • 保留原来的CommissionInfo类和行为

  • 为轻松创建用户定义的佣金打开大门

  • 使格式 xx% 成为新佣金方案的默认值,而不是 0.xx(只是个人喜好问题),保持行为可配置

笔记

请参阅下面的CommInfoBase文档字符串以获取参数参考

定义佣金计划

它涉及 1 或 2 个步骤

  1. 子类CommInfoBase

    只需更改默认参数就足够了。 backtrader已经使用模块backtrader .commissions中的一些定义来做到这一点。期货的常规行业标准是每份合约和每轮固定金额。定义可以如下:

    class CommInfo_Futures_Fixed(CommInfoBase):
        params = (
            ('stocklike', False),
            ('commtype', CommInfoBase.COMM_FIXED),
        )
    

    对于股票和 perc-wise 佣金:

    class CommInfo_Stocks_Perc(CommInfoBase):
        params = (
            ('stocklike', True),
            ('commtype', CommInfoBase.COMM_PERC),
        )
    

    如上所述,此处解释百分比的默认值(作为参数commission传递)是: xx% 。如果希望旧的/其他行为0.xx ,可以轻松完成:

    class CommInfo_Stocks_PercAbs(CommInfoBase):
        params = (
            ('stocklike', True),
            ('commtype', CommInfoBase.COMM_PERC),
            ('percabs', True),
        )
    
  2. 覆盖(如果需要) _getcommission方法

    定义为:

    def _getcommission(self, size, price, pseudoexec):
       '''Calculates the commission of an operation at a given price
    
       pseudoexec: if True the operation has not yet been executed
       '''
    

    下面的实际示例中的更多详细信息

如何将此应用到平台

一旦CommInfoBase子类就位,诀窍就是使用broker.addcommissioninfo而不是通常的broker.setcommission 。后者将在内部使用旧的CommissionInfoObject

做起来比说的容易:

...

comminfo = CommInfo_Stocks_PercAbs(commission=0.005)  # 0.5%
cerebro.broker.addcommissioninfo(comminfo)

addcommissioninfo方法定义如下:

def addcommissioninfo(self, comminfo, name=None):
    self.comminfo[name] = comminfo

设置name意味着comminfo对象将仅适用于具有该名称的资产。默认值None意味着它适用于系统中的所有资产。

一个实际的例子

Ticket #45询问适用于期货的佣金计划,以百分比计算,并使用合约的整个“虚拟”价值的佣金百分比。即:在佣金计算中包括未来乘数。

这应该很容易:

import backtrader as bt

class CommInfo_Fut_Perc_Mult(bt.CommInfoBase):
    params = (
      ('stocklike', False),  # Futures
      ('commtype', bt.CommInfoBase.COMM_PERC),  # Apply % Commission
    # ('percabs', False),  # pass perc as xx% which is the default
    )

    def _getcommission(self, size, price, pseudoexec):
        return size * price * self.p.commission * self.p.mult

将其放入系统:

comminfo = CommInfo_Fut_Perc_Mult(
    commission=0.1,  # 0.1%
    mult=10,
    margin=2000  # Margin is needed for futures-like instruments
)

cerebro.addcommissioninfo(comminfo)

如果首选格式0.xx作为默认值,只需将 param percabs设置为True

class CommInfo_Fut_Perc_Mult(bt.CommInfoBase):
    params = (
      ('stocklike', False),  # Futures
      ('commtype', bt.CommInfoBase.COMM_PERC),  # Apply % Commission
      ('percabs', True),  # pass perc as 0.xx
    )

comminfo = CommInfo_Fut_Perc_Mult(
    commission=0.001,  # 0.1%
    mult=10,
    margin=2000  # Margin is needed for futures-like instruments
)

cerebro.addcommissioninfo(comminfo)

这一切都应该解决问题。

解释pseudoexec

让我们回顾一下_getcommission的定义:

def _getcommission(self, size, price, pseudoexec):
    '''Calculates the commission of an operation at a given price

    pseudoexec: if True the operation has not yet been executed
    '''

pseudoexec arg 的目的可能看起来晦涩难懂,但它是有目的的。

  • 平台可能会调用该方法来进行可用现金的预计算和一些其他任务

  • 这意味着该方法可能(并且实际上会)使用相同的参数多次调用

pseudoexec指示调用是否对应于订单的实际运行。尽管乍一看这似乎并不“相关”,但如果考虑到以下情况:

  • 一旦谈判合约数量超过5000个单位,经纪人提供期货往返佣金50%的折扣

    在这种情况下,如果没有pseudoexec ,对该方法的多次非运行调用将很快触发折扣到位的假设。

让场景发挥作用:

import backtrader as bt

class CommInfo_Fut_Discount(bt.CommInfoBase):
    params = (
      ('stocklike', False),  # Futures
      ('commtype', bt.CommInfoBase.COMM_FIXED),  # Apply Commission

      # Custom params for the discount
      ('discount_volume', 5000),  # minimum contracts to achieve discount
      ('discount_perc', 50.0),  # 50.0% discount
    )

    negotiated_volume = 0  # attribute to keep track of the actual volume

    def _getcommission(self, size, price, pseudoexec):
        if self.negotiated_volume > self.p.discount_volume:
           actual_discount = self.p.discount_perc / 100.0
        else:
           actual_discount = 0.0

        commission = self.p.commission * (1.0 - actual_discount)
        commvalue = size * price * commission

        if not pseudoexec:
           # keep track of actual real executed size for future discounts
           self.negotiated_volume += size

        return commvalue

pseudoexec的目的和存在现在希望很清楚。

CommInfoBase 文档字符串和参数

请参阅佣金:股票与期货以供CommInfoBase参考

推荐阅读

相关文章

Backtrader砖块

Renko Bricks 是呈现价格演变的另一种方式,其中价格比时间发挥更重要的作用。这已在1.9.54.122的1.9.54.122版本中作为过滤器引入Stockcharts 对 Renko Bricks 有很好的参考。

Backtrader教程:观察者 - 参考

基准 backtrader类 .observers.基准() 此 observer 存储策略的回报和参考资产的回报,参考资产是传递到系统的数据之一。

BacktraderMFI 通用

在最近的Canonical vs Non-Canonical 帖子中 MFI ,开发了(aka MoneyFlowIndicator)。 尽管它是以规范的方式开发的,但它仍然提供了一些改进和成为通用的空间。

Backtrader同步不同市场

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

Backtrader回溯

在一些关于改进的ShapeRatio的提示之后, backtrader 已将此分析仪添加到其武器库中。 文献位于: 从对数回报的好处开始,并遵循在SharpeRatio方程的分母中具有标准偏差的副作用,本文档开发了该分析仪的公式和期望。

Backtrader教程:绘图 - 日期范围

该版本1.9.31.x 增加了制作部分绘图的功能。 使用策略实例中保存的完整时间戳数组的索引 或者使用实际datetime.date 或 datetime.datetime 实例来限制必须绘制的内容。 一切都超过标准cerebro.plot。

Backtrader动态指针

指针是困难的野兽。不是因为它们通常难以编码,而是主要是因为名称具有误导性,并且人们对指针是什么有不同的期望。让我们尝试至少定义什么是反向交易者生态系统中的指针。它是一个定义至少一个输出行的对象,可以定义影响其行为的参数,并将一个或多个数据馈送作为输入。

Backtrader开场作弊

“发布”1.9.44.116 添加了对 Cheat-On-Open的支持。这似乎是那些全力以赴的人的需求功能,他们在酒吧 close 后进行了计算,但希望与 open 价格相匹配。 当开盘价跳空(上涨或下跌,取决于是否buysell有效)并且现金不足以进行全面运营时,这样的用例就会失败。这将强制代理拒绝该操作。

Backtrader教程:数据馈送 - 熊猫

注意 pandas 并且必须安装其依赖项 支持Pandas Dataframes似乎受到很多人的关注,他们依赖于已经可用的解析代码来分析不同的数据源(包括CSV)和Pandas提供的其他功能。 数据馈送的重要声明。 注意 这些只是 声明。不要盲目拷贝此代码。

Backtrader动量策略

在另一篇伟大的文章中,泰迪·科克(Teddy Koker)再次展示了算法交易策略的发展之路: 研究优先应用 pandas 回溯测试,然后使用 backtrader 荣誉!!! 该帖子可以在以下位置找到: 泰迪·科克(Teddy Koker)给我留言,问我是否可以评论 backtrader的用法。