From 00a2dfb37c45af1371112dc81cd60c21ac5ee5a0 Mon Sep 17 00:00:00 2001 From: fasiondog Date: Sun, 3 Mar 2024 18:03:50 +0800 Subject: [PATCH] spearman(continue) --- hikyuu_cpp/hikyuu/indicator/IndicatorImp.cpp | 23 +-- .../hikyuu/indicator/test_SPEARMAN.cpp | 194 ++++++++++++++++++ 2 files changed, 204 insertions(+), 13 deletions(-) create mode 100644 hikyuu_cpp/unit_test/hikyuu/indicator/test_SPEARMAN.cpp diff --git a/hikyuu_cpp/hikyuu/indicator/IndicatorImp.cpp b/hikyuu_cpp/hikyuu/indicator/IndicatorImp.cpp index 4fc3dd17..860840cb 100644 --- a/hikyuu_cpp/hikyuu/indicator/IndicatorImp.cpp +++ b/hikyuu_cpp/hikyuu/indicator/IndicatorImp.cpp @@ -1568,7 +1568,7 @@ static void spearmanLevel(const IndicatorImp::value_t *data, IndicatorImp::value std::sort( data_index.begin(), data_index.end(), std::bind( - std::greater(), + std::less(), std::bind(&std::pair::first, std::placeholders::_1), std::bind(&std::pair::first, std::placeholders::_2))); @@ -1620,8 +1620,11 @@ void IndicatorImp::execute_spearman() { return; } + discard++; + setDiscard(discard); + size_t startPos = discard; - size_t first_end = startPos + n >= total ? total : startPos + n; + size_t first_end = startPos + n - 1 >= total ? total : startPos + n - 1; auto levela = std::make_unique(n); auto levelb = std::make_unique(n); @@ -1636,8 +1639,8 @@ void IndicatorImp::execute_spearman() { size_t n1 = 2; auto const *a = maxdata + startPos + 1 - n1; - auto const *b = mindata + startPos + startPos + 2 - diff - n1; - for (size_t i = startPos + 1; i < first_end; i++) { + auto const *b = mindata + startPos + 1 - diff - n1; + for (size_t i = startPos; i < first_end; i++) { spearmanLevel(a, ptra, n1); spearmanLevel(b, ptrb, n1); value_t sum = 0.0; @@ -1645,16 +1648,12 @@ void IndicatorImp::execute_spearman() { sum += std::pow(ptra[j] - ptrb[j], 2); } dst[i] = 1 - 6.0 * sum / (std::pow(value_t(n1), 3) - n1); - a++; - b++; n1++; } - // auto const *a = maxdata + discard - n; - // auto const *b = mindata + discard + discard - diff - n; - for (size_t i = discard; i < total; ++i) { - // auto *ptra = levela.get(); - // auto *ptrb = levelb.get(); + a++; + b++; + for (size_t i = first_end; i < total; ++i) { spearmanLevel(a, ptra, n); spearmanLevel(b, ptrb, n); value_t sum = 0.0; @@ -1666,8 +1665,6 @@ void IndicatorImp::execute_spearman() { b++; } } - - setDiscard(discard + 2); } void IndicatorImp::_dyn_calculate(const Indicator &ind) { diff --git a/hikyuu_cpp/unit_test/hikyuu/indicator/test_SPEARMAN.cpp b/hikyuu_cpp/unit_test/hikyuu/indicator/test_SPEARMAN.cpp new file mode 100644 index 00000000..24070bd8 --- /dev/null +++ b/hikyuu_cpp/unit_test/hikyuu/indicator/test_SPEARMAN.cpp @@ -0,0 +1,194 @@ +/* + * test_COS.cpp + * + * Copyright (c) 2019 hikyuu.org + * + * Created on: 2019-5-1 + * Author: fasiondog + */ + +#include "../test_config.h" +#include +#include +#include +#include + +using namespace hku; + +/** + * @defgroup test_indicator_COS test_indicator_CORR + * @ingroup test_hikyuu_indicator_suite + * @{ + */ + +static void spearmanLevel(const IndicatorImp::value_t *data, IndicatorImp::value_t *level, + size_t total) { + std::vector> data_index(total); + for (size_t i = 0; i < total; i++) { + data_index[i].first = data[i]; + data_index[i].second = i; + } + + std::sort( + data_index.begin(), data_index.end(), + std::bind( + std::less(), + std::bind(&std::pair::first, std::placeholders::_1), + std::bind(&std::pair::first, std::placeholders::_2))); + + size_t i = 0; + while (i < total) { + size_t count = 1; + IndicatorImp::value_t score = i + 1.0; + for (size_t j = i + 1; j < total; j++) { + if (data_index[i].first != data_index[j].first) { + break; + } + count++; + score += j + 1; + } + score = score / count; + for (size_t j = 0; j < count; j++) { + level[data_index[i + j].second] = score; + } + i += count; + } +} + +/** @par 检测点 */ +TEST_CASE("test_spearmanLevel") { + std::vector a{3., 8., 4., 7., 2.}; + size_t totala = a.size(); + auto levela = std::make_unique(totala); + auto *ptra = levela.get(); + spearmanLevel(a.data(), levela.get(), totala); + + std::vector expecta = {2., 5., 3., 4., 1.}; + for (size_t i = 0; i < totala; i++) { + CHECK_EQ(ptra[i], doctest::Approx(expecta[i])); + } + + std::vector b{5., 10., 8., 10., 6.}; + size_t totalb = b.size(); + auto levelb = std::make_unique(totalb); + auto *ptrb = levelb.get(); + spearmanLevel(b.data(), levelb.get(), totalb); + + std::vector expectb = {1., 4.5, 3., 4.5, 2.}; + for (size_t i = 0; i < totalb; i++) { + CHECK_EQ(ptrb[i], doctest::Approx(expectb[i])); + } +} + +/** @par 检测点 */ +TEST_CASE("test_SPEARMAN") { + Indicator result; + + // 空指标 + result = SPEARMAN(Indicator(), Indicator(), 10); + CHECK_UNARY(result.empty()); + + PriceList a{3., 8., 4., 7., 2.}; + PriceList b{5., 10., 8., 10., 6.}; + + Indicator x = PRICELIST(a); + Indicator y = PRICELIST(b); + + // 非法参数 n + result = SPEARMAN(x, y, 0); + CHECK_UNARY(result.empty()); + result = SPEARMAN(x, y, 1); + CHECK_UNARY(result.empty()); + + // 正常情况 + PriceList expect{Null(), 1., 1., 0.95, 0.875}; + result = SPEARMAN(x, y, a.size()); + CHECK_EQ(result.name(), "SPEARMAN"); + CHECK_EQ(result.discard(), 1); + CHECK_EQ(result.size(), a.size()); + + for (size_t i = result.discard(); i < result.size(); i++) { + CHECK_EQ(result[i], doctest::Approx(expect[i])); + } + + result = SPEARMAN(x, y, 4); + CHECK_EQ(result.name(), "SPEARMAN"); + CHECK_EQ(result.discard(), 1); + CHECK_EQ(result.size(), a.size()); +} + +//----------------------------------------------------------------------------- +// benchmark +//----------------------------------------------------------------------------- +#if ENABLE_BENCHMARK_TEST +TEST_CASE("test_SPEARMAN_benchmark") { + // Stock stock = getStock("sh000001"); + // KData kdata = stock.getKData(KQuery(0)); + // Indicator c = kdata.close(); + // int cycle = 1000; // 测试循环次数 + + // { + // BENCHMARK_TIME_MSG(test_SPEARMAN_benchmark, cycle, fmt::format("data len: {}", + // c.size())); SPEND_TIME_CONTROL(false); for (int i = 0; i < cycle; i++) { + // Indicator ind = ABS(); + // Indicator result = ind(c); + // } + // } +} +#endif + +//----------------------------------------------------------------------------- +// test export +//----------------------------------------------------------------------------- +#if HKU_SUPPORT_SERIALIZATION + +/** @par 检测点 */ +TEST_CASE("test_CORR_export") { + StockManager &sm = StockManager::instance(); + string filename(sm.tmpdir()); + filename += "/COS.xml"; + + Stock stock = sm.getStock("sh000001"); + KData kdata = stock.getKData(KQuery(-20)); + Indicator x1 = CORR(CLOSE(kdata), OPEN(kdata), 10); + { + std::ofstream ofs(filename); + boost::archive::xml_oarchive oa(ofs); + oa << BOOST_SERIALIZATION_NVP(x1); + } + + Indicator x2; + { + std::ifstream ifs(filename); + boost::archive::xml_iarchive ia(ifs); + ia >> BOOST_SERIALIZATION_NVP(x2); + } + + CHECK_EQ(x2.name(), "CORR"); + CHECK_EQ(x1.size(), x2.size()); + CHECK_EQ(x1.discard(), x2.discard()); + CHECK_EQ(x1.getResultNumber(), x2.getResultNumber()); + for (size_t i = x1.discard(); i < x1.size(); ++i) { + if (std::isnan(x1[i])) { + CHECK_UNARY(std::isnan(x2[i])); + } else { + CHECK_EQ(x1[i], doctest::Approx(x2[i])); + } + } + + Indicator x11 = x1.getResult(1); + Indicator x21 = x2.getResult(1); + CHECK_EQ(x11.size(), x21.size()); + CHECK_EQ(x11.discard(), x21.discard()); + CHECK_EQ(x11.getResultNumber(), x21.getResultNumber()); + for (size_t i = x11.discard(); i < x21.size(); ++i) { + if (std::isnan(x11[i])) { + CHECK_UNARY(std::isnan(x21[i])); + } else { + CHECK_EQ(x11[i], doctest::Approx(x21[i])); + } + } +} +#endif /* #if HKU_SUPPORT_SERIALIZATION */ + +/** @} */