I am trying to convert the snippet from https://medium.datadriveninvestor.com/how-to-detect-support-resistance-levels-and-breakout-using-python-f8b5dac42f21 into backtrader custom indicator. However, I encounter error AttributeError: 'Lines_LineSeries_DataSeries_OHLC_OHLCDateTime_Abst' object has no attribute 'shape'
The support and resistance snippet I want to convert:
#method 1: fractal candlestick pattern
# determine bullish fractal
def is_support(df,i):
cond1 = df['Low'][i] < df['Low'][i-1]
cond2 = df['Low'][i] < df['Low'][i+1]
cond3 = df['Low'][i+1] < df['Low'][i+2]
cond4 = df['Low'][i-1] < df['Low'][i-2]
return (cond1 and cond2 and cond3 and cond4)
# determine bearish fractal
def is_resistance(df,i):
cond1 = df['High'][i] > df['High'][i-1]
cond2 = df['High'][i] > df['High'][i+1]
cond3 = df['High'][i+1] > df['High'][i+2]
cond4 = df['High'][i-1] > df['High'][i-2]
return (cond1 and cond2 and cond3 and cond4)
# to make sure the new level area does not exist already
def is_far_from_level(value, levels, df):
ave = np.mean(df['High'] - df['Low'])
return np.sum([abs(value-level)<ave for _,level in levels])==0
# a list to store resistance and support levels
levels = []
for i in range(2, df.shape[0] - 2):
if is_support(df, i):
low = df['Low'][i]
if is_far_from_level(low, levels, df):
levels.append((i, low))
elif is_resistance(df, i):
high = df['High'][i]
if is_far_from_level(high, levels, df):
levels.append((i, high))
When I convert to backtarder by create custom indicator under bt.Indicator
class SR_Fractal(bt.Indicator):
lines = ("S","R")
plotinfo = dict(subplot = True)
plotlines = dict(
Support = dict(_name='S',color='red'),
Resistance = dict(_name='R',color='green')
)
def __init__(self):
# determine bullish fractal
def is_support(self):
cond1 = self.data.low[0]< self.data.low[-1]
cond2 = self.data.low[0]< self.data.low[1]
cond3 = self.data.low[1]< self.data.low[2]
cond4 = self.data.low[-1]< self.data.low[-2]
return (cond1 and cond2 and cond3 and cond4)
# determine bearish fractal
def is_resistance(self):
cond1 = self.data.high[0] > self.data.high[-1]
cond2 = self.data.high[0] > self.data.high[1]
cond3 = self.data.high[1] > self.data.high[2]
cond4 = self.data.high[-1] > self.data.high[-2]
return (cond1 and cond2 and cond3 and cond4)
# to make sure the new level area does not exist already
def is_far_from_level(value, levels, self):
ave = np.mean(self.data.high - self.data.low)
return np.sum([abs(value-level)<ave for _,level in levels])==0
# a list to store resistance and support levels
levels = []
for i in range(2, self.data.shape[0] - 2):
if is_support(self.data, i):
low = self.data.low[i]
if is_far_from_level(low, levels, self):
levels.append((i, low))
elif is_resistance(self.data, i):
high = self.data.high[i]
if is_far_from_level(high, levels, self):
levels.append((i, high))
Please advice the correct way I shall amend to get the support resistance correct