For code/output blocks: Use ``` (aka backtick or grave accent) in a single line before and after the block. See:

broker.addcommissioninfo: how to add two classes Dividends and Commision?

  • I'm testing portfolios on different markets (single or global, for example France, US). For each market I have class with commisions logic, for example:

    import backtrader as bt
    class CommIB(bt.CommInfoBase):
        params = (
            ('commission', 0.0035),
            ('stocklike', True),  # Stocks
            ('commtype', bt.CommInfoBase.COMM_FIXED),  # Apply fixed Commission
            ('min_comm', 0.35),  # USD
            ('max_comm', 0.005),
            ('on_slippage', 0.001), 
        def _getcommission(self, size, price, pseudoexec):
            commis = abs(size) * self.p.commission
            trade_value = abs(size) * price
            max_commis = trade_value * self.p.max_comm
            slipp_value = trade_value * self.p.on_slippage
            if self._commtype == self.COMM_PERC:
                return trade_value * self.p.commission
            if commis < self.p.min_comm:
                return self.p.min_comm + trade_value * self.p.on_slippage
            elif commis > max_commis:
                return max_commis + slipp_value
                return commis + slipp_value

    Also there is a unified class, that apply accrues dividends on holding shares:

    import backtrader as bt
    import numpy as np
    class Dividends(bt.CommissionInfo):
        params = (
            ('interest_long', True),
            ('path_data', '..\\Data\\DIV Data')
        def __init__(self):
            super(Dividends, self).__init__()
            self.div_data = div_loader(self.p.path_data)
        def _get_credit_interest(self, data, size, price, days, dt0, dt1):
            amount_total = 0
            if (dt1 in self.div_data.index) & (data._name in self.div_data.columns):
                amount = self.div_data.loc[dt1, data._name]
                if ~np.isnan(amount):
                    amount_total = -amount * size
                    print('Dividend found:', data._name,
                          'Held shares:', size,
                          'Price:', price,
                          # 'Days:', days,
                          'dt0,dt1:', dt0, dt1,
                          'DIV Amount:', amount,
                          'DIV Total:', -amount_total)
            return amount_total

    If to test strategy only on the US market, it's obviously, that the next syntax work's well only for the Dividend accruals, (CommIB() overriden):

    Solving of this is creating a single class with the CommIB and the Dividends logic that could works in one market (although it is inconvenient). But if to test strategy on Global market, with the different commissions for the different markets, then the task seems impossible.
    It would great if the method addcommissioninfo would supports the syntax like this (doesn't overriding instance self.comminfo[name] in every time, but adding):

        for stock in stock_list_US + stock_list_France:
  , name=stock)
        for stock in stock_list_US:
  , name=stock)
        for stock in stock_list_France:
  , name=stock)

  • Backtrader allows you to connect commission scheme to data feed. Check the docs -
    Commission schemes

  • @ab_trader yes, it's clear, thanks.

    To the question above how to use two classes CommIB and Dividends I found simple solution with inheritance like this:

    class Dividends(bt.CommissionInfo):
        params = (...)
       def _get_credit_interest(self, data, size, price, days, dt0, dt1):
          ''' some logic '''
    class CommIB_US(Dividends):
        params = (...)
        def _getcommission(self, size, price, pseudoexec):
            ''' some logic '''
    class CommIB_France(Dividends):
        params = (...)
        def _getcommission(self, size, price, pseudoexec):
            ''' some logic '''

    And then set commission scheme for each datafeed:, name=some_france_stock_feed_name)

  • The problem with this approach is around edge cases: if we buy on the ex-div date, the function will run and return dividend, even though it shouldn't. Likewise, if we sell on ex-div date the function won't run and the dividend won't be calculated.

Log in to reply