Quantopian's community platform is shutting down. Please read this post for more information and download your code.
Back to Community
what is the difference between TALIB MACD and built in factor MovingAverageConvergenceDivergenceSignal?

I got confused at 2 problems: please reference attached notebook
1. when using get_pricing method, 2016-03-01 close price is 100.53, and when using pipeline USEquityPricing.close.latest, 2016-03-01 close price is 96.65, but 03-02 is 100.53, seems all data is one day early, why is it?

  1. seems the return value from TALIB MACD is totally different from builtin factor MovingAverageConvergenceDivergenceSignal? what is the return value from MovingAverageConvergenceDivergenceSignal?

thank you for your answering.

alex.

9 responses

Trying to find out what does the return value for MovingAverageConvergenceDivergenceSignal represent too...

Any luck figuring out what MovingAverageConvergenceDivergenceSignal represents?

@junwi c @Logan Robertson

I have this question too...

class MovingAverageConvergenceDivergenceSignal(CustomFactor):  
    """  
    Moving Average Convergence/Divergence (MACD) Signal line  
    https://en.wikipedia.org/wiki/MACD  
    A technical indicator originally developed by Gerald Appel in the late  
    1970's. MACD shows the relationship between two moving averages and  
    reveals changes in the strength, direction, momentum, and duration of a  
    trend in a stock's price.  
    **Default Inputs:** :data:`zipline.pipeline.data.USEquityPricing.close`  
    Parameters  
    ----------  
    fast_period : int > 0, optional  
        The window length for the "fast" EWMA. Default is 12.  
    slow_period : int > 0, > fast_period, optional  
        The window length for the "slow" EWMA. Default is 26.  
    signal_period : int > 0, < fast_period, optional  
        The window length for the signal line. Default is 9.  
    Notes  
    -----  
    Unlike most pipeline expressions, this factor does not accept a  
    ``window_length`` parameter. ``window_length`` is inferred from  
    ``slow_period`` and ``signal_period``.  
    """  
    inputs = (USEquityPricing.close,)  
    # We don't use the default form of `params` here because we want to  
    # dynamically calculate `window_length` from the period lengths in our  
    # __new__.  
    params = ('fast_period', 'slow_period', 'signal_period')

    @expect_bounded(  
        __funcname='MACDSignal',  
        fast_period=(1, None),  # These must all be >= 1.  
        slow_period=(1, None),  
        signal_period=(1, None),  
    )  
    def __new__(cls,  
                fast_period=12,  
                slow_period=26,  
                signal_period=9,  
                *args,  
                **kwargs):

        if slow_period <= fast_period:  
            raise ValueError(  
                "'slow_period' must be greater than 'fast_period', but got\n"  
                "slow_period={slow}, fast_period={fast}".format(  
                    slow=slow_period,  
                    fast=fast_period,  
                )  
            )

        return super(MovingAverageConvergenceDivergenceSignal, cls).__new__(  
            cls,  
            fast_period=fast_period,  
            slow_period=slow_period,  
            signal_period=signal_period,  
            window_length=slow_period + signal_period - 1,  
            *args, **kwargs  
        )

    def _ewma(self, data, length):  
        decay_rate = 1.0 - (2.0 / (1.0 + length))  
        return average(  
            data,  
            axis=1,  
            weights=exponential_weights(length, decay_rate)  
        )

    def compute(self, today, assets, out, close, fast_period, slow_period,  
                signal_period):  
        slow_EWMA = self._ewma(  
            rolling_window(close, slow_period),  
            slow_period  
        )  
        fast_EWMA = self._ewma(  
            rolling_window(close, fast_period)[-signal_period:],  
            fast_period  
        )  
        macd = fast_EWMA - slow_EWMA  
        out[:] = self._ewma(macd.T, signal_period)  

I have the same question. I have tried looking into the zipline classes for answers, but do not have the technical knowledge to figure out what exactly it does. the above is the code found in the class MovingAverageConvergenceDivergence

From the code, it looks MovingAverageConvergenceDivergenceSignal only returns histogram, while talib.MACD() returns macd, signal, hist?

macd = fast_EWMA - slow_EWMA  
 out[:] = self._ewma(macd.T, signal_period)  

Looks to me like MovingAverageConverganceDiverganceSignal only returns the Signal line (EMA of the MACD). The MACD Histogram is the
MACD - Signal line
or in other words:
MACD - EMA(MACD,9)

From what I can see in the talib documentation, their MACD function returns the MACD, Signal line, and the Histogram all at once. But it operates on different data types, so you can't use USEquityPricing.close directly without first converting it (I think talib uses a numpy array?)

Confirmed. It means that we need to calculate MACD line and Histogram line to generate buy & sell signals. To do this, we must create CustomFactors or, alternatively use talib's MACD. Best would be to have the same outputs in class MovingAverageConvergenceDivergenceSignal (MACD, Signal line, and Histogram) than the one returned by talib.

# talib MACD in Pipeline 

from quantopian.pipeline.data.builtin import USEquityPricing  
from quantopian.pipeline import Pipeline, CustomFactor  
import numpy as np  
import talib

# -------------------------  
FAST, SLOW, SIG = 12, 26, 9  
# -------------------------

class MACD_Raw(CustomFactor):  
    inputs = [USEquityPricing.close]  
    window_length = FAST + SLOW + SIG

    def compute(self, today, assets, out, close):  
        macd_raw = []

        for col in close.T:  
            try:  
                macd, _, _ = talib.MACD(col,  FAST,  SLOW, SIG)  
                macd_raw.append(macd[-1])  
            except:  
                macd_raw.append(np.nan)  
        out[:] = macd_raw  

class MACD_Signal(CustomFactor):  
    inputs = [USEquityPricing.close]  
    window_length = FAST + SLOW + SIG

    def compute(self, today, assets, out, close):  
        sig_lines = []

        for col in close.T:  
            try:  
                _, signal_line, _ = talib.MACD(col, FAST, SLOW, SIG)  
                sig_lines.append(signal_line[-1])  
            except:  
                sig_lines.append(np.nan)  
        out[:] = sig_lines  

class MACD_Hist(CustomFactor):  
    inputs = [USEquityPricing.close]  
    window_length = FAST + SLOW + SIG

    def compute(self, today, assets, out, close):  
        macd_hist = []

        for col in close.T:  
            try:  
                _, _, hist = talib.MACD(col, FAST,  SLOW, SIG)  
                macd_hist.append(hist[-1])  
            except:  
                macd_hist.append(np.nan)  
        out[:] = macd_hist  

Thank you very much for sharing Vladimir! We can create a single class to calculate the 3 indicators.