Search code examples
pythonindicator

shorten long Python indicator


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!

chart


Solution

  • 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()
    

    inside Body candles

    Thanks once again. it took me a while to get to it but I did eventually. I thought I should let you know.