Quantopian's community platform is shutting down. Please read this post for more information and download your code.
Back to Community
TA-Lib for Pipeline

The attached notebook includes 28 TA-Lib functions implemented as Custom Factors for ease of integration with Pipeline. These functions, for the most part, produce an identical result to the iterative TA-Lib implementations, but do this far faster.

Please feel free to clone the notebook and share your feedback below. Do these functions boost the performance of your algorithms? How do they compare to your own implementations of the TA-Lib library?

The TA-Lib library can be found here.

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.

11 responses

This...

class LINEARREG_INTERCEPT(CustomFactor):  
    """  
    Intercept of Trendline

    **Default Inputs:**  USEquitypricing.close

    **Default Window Length:** 14

    http://www.stat.cmu.edu/~cshalizi/mreg/15/lectures/06/lecture-06.pdf  
    """  
    inputs=[USEquityPricing.close]  
    window_length=14

    # using MLE  
    def compute(self, today, assets, out, close):

        # prepare X matrix (x_is - x_bar)  
        X = range(self.window_length)  
        X_bar = np.nanmean(X)  
        X_vector = X - X_bar  
        X_matrix = np.tile(X_vector, (len(close.T), 1)).T

        # prepare Y vectors (y_is - y_bar)  
        Y_bar = np.nanmean(close, axis=0)  
        Y_bars = np.tile(Y_bar, (self.window_length, 1))  
        Y_matrix = close - Y_bars

        # multiply X matrix an Y matrix and sum (dot product)  
        # then divide by variance of X  
        # this gives the MLE of Beta  
        betas = (np.sum((X_matrix * Y_matrix), axis=0) / X_var) / (self.window_length)

        # prepare variance of X  
        X_var = np.nanvar(X)

        # now use to get to MLE of alpha  
        out[:] = Y_bar - (betas * X_bar)  

Returns...
UnboundLocalError: local variable 'X_var' referenced before assignment

moving this line should fix it?
X_var = np.nanvar(X)

@Martin Thanks so much for flagging this up. That does indeed fix the issue. I will amend the notebook to include this change. Thanks again!

It seems the default lengths for the indicators cannot be changed without throwing errors like:

/usr/local/lib/python2.7/dist-packages/numpy/lib/function_base.pyc in average(a, axis, weights, returned)
    529             if wgt.shape[0] != a.shape[axis]:  
    530                 raise ValueError(  
--> 531                     "Length of weights not compatible with specified axis.")  
    532  
    533             # setup wgt to broadcast along axis

ValueError: Length of weights not compatible with specified axis.  

This seems to do the trick for allowing any length though:

class ADX(CustomFactor):  
#     Average Directional Movement Index

#     Momentum indicator. Smoothed DX

#     **Default Inputs:** USEquityPricing.high, USEquityPricing.low, USEquitypricing.close

#     **Default Window Length:** 29

#     https://www.fidelity.com/learning-center/trading-investing/technical-analysis/technical-indicator-guide/DMI  
    inputs = [USEquityPricing.high, USEquityPricing.low, USEquityPricing.close]  
    true_length = 120 #Whatever length desired  
    window_length = true_length+true_length+1  
    def compute(self, today, assets, out, high, low, close):

        # positive directional index  
        plus_di = 100 * np.cumsum(plus_dm_helper(high, low) / trange_helper(high, low, close), axis=0)

        # negative directional index  
        minus_di = 100 * np.cumsum(minus_dm_helper(high, low) / trange_helper(high, low, close), axis=0)

        # full dx with 15 day burn-in period  
        dx_frame = (np.abs(plus_di - minus_di) / (plus_di + minus_di) * 100.)[self.true_length:]

        # 14-day EMA  
        span = float(self.true_length)  
        decay_rate = 2. / (span + 1.)  
        weights = weights_long = np.full(span, decay_rate, float) ** np.arange(span + 1, 1, -1)

        # return EMA  
        out[:] = np.average(dx_frame, axis=0, weights=weights)  

@Andrew, glad you could find a workaround! The hope with this notebook is that the community will be able to take the code for these indicators and tinker and improve on them in their own algos, exactly like you're doing here. We may eventually create a fully parameterized function library like that of TA-Lib, but, for now, adjusting the custom factors themselves is the exactly the right thing to be doing! Hope you are finding the code useful.

Hi, @Gil Wassermann, it would be really helpful if you could describe how your example could be changed by limiting the stocks in the pipeline so that the stocks to trade (and also have data considered etc) are only applied to 1 instrument that could be selected by referencing the symbol (e.g. an ETF for example)? How could the output of your example be changed so that for instance only the row for AAPL is shown (and calculations only done on this security of course)? Is this possible - I've spent ages trying to find a way to do this by looking at things like set_universe (which is depreciated anyway it seems) but haven't been able to get anywhere - any help would be really appreciated...
Thanks,

@Adrian, there are a few ways to do this. The one I would recommend is to write a function that that takes as an input the pipeline output, takes this pandas.DataFrame and returns only the columns you want. In research, you might find symbols('AAPL') helpful for selecting your desired column(s)

@Adrian, try this:

filter_symbols = share_class_reference.symbol.latest.element_of(['AAPL'])

Pipeline(  
    columns = {  
        'ATR' : ATR(),  
    },  
    screen = filter_symbols  
)

Adrian,

Another approach to filtering a pipeline to a subset of one or more securities is to create a custom filter. See attached notebook.

Dan

@Andrew that fix works! However I don't want to use the same length for the exponential smoothing and it throws up the same error using any value other than specified as true_length. How to fix?

Hello,

I am trying to implement many custom functions such as ADX, ATR, MFI, and CCI and I keep getting the errors:

NameError: global name 'plus_dm_helper' is not defined
and
NameError: global name 'plus_trange_helper' is not defined

This happens for many of the custom factors it seems. Do we have to define these somehow or import something ?

Thanks in advance!

@Sam, in the beginning of the notebook, right under functions, you will see:

Functions
""" HELPER FUNCTIONS
"""

def plus_dm_helper(high, low):
"""
Returns positive directional movement. Abstracted for use with more complex factors

https://www.fidelity.com/learning-center/trading-investing/technical-analysis/technical-indicator-guide/DMI

Parameters

etc....

you just need to copy those in your code as well.