Here is a code I wrote to help me define a strategy. It works well but I feel the code is too long and I am wondering if there is an efficient way of doing the same with for loops. The code searches for a set of candlesticks whose bodies are contained within another prior bar. With my clunky method, I could only design is for a minimum of 2 candles and a maximum of seven. Could a for loop be used to fetch as much candles that could fulfill this criteria? thanks in advance.
def eATR(df1,n=14):
"""This calculates the Average True Range of of a dataframe of the open,
high, low, and close data of an instrument"""
df = df1[['Open', 'High', 'Low', 'Close',]]
# True Range
df['TR'] = 0
for i in range(len(df)):
try:
df.iloc[i, 4] = max(df.iat[i,1] - df.iat[i,2],
abs(df.iat[i,1] - df.iat[i-1,3]),
abs(df.iat[i,2] - df.iat[i-1,3]))
except ValueError:
pass
# eATR
df['eATR']= df['TR'].ewm(span=n, adjust=False).mean()
df.drop(['TR'], axis = 1, inplace=True)
return df['eATR']
def contraction(data):
df = data.copy()
e_ATR = eATR(df)
bodyHi = df[['Open', 'Close']].apply(max,axis=1)
bodyLo = df[['Open', 'Close']].apply(min,axis=1)
topWick = abs(df['High'] - bodyHi)
botWick = abs(bodyLo - df['Low'])
bodyLen = abs(bodyHi - bodyLo)
canLen = df['High'] - df['Low']
per = 1.5
contraction = np.where((df['High'].shift(7) >= bodyHi.shift(6))
& (df['High'].shift(7) >= bodyHi.shift(5))
& (df['High'].shift(7) >= bodyHi.shift(4))
& (df['High'].shift(7) >= bodyHi.shift(3))
& (df['High'].shift(7) >= bodyHi.shift(2))
& (df['High'].shift(7) >= bodyHi.shift(1))
& (df['High'].shift(7) >= bodyHi.shift(0))
& (df['Low'].shift(7) <= bodyLo.shift(6))
& (df['Low'].shift(7) <= bodyLo.shift(5))
& (df['Low'].shift(7) <= bodyLo.shift(4))
& (df['Low'].shift(7) <= bodyLo.shift(3))
& (df['Low'].shift(7) <= bodyLo.shift(2))
& (df['Low'].shift(7) <= bodyLo.shift(1))
& (df['Low'].shift(7) <= bodyLo.shift(0))
& (canLen.shift(0) <= canLen.shift(7) * per)
& (canLen.shift(1) <= canLen.shift(7) * per)
& (canLen.shift(2) <= canLen.shift(7) * per)
& (canLen.shift(3) <= canLen.shift(7) * per)
& (canLen.shift(4) <= canLen.shift(7) * per)
& (canLen.shift(5) <= canLen.shift(7) * per)
& (canLen.shift(6) <= canLen.shift(7) * per)
| (df['High'].shift(6) >= bodyHi.shift(5))
& (df['High'].shift(6) >= bodyHi.shift(4))
& (df['High'].shift(6) >= bodyHi.shift(3))
& (df['High'].shift(6) >= bodyHi.shift(2))
& (df['High'].shift(6) >= bodyHi.shift(1))
& (df['High'].shift(6) >= bodyHi.shift(0))
& (df['Low'].shift(6) <= bodyLo.shift(5))
& (df['Low'].shift(6) <= bodyLo.shift(4))
& (df['Low'].shift(6) <= bodyLo.shift(3))
& (df['Low'].shift(6) <= bodyLo.shift(2))
& (df['Low'].shift(6) <= bodyLo.shift(1))
& (df['Low'].shift(6) <= bodyLo.shift(0))
& (canLen.shift(0) <= canLen.shift(6) * per)
& (canLen.shift(1) <= canLen.shift(6) * per)
& (canLen.shift(2) <= canLen.shift(6) * per)
& (canLen.shift(3) <= canLen.shift(6) * per)
& (canLen.shift(4) <= canLen.shift(6) * per)
& (canLen.shift(5) <= canLen.shift(6) * per)
| (df['High'].shift(5) >= bodyHi.shift(4))
& (df['High'].shift(5) >= bodyHi.shift(3))
& (df['High'].shift(5) >= bodyHi.shift(2))
& (df['High'].shift(5) >= bodyHi.shift(1))
& (df['High'].shift(5) >= bodyHi.shift(0))
& (df['Low'].shift(5) <= bodyLo.shift(4))
& (df['Low'].shift(5) <= bodyLo.shift(3))
& (df['Low'].shift(5) <= bodyLo.shift(2))
& (df['Low'].shift(5) <= bodyLo.shift(1))
& (df['Low'].shift(5) <= bodyLo.shift(0))
& (canLen.shift(0) <= canLen.shift(5) * per)
& (canLen.shift(1) <= canLen.shift(5) * per)
& (canLen.shift(2) <= canLen.shift(5) * per)
& (canLen.shift(3) <= canLen.shift(5) * per)
& (canLen.shift(4) <= canLen.shift(5) * per)
| (df['High'].shift(4) >= bodyHi.shift(3))
& (df['High'].shift(4) >= bodyHi.shift(2))
& (df['High'].shift(4) >= bodyHi.shift(1))
& (df['High'].shift(4) >= bodyHi.shift(0))
& (df['Low'].shift(4) <= bodyLo.shift(3))
& (df['Low'].shift(4) <= bodyLo.shift(2))
& (df['Low'].shift(4) <= bodyLo.shift(1))
& (df['Low'].shift(4) <= bodyLo.shift(0))
& (canLen.shift(0) <= canLen.shift(4) * per)
& (canLen.shift(1) <= canLen.shift(4) * per)
& (canLen.shift(2) <= canLen.shift(4) * per)
& (canLen.shift(3) <= canLen.shift(4) * per)
| (df['High'].shift(3) >= bodyHi.shift(2))
& (df['High'].shift(3) >= bodyHi.shift(1))
& (df['High'].shift(3) >= bodyHi.shift(0))
& (df['Low'].shift(3) <= bodyLo.shift(2))
& (df['Low'].shift(3) <= bodyLo.shift(1))
& (df['Low'].shift(3) <= bodyLo.shift(0))
& (canLen.shift(0) <= canLen.shift(3) * per)
& (canLen.shift(1) <= canLen.shift(3) * per)
& (canLen.shift(1) <= canLen.shift(3) * per)
| (df['High'].shift(2) >= bodyHi.shift(1))
& (df['High'].shift(2) >= bodyHi.shift(0))
& (df['Low'].shift(2) <= bodyLo.shift(1))
& (df['Low'].shift(2) <= bodyLo.shift(0))
& (canLen.shift(0) <= canLen.shift(2) * per)
& (canLen.shift(1) <= canLen.shift(2) * per), 1, 0)
return contraction
Here is the output on my chart colored in 'burlywood' when the above criteria is met.
Thanks in anticipation!
The purpose of the code was to help me identify some candles that met a certain criteria. My implementation was too long and the idea for the implementation didn't look pythonic to me; something more from what i'd do back when I was learning qBasic. @RufusVS you gave me a hint on how to go about it and this is my final code as opposed to the one I had posted earlier.
def contract(data, per = 1.5):
df = data[['open', 'high', 'low', 'close']].copy()
df['bodyHi'] = df[['open', 'close']].apply(max,axis=1)
df['bodyLo'] = df[['open', 'close']].apply(min,axis=1)
df['canLen'] = df['high'] - df['low']
df['eATR'] = eATR(df)
df['contraction'] = 0
for i in range(len(df)):
if df['canLen'].iloc[i] < (2 * df['eATR'].iloc[i]):
for j in range(i+1, len(df)):
if (df['bodyHi'].iloc[j] < df['high'].iloc[i]) and (df['bodyLo'].iloc[j] > df['low'].iloc[i]):
df['contraction'].iloc[j] = 1
else:
break
return df['contraction'].to_frame()
Thanks once again. it took me a while to get to it but I did eventually. I thought I should let you know.