Quantopian's community platform is shutting down. Please read this post for more information and download your code.
Back to Community
Average True Range Custom Factor

I'm writing an average true range function as a custom factor for the pipeline. The true range of a day is the highest value between the ranges of today's high and low, and yesterday's close and today's high and low. The average true range is the average of all the day's true range within the window length. In the code, I loop the true range calculation with "i" counting the amount of times the loop has run. I define "i" as 0 before the loop but when I debug, I get an error [The truth value of an array with more than one element is ambiguous. Use a.any() or a.all())] when I say i = i + 1. I don't believe I have redefined i as an array anywhere in my code. Perhaps there is something I am overlooking?

class ATR(CustomFactor):  
    def compute(self, today, asset_ids, out, close, high, low):  
        window_length = 20  
        hl  = []  
        hc = []  
        lc = []  
        tr = []  
        i = 0  
        while i < window_length:  
            hl.append(high[-i] - low [-i])  
            hc.append(high[-i] - close[-i - 1])  
            lc.append(low[-i] - close[-i - 1])  
            tr.append(max(hl[i], hc[i], lc[i]))  
            i = i + 1  
        ATR = mean.tr  
        out[:] = ATR  
2 responses

The problem shows up at 'max(hl[i], hc[i], lc[i])'. It's not 'i' that's throwing the error.

You are probably expecting 'hl', 'hc', and 'lc' to be lists of scalers. They are not. They are lists of numpy arrays. The 'max' method doesn't understand numpy arrays as parameters. That's what is causing the error.

The problem actually starts with perhaps a misunderstanding of what 'close', 'high', and 'low' are. Take a look at the documentation for inputs to custom factors (https://www.quantopian.com/help#quantopian_pipeline_CustomFactor). These are 2 dimensional numpy arrays. The rows (axis 0) are the dates. The columns (axis 1) are the securities. The dates are indexed backwards so 'high[-1]' returns a 1 dimensional array of the latest highs for all securities. When you append 'high[-i] - low[-i]', for example, you are actually appending a 1 dimensional array to the 'hl' list.

The column headers of 'close', 'high', and 'low' are the security IDs (SIDs) passed in the 'asset_ids' parameter. So, as an example, high[-1, 0] would return a scaler of the latest high for the first security in the 'asset_ids'.

I'd forget the loop approach. Loops like this aren't very 'pythonic' and at the very least tend to be slow. Use the built in array handling methods provided by pandas and numpy instead.

If you are looking for an Average True Range custom factor, then look here https://www.quantopian.com/posts/custom-factor-atr . The last post by Nathaniel has a very elegant 3 line implementation. Very 'pythonic'.

Good luck.

Thanks!