| Signature | Description |
|---|---|
enum class stationary_test : unsigned char { // Kwiatkowski-Phillips-Schmidt–Shin (KPSS) // In econometrics, Kwiatkowski–Phillips–Schmidt–Shin (KPSS) tests are // used for testing a null hypothesis that an observable time series is stationary around a deterministic // trend (i.e. trend-stationary) against the alternative of a unit root. Contrary to most unit root tests, // the presence of a unit root is not the null hypothesis but the alternative. Additionally, in the KPSS // test, the absence of a unit root is not a proof of stationarity but, by design, of trend-stationarity. // This is an important distinction since it is possible for a time series to be non-stationary, have no // unit root yet be trend-stationary. // // In a KPSS test, a higher test statistic value (meaning a larger calculated KPSS statistic) indicates a // greater likelihood that the time series is not stationary around a deterministic trend, while a lower // value suggests stationarity; essentially, you want a low KPSS test value to conclude stationarity. // kpss = 1, // Augmented Dickey-Fuller (ADF) // In statistics, an augmented Dickey–Fuller test (ADF) tests the null hypothesis that a unit root is // present in a time series sample. The alternative hypothesis depends on which version of the test is // used, but is usually stationarity or trend-stationarity. It is an augmented version of the // Dickey–Fuller test for a larger and more complicated set of time series models. The augmented // Dickey–Fuller (ADF) statistic, used in the test, is a negative number. The more negative it is, the // stronger the rejection of the hypothesis that there is a unit root at some level of confidence. // // To interpret an ADF test statistic, compare its value to the critical value at a chosen significance // level (usually 0.05): if the test statistic is less than the critical value, you reject the null // hypothesis and conclude that the time series is stationary; if it's greater than the critical value, // you fail to reject the null hypothesis, indicating non-stationarity; a more negative ADF statistic // signifies stronger evidence against the null hypothesis (i.e., more likely stationary). // adf = 2, }; struct StationaryTestParams { // Only considered for KPSS test // double critical_values[4] { 0.347, 0.463, 0.574, 0.739 }; // Only considered for ADF test // std::size_t adf_lag { 1 }; bool adf_with_trend { false }; }; |
Methods to test if a time-series is stationary Also, a struct to contain the necessary parameters to StationaryCheckVisitor constructor |
| Signature | Description | Parameters |
|---|---|---|
#include <DataFrame/DataFrameStatsVisitors.h> template<arithmetic T, typename I = unsigned long> struct StationaryCheckVisitor; // ------------------------------------- template<typename T, typename I = unsigned long> using stac_v = StationaryCheckVisitor<T, I>; |
This is a "single action visitor", meaning it is passed the whole data vector in one call and you must use the single_act_visit() interface. This visitor uses the specified method to test if the given time-series (i.e., column) is stationary. This visitor has the following methods to get results: get_kpss_value(): Returns the KPSS calcuated value. get_kpss_statistic(): Returns the percentage calculated by comparing KPSS value against critical_values. get_adf_statistic(): Returns the ADF calcuated statistics.
explicit
StationaryCheckVisitor(stationary_test method,
const StationaryTestParams params = { })
method: One of the above methods.params: Necessary parameters depending what method is being used. |
T: Column data type. I: Index type. |
static void test_StationaryCheckVisitor() { std::cout << "\nTesting StationaryCheckVisitor{ } ..." << std::endl; StrDataFrame df; try { df.read("IBM.csv", io_format::csv2); } catch (const DataFrameError &ex) { std::cout << ex.what() << std::endl; } RandGenParams<double> p; p.mean = 0; p.std = 1; p.seed = 123; df.load_column("normal_col", gen_normal_dist<double>(df.get_index().size(), p)); p.max_value = 1000; p.min_value = -1000; df.load_column("uniform col", gen_uniform_real_dist<double>(df.get_index().size(), p)); std::vector<double> log_close; log_close.reserve(df.get_index().size()); for (const auto val : df.get_column<double>("IBM_Close")) log_close.push_back(std::log(val)); df.load_column("log close", std::move(log_close)); DecomposeVisitor<double, std::string> d_v (280, 0.6, 0.01); df.single_act_visit<double>("IBM_Close", d_v); df.load_column("residual close", std::move(d_v.get_residual())); // KPSS tests // StationaryCheckVisitor<double, std::string> sc { stationary_test::kpss }; df.single_act_visit<double>("IBM_Close", sc); assert(std::fabs(sc.get_kpss_value() - 63.5831) < 0.0001); assert(sc.get_kpss_statistic() == 0); df.single_act_visit<double>("normal_col", sc); assert(sc.get_kpss_value() < 0.078); assert(sc.get_kpss_statistic() == 0.1); df.single_act_visit<double>("uniform col", sc); assert(sc.get_kpss_value() < 0.08); assert(sc.get_kpss_statistic() == 0.1); df.single_act_visit<double>("log close", sc); assert(sc.get_kpss_value() < 62.7013); assert(sc.get_kpss_statistic() == 0); df.single_act_visit<double>("residual close", sc); assert(sc.get_kpss_value() < 46.41); assert(sc.get_kpss_statistic() == 0); // ADF tests // StationaryCheckVisitor<double, std::string> sc2 { stationary_test::adf, { .adf_lag = 10, .adf_with_trend = false } }; df.single_act_visit<double>("IBM_Close", sc2); assert(std::fabs(sc2.get_adf_statistic() - 0.989687) < 0.00001); StationaryCheckVisitor<double, std::string> sc3 { stationary_test::adf, { .adf_lag = 25, .adf_with_trend = false } }; df.single_act_visit<double>("IBM_Close", sc3); assert(std::fabs(sc3.get_adf_statistic() - 0.974531) < 0.0000001); StationaryCheckVisitor<double, std::string> sc4 { stationary_test::adf, { .adf_lag = 10, .adf_with_trend = false } }; df.single_act_visit<double>("normal_col", sc4); assert(std::fabs(sc4.get_adf_statistic() - 0.0286854) < 0.0000001); StationaryCheckVisitor<double, std::string> sc5 { stationary_test::adf, { .adf_lag = 25, .adf_with_trend = false } }; df.single_act_visit<double>("normal_col", sc5); assert(std::fabs(sc5.get_adf_statistic() - -0.0017814) < 0.0000001); // ADF tests with trend // StationaryCheckVisitor<double, std::string> sc6 { stationary_test::adf, { .adf_lag = 10, .adf_with_trend = true } }; df.single_act_visit<double>("IBM_Close", sc6); assert(std::fabs(sc6.get_adf_statistic() - 0.977705) < 0.000001); StationaryCheckVisitor<double, std::string> sc7 { stationary_test::adf, { .adf_lag = 25, .adf_with_trend = true } }; df.single_act_visit<double>("IBM_Close", sc7); assert(std::fabs(sc7.get_adf_statistic() - 0.946614) < 0.000001); StationaryCheckVisitor<double, std::string> sc8 { stationary_test::adf, { .adf_lag = 10, .adf_with_trend = true } }; df.single_act_visit<double>("normal_col", sc8); assert(std::fabs(sc8.get_adf_statistic() - 0.0286834) < 0.0000001); StationaryCheckVisitor<double, std::string> sc9 { stationary_test::adf, { .adf_lag = 25, .adf_with_trend = true } }; df.single_act_visit<double>("normal_col", sc9); assert(std::fabs(sc9.get_adf_statistic() - -0.00178569) < 0.0000001); StationaryCheckVisitor<double, std::string> sc10 { stationary_test::adf, { .adf_lag = 10, .adf_with_trend = true } }; df.single_act_visit<double>("log close", sc10); assert(std::fabs(sc10.get_adf_statistic() - 0.972062) < 0.000001); StationaryCheckVisitor<double, std::string> sc11 { stationary_test::adf, { .adf_lag = 10, .adf_with_trend = true } }; df.single_act_visit<double>("residual close", sc11); assert(std::fabs(sc11.get_adf_statistic() - 0.679027) < 0.000001); }