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

Custom Laguerre RSI math.log isues



  • So I am trying to code the Mobius laguerre RSI which has an adaptive gamma, based off of Fractal energy/Chop index values. This is different from BT's build in Laguerre RSI which has a constant value for gamma. However, my math.log is throwing a:

    "Must be a real number,not LinesOperation" error on
    self.y = math.log(self.z)
    Do I need to convert it to a int? Any help is greatly appreciated.

    Code:

    from __future__ import (absolute_import, division, print_function,
                            unicode_literals)
    import argparse
    import backtrader as bt
    import backtrader.feeds as btfeeds
    import backtrader.indicators as btind
    from datetime import datetime
    from pprint import pprint
    import pandas as pd
    import math
    from numpy import arange
    from backtrader.indicators import StdDev
    from backtrader.indicators import EMA
    pd.set_option('display.max_rows', 500)
    class gamma1(bt.Indicator):
        lines = ('dummyline',)
    
        params = (('value', 5),)
    
        def __init__(self):
            self.m  = bt.If(self.data.high > self.data.close[1], self.data.high, self.data.close[-1])
            self.n = bt.If(self.data.low < self.data.close[1], self.data.low, self.data.close[-1])
            self.a = self.m - self.n
            self.b = btind.SumN(self.a, period=8)
            self.hl = btind.Highest(self.data.high, period=8)-btind.Lowest(self.data.low, period=8)
            self.z = self.b/self.hl
            self.y = math.log(self.z)
            r = math.log(8)
            
            self.lines.dummyline = self.y/r
    class CLaguerreRSI(bt.Indicator):
        alias = ('CLRSI',)
        lines = ('lrsi',)
        params = (('e', 0.5),)
    
        plotinfo = dict(
            plotymargin=0.15,
            plotyticks=[0.0, 0.2, 0.5, 0.8, 1.0]
        )
    
        def __init__(self):
            self.addminperiod(6)
            self.l0 = [0, 0]
            self.l1 = [0, 0]
            self.l2 = [0, 0]
            self.l3 = [0, 0]
            self.gamma = gamma1(self.data)
            self.o = (self.data.open+self.data.close[-1])/2
            self.h = bt.If(self.data.high  > self.data.close(-1),self.data.high, self.data.close(-1))
            self.l = bt.If(self.data.low  < self.data.close(-1),self.data.low, self.data.close(-1))
            self.c = (self.o+self.h+self.l+self.data.close)/4
            super(CLaguerreRSI, self).__init__()
    
        def next(self):
            self.l0.insert(0, ((1 - self.gamma) * self.c +
                               self.gamma * self.l0[0]))
            self.l1.insert(0, (-self.gamma * self.l0[0] + self.l0[1] +
                               self.gamma * self.l1[0]))
            self.l2.insert(0, (-self.gamma * self.l1[0] + self.l1[1] +
                               self.gamma * self.l2[0]))
            self.l3.insert(0, (-self.gamma * self.l2[0] + self.l2[1] +
                               self.gamma * self.l3[0]))
            del self.l0[2:]
            del self.l1[2:]
            del self.l2[2:]
            del self.l3[2:]
    
            cu = bt.If(self.l0[0] >= self.l1[0], self.l0[0] - self.l1[0], 0)
            cd = bt.If(self.l0[0] < self.l1[0], self.l1[0] - self.l0[0], 0)
    
            cu = bt.If(self.l1[0] >= self.l2[0], cu + self.l1[0] - self.l2[0], 0)
            cd = bt.If(self.l1[0] < self.l2[0], cd + self.l2[0] - self.l1[0] , 0)
           
            cu = bt.If(self.l2[0] >= self.l3[0], cu + self.l2[0] - self.l3[0], 0)
            cd = bt.If(self.l2[0] < self.l3[0], cd + self.l3[0] - self.l2[0] , 0)
            self.lines.lrsi = cu / (cu + cd)
    class SMAStrategy(bt.Strategy):
        params = (
            ('period', 10), ('period2', 10),
        )
        def __init__(self):
            self.startcash = self.broker.getvalue()
            self.o = (self.data.open+self.data.close[-1])/2
            self.h = bt.If(self.data.high  > self.data.close(-1),self.data.high, self.data.close(-1))
            self.l = bt.If(self.data.low  < self.data.close(-1),self.data.low, self.data.close(-1))
            self.c = (self.o+self.h+self.l+self.data.close)/4
            self.atr = btind.AverageTrueRange(self.data, period = 14)
            self.filt = btind.LaguerreFilter(self.data.close, gamma = .8)
            self.rsi = btind.LRSI(self.c, gamma = .05)
            self.rsi_exit =  btind.LRSI(self.c, gamma = .5)
            self.BB = btind.BollingerBands(self.data, period = 20, devfactor =2, movav=bt.indicators.MovAv.Exponential)
            self.mLRSI = CLaguerreRSI(self.data)
        
        def next(self): 
    
            if self.position:
                if (self.mLRSI == 0 or (self.mLRSI < self.mLRSI[-1] and self.mLRSI < .8))  and self.position.size > 0:
                    self.close(size=self.position.size)
                if (self.mLRSI ==1 or (self.mLRSI > self.mLRSI[-1] and self.mLRSI > .2))  and self.position.size < 0:
                    self.close(size=self.position.size)
            if not self.position:
                if (self.mLRSI == 1 or (self.mLRSI > self.mLRSI[-1] and self.mLRSI > .2)) and self.data.close > self.filt:
                    self.buy(size=10)
                    #print('{},BUY,{}'.format(self.datetime.datetime(), self.data.close[0]))
                    #print(self.datetime.date())
                if (self.mLRSI ==0 or (self.mLRSI < self.mLRSI[-1] and self.mLRSI < .8)) and self.data.close < self.filt:
                    self.sell(size=10)
                    #print('{},SELL,{}'.format(self.datetime.datetime(), self.data.close[0]))
                    #print(self.datetime.date())
            
            
            
    def printTradeAnalysis(analyzer):
        '''
        Function to print the Technical Analysis results in a nice format.
        '''
        #Get the results we are interested in
        #total_open = analyzer.total.open
        #total_closed = analyzer.total.closed
        total_won = analyzer.won.total
        total_lost = analyzer.lost.total
        #pnl_net = round(analyzer.pnl.net.total,2)
        '''
        longWinRate = analyzer.long.won/(analyzer.long.won+analyzer.long.lost)
        longLossRate = analyzer.long.lost/(analyzer.long.won+analyzer.long.lost)
        longAvgWin = analyzer.long.pnl.won.average
        longAvgLoss = abs(analyzer.long.pnl.lost.average)
        longExpect = (longAvgWin*longWinRate)-(longAvgLoss*longLossRate)
        longPF = analyzer.long.pnl.won.total/abs(analyzer.long.pnl.lost.total)
    
        shortWinRate = analyzer.short.won/(analyzer.short.won+analyzer.short.lost)
        shortLossRate = analyzer.short.lost/(analyzer.short.won+analyzer.short.lost)
        shortAvgWin = analyzer.short.pnl.won.average
        shortAvgLoss = abs(analyzer.short.pnl.lost.average)
        shortExpect = (shortAvgWin*shortWinRate)-(shortAvgLoss*shortLossRate)
        shortPF = analyzer.short.pnl.won.total/abs(analyzer.short.pnl.lost.total)
        '''
        winRate = total_won/(total_won+total_lost)
        bearWinRate = total_lost/(total_won+total_lost)
        avgwin = analyzer.won.pnl.average
        avgloss = abs(analyzer.lost.pnl.average)
        totalExpect = (avgwin*winRate)-(avgloss*bearWinRate)
        #totalPF = analyzer.won.pnl.total/abs(analyzer.lost.pnl.total)
        print(winRate)
        print(totalExpect)
        #print(analyzer.SharpeRatio)
        print(analyzer.total.total)
        #return "{:.2%}".format(winRate), round(analyzer.won.pnl.average,2), round(analyzer.lost.pnl.average,2), round(totalExpect,2), round(analyzer.len.average,2), analyzer.streak.won.longest, analyzer.streak.lost.longest
    def runstrat():  
        # Create a cerebro entity
        #for grp in groups:
        startcash = 10000
        #cerebro = bt.Cerebro(stdstats=False)
    
        # Add a strategy
    
        # Load the Data
        cerebro = bt.Cerebro(stdstats=False)
        #cerebro.optstrategy(SMAStrategy)
        cerebro.addstrategy(SMAStrategy,)
    
        #cerebro.addanalyzer(bt.analyzers.TradeAnalyzer, _name="ta")
    
        data = bt.feeds.YahooFinanceData(
        dataname='BA',
        fromdate = datetime(2000,1,1),
        todate = datetime(2020,8,17),
        timeframe = bt.TimeFrame.Days,
        buffered= True
        )
        cerebro.adddata(data)  # First add the original data - smaller timeframe
        #cerebro.strat(SMAStrategy )
        #cerebro.broker.setcash(startcash)
    
        # Run over everything
        cerebro.addanalyzer(bt.analyzers.TradeAnalyzer, _name="ta")
        cerebro.addanalyzer(bt.analyzers.SharpeRatio, _name='mysharpe')
        #cerebro.addanalyzer(bt.analyzers.SQN, _name="sqn")
        strategies = cerebro.run()
        firstStrat = strategies[0]
        portvalue = cerebro.broker.getvalue()
        pnl = portvalue - startcash
        printTradeAnalysis(firstStrat.analyzers.ta.get_analysis())
     
    
    if __name__ == '__main__':
        runstrat()
    


  • @Paul-Park said in Custom Laguerre RSI math.log isues:

        self.hl = btind.Highest(self.data.high, period=8)-btind.Lowest(self.data.low, period=8)
        self.z = self.b/self.hl
        self.y = math.log(self.z)
    

    self.y is made up of lines objects, self.b divided by self.h1.

    math.log works on a scalar and will not apply properly to the lines object, self.z.

    In order to do this, you need to put self.y in next in the indicator and calculate it individually in each bar.

    def next(self):
        self.y[0] = math.log(self.z[0])
    


  • @run-out Thanks! I made the changes you recommended however now I get a math domain error.



  • @run-out Thank You! So I fixed the original error.

    Code:

    class gamma1(bt.Indicator):
        lines = ('dummyline',)
    
        params = (('value', 5),)
    
        def __init__(self):
            self.m  = bt.If(self.data.high > self.data.close[-1], self.data.high, self.data.close[-1])
            self.n = bt.If(self.data.low < self.data.close[-1], self.data.low, self.data.close[-1])
            self.a = self.m - self.n
            self.b = btind.SumN(self.a, period=8)
            self.hl = btind.Highest(self.data.high, period=8)-btind.Lowest(self.data.low, period=8)
            
            
        def next(self):
            z = self.b/self.hl
            y = math.log(z)
            r = math.log(8)
            self.lines.dummyline = y/r
    

    However the last line, self.lines/dummylin = y/r, gets an error of float object is not callable. After some googling most issues seem to be from misuse of parenthesis however I do not see that in my code. Any guidance is much appreciated.



  • Try these changes:

    Round brackets in init.
    Square brackets with zero in next to indicate current bar. [0]

    class gamma1(bt.Indicator):
        lines = ('dummyline',)
    
        params = (('value', 5),)
    
        def __init__(self):
            self.m  = bt.If(self.data.high > self.data.close(-1), self.data.high, self.data.close(-1))
            self.n = bt.If(self.data.low < self.data.close(-1), self.data.low, self.data.close(-1))
            self.a = self.m - self.n
            self.b = btind.SumN(self.a, period=8)
            self.hl = btind.Highest(self.data.high, period=8)-btind.Lowest(self.data.low, period=8)
            
            
        def next(self):
            z = self.b[0]/self.hl[0]
            y = math.log(z[0])
            r = math.log(8)
            self.lines.dummyline = y[0]/r
    


  • @run-out In the next() I have tried using brackets for current bar however for variable y and z I get a float object is not subscriptable error.



  • @Paul-Park said in Custom Laguerre RSI math.log isues:

    @run-out In the next() I have tried using brackets for current bar however for variable y and z I get a float object is not subscriptable error.

    Could you include the error message in full please?



  • @run-out Yup here it is.

        y = math.log(z[0])                                                                                                  TypeError: 'float' object is not subscriptable  
    


  • @run-out Found a solution to the problem. Instead of y/r i used bt.DivByZero(y,r)

    However, when I try printing the values of gamma1() in my strategy to check the values I get this weird printout.

    <__main__.gamma1 object at 0x0D274E68>
    

    Haven't seen this anywhere else in this community hope you could help.

          self.gamma = gamma1(self.data)
        
        def next(self): 
            print(self.gamma)
       
    


  • @run-out Thanks for all your help its working now. I just need to figure out why gamma1() only outputs nan.

    I appreciate all your help @run-out



  • @Paul-Park said in Custom Laguerre RSI math.log isues:

    self.gamma = gamma1(self.data)

    gamma1 is an indicator. You can retrieve lines from an indicator.

    If you make self.gamma equal to gamma1() you are setting the variable equal to the entire indicator object.

    You need to retrieve the line from gamma so it would look like:

    self.gamma = gamma1(self.data).dummyline
    

    Then in next:

    def next(self): 
        print(self.gamma.dummyline[0])
    

    You may wish to name dummyline something relevant.



  • @run-out I originally tried this but got a, linebuffer has no attribute dummyline, in the next() function. Shouldn't setting self.gamma to dummyline in the init be enough to call it later on without dummyline[0]


Log in to reply
 

});