Navigation

    Backtrader Community

    • Register
    • Login
    • Search
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • Search
    For code/output blocks: Use ``` (aka backtick or grave accent) in a single line before and after the block. See: http://commonmark.org/help/

    Percent Price Oscillator conversion

    Indicators/Strategies/Analyzers
    2
    9
    46
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • A
      amit last edited by

      Hello,

      I am new to the backtrader community and need help with a specific indicator that I am trying to convert. Indicator is used for finding market tops and bottom based on the calculations.

      I am struggling to replicate those calculations in backtrader. Below is the specific function that I am not sure how to convert. As you can see in the function it used L0[1], I am not sure how to get this value. I was thinking of putting this value in an array but how would I reference it. or I should create an array the first time it will be zero and for the next candle it will have an value at index 1 and keep track of the candle number and use always candle-1. just thinking out loud

      lag(g, p) =>
      L0 = (1 - g)p+gnz(L0[1])
      L1 = -gL0+nz(L0[1])+gnz(L1[1])
      L2 = -gL1+nz(L1[1])+gnz(L2[1])
      L3 = -gL2+nz(L2[1])+gnz(L3[1])
      f = (L0 + 2L1 + 2L2 + L3)/6
      f

      Link to the Indicator
      https://www.tradingview.com/script/ngr0qRmw-CM-Laguerre-PPO-PercentileRank-Mkt-Tops-Bottoms/

      A 1 Reply Last reply Reply Quote 0
      • A
        ab_trader @amit last edited by

        @amit this looks like recursive indicator, so I would search docs and arcticles for this approach:
        https://backtrader.com/docu/
        https://backtrader.com/blog/

        Look on how the recursive built-in indicators are developed.
        https://github.com/mementum/backtrader/tree/master/backtrader/indicators

        Also search the forum, IIRC Laguerre indicators were discussed here.

        A 1 Reply Last reply Reply Quote 0
        • A
          amit @ab_trader last edited by

          @ab_trader Thank you for having a look. I will keep digging and share if I find anything

          1 Reply Last reply Reply Quote 0
          • A
            ab_trader last edited by

            https://backtrader.com/blog/posts/2018-01-27-recursive-indicators/recursive-indicator/

            1 Reply Last reply Reply Quote 1
            • A
              ab_trader last edited by

              https://community.backtrader.com/topic/204/laguerre-rsi/

              A 1 Reply Last reply Reply Quote 1
              • A
                amit @ab_trader last edited by

                @ab_trader Hello, thank you for the reference and apologies for late reply. I was trying to make the code changes and make it work.

                As in the suggested post I managed to get the array values correctly populated. thank you for that.

                Now I am stuck at PercentRank indicatot. its returning no value. and when I do next() on pctRankT it gives Divide by zero error. I looked in the lambda function, is it that it has to have all the lookback values before it can be used. I am using ccxtfeed to get the data from Binance.

                pctRankT = bt.indicators.PercentRank(ppoT, period=self.params.LookBackTop)
                pctRankB = bt.indicators.PercentRank(ppoB, period=self.params.LookBackBottom) * -1

                if(pctRankT >= self.params.ExtPercent or (pctRankT >= self.params.WarPercent and pctRankT < self.params.ExtPercent)):
                top = 1

                Thank you very much for your help.

                A 1 Reply Last reply Reply Quote 0
                • A
                  amit @amit last edited by

                  @ab_trader Just wanted to check, is there anywhere I can send you the code. I just need bit of guidance.

                  Regards

                  A 1 Reply Last reply Reply Quote 0
                  • A
                    ab_trader @amit last edited by

                    @amit said in Percent Price Oscillator conversion:

                    Just wanted to check, is there anywhere I can send you the code. I just need bit of guidance.

                    usually if somebody needs help, they post the scripts here.

                    A 1 Reply Last reply Reply Quote 0
                    • A
                      amit @ab_trader last edited by

                      @ab_trader hello, here is the full code.

                      import backtrader as bt
                      import math

                      class CustomStrategy(bt.Strategy):
                      # Moving average parameters
                      params = (('OscPeriod',50),('AdxPeriod',14), ('AtrPeriod',24),
                      ('ExtPercent',70),('WarPercent',90),
                      ('PPOShort',0.4),('PPOLong',0.8),
                      ('LookBackTop',200),('LookBackBottom',200),
                      ('AdxRange',20))

                      def log(self, txt, dt=None):
                      	dt = dt or self.datas[0].datetime.date(0)
                      	print(f'{dt.isoformat()} {txt}') # Comment this line when running optimization
                      
                      def __init__(self):
                      	self.L0S = [0,0]
                      	self.L1S=[0,0]
                      	self.L2S=[0,0]
                      	self.L3S=[0,0]
                      
                      	self.L0L = [0,0]
                      	self.L1L=[0,0]
                      	self.L2L=[0,0]
                      	self.L3L=[0,0]
                      
                      
                      	self.dataclose = self.datas[0].close
                      	
                      	# Order variable will contain ongoing order details/status
                      	self.order = None
                      
                      	# Adx values
                      	self.pDi = bt.indicators.AverageDirectionalMovementIndex(self.datas[0],period=self.params.AdxPeriod).DIplus
                      	self.mDi = bt.indicators.AverageDirectionalMovementIndex(self.datas[0],period=self.params.AdxPeriod).DIminus
                      
                      	# ATR values
                      	self.atr = bt.indicators.AverageTrueRange(self.datas[0],period=self.params.AtrPeriod)
                      
                      	#Calculate TP
                      	self.tpBuy = self.datas[0].close + self.atr *0.95
                      	self.tpSell = self.datas[0].close - self.atr *0.95
                      
                      	#calculate stop loss
                      	#self.fractal = bt.studies.contrib.fractal.Fractal(self.datas, period=2, bardist=0.01).lines
                      	#self.fup = self.fractal.fractal_bullish[0]
                      	#self.fdown = self.fractal.fractal_bearish[0]
                      	
                      	#Previous Day Close
                      	self.close = LastClose(self.datas[1])
                      
                      	#hl2
                      	self.hl2=(self.data.high+self.data.low)/2
                      	self.text =0
                      
                      
                      def notify_order(self, order):
                      	if order.status in [order.Submitted, order.Accepted]:
                      		# An active Buy/Sell order has been submitted/accepted - Nothing to do
                      		return
                      
                      	# Check if an order has been completed
                      	# Attention: broker could reject order if not enough cash
                      	if order.status in [order.Completed]:
                      		if order.isbuy():
                      			self.log(f'BUY EXECUTED, {order.executed.price:.2f}')
                      		elif order.issell():
                      			self.log(f'SELL EXECUTED, {order.executed.price:.2f}')
                      		self.bar_executed = len(self)
                      
                      	elif order.status in [order.Canceled, order.Margin, order.Rejected]:
                      		self.log('Order Canceled/Margin/Rejected')
                      
                      	# Reset orders
                      	self.order = None
                      
                      def lagS(self,g,p):
                      
                      	self.L0S.insert(0,  (1 - g) * p + g * self.L0S[1] )
                      	self.L1S.insert(0,  -g * self.L0S[0] + self.L0S[1] + g * self.L1S[1])
                      	self.L2S.insert(0,  -g * self.L1S[0] + self.L1S[1] + g * self.L2S[1])
                      	self.L3S.insert(0,  -g * self.L2S[0] + self.L2S[1] + g * self.L3S[1])
                      	f  = (self.L0S[0] + 2 * self.L1S[0] + 2 * self.L2S[0] + self.L3S[0]) / 6
                      	return f
                      
                      def lagL(self,g,p):
                      
                      	self.L0L.insert(0,  (1 - g) * p + g * self.L0L[1] )
                      	self.L1L.insert(0,  -g * self.L0L[0] + self.L0L[1] + g * self.L1L[1])
                      	self.L2L.insert(0,  -g * self.L1L[0] + self.L1L[1] + g * self.L2L[1])
                      	self.L3L.insert(0,  -g * self.L2L[0] + self.L2L[1] + g * self.L3L[1])
                      	f  = (self.L0L[0] + 2 * self.L1L[0] + 2 * self.L2L[0] + self.L3L[0]) / 6
                      	return f
                      
                      
                      def next(self):
                      	
                      	lmas=0
                      	lmal=0
                      	top =0
                      	bottom =0
                      
                      
                          #Top & Bottom calculations
                      	lmal = self.lagL(self.params.PPOLong,self.hl2[0])
                      	lmas = self.lagS(self.params.PPOShort,self.hl2[0]) 
                      	
                          #Remove any data beyond 2 iterations
                      	del self.L0S[2:]
                      	del self.L1S[2:]
                      	del self.L2S[2:]
                      	del self.L3S[2:]
                      
                      	del self.L0L[2:]
                      	del self.L1L[2:]
                      	del self.L2L[2:]
                      	del self.L3L[2:]
                      
                      	
                      	pctileB = self.params.ExtPercent * -1
                      	wrnpctileB = self.params.WarPercent * -1
                      
                      	ppoT = (lmas-lmal)/lmal*100
                      	ppoB = (lmal - lmas)/lmal*100
                      
                      	pctRankT = bt.indicators.PercentRank(ppoT, period=self.params.LookBackTop)
                      	pctRankB =  bt.indicators.PrettyGoodOscillator .PercentRank(ppoB, period=self.params.LookBackBottom) * -1
                      
                      	if(pctRankT >= self.params.ExtPercent or (pctRankT >= self.params.WarPercent and pctRankT < self.params.ExtPercent)):
                      		top = 1
                      
                      	if(pctRankB <= pctileB or (pctRankB <= wrnpctileB and pctRankB > pctileB)):
                      		bottom = 1
                      
                      
                      	# Check for open orders
                      	if self.order:	
                      		return
                      
                      	# Check if we are in the market
                      	if not self.position:
                      
                      		# We are not in the market, look for a signal to OPEN trades
                      		#Calculate Top and Bottom if the Color on HMA is changed
                      		if(top == 1 and self.pdi > self.params.AdxRange):
                      			self.log(f'BUY CREATE {self.dataclose[0]:2f}')
                      			# Keep track of the	 created order to avoid a 2nd order
                      			self.order = self.buy()
                      		elif (bottom == 1 and self.mdi > self.params.AdxRange):
                      			self.log(f'SELL CREATE {self.dataclose[0]:2f}')
                      			# Keep track of the created order to avoid a 2nd order
                      			self.order = self.sell()
                      	else:
                      		if ( (self.position.size>0) and (self.dataclose[0] >= self.tpBuy) ):
                      			self.log(f'CLOSE CREATE {self.dataclose[0]:2f}')
                      			self.order = self.close()
                      		elif ( (self.position.size<0) and (self.dataclose[0] <= self.tpSell) ):
                      			self.log(f'CLOSE CREATE {self.dataclose[0]:2f}')
                      			self.order = self.close()
                      1 Reply Last reply Reply Quote 0
                      • 1 / 1
                      • First post
                        Last post
                      Copyright © 2016, 2017, 2018 NodeBB Forums | Contributors
                      $(document).ready(function () { app.coldLoad(); }); }