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)
       
    

Log in to reply
 

});