美文网首页
8.3 User Defined Commissions

8.3 User Defined Commissions

作者: wanggs66 | 来源:发表于2020-04-27 23:20 被阅读0次

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.

  • The platform may call this method to do precalculation of available cash and some other tasks

  • This means that the method may (and it actually will) be called more than once with the same parameters

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:

  • A broker offers a 50% discount on futures round-trip commission once the amount of negotiated contracts has exceeeded 5000 units

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

相关文章

网友评论

      本文标题:8.3 User Defined Commissions

      本文链接:https://www.haomeiwen.com/subject/yhvpwhtx.html