## SAS Macro to Test Stationarity in Batch

To determine if a time series is stationary or has the unit root, three methods can be used:

A. The most intuitive way, which is also sufficient in most cases, is to eyeball the ACF (Autocorrelation Function) plot of the time series. The ACF pattern with a fast decay might imply a stationary series.

B. Statistical tests for Unit Roots, e.g. ADF (Augmented Dickey–Fuller) or PP (Phillips–Perron) test, could be employed as well. With the Null Hypothesis of Unit Root, a statistically significant outcome might suggest a stationary series.

C. In addition to the aforementioned tests for Unit Roots, statistical tests for stationarity, e.g. KPSS (Kwiatkowski–Phillips–Schmidt–Shin) test, might be an useful complement as well. With the Null Hypothesis of stationarity, a statistically insignificant outcome might suggest a stationary series.

By testing both the unit root and stationarity, the analyst should be able to have a better understanding about the data nature of a specific time series.

The SAS macro below is a convenient wrapper of stationarity tests for many time series in the production environment. **(Please note that this macro only works for SAS 9.2 or above.)**

%macro stationary(data = , vars =); ***********************************************************; * THIS SAS MACRO IS TO DO STATIONARITY TESTS FOR MANY *; * TIME SERIES *; * ------------------------------------------------------- *; * INPUT PARAMETERS: *; * DATA: A INPUT SAS DATASET *; * VARS: A LIST OF TIME SERIES *; * ------------------------------------------------------- *; * AUTHOR: WENSUI.LIU@53.COM *; ***********************************************************; options nocenter nonumber nodate mprint mlogic symbolgen orientation = landscape ls = 150 formchar = "|----|+|---+=|-/\<>*"; %local sig loop; %let sig = 0.1; %let loop = 1; %do %while (%scan(&vars, &loop) ne %str()); %let x = %scan(&vars, &loop); proc sql noprint; select int(12 * ((count(&x) / 100) ** 0.25)) into :nlag1 from &data; select int(max(1, (count(&x) ** 0.5) / 5)) into :nlag2 from &data; quit; ods listing close; ods output kpss = _kpss (drop = model lags rename = (prob = probeta)) adf = _adf (drop = model lags rho probrho fstat probf rename = (tau = adf_tau probtau = adf_probtau)) philperron = _pp (drop = model lags rho probrho rename = (tau = pp_tau probtau = pp_probtau)); proc autoreg data = &data; model &x = / noint stationarity = (adf = &nlag1, phillips = &nlag2, kpss = (kernel = nw lag = &nlag1)); run; quit; ods listing; proc sql noprint; create table _1 as select upcase("&x") as vars length = 32, upcase(_adf.type) as type, _adf.adf_tau, _adf.adf_probtau, _pp.pp_tau, _pp.pp_probtau, _kpss.eta, _kpss.probeta, case when _adf.adf_probtau < &sig or _pp.pp_probtau < &sig or _kpss.probeta > &sig then "*" else " " end as _flg, &loop as _i, monotonic() as _j from _adf inner join _pp on _adf.type = _pp.type inner join _kpss on _adf.type = _kpss.type; quit; %if &loop = 1 %then %do; data _result; set _1; run; %end; %else %do; proc append base = _result data = _1; run; %end; proc datasets library = work nolist; delete _1 _adf _pp _kpss / memtype = data; quit; %let loop = %eval(&loop + 1); %end; proc sort data = _result; by _i _j; run; proc report data = _result box spacing = 1 split = "/" nowd; column("STATISTICAL TESTS FOR STATIONARITY/ " vars type adf_tau adf_probtau pp_tau pp_probtau eta probeta _flg); define vars / "VARIABLES/ " width = 20 group order order = data; define type / "TYPE/ " width = 15 order order = data; define adf_tau / "ADF TEST/FOR/UNIT ROOT" width = 10 format = 8.2; define adf_probtau / "P-VALUE/FOR/ADF TEST" width = 10 format = 8.4 center; define pp_tau / "PP TEST/FOR/UNIT ROOT" width = 10 format = 8.2; define pp_probtau / "P-VALUE/FOR/PP TEST" width = 10 format = 8.4 center; define eta / "KPSS TEST/FOR/STATIONARY" width = 10 format = 8.2; define probeta / "P-VALUE/FOR/KPSS TEST" width = 10 format = 8.4 center; define _flg / "STATIONARY/FLAG" width = 10 center; run; %mend stationary;