def grangercausalitytests(x, maxlag, addconst=True, verbose=True):
    "four tests for granger non causality of 2 timeseries\n\n    all four tests give similar results\n    `params_ftest` and `ssr_ftest` are equivalent based on F test which is\n    identical to lmtest:grangertest in R\n\n    Parameters\n    ----------\n    x : array, 2d\n        data for test whether the time series in the second column Granger\n        causes the time series in the first column\n    maxlag : integer\n        the Granger causality test results are calculated for all lags up to\n        maxlag\n    verbose : bool\n        print results if true\n\n    Returns\n    -------\n    results : dictionary\n        all test results, dictionary keys are the number of lags. For each\n        lag the values are a tuple, with the first element a dictionary with\n        teststatistic, pvalues, degrees of freedom, the second element are\n        the OLS estimation results for the restricted model, the unrestricted\n        model and the restriction (contrast) matrix for the parameter f_test.\n\n    Notes\n    -----\n    TODO: convert to class and attach results properly\n\n    The Null hypothesis for grangercausalitytests is that the time series in\n    the second column, x2, does NOT Granger cause the time series in the first\n    column, x1. Grange causality means that past values of x2 have a\n    statistically significant effect on the current value of x1, taking past\n    values of x1 into account as regressors. We reject the null hypothesis\n    that x2 does not Granger cause x1 if the pvalues are below a desired size\n    of the test.\n\n    The null hypothesis for all four test is that the coefficients\n    corresponding to past values of the second time series are zero.\n\n    'params_ftest', 'ssr_ftest' are based on F distribution\n\n    'ssr_chi2test', 'lrtest' are based on chi-square distribution\n\n    References\n    ----------\n    http://en.wikipedia.org/wiki/Granger_causality\n    Greene: Econometric Analysis\n\n    "
    from scipy import stats
    x = np.asarray(x)
    if (x.shape[0] <= ((3 * maxlag) + int(addconst))):
        raise ValueError('Insufficient observations. Maximum allowable lag is {0}'.format((int(((x.shape[0] - int(addconst)) / 3)) - 1)))
    resli = {}
    for mlg in range(1, (maxlag + 1)):
        result = {}
        if verbose:
            print('\nGranger Causality')
            print('number of lags (no zero)', mlg)
        mxlg = mlg
        dta = lagmat2ds(x, mxlg, trim='both', dropex=1)
        if addconst:
            dtaown = add_constant(dta[:, 1:(mxlg + 1)], prepend=False)
            dtajoint = add_constant(dta[:, 1:], prepend=False)
        else:
            raise NotImplementedError('Not Implemented')
        res2down = OLS(dta[:, 0], dtaown).fit()
        res2djoint = OLS(dta[:, 0], dtajoint).fit()
        fgc1 = ((((res2down.ssr - res2djoint.ssr) / res2djoint.ssr) / mxlg) * res2djoint.df_resid)
        if verbose:
            print(('ssr based F test:         F=%-8.4f, p=%-8.4f, df_denom=%d, df_num=%d' % (fgc1, stats.f.sf(fgc1, mxlg, res2djoint.df_resid), res2djoint.df_resid, mxlg)))
        result['ssr_ftest'] = (fgc1, stats.f.sf(fgc1, mxlg, res2djoint.df_resid), res2djoint.df_resid, mxlg)
        fgc2 = ((res2down.nobs * (res2down.ssr - res2djoint.ssr)) / res2djoint.ssr)
        if verbose:
            print(('ssr based chi2 test:   chi2=%-8.4f, p=%-8.4f, df=%d' % (fgc2, stats.chi2.sf(fgc2, mxlg), mxlg)))
        result['ssr_chi2test'] = (fgc2, stats.chi2.sf(fgc2, mxlg), mxlg)
        lr = ((- 2) * (res2down.llf - res2djoint.llf))
        if verbose:
            print(('likelihood ratio test: chi2=%-8.4f, p=%-8.4f, df=%d' % (lr, stats.chi2.sf(lr, mxlg), mxlg)))
        result['lrtest'] = (lr, stats.chi2.sf(lr, mxlg), mxlg)
        rconstr = np.column_stack((np.zeros((mxlg, mxlg)), np.eye(mxlg, mxlg), np.zeros((mxlg, 1))))
        ftres = res2djoint.f_test(rconstr)
        if verbose:
            print(('parameter F test:         F=%-8.4f, p=%-8.4f, df_denom=%d, df_num=%d' % (ftres.fvalue, ftres.pvalue, ftres.df_denom, ftres.df_num)))
        result['params_ftest'] = (np.squeeze(ftres.fvalue)[()], np.squeeze(ftres.pvalue)[()], ftres.df_denom, ftres.df_num)
        resli[mxlg] = (result, [res2down, res2djoint, rconstr])
    return resli
four tests for granger non causality of 2 timeseries

all four tests give similar results
`params_ftest` and `ssr_ftest` are equivalent based on F test which is
identical to lmtest:grangertest in R

Parameters
----------
x : array, 2d
    data for test whether the time series in the second column Granger
    causes the time series in the first column
maxlag : integer
    the Granger causality test results are calculated for all lags up to
    maxlag
verbose : bool
    print results if true

Returns
-------
results : dictionary
    all test results, dictionary keys are the number of lags. For each
    lag the values are a tuple, with the first element a dictionary with
    teststatistic, pvalues, degrees of freedom, the second element are
    the OLS estimation results for the restricted model, the unrestricted
    model and the restriction (contrast) matrix for the parameter f_test.

Notes
-----
TODO: convert to class and attach results properly

The Null hypothesis for grangercausalitytests is that the time series in
the second column, x2, does NOT Granger cause the time series in the first
column, x1. Grange causality means that past values of x2 have a
statistically significant effect on the current value of x1, taking past
values of x1 into account as regressors. We reject the null hypothesis
that x2 does not Granger cause x1 if the pvalues are below a desired size
of the test.

The null hypothesis for all four test is that the coefficients
corresponding to past values of the second time series are zero.

'params_ftest', 'ssr_ftest' are based on F distribution

'ssr_chi2test', 'lrtest' are based on chi-square distribution

References
----------
http://en.wikipedia.org/wiki/Granger_causality
Greene: Econometric Analysis
def grangercausalitytests(x, maxlag, addconst=True, verbose=True):
    "four tests for granger non causality of 2 timeseries\n\n    all four tests give similar results\n    `params_ftest` and `ssr_ftest` are equivalent based on F test which is\n    identical to lmtest:grangertest in R\n\n    Parameters\n    ----------\n    x : array, 2d\n        data for test whether the time series in the second column Granger\n        causes the time series in the first column\n    maxlag : integer\n        the Granger causality test results are calculated for all lags up to\n        maxlag\n    verbose : bool\n        print results if true\n\n    Returns\n    -------\n    results : dictionary\n        all test results, dictionary keys are the number of lags. For each\n        lag the values are a tuple, with the first element a dictionary with\n        teststatistic, pvalues, degrees of freedom, the second element are\n        the OLS estimation results for the restricted model, the unrestricted\n        model and the restriction (contrast) matrix for the parameter f_test.\n\n    Notes\n    -----\n    TODO: convert to class and attach results properly\n\n    The Null hypothesis for grangercausalitytests is that the time series in\n    the second column, x2, does NOT Granger cause the time series in the first\n    column, x1. Grange causality means that past values of x2 have a\n    statistically significant effect on the current value of x1, taking past\n    values of x1 into account as regressors. We reject the null hypothesis\n    that x2 does not Granger cause x1 if the pvalues are below a desired size\n    of the test.\n\n    The null hypothesis for all four test is that the coefficients\n    corresponding to past values of the second time series are zero.\n\n    'params_ftest', 'ssr_ftest' are based on F distribution\n\n    'ssr_chi2test', 'lrtest' are based on chi-square distribution\n\n    References\n    ----------\n    http://en.wikipedia.org/wiki/Granger_causality\n    Greene: Econometric Analysis\n\n    "
    from scipy import stats
    x = np.asarray(x)
    if (x.shape[0] <= ((3 * maxlag) + int(addconst))):
        raise ValueError('Insufficient observations. Maximum allowable lag is {0}'.format((int(((x.shape[0] - int(addconst)) / 3)) - 1)))
    resli = {}
    for mlg in range(1, (maxlag + 1)):
        result = {}
        if verbose:
            print('\nGranger Causality')
            print('number of lags (no zero)', mlg)
        mxlg = mlg
        dta = lagmat2ds(x, mxlg, trim='both', dropex=1)
        if addconst:
            dtaown = add_constant(dta[:, 1:(mxlg + 1)], prepend=False)
            dtajoint = add_constant(dta[:, 1:], prepend=False)
        else:
            raise NotImplementedError('Not Implemented')
        res2down = OLS(dta[:, 0], dtaown).fit()
        res2djoint = OLS(dta[:, 0], dtajoint).fit()
        fgc1 = ((((res2down.ssr - res2djoint.ssr) / res2djoint.ssr) / mxlg) * res2djoint.df_resid)
        if verbose:
            print(('ssr based F test:         F=%-8.4f, p=%-8.4f, df_denom=%d, df_num=%d' % (fgc1, stats.f.sf(fgc1, mxlg, res2djoint.df_resid), res2djoint.df_resid, mxlg)))
        result['ssr_ftest'] = (fgc1, stats.f.sf(fgc1, mxlg, res2djoint.df_resid), res2djoint.df_resid, mxlg)
        fgc2 = ((res2down.nobs * (res2down.ssr - res2djoint.ssr)) / res2djoint.ssr)
        if verbose:
            print(('ssr based chi2 test:   chi2=%-8.4f, p=%-8.4f, df=%d' % (fgc2, stats.chi2.sf(fgc2, mxlg), mxlg)))
        result['ssr_chi2test'] = (fgc2, stats.chi2.sf(fgc2, mxlg), mxlg)
        lr = ((- 2) * (res2down.llf - res2djoint.llf))
        if verbose:
            print(('likelihood ratio test: chi2=%-8.4f, p=%-8.4f, df=%d' % (lr, stats.chi2.sf(lr, mxlg), mxlg)))
        result['lrtest'] = (lr, stats.chi2.sf(lr, mxlg), mxlg)
        rconstr = np.column_stack((np.zeros((mxlg, mxlg)), np.eye(mxlg, mxlg), np.zeros((mxlg, 1))))
        ftres = res2djoint.f_test(rconstr)
        if verbose:
            print(('parameter F test:         F=%-8.4f, p=%-8.4f, df_denom=%d, df_num=%d' % (ftres.fvalue, ftres.pvalue, ftres.df_denom, ftres.df_num)))
        result['params_ftest'] = (np.squeeze(ftres.fvalue)[()], np.squeeze(ftres.pvalue)[()], ftres.df_denom, ftres.df_num)
        resli[mxlg] = (result, [res2down, res2djoint, rconstr])
    return resli