From 5bc8d0dc8f95f53e86fd4e3e461158ceb09af4c6 Mon Sep 17 00:00:00 2001 From: fasiondog Date: Sun, 3 Sep 2023 19:10:05 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96STDED/STDP=EF=BC=8C=E4=BD=BF?= =?UTF-8?q?=E7=94=A8=E7=A7=BB=E4=BD=8D=E7=AE=97=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hikyuu_cpp/hikyuu/indicator/imp/IStdev.cpp | 58 ++++++++++++------- hikyuu_cpp/hikyuu/indicator/imp/IStdp.cpp | 56 +++++++++++------- .../unit_test/hikyuu/indicator/test_STDEV.cpp | 14 ++--- .../unit_test/hikyuu/indicator/test_STDP.cpp | 8 ++- .../unit_test/hikyuu/indicator/test_VAR.cpp | 4 +- 5 files changed, 88 insertions(+), 52 deletions(-) diff --git a/hikyuu_cpp/hikyuu/indicator/imp/IStdev.cpp b/hikyuu_cpp/hikyuu/indicator/imp/IStdev.cpp index d7350cad..f6d5ef5c 100644 --- a/hikyuu_cpp/hikyuu/indicator/imp/IStdev.cpp +++ b/hikyuu_cpp/hikyuu/indicator/imp/IStdev.cpp @@ -26,40 +26,54 @@ bool IStdev::check() { void IStdev::_calculate(const Indicator& data) { size_t total = data.size(); - int n = getParam("n"); - - m_discard = data.discard() + n - 1; + m_discard = data.discard(); if (m_discard >= total) { m_discard = total; return; } - Indicator ma = MA(data, n); - size_t N = n - 1; - for (size_t i = discard(); i < total; ++i) { - price_t mean = ma[i]; - price_t sum = 0.0; - for (size_t j = i + 1 - n; j <= i; ++j) { - sum += std::pow(data[j] - mean, 2); - } - _set(std::sqrt(sum / N), i); + int n = getParam("n"); + + vector pow_buf(data.size()); + price_t ex = 0.0, ex2 = 0.0; + size_t num = 0; + size_t start_pos = m_discard; + size_t first_end = start_pos + n >= total ? total : start_pos + n; + price_t k = data[start_pos]; + for (size_t i = start_pos; i < first_end; i++) { + num++; + price_t d = data[i] - k; + ex += d; + price_t d_pow = std::pow(d, 2); + pow_buf[i] = d_pow; + ex2 += d_pow; + _set(num == 1 ? 0. : std::sqrt((ex2 - std::pow(ex, 2) / num) / (num - 1)), i); + } + + for (size_t i = first_end; i < total; i++) { + ex -= data[i - n] - k; + ex2 -= pow_buf[i - n]; + price_t d = data[i] - k; + ex += d; + price_t d_pow = std::pow(d, 2); + pow_buf[i] = d_pow; + ex2 += d_pow; + _set(std::sqrt((ex2 - std::pow(ex, 2) / n) / (n - 1)), i); } } void IStdev::_dyn_run_one_step(const Indicator& ind, size_t curPos, size_t step) { - HKU_IF_RETURN(step > 0 && curPos < ind.discard() + step - 1, void()); size_t start = _get_step_start(curPos, step, ind.discard()); - price_t sum = 0.0; + size_t num = 0; + price_t ex = 0.0, ex2 = 0.0; + price_t k = ind[start]; for (size_t i = start; i <= curPos; i++) { - sum += ind[i]; + num++; + price_t d = ind[i] - k; + ex += d; + ex2 += std::pow(d, 2); } - price_t mean = sum / step; - sum = 0.0; - size_t N = step - 1; - for (size_t i = start; i <= curPos; i++) { - sum += std::pow(ind[i] - mean, 2); - } - _set(std::sqrt(sum / N), curPos); + _set(num <= 1 ? 0.0 : std::sqrt((ex2 - std::pow(ex, 2) / num) / (num - 1)), curPos); } Indicator HKU_API STDEV(int n) { diff --git a/hikyuu_cpp/hikyuu/indicator/imp/IStdp.cpp b/hikyuu_cpp/hikyuu/indicator/imp/IStdp.cpp index 8da7e23f..cb1a8e20 100644 --- a/hikyuu_cpp/hikyuu/indicator/imp/IStdp.cpp +++ b/hikyuu_cpp/hikyuu/indicator/imp/IStdp.cpp @@ -28,38 +28,54 @@ bool IStdp::check() { void IStdp::_calculate(const Indicator& data) { size_t total = data.size(); - int n = getParam("n"); - - m_discard = data.discard() + n - 1; + m_discard = data.discard(); if (m_discard >= total) { m_discard = total; return; } - Indicator ma = MA(data, n); - for (size_t i = discard(); i < total; ++i) { - price_t mean = ma[i]; - price_t sum = 0.0; - for (size_t j = i + 1 - n; j <= i; ++j) { - sum += std::pow(data[j] - mean, 2); - } - _set(std::sqrt(sum / n), i); + int n = getParam("n"); + + vector pow_buf(data.size()); + price_t ex = 0.0, ex2 = 0.0; + size_t num = 0; + size_t start_pos = m_discard; + size_t first_end = start_pos + n >= total ? total : start_pos + n; + price_t k = data[start_pos]; + for (size_t i = start_pos; i < first_end; i++) { + num++; + price_t d = data[i] - k; + ex += d; + price_t d_pow = std::pow(d, 2); + pow_buf[i] = d_pow; + ex2 += d_pow; + _set(std::sqrt((ex2 - std::pow(ex, 2) / num) / num), i); + } + + for (size_t i = first_end; i < total; i++) { + ex -= data[i - n] - k; + ex2 -= pow_buf[i - n]; + price_t d = data[i] - k; + ex += d; + price_t d_pow = std::pow(d, 2); + pow_buf[i] = d_pow; + ex2 += d_pow; + _set(std::sqrt((ex2 - std::pow(ex, 2) / n) / n), i); } } void IStdp::_dyn_run_one_step(const Indicator& ind, size_t curPos, size_t step) { - HKU_IF_RETURN(step > 0 && curPos < ind.discard() + step - 1, void()); size_t start = _get_step_start(curPos, step, ind.discard()); - price_t sum = 0.0; + size_t num = 0; + price_t ex = 0.0, ex2 = 0.0; + price_t k = ind[start]; for (size_t i = start; i <= curPos; i++) { - sum += ind[i]; + num++; + price_t d = ind[i] - k; + ex += d; + ex2 += std::pow(d, 2); } - price_t mean = sum / step; - sum = 0.0; - for (size_t i = start; i <= curPos; i++) { - sum += std::pow(ind[i] - mean, 2); - } - _set(std::sqrt(sum / step), curPos); + _set(num == 0 ? 0.0 : std::sqrt((ex2 - std::pow(ex, 2) / num) / num), curPos); } Indicator HKU_API STDP(int n) { diff --git a/hikyuu_cpp/unit_test/hikyuu/indicator/test_STDEV.cpp b/hikyuu_cpp/unit_test/hikyuu/indicator/test_STDEV.cpp index 13c403b2..11db7825 100644 --- a/hikyuu_cpp/unit_test/hikyuu/indicator/test_STDEV.cpp +++ b/hikyuu_cpp/unit_test/hikyuu/indicator/test_STDEV.cpp @@ -35,13 +35,13 @@ TEST_CASE("test_STDEV") { Indicator ind = PRICELIST(d); Indicator dev = STDEV(ind, 10); CHECK_EQ(dev.size(), 15); - CHECK_UNARY(std::isnan(dev[8])); - CHECK_LT(std::fabs(dev[9] - 2.923088), 0.000001); - CHECK_LT(std::fabs(dev[10] - 3.142893), 0.000001); - CHECK_LT(std::fabs(dev[11] - 2.830390), 0.000001); - CHECK_LT(std::fabs(dev[12] - 3.267686), 0.000001); - CHECK_LT(std::fabs(dev[13] - 3.653004), 0.000001); - CHECK_LT(std::fabs(dev[14] - 4.001388), 0.000001); + + vector expected{0, 0.707107, 1, 1.29099, 1.58114, + 1.47196, 1.97605, 1.83225, 2.44949, 2.92309, + 3.14289, 2.83039, 3.26769, 3.653, 4.00139}; + for (size_t i = 0; i < dev.size(); i++) { + CHECK_EQ(dev[i], doctest::Approx(expected[i]).epsilon(0.0001)); + } /** @arg n = 1时 */ dev = STDEV(ind, 1); diff --git a/hikyuu_cpp/unit_test/hikyuu/indicator/test_STDP.cpp b/hikyuu_cpp/unit_test/hikyuu/indicator/test_STDP.cpp index 9eee6453..dbe1b940 100644 --- a/hikyuu_cpp/unit_test/hikyuu/indicator/test_STDP.cpp +++ b/hikyuu_cpp/unit_test/hikyuu/indicator/test_STDP.cpp @@ -36,7 +36,13 @@ TEST_CASE("test_STDP") { Indicator dev = STDP(ind, 10); CHECK_EQ(dev.name(), "STDP"); CHECK_EQ(dev.size(), 15); - CHECK_UNARY(std::isnan(dev[8])); + + vector expected{0, 0.5, 0.816497, 1.11803, 1.41421, 1.34371, 1.82946, 1.71391, + 2.3094, 2.77308, 2.98161, 2.68514, 3.1, 3.46554, 3.79605}; + for (size_t i = 0; i < dev.size(); i++) { + CHECK_EQ(dev[i], doctest::Approx(expected[i]).epsilon(0.0001)); + } + CHECK_LT(std::fabs(dev[9] - 2.77308), 0.00001); CHECK_LT(std::fabs(dev[10] - 2.98161), 0.00001); CHECK_LT(std::fabs(dev[11] - 2.68514), 0.00001); diff --git a/hikyuu_cpp/unit_test/hikyuu/indicator/test_VAR.cpp b/hikyuu_cpp/unit_test/hikyuu/indicator/test_VAR.cpp index 1d14b084..f1948663 100644 --- a/hikyuu_cpp/unit_test/hikyuu/indicator/test_VAR.cpp +++ b/hikyuu_cpp/unit_test/hikyuu/indicator/test_VAR.cpp @@ -39,9 +39,9 @@ TEST_CASE("test_VAR") { CHECK_EQ(dev.name(), "VAR"); CHECK_EQ(dev.size(), 15); - vector expected{0., 0.55, 1., 1.666667, 2.5, 2.16667, 3.90476, 3.35714, + vector expected{0., 0.5, 1., 1.666667, 2.5, 2.16667, 3.90476, 3.35714, 6., 8.54444, 9.87778, 8.01111, 10.6778, 13.3444, 16.0111}; - for (size_t i = 9; i < dev.size(); i++) { + for (size_t i = 0; i < dev.size(); i++) { CHECK_EQ(dev[i], doctest::Approx(expected[i]).epsilon(0.001)); }