mirror of
https://gitee.com/fasiondog/hikyuu.git
synced 2024-11-30 02:48:57 +08:00
调整 SPEARMAN 实现
This commit is contained in:
parent
e46c2044df
commit
3ba6a0767f
@ -869,7 +869,7 @@
|
||||
|
||||
:param Indicator ind1: 输入参数1
|
||||
:param Indicator ind2: 输入参数2
|
||||
:param int n: 指定窗口
|
||||
:param int n: 滚动窗口(大于2 或 等于0),等于0时,代表 n 实际使用 ind 的长度
|
||||
|
||||
|
||||
.. py:function:: SQRT([data])
|
||||
|
@ -315,14 +315,4 @@ Indicator HKU_API CORR(const Indicator& ind1, const Indicator& ind2, int n) {
|
||||
return p->calculate();
|
||||
}
|
||||
|
||||
// Indicator HKU_API SPEARMAN(const Indicator& ind1, const Indicator& ind2, int n) {
|
||||
// HKU_ERROR_IF_RETURN(!ind1.getImp() || !ind2.getImp(), Indicator(),
|
||||
// "ind1 or ind2 is Null Indicator!");
|
||||
// HKU_ERROR_IF_RETURN(n < 2, Indicator(), "Invalid param n: {} (need >= 2)", n);
|
||||
// IndicatorImpPtr p = make_shared<IndicatorImp>("SPEARMAN");
|
||||
// p->setParam<int>("n", n);
|
||||
// p->add(IndicatorImp::SPEARMAN, ind1.getImp(), ind2.getImp());
|
||||
// return p->calculate();
|
||||
// }
|
||||
|
||||
} /* namespace hku */
|
||||
|
@ -387,14 +387,6 @@ Indicator HKU_API IF(const Indicator& x, Indicator::value_t a, Indicator::value_
|
||||
*/
|
||||
Indicator HKU_API CORR(const Indicator& ind1, const Indicator& ind2, int n);
|
||||
|
||||
/**
|
||||
* Spearman 相关系数
|
||||
* @param ind1 指标1
|
||||
* @param ind2 指标2
|
||||
* @ingroup Indicator
|
||||
*/
|
||||
// Indicator HKU_API SPEARMAN(const Indicator& ind1, const Indicator& ind2, int n);
|
||||
|
||||
} /* namespace hku */
|
||||
|
||||
#if FMT_VERSION >= 90000
|
||||
|
@ -97,10 +97,6 @@ string HKU_API getOPTypeName(IndicatorImp::OPType op) {
|
||||
name = "CORR";
|
||||
break;
|
||||
|
||||
case IndicatorImp::SPEARMAN:
|
||||
name = "SPEARMAN";
|
||||
break;
|
||||
|
||||
default:
|
||||
name = "UNKNOWN";
|
||||
break;
|
||||
@ -542,10 +538,6 @@ string IndicatorImp::formula() const {
|
||||
buf << m_name << "(" << m_left->formula() << ", " << m_right->formula() << ")";
|
||||
break;
|
||||
|
||||
case SPEARMAN:
|
||||
buf << m_name << "(" << m_left->formula() << ", " << m_right->formula() << ")";
|
||||
break;
|
||||
|
||||
default:
|
||||
HKU_ERROR("Wrong optype! {}", int(m_optype));
|
||||
break;
|
||||
@ -809,10 +801,6 @@ Indicator IndicatorImp::calculate() {
|
||||
execute_corr();
|
||||
break;
|
||||
|
||||
case SPEARMAN:
|
||||
execute_spearman();
|
||||
break;
|
||||
|
||||
default:
|
||||
HKU_ERROR("Unkown Indicator::OPType! {}", int(m_optype));
|
||||
break;
|
||||
@ -1557,116 +1545,6 @@ void IndicatorImp::execute_corr() {
|
||||
setDiscard(discard + 2);
|
||||
}
|
||||
|
||||
static void spearmanLevel(const IndicatorImp::value_t *data, IndicatorImp::value_t *level,
|
||||
size_t total) {
|
||||
std::vector<std::pair<IndicatorImp::value_t, size_t>> 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<IndicatorImp::value_t>(),
|
||||
std::bind(&std::pair<IndicatorImp::value_t, size_t>::first, std::placeholders::_1),
|
||||
std::bind(&std::pair<IndicatorImp::value_t, size_t>::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;
|
||||
}
|
||||
}
|
||||
|
||||
void IndicatorImp::execute_spearman() {
|
||||
m_right->calculate();
|
||||
m_left->calculate();
|
||||
|
||||
const IndicatorImp *maxp, *minp;
|
||||
if (m_right->size() > m_left->size()) {
|
||||
maxp = m_right.get();
|
||||
minp = m_left.get();
|
||||
} else {
|
||||
maxp = m_left.get();
|
||||
minp = m_right.get();
|
||||
}
|
||||
|
||||
size_t total = maxp->size();
|
||||
size_t discard = maxp->size() - minp->size() + minp->discard();
|
||||
if (discard < maxp->discard()) {
|
||||
discard = maxp->discard();
|
||||
}
|
||||
|
||||
size_t result_number = std::min(minp->getResultNumber(), maxp->getResultNumber());
|
||||
size_t diff = maxp->size() - minp->size();
|
||||
_readyBuffer(total, result_number);
|
||||
|
||||
int n = getParam<int>("n");
|
||||
if (n < 2 || discard + 2 > total) {
|
||||
setDiscard(total);
|
||||
return;
|
||||
}
|
||||
|
||||
discard += n - 1;
|
||||
setDiscard(discard);
|
||||
|
||||
auto levela = std::make_unique<value_t[]>(n);
|
||||
auto levelb = std::make_unique<value_t[]>(n);
|
||||
auto *ptra = levela.get();
|
||||
auto *ptrb = levelb.get();
|
||||
|
||||
// 不处理 n 不足的情况,防止只需要计算全部序列时,过于耗时
|
||||
double back = std::pow(n, 3) - n;
|
||||
vector<IndicatorImp::value_t> tmpa;
|
||||
vector<IndicatorImp::value_t> tmpb;
|
||||
tmpa.reserve(n);
|
||||
tmpa.reserve(n);
|
||||
for (size_t r = 0; r < result_number; ++r) {
|
||||
auto *dst = this->data(r);
|
||||
auto const *maxdata = maxp->data(r);
|
||||
auto const *mindata = minp->data(r);
|
||||
auto const *a = maxdata + discard + 1 - n;
|
||||
auto const *b = mindata + discard + 1 - diff - n;
|
||||
for (size_t i = discard; i < total; ++i) {
|
||||
tmpa.clear();
|
||||
tmpb.clear();
|
||||
for (int j = 0; j < n; j++) {
|
||||
if (!std::isnan(a[j]) && !std::isnan(b[j])) {
|
||||
tmpa.push_back(a[j]);
|
||||
tmpb.push_back(b[j]);
|
||||
}
|
||||
}
|
||||
int act_count = tmpa.size();
|
||||
if (act_count < 2) {
|
||||
continue;
|
||||
}
|
||||
spearmanLevel(tmpa.data(), ptra, act_count);
|
||||
spearmanLevel(tmpb.data(), ptrb, act_count);
|
||||
value_t sum = 0.0;
|
||||
for (int j = 0; j < act_count; j++) {
|
||||
sum += std::pow(ptra[j] - ptrb[j], 2);
|
||||
}
|
||||
dst[i] = act_count == n ? 1.0 - 6.0 * sum / back
|
||||
: 1.0 - 6.0 * sum / (std::pow(act_count, 3) - act_count);
|
||||
a++;
|
||||
b++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void IndicatorImp::_dyn_calculate(const Indicator &ind) {
|
||||
// SPEND_TIME(IndicatorImp__dyn_calculate);
|
||||
const auto &ind_param = getIndParamImp("n");
|
||||
|
@ -31,25 +31,24 @@ class HKU_API IndicatorImp : public enable_shared_from_this<IndicatorImp> {
|
||||
|
||||
public:
|
||||
enum OPType {
|
||||
LEAF, ///< 叶子节点
|
||||
OP, /// OP(OP1,OP2) OP1->calcalue(OP2->calculate(ind))
|
||||
ADD, ///< 加
|
||||
SUB, ///< 减
|
||||
MUL, ///< 乘
|
||||
DIV, ///< 除
|
||||
MOD, ///< 取模
|
||||
EQ, ///< 等于
|
||||
GT, ///< 大于
|
||||
LT, ///< 小于
|
||||
NE, ///< 不等于
|
||||
GE, ///< 大于等于
|
||||
LE, ///< 小于等于
|
||||
AND, ///< 与
|
||||
OR, ///< 或
|
||||
WEAVE, ///< 特殊的,需要两个指标作为参数的指标
|
||||
OP_IF, /// if操作
|
||||
CORR, ///< 相关系数,需要两个指标作为参数
|
||||
SPEARMAN, ///< spearman 相关系数
|
||||
LEAF, ///< 叶子节点
|
||||
OP, /// OP(OP1,OP2) OP1->calcalue(OP2->calculate(ind))
|
||||
ADD, ///< 加
|
||||
SUB, ///< 减
|
||||
MUL, ///< 乘
|
||||
DIV, ///< 除
|
||||
MOD, ///< 取模
|
||||
EQ, ///< 等于
|
||||
GT, ///< 大于
|
||||
LT, ///< 小于
|
||||
NE, ///< 不等于
|
||||
GE, ///< 大于等于
|
||||
LE, ///< 小于等于
|
||||
AND, ///< 与
|
||||
OR, ///< 或
|
||||
WEAVE, ///< 特殊的,需要两个指标作为参数的指标
|
||||
OP_IF, /// if操作
|
||||
CORR, ///< 相关系数,需要两个指标作为参数
|
||||
INVALID
|
||||
};
|
||||
|
||||
|
@ -13,8 +13,10 @@ namespace hku {
|
||||
* Spearman 相关系数
|
||||
* @param ind1 指标1
|
||||
* @param ind2 指标2
|
||||
* @param n 滚动窗口(大于2 或 等于0),等于0时,代表 n 实际使用 ind 的长度
|
||||
* @ingroup Indicator
|
||||
*/
|
||||
Indicator HKU_API SPEARMAN(int n = 0);
|
||||
Indicator HKU_API SPEARMAN(const Indicator& ind1, const Indicator& ind2, int n = 0);
|
||||
|
||||
} // namespace hku
|
@ -18,8 +18,13 @@ ISpearman::ISpearman() : IndicatorImp("SPEARMAN") {
|
||||
setParam<int>("n", 0);
|
||||
}
|
||||
|
||||
ISpearman::ISpearman(const Indicator &ref_ind) : IndicatorImp("SPEARMAN"), m_ref_ind(ref_ind) {
|
||||
setParam<int>("n", 0);
|
||||
ISpearman::ISpearman(int n) : IndicatorImp("SPEARMAN") {
|
||||
setParam<int>("n", n);
|
||||
}
|
||||
|
||||
ISpearman::ISpearman(const Indicator &ref_ind, int n)
|
||||
: IndicatorImp("SPEARMAN"), m_ref_ind(ref_ind) {
|
||||
setParam<int>("n", n);
|
||||
}
|
||||
|
||||
ISpearman::~ISpearman() {}
|
||||
@ -135,10 +140,14 @@ void ISpearman::_calculate(const Indicator &ind) {
|
||||
}
|
||||
}
|
||||
|
||||
Indicator HKU_API SPEARMAN(int n) {
|
||||
return make_shared<ISpearman>(n);
|
||||
}
|
||||
|
||||
Indicator HKU_API SPEARMAN(const Indicator &ind1, const Indicator &ind2, int n) {
|
||||
ISpearman *p = new ISpearman(ind2);
|
||||
p->setParam<int>("n", n);
|
||||
return IndicatorImpPtr(p);
|
||||
auto p = make_shared<ISpearman>(ind2, n);
|
||||
Indicator result(p);
|
||||
return result(ind1);
|
||||
}
|
||||
|
||||
} // namespace hku
|
@ -14,7 +14,8 @@ namespace hku {
|
||||
class ISpearman : public IndicatorImp {
|
||||
public:
|
||||
ISpearman();
|
||||
ISpearman(const Indicator& ref_ind);
|
||||
ISpearman(int n);
|
||||
ISpearman(const Indicator& ref_ind, int n);
|
||||
virtual ~ISpearman();
|
||||
|
||||
virtual bool check() override;
|
||||
|
@ -152,34 +152,34 @@ TEST_CASE("test_SPEARMAN") {
|
||||
CHECK_EQ(result[i], doctest::Approx(expect[i]));
|
||||
}
|
||||
|
||||
// expect = {Null<price_t>(), Null<price_t>(), 1., 0.875, 1.};
|
||||
// result = SPEARMAN(x, y, 3);
|
||||
// CHECK_EQ(result.name(), "SPEARMAN");
|
||||
// CHECK_EQ(result.discard(), 2);
|
||||
// CHECK_EQ(result.size(), a.size());
|
||||
// for (size_t i = result.discard(); i < result.size(); i++) {
|
||||
// CHECK_EQ(result[i], doctest::Approx(expect[i]));
|
||||
// }
|
||||
expect = {Null<price_t>(), Null<price_t>(), 1., 0.875, 1.};
|
||||
result = SPEARMAN(x, y, 3);
|
||||
CHECK_EQ(result.name(), "SPEARMAN");
|
||||
CHECK_EQ(result.discard(), 2);
|
||||
CHECK_EQ(result.size(), a.size());
|
||||
for (size_t i = result.discard(); i < result.size(); i++) {
|
||||
CHECK_EQ(result[i], doctest::Approx(expect[i]));
|
||||
}
|
||||
|
||||
// /** @arg 包含 nan 值 */
|
||||
// price_t null_value = Null<price_t>();
|
||||
// auto x = PRICELIST({3., 8., null_value, 4., 7., 2., null_value, null_value});
|
||||
// auto y = PRICELIST({null_value, 5., 10., 8., null_value, 10., 6., null_value});
|
||||
// // expect = {null_value, , 1., 0.875, 1.};
|
||||
// // nan, 8, nan, 4, nan, 2, nan
|
||||
// // nan, 5, nan, 8, nan, 10, nan,
|
||||
// result = SPEARMAN(x, y, 4);
|
||||
// HKU_INFO("{}", result);
|
||||
// for (size_t i = result.discard(); i < result.size(); i++) {
|
||||
// HKU_INFO("{}: {}", i, result[i]);
|
||||
// }
|
||||
/** @arg 包含 nan 值 */
|
||||
price_t null_value = Null<price_t>();
|
||||
x = PRICELIST({3., 8., null_value, 4., 7., 2., null_value, null_value});
|
||||
y = PRICELIST({null_value, 5., 10., 8., null_value, 10., 6., null_value});
|
||||
// expect = {null_value, , 1., 0.875, 1.};
|
||||
// nan, 8, nan, 4, nan, 2, nan
|
||||
// nan, 5, nan, 8, nan, 10, nan,
|
||||
result = SPEARMAN(x, y, 4);
|
||||
HKU_INFO("{}", result);
|
||||
for (size_t i = result.discard(); i < result.size(); i++) {
|
||||
HKU_INFO("{}: {}", i, result[i]);
|
||||
}
|
||||
|
||||
// x = PRICELIST({8., 4., 2.});
|
||||
// y = PRICELIST({5., 8., 10.});
|
||||
// result = SPEARMAN(x, y, x.size());
|
||||
// HKU_INFO("{}", result);
|
||||
// HKU_INFO("{}", std::pow(null_value, 2));
|
||||
// HKU_INFO("{}", 1.0 * 6.0 * null_value / (std::pow(x.size(), 3) - x.size()));
|
||||
x = PRICELIST({8., 4., 2.});
|
||||
y = PRICELIST({5., 8., 10.});
|
||||
result = SPEARMAN(x, y, x.size());
|
||||
HKU_INFO("{}", result);
|
||||
HKU_INFO("{}", std::pow(null_value, 2));
|
||||
HKU_INFO("{}", 1.0 * 6.0 * null_value / (std::pow(x.size(), 3) - x.size()));
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -210,50 +210,50 @@ TEST_CASE("test_SPEARMAN_benchmark") {
|
||||
|
||||
/** @par 检测点 */
|
||||
TEST_CASE("test_SPEARMAN_export") {
|
||||
// StockManager &sm = StockManager::instance();
|
||||
// string filename(sm.tmpdir());
|
||||
// filename += "/SPEARMAN.xml";
|
||||
StockManager &sm = StockManager::instance();
|
||||
string filename(sm.tmpdir());
|
||||
filename += "/SPEARMAN.xml";
|
||||
|
||||
// Stock stock = sm.getStock("sh000001");
|
||||
// KData kdata = stock.getKData(KQuery(-20));
|
||||
// Indicator x1 = SPEARMAN(CLOSE(kdata), OPEN(kdata), 10);
|
||||
// {
|
||||
// std::ofstream ofs(filename);
|
||||
// boost::archive::xml_oarchive oa(ofs);
|
||||
// oa << BOOST_SERIALIZATION_NVP(x1);
|
||||
// }
|
||||
Stock stock = sm.getStock("sh000001");
|
||||
KData kdata = stock.getKData(KQuery(-20));
|
||||
Indicator x1 = SPEARMAN(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);
|
||||
// }
|
||||
Indicator x2;
|
||||
{
|
||||
std::ifstream ifs(filename);
|
||||
boost::archive::xml_iarchive ia(ifs);
|
||||
ia >> BOOST_SERIALIZATION_NVP(x2);
|
||||
}
|
||||
|
||||
// CHECK_EQ(x2.name(), "SPEARMAN");
|
||||
// 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]));
|
||||
// }
|
||||
// }
|
||||
CHECK_EQ(x2.name(), "SPEARMAN");
|
||||
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]));
|
||||
// }
|
||||
// }
|
||||
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 */
|
||||
|
||||
|
@ -466,6 +466,9 @@ Indicator (*ZHBOND10_2)(const DatetimeList&, double) = ZHBOND10;
|
||||
Indicator (*ZHBOND10_3)(const KData& k, double) = ZHBOND10;
|
||||
Indicator (*ZHBOND10_4)(const Indicator&, double) = ZHBOND10;
|
||||
|
||||
Indicator (*SPEARMAN_1)(int) = SPEARMAN;
|
||||
Indicator (*SPEARMAN_2)(const Indicator&, const Indicator&, int) = SPEARMAN;
|
||||
|
||||
void export_Indicator_build_in(py::module& m) {
|
||||
m.def("KDATA", KDATA1);
|
||||
m.def("KDATA", KDATA3, R"(KDATA([data])
|
||||
@ -1645,12 +1648,13 @@ void export_Indicator_build_in(py::module& m) {
|
||||
:param DatetimeList|KDate|Indicator data: 输入的日期参考,优先使用上下文中的日期
|
||||
:param float default_val: 如果输入的日期早于已有国债数据的最早记录,则使用此默认值)");
|
||||
|
||||
m.def("SPEARMAN", SPEARMAN, py::arg("ind1"), py::arg("ind2"), py::arg("n"),
|
||||
R"(SPEARMAN(ind1, ind2, n)
|
||||
m.def("SPEARMAN", SPEARMAN_1, py::arg("n") = 0);
|
||||
m.def("SPEARMAN", SPEARMAN_2, py::arg("ind1"), py::arg("ind2"), py::arg("n") = 0,
|
||||
R"(SPEARMAN(ind1, ind2[, n])
|
||||
|
||||
Spearman 相关系数
|
||||
|
||||
:param Indicator ind1: 输入参数1
|
||||
:param Indicator ind2: 输入参数2
|
||||
:param int n: 指定窗口)");
|
||||
:param int n: 滚动窗口(大于2 或 等于0),等于0时,代表 n 实际使用 ind 的长度)");
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user