Quantopian's community platform is shutting down. Please read this post for more information and download your code.
Back to Community
How to build a customer "indicator in indicator" built-in-factor?

Hi,

Using indicator in indicator is quite normal. I tried to build such a customer "indicator in indicator" built-in-factor but fialt. I got error as I run it:
" Runtime exception: AttributeError: type object 'MyTalibRSI' has no attribute 'rsi'
"

Below is my code

"""
This is a template algorithm on Quantopian for you to adapt and fill in.  
"""
from quantopian.algorithm import attach_pipeline, pipeline_output  
from quantopian.pipeline import Pipeline  
from quantopian.pipeline.data.builtin import USEquityPricing  
from quantopian.pipeline.factors import AverageDollarVolume  
from quantopian.pipeline.filters.morningstar import Q1500US  
from quantopian.pipeline.factors import CustomFactor  
from collections import defaultdict  
from quantopian.pipeline.filters import StaticAssets

import numpy as np  
import pandas as pd  
import math  
import talib

class MyTalibRSI(CustomFactor):  
    inputs = (USEquityPricing.close,)  
    params = {'rsi_len' : 14,}  
    window_length = 60 # allow at least 4 times RSI len for proper smoothing  
    def compute(self, today, assets, out, close, rsi_len):  
        # TODO: figure out how this can be coded without a loop  
        rsi = []  
        for col in close.T:  
            try:  
                rsi.append(talib.RSI(col, timeperiod=rsi_len)[-1])  
            except:  
                rsi.append(np.nan)  
        out[:] = rsi

class MyDoubleRSI(CustomFactor):  
    inputs = (MyTalibRSI.rsi,)  
    outputs = ['rsi']  
    params = {'rsi_len' : 14,}  
    window_length = 60 # allow at least 4 times RSI len for proper smoothing  
    def compute(self, today, assets, out, rsi, rsi_len):  
        # TODO: figure out how this can be coded without a loop  
        rsi = []  
        for col in rsi.T:  
            try:  
                rsi.append(talib.RSI(col, timeperiod=rsi_len)[-1])  
            except:  
                rsi.append(np.nan)  
        out.rsi[:] = rsi  
def initialize(context):  
    """  
    Called once at the start of the algorithm.  
    """  
    context.stock = sid(8554) # SPY  
    # Create our dynamic stock selector.  
    attach_pipeline(make_pipeline(context), 'my_pipeline')  
def make_pipeline(context):  
    """  
    A function to create our dynamic stock selector (pipeline). Documentation on  
    pipeline can be found here: https://www.quantopian.com/help#pipeline-title  
    """  
    sec_mask = StaticAssets([context.stock])  
    my_mask = sec_mask  
    # Factor of yesterday's close price.  
    yesterday_close = USEquityPricing.close.latest

    rsi = MyTalibRSI(rsi_len=14, window_length = 80)  
    double_rsi = MyDoubleRSI(inputs=[MyTalibRSI.rsi], rsi_len=14, window_length = 80)  
    pipe = Pipeline(  
        screen = my_mask,  
        columns = {  
            'close': yesterday_close,  
            'rsi': rsi,  
            'double_rsi': double_rsi,  
        }  
    )  
    return pipe  
def before_trading_start(context, data):  
    """  
    Called every day before market open.  
    """  
    context.output = pipeline_output('my_pipeline').dropna()  
#    log.info("Length of DF:%d" %len(context.output))  
    log.info("Original DF:\n%s" %context.output)  
    # These are the securities that we are interested in trading each day.  
    context.security_list = context.output.index  

3 responses

Hi Thomas,

You can use a pipeline Factor as the input to another Factor as long as the input is window safe. You can find a good explanation of window safety in this community post.

Aside from that, the syntax you are using, MyTalibRSI.rsi, is looking for a rsi attribute in the MyTalibRSI class. To pass the result of MyTalibRSI to MyDoubleRSI you should do this instead:

    rsi = MyTalibRSI(rsi_len=14, window_length = 80)  
    double_rsi = MyDoubleRSI(inputs=[rsi], rsi_len=14, window_length = 80)  

Also, in your MyDoubleRSI's compute method, you reuse the input variable's name rsi to create a list. This will give you an error when you try to transpose the input with rsi.T.

Attached you will find a backtest that addresses these errors.

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.

Hi Ernesto,

Great! Many thanks!

But I want to know if it is possible to make/write the MyTalibRSI() as a library sothat I just need import it and not write its source code here in the program?

@Thomas,

Currently, the IDE does not support importing functions or classes from custom modules. This feature has been requested in the past, and it is definitely in our radar for future improvements to the platform. I will add your up-vote to the feature request.