@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()
```