get_leverage() calls



  • Hello,
    Just wondering what logic is for the following get_leverage call:

    self.broker.get_leverage()

    To get the actual allowed leverage, I understand that the documentation states I should use self.broker.getcommissioninfo(self.data).get_leverage() and it will return the maximum allowed leverage from the commission scheme used on the data provided.

    https://www.backtrader.com/docu/commission-schemes/commission-schemes.html#backtrader.CommissionInfo.get_leverage

    However, self.broker.get_leverage() appears to be doing a different calculation and I would just like to verify what it should be doing. I did not see this call listed in the broker reference. This makes me wonder whether it is officially supported or perhaps documented elsewhere?

    https://www.backtrader.com/docu/broker.html

    Below is some output from the terminal during each next() call when I am in a position. I am setup to use 50:1 leverage and trading EUR/USD on a daily timeframe.

    broker.get_leverage:               145.19184069936887
    getcomissioninfo.get_leverage:     50
    broker.get_leverage:               178.6195034400227
    getcomissioninfo.get_leverage:     50
    broker.get_leverage:               474.8882681564292
    getcomissioninfo.get_leverage:     50
    broker.get_leverage:               327.1642405932362
    getcomissioninfo.get_leverage:     50
    broker.get_leverage:               208.94326737873922
    getcomissioninfo.get_leverage:     50
    broker.get_leverage:               157.34070563454415
    getcomissioninfo.get_leverage:     50
    broker.get_leverage:               132.42585214696592
    getcomissioninfo.get_leverage:     50
    

    and the next() call:

        def next(self):
            bar = len(self.data)
            #print(bar)
            com = self.broker.getcommissioninfo(self.data).get_leverage()
            print('broker.get_leverage:               {}'.format(self.broker.get_leverage()))
            print('getcomissioninfo.get_leverage:     {}'.format(com))
    

    Note: This is not blocking anything for me, I am just curious and would like a better understanding. No rush to reply.


  • administrators

    @ThatBlokeDave said in get_leverage() calls:

    To get the actual allowed leverage, I understand that the documentation states I should use self.broker.getcommissioninfo(self.data).get_leverage() and it will return the maximum allowed leverage from the commission scheme used on the data provided.

    A pointer to the part in the docs that state the that you should use self.broker.getcommissioninfo(self.data).get_leverage() would be welcome. Because it shouldn't be so. The method is meant for usage inside the broker. Unless you subclass the scheme, that method will return whatever you have used during instantiation.

    @ThatBlokeDave said in get_leverage() calls:

    However, self.broker.get_leverage() appears to be doing a different calculation

    It's not a different calculation. It's different altogether. Invoking that method, which is intended for user consumption unlike the one above, reports the actual leverage level in the market.

    Seeing the output some initial thoughts:

    • There is a bug in the calculation
    • You are using a multiplier

    But with just the printouts and no background it's difficult to make any kind of diagnosis.



  • A pointer to the part in the docs that state the that you should use self.broker.getcommissioninfo(self.data).get_leverage() would be welcome.

    I did provide a pointer... Possibly the docs have been misinterpreted. Simply I wanted to get the leverage used within a strategy and found the line:

    Returns the level of leverage allowed for this comission scheme

    This seemed perfect for my needs and returns the value I wanted.

    I am not setting any multiplier. This is actually linked to my question about Margin close outs the other day. I am trying to see if I can implement it in the strategy.

    It is a work in progress but I will post it below.... I still need to come up with a good way of accounting for applying the correct margin when the base account is not the same as the currency in which the instrument is denominated in. I.e I need to account for a currency exchange.

    import backtrader as bt
    from datetime import datetime
    
    
    class MarginCO(bt.Strategy):
        '''
        This strategy contains some additional methods that can be used to calcuate
        whether a position should be subject to a margin close out from Oanda.
        '''
        def check_mco(self, value, margin_used):
            '''
            Make a check to see if the margin close out value has fallen below half
            of the margin used, close the position.
    
            value: value of the portfolio for a given data. This is essentially the
            same as the margin close out value which is balance + pnl
            margin_used: Initial margin
            '''
    
            if value < (margin_used /2):
                close = self.close()
                close.addinfo(name='MCO')
            else:
                return
    
        def notify_order(self,order):
    
            if order.status == order.Completed:
                ep = order.executed.price
                es = order.executed.size
                tv = ep * es
                leverage = self.broker.getcommissioninfo(self.data).get_leverage()
                self.margin = (ep * es) / leverage
                if 'name' in order.info:
                    if order.info['name'] == 'Entry':
                        print('{}: Entry Order Completed '.format(self.dt))
                        print('{}: Order Executed Price: {}, Executed Size {}'.format(self.dt,ep,es,))
                        print('{}: Position Value: {} Margin Used: {}'.format(self.dt,tv,self.margin))
                    elif order.info['name'] == 'MCO':
                        print('{}: WARNING: Margin Close Out'.format(self.dt))
                    else:
                        print('{}: Close Order Completed'.format(self.dt))
    
    
    class Mltests(MarginCO):
        params = (('size', 10000),)
    
        def __init__(self):
            self.count = 0
            self.buybars = [1, 150]
            self.closebars = [100, 250]
    
        def next(self):
            bar = len(self.data)
            self.dt = self.data.datetime.date()
            ex_rate = self.datas[1].close[0]
            com = self.broker.getcommissioninfo(self.data).get_leverage()
            print('broker.get_leverage:               {}'.format(self.broker.get_leverage()))
            print('getcomissioninfo.get_leverage:     {}'.format(com))
            print('{} Close: {}'.format(self.datas[1]._name, ex_rate))
            if not self.position:
                if bar in self.buybars:
                    entry = self.buy(size=self.p.size)
                    entry.addinfo(name='Entry')
            else:
                self.check_mco(value=self.broker.get_value(), margin_used=self.margin)
                if bar in self.closebars:
                    close = self.close()
                    close.addinfo(name='Close')
    
            self.count += 1
    
        def notify_trade(self, trade):
            if trade.isclosed:
                print('{}: Trade closed '.format(self.dt))
                print('{}: PnL Gross {}, Net {}\n\n'.format(self.dt,
                                                    round(trade.pnl,2),
                                                    round(trade.pnlcomm,2)))
    
    
    
    class OandaCSVData(bt.feeds.GenericCSVData):
        params = (
            ('nullvalue', float('NaN')),
            ('dtformat', '%Y-%m-%dT%H:%M:%S.%fZ'),
            ('datetime', 6),
            ('time', -1),
            ('open', 5),
            ('high', 3),
            ('low', 4),
            ('close', 1),
            ('volume', 7),
            ('openinterest', -1),
        )
    
    
    
    tframes = dict(
        minutes=bt.TimeFrame.Minutes,
        daily=bt.TimeFrame.Days,
        weekly=bt.TimeFrame.Weeks,
        monthly=bt.TimeFrame.Months)
    
    
    #Variable for our starting cash
    startcash = 10000
    
    #Create an instance of cerebro
    cerebro = bt.Cerebro()
    
    #Set commission
    cerebro.broker.setcommission(leverage=50)
    
    #Add our strategy
    cerebro.addstrategy(Mltests)
    
    #get oanda data
    data = OandaCSVData(
        dataname='data/EUR_USD-2005-2017-D1.csv',
        romdate=datetime(2005,1,1),
        todate=datetime(2006,1,1))
    
    data1 = OandaCSVData(
        dataname='data/EUR_GBP-2005-2017-D1.csv',
        romdate=datetime(2005,1,1),
        todate=datetime(2006,1,1))
    
    #Add the data to Cerebro
    cerebro.adddata(data, name='inst')
    cerebro.adddata(data1, name='ex_rate') #exchange rate for GBP to EUR
    # Set our desired cash start
    cerebro.broker.setcash(startcash)
    
    # Run over everything
    cerebro.run()
    
    
    portvalue = cerebro.broker.getvalue()
    pnl = portvalue - startcash
    
    print('Final Portfolio Value: ${}'.format(portvalue))
    print('P/L: ${}'.format(pnl))
    
    #Finally plot the end results
    cerebro.plot(style='candlestick')
    

  • administrators

    The pointer is to the reference of the class which can be overridden CommInfoBase. It doesn't say that you get your actual leverage from that call nor that this is meant for user consumption. That class provides an interface which is used by the broker, not by the end user.

    Of course you may override it and call it if it serves your purpose.



  • Ok thanks.

    Sure, since I am trying to simulate a margin close out, I think this serves a good purpose as I can use this to work out the initial margin required for a position.


Log in to reply
 

Looks like your connection to Backtrader Community was lost, please wait while we try to reconnect.