Quantopian's community platform is shutting down. Please read this post for more information and download your code.
Back to Community
Get EMA of RSI

Hi,

I am in the Research environment (notebook). I am trying to get the EMA of the RSI, but I get the error

NoneType' object has no attribute 'format'

Here's the relevant code.

def EMA(length, inputs=USEquityPricing.close, mask=QTradableStocksUS()):  
    return (  
        ExponentialWeightedMovingAverage(  
            inputs=[inputs],  
            window_length=length,  
            mask=mask,  
            decay_rate=(1 - (2.0 / (1 + length)))  
        )  
    )

class RSI_Score(CustomFactor):  
    inputs=[RSI]  
    window_length=1  
    def compute(self, today, assets, out, rsi):  
        rsi_ema = EMA(21, rsi)  
        out[:] = rsi_ema  
def make_pipeline():  
    base_universe = QTradableStocksUS()  
    '''  
    Factors  
    '''  
    rsi_score = RSI_Score()  
    return Pipeline(  
        columns = {  
            'factor': rsi_score  
        },  
        screen=base_universe  
    )  
4 responses

I'll certainly not be the first ever to say that python error messages aren't very helpful at times. This is perhaps one of those times.

The error NoneType' object has no attribute 'format' stems from the following line

    inputs=[RSI]  

This should be

    inputs=[RSI()]  

In the first case one is passing the class RSI while in the second case, by adding the parenthesis, one is passing an instance of RSI. Custom factors expect instances.

However, once that is fixed there will still be another issue. The ExponentialWeightedMovingAverage factor, like all factors, expects either a 'BoundColumn' or another factor as an input. In the following code, 'rsi' is an ndarray and not a BoundColumn or a factor.

    def compute(self, today, assets, out, rsi):  
        rsi_ema = EMA(21, rsi)  
        out[:] = rsi_ema 

What to do? How does one get the exponentially weighted moving average (ewma) of the RSI? One could fix the two custom factors (RSI_Score and EMA) and calculate it that way. However, one doesn't need to write custom factors. One can simply use the built in ones.

Remember that factors can accept either a 'BoundColumn' or another factor as an input. A 'BoundColumn' is something like USEquityPricing.close or Fundamentals.current_assets. A factor is, well, a factor. The only requirement for factors is they must be window_safe (see the docs for more on that https://www.quantopian.com/docs/recipes/pipeline-recipes#recipe-custom-factor-into-custom-factor). So, to get the ewma of an RSI factor, simply pass the RSI factor to ExponentialWeightedMovingAverage. Like this example

    rsi = RSI()  
    rsi_ewma = ExponentialWeightedMovingAverage(inputs=[rsi], window_length=21, decay_rate=.5)

There are a couple of convenience methods one may want to use. First, ExponentialWeightedMovingAverage can also be imported as EWMA. This saves some typing and makes the code a bit shorter. Second, often one knows the ewma 'span' and not the decay rate. There is a class method from_span which allows for the span to be inputted directly. There is an example in the documentation https://www.quantopian.com/docs/api-reference/pipeline-api-reference#quantopian.pipeline.factors.ExponentialWeightedMovingAverage

See the attached notebook. Again, one could write their own custom factor to do this, but in this case it's probably easier to use the built in ones.

Disclaimer

The material on this website is provided for informational purposes only and does not constitute an offer to sell, a solicitation to buy, or a recommendation or endorsement for any security or strategy, nor does it constitute an offer to provide investment advisory services by Quantopian. In addition, the material offers no opinion with respect to the suitability of any security or specific investment. No information contained herein should be regarded as a suggestion to engage in or refrain from any investment-related course of action as none of Quantopian nor any of its affiliates is undertaking to provide investment advice, act as an adviser to any plan or entity subject to the Employee Retirement Income Security Act of 1974, as amended, individual retirement account or individual retirement annuity, or give advice in a fiduciary capacity with respect to the materials presented herein. If you are an individual retirement or other investor, contact your financial advisor or other fiduciary unrelated to Quantopian about whether any given investment idea, strategy, product or service described herein may be appropriate for your circumstances. All investments involve risk, including loss of principal. Quantopian makes no guarantees as to the accuracy or completeness of the views expressed in the website. The views are subject to change, and may have become unreliable for various reasons, including changes in market conditions or economic circumstances.

Thanks for the response, Dan. It makes more sense, now.

I still have an issue; I want to use the EWMA of the RSI as well as the RSI and create a score out of it, hence my factor name RSI_Score.
So, I still need to pass in the EWMA of the RSI + the RSI into my factor. Is this possible?

All factors, including custom factors, can accept other factors as inputs. The only requirement is the input factors must be window_safe (see the docs for more on that https://www.quantopian.com/docs/recipes/pipeline-recipes#recipe-custom-factor-into-custom-factor). So yes, the factors EWMA and RSI can be passed to a custom factor. Maybe something like this.

class RSI_Score(CustomFactor):  
    """  
    Custom factor to calculate a score from inputs rsi and rsi_ewma  
    Here it simply returns the ratio of the two  
    Ensure the inputs are passed in the order inputs=[rsi, rsi_ewma]  
    """  
    window_length = 1  
    def compute(self, today, assets, out, rsi_value, rsi_ewma_value):  
        # rsi_value and rsi_ewma_value are ndarrays  
        # The number of rows is equal to the window_length  
        # There is a column for each security  
        # They can be manipulated like any numpy ndarray  
        score = rsi_value / rsi_ewma_value  
        # Return the latest value (ie -1)  
        out[:] = score[-1]

    # Factors can be inputs to other factors including custom factors  
    # Assume rsi and rsi_ewma are an RSI factor and the EWMA of an RSI factor  
    rsi_score = RSI_Score(inputs=[rsi, rsi_ewma])  

Of course one can put any calculations in the compute method. Also, one doesn't always need a custom factor. The above calculation can also be done using basic operands.

    rsi_score = rsi / rsi_ewma

See the attached notebook.

Thanks Dan! :)