8.3 User Defined Commissions

2020-04-27  本文已影响0人  wanggs66

Defining a Commission Scheme

It involves 1 or 2 steps

  1. Subclassing CommInfoBase

Simply changing the default parameters may be enough. backtrader already does this with some definitions present in the module

  1. Overriding (if needed be) the _getcommission method

    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
    '''
    

How to apply this to the platform

Once a CommInfoBase subclass is in place the trick is to use broker.addcommissioninfo rather than the usual broker.setcommission. The latter will internally use the legacy CommissionInfoObject.

Easier done than said:

...

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

The addcommissioninfo method is defined as follows:

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

Setting name means that the comminfo object will only apply to assets with that name. The default value of None means it applies to all assets in the system.

Explaining pseudoexec

The purpose of the pseudoexec arg may seem obscure but it serves a purpose.

pseudoexec indicates whether the call corresponds to the actual execution of an order. (pseudoexec 标记了某一次订单的执行是不是真正的执行,如果不是实际执行的订单,则该变量为True) Although at first sight this may not seem “relevant”, it is if scenarios like the following are considered:

In such case and if pseudoexec was not there, the multiple non-execution calls to the method would quickly trigger the assumption that the discount is in place.

Putting the scenario to work:

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
上一篇 下一篇

猜你喜欢

热点阅读