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

Notify_trade: trade.size is zero at trade closed



  • Hey All,

    I've added a new sizer to enable partial contracts to buy based on cash available (crypto space). Algo seems to work fine except that at closed trades the trade.size is printed as zero.
    Any thoughts on the reason of this behaviour?
    How could I easily get the given trade's quantity, price data?

    Thanks a lot

    here're the main elements:

    class maxRiskSizer(bt.Sizer):
        params = (('risk', 1),)
     
        def __init__(self):
            if self.p.risk > 1 or self.p.risk < 0:
                raise ValueError('Risk parameter is not ok!')
     
        def _getsizing(self, comminfo, cash, data, isbuy):
            if isbuy == True:
                size = (cash * self.p.risk) / data[0]
            else:
                size = ((cash * self.p.risk) / data[0]) * -1
            return size
    
    class SmaCross(bt.Strategy):
    ...
            def notify_trade(self, trade):
                if trade.justopened:
                    print('----TRADE OPENED----')
                    print('Size: {:.3f}, value: {:.3f}'.format(trade.size, trade.value))
                elif trade.isclosed:
                    print('----TRADE CLOSED----')
                    print('Profit: {} Gross {}, Net {}'.format(trade.size, round(trade.pnl,2), round(trade.pnlcomm,2)))
                else:
                    return
    

    This gives the following output:

    ----TRADE OPENED----
    Size: 0.670, value: 9997.320
    ----TRADE CLOSED----
    Profit: 0.0 Gross 361.16, Net 361.16
    ----TRADE OPENED----
    Size: 0.728, value: 10361.163
    ----TRADE CLOSED----
    Profit: 0.0 Gross -802.0, Net -802.0
    ----TRADE OPENED----
    Size: 0.688, value: 9557.100
    ...
    


  • Seems logical: trade already closed, all sold or covered, now size is equal zero. Why it should be different?

    If you want to keep size of the trade after it is closed, then keep size from trade.openevent. If you are changing trade size, then work with the appropriate orders data - Orders. Or track position size during trading - Position.


  • administrators

    @julianus said in Notify_trade: trade.size is zero at trade closed:

    Any thoughts on the reason of this behaviour?

    @ab_trader said in Notify_trade: trade.size is zero at trade closed:

    If you are changing trade size

    The answer by @ab_trader is already pointing out the reason: the size of a trade can change. It would seem that you think a trade is made up solely of a single order, but a Trade can have many different sizes from its birth until it dies.

    See this simple example:

    • You open a long trade with size 10
    • You sell to reduce the size to 5
    • You buy to increase size to 25
    • You sell to close the trade (size is 0) and you actually sell so much with a single order, that you actually open a 2nd (new) trade with size -5

    See Docs - Trade



  • @ab_trader, @backtrader thanks.
    What's strange is that other trade subclasses (trade.pnl, trade.pnlcomm) give the correct figure, while trade.value did not at the same call. Or these are handled differently by bt?



  • In your code different outputs are called for tradejust.opened state and trade.isclosed state. So it is impossible to compare outputs for trade.value, trade.pnl and trade.pnlcomm for different trade states. Not sure how you did it, probably used another code. Only trade.size appeared in both states, but it is named as Profit (why?) second time.

    I am more than sure that bt returns correct figures every time, but it is difficult to check correctly due to some inconsistency in the code.


  • administrators

    @julianus said in Notify_trade: trade.size is zero at trade closed:

    while trade.value did not at the same call

    What is wrong with trade.value? You print it once and it shows the value. What are you expecting?

    You a printing "Profit: {}" and using trade.size for it. That's for sure giving the wrong idea when one is reading the output.

    @julianus said in Notify_trade: trade.size is zero at trade closed:

    What's strange is that other trade subclasses (trade.pnl, trade.pnlcomm)

    Those are NOT subclasses. They are attributes (call them values if you wish)



  • @backtrader, @ab_trader, thanks for the prompt answer.
    I've cleaned the code a little, unfortunately zero still appears ('Profit' stuck there incorrectly during my tries, should've been switched like below).

    Full code:

    from collections import OrderedDict
    
    class maxRiskSizer(bt.Sizer):
        params = (('risk', 1),)
     
        def __init__(self):
            if self.p.risk > 1 or self.p.risk < 0:
                raise ValueError('Risk parameter is not ok!')
     
        def _getsizing(self, comminfo, cash, data, isbuy):
            if isbuy == True:
                size = (cash * self.p.risk) / data[0]
            else:
                size = ((cash * self.p.risk) / data[0]) * -1
            return size
    
    class SmaCross(bt.Strategy):
            params = (
                ('pfast', 15),
                ('pslow', 100),
                ('printlog', False),
            )
        
            def log(self, txt, dt=None):
                ''' Logging function fot this strategy'''
                dt = dt or self.datas[0].datetime.datetime(0)
                print('%s, %s' % (dt.isoformat(), txt))
    
            def __init__(self):
                self.dataclose = self.datas[0].close
                
                self.order = None
                self.buyprice = None
                self.buycomm = None
                
                self.sma1 = bt.ind.SimpleMovingAverage(self.data.close, period=self.params.pfast)
                self.sma2 = bt.ind.SimpleMovingAverage(self.data.close, period=self.params.pslow)
                self.Cross = bt.ind.CrossOver(self.sma1, self.sma2)
            
            def next(self):
                if self.order:
                    return
                
                if not self.position:
                    if self.Cross and pd.notna(self.sma1[0] and self.sma2[0]):
                        self.buy()
                        
                else:
                    if self.Cross == -1:
                        self.close()
                        
            def notify_trade(self, trade):
                if trade.justopened:
                    print('----TRADE OPENED----')
                    print('Size: {:.3f}, value: {:.3f}'.format(trade.size, trade.value))
                elif trade.isclosed:
                    print('----TRADE CLOSED----')
                    print('Size: {:.3f} Profit: Gross {:.3f}, Net {:.3f}'.format(trade.size, trade.pnl, trade.pnlcomm))
                else:
                    return
                
    
    if __name__ == '__main__':
        
        startcash = 10000
        
        cerebro = bt.Cerebro()
        
        cerebro.addstrategy(SmaCross)
    
        modpath = os.path.dirname('D:\\_projectPy\\')
        datapath = os.path.join(modpath, 'test4.csv')
    
        data = bt.feeds.GenericCSVData(
            dataname=datapath,
            timeframe=bt.TimeFrame.Minutes, compression=60,
            datetime=0,
            open = 1,
            high = 3,
            low = 4,
            close = 2,
            volume = 5,
            openinterest = -1,
            fromdate = datetime(2018, 1, 1, 1, 0, 1),
            todate = datetime(2018, 1, 20, 0, 0, 1),
            separator=',',
            dtformat=('%Y-%m-%d %H:%M:%S')
            )
    
        cerebro.adddata(data)
        
        cerebro.broker.setcash(startcash)
        
        cerebro.addsizer(maxRiskSizer, risk=1)
        
        strategies = cerebro.run(maxcpus=1)
    

    Output:

    ----TRADE OPENED----
    Size: 0.670, value: 9997.320
    ----TRADE CLOSED----
    Size: 0.000 Profit: Gross 361.163, Net 361.163
    ----TRADE OPENED----
    Size: 0.728, value: 10361.163
    ----TRADE CLOSED----
    Size: 0.000 Profit: Gross -801.999, Net -801.999
    ----TRADE OPENED----
    Size: 0.688, value: 9557.100
    ----TRADE CLOSED----
    Size: 0.000 Profit: Gross -496.562, Net -496.562
    

  • administrators

    @julianus said in Notify_trade: trade.size is zero at trade closed:

    unfortunately zero still appears

    And it will always appear. As stated above by @ab_trader and myself: when the trade is closed, it is closed because the size is 0.

    You may want to re-elaborate what your problem actually is and what you are missing, because right not it is unclear.



  • @backtrader, ok thanks understood.
    I asked this one as the second question in my initial post:
    "How could I easily get the given trade's quantity, price data?"


  • administrators

    @ab_trader said in Notify_trade: trade.size is zero at trade closed:

    If you want to keep size of the trade after it is closed, then keep size from trade.open event. If you are changing trade size, then work with the appropriate orders data - Orders. Or track position size during trading - Position.



  • @backtrader, ok.

    I'm going to deep-dive in the platform once again from the beginning, so then hopefully those questions/topics will be clearer.

    Don't you consider having a discord channel for very interactive chats?

    Thanks anyway.