Skip to content

Commit

Permalink
Merge pull request #189 from fasiondog/feature/analysis
Browse files Browse the repository at this point in the history
优化 ALIGN,增加 use_null 参数控制对齐填充
  • Loading branch information
fasiondog committed Mar 7, 2024
2 parents 2108f34 + 6ced97d commit 5467245
Show file tree
Hide file tree
Showing 5 changed files with 261 additions and 63 deletions.
5 changes: 3 additions & 2 deletions docs/source/indicator/indicator.rst
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,13 @@
:rtype: Indicator


.. py:function:: ALIGN(data, ref):
.. py:function:: ALIGN(data, ref[, use_null=True]):
按指定的参考日期对齐

:param Indicator data: 输入数据
:param ref: 指定做为日期参考的 DatetimeList、Indicator 或 KData
:param DatetimeList|Indicator|KData ref: 指定做为日期参考的 DatetimeList、Indicator 或 KData
:param bool use_null: 缺失数据使用 nan 填充; 否则使用小于对应日期且最接近对应日期的数据
:retype: Indicator

.. py:function:: AMA([data, n=10, fast_n=2, slow_n=30])
Expand Down
23 changes: 12 additions & 11 deletions hikyuu_cpp/hikyuu/indicator/crt/ALIGN.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,21 +19,22 @@ namespace hku {
* 按指定日期对齐
* @ingroup Indicator
*/
Indicator HKU_API ALIGN(const DatetimeList&);
Indicator ALIGN(const Indicator& ind, const DatetimeList& ref);
Indicator ALIGN(const Indicator& ind, const Indicator& ref);
Indicator ALIGN(const Indicator& ind, const KData& ref);

inline Indicator ALIGN(const Indicator& ind, const DatetimeList& ref) {
return ALIGN(ref)(ind);
Indicator HKU_API ALIGN(bool use_null = true);
Indicator HKU_API ALIGN(const DatetimeList&, bool use_null = true);
Indicator ALIGN(const Indicator& ind, const DatetimeList& ref, bool use_null = true);
Indicator ALIGN(const Indicator& ind, const Indicator& ref, bool use_null = true);
Indicator ALIGN(const Indicator& ind, const KData& ref, bool use_null = true);

inline Indicator ALIGN(const Indicator& ind, const DatetimeList& ref, bool use_null) {
return ALIGN(ref, use_null)(ind);
}

inline Indicator ALIGN(const Indicator& ind, const Indicator& ref) {
return ALIGN(ref.getDatetimeList())(ind);
inline Indicator ALIGN(const Indicator& ind, const Indicator& ref, bool use_null) {
return ALIGN(ref.getDatetimeList(), use_null)(ind);
}

inline Indicator ALIGN(const Indicator& ind, const KData& ref) {
return ALIGN(ref.getDatetimeList())(ind);
inline Indicator ALIGN(const Indicator& ind, const KData& ref, bool use_null) {
return ALIGN(ref.getDatetimeList(), use_null)(ind);
}

} // namespace hku
Expand Down
86 changes: 65 additions & 21 deletions hikyuu_cpp/hikyuu/indicator/imp/IAlign.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,9 @@ BOOST_CLASS_EXPORT(hku::IAlign)

namespace hku {

IAlign::IAlign() : IndicatorImp("ALIGN", 1) {
setParam<DatetimeList>("align_date_list", DatetimeList());
IAlign::IAlign() : IndicatorImp("ALIGN") {
setParam<DatetimeList>("align_date_list", DatetimeList()); // 要对齐的日期序列(须已升序排列)
setParam<bool>("use_null", true); // 缺失的数据是否使用 nan 填充
}

IAlign::~IAlign() {}
Expand All @@ -29,6 +30,13 @@ void IAlign::_calculate(const Indicator& ind) {
// ref_date_list 参数会影响 IndicatorImp 全局,勿随意修改
DatetimeList dates = getParam<DatetimeList>("align_date_list");
size_t total = dates.size();

// 如果 align_date_list 无效,则尝试取自身上下文中的日期作为参考日期
if (0 == total) {
dates = getContext().getDatetimeList();
total = dates.size();
}

m_result_num = ind.getResultNumber();
_readyBuffer(total, m_result_num);

Expand All @@ -38,17 +46,27 @@ void IAlign::_calculate(const Indicator& ind) {
return;
}

// 处理本身没有上下文日期的指标
if (ind.getDatetimeList().size() == 0) {
bool use_null = getParam<bool>("use_null");

// 处理传入的数据本身没有上下文日期的指标,无法对标的情况:
// 1.如果 use_null, 则直接返回,m_discard 标记全部
// 2.数据长度小于等于日期序列长度,则按右对齐,即最后的数据对应最后的日期,前面缺失的数据做抛弃处理
// 3.数据长度大于日期序列长度,按右对其,前面超出日期序列的数据丢弃
DatetimeList ind_dates = ind.getDatetimeList();
if (ind_dates.size() == 0) {
if (use_null) {
m_discard = total;
return;
}

if (ind_total <= total) {
size_t offset = total - ind_total;
m_discard = offset + ind.discard();
for (size_t r = 0; r < m_result_num; r++) {
auto const* src = ind.data(r);
auto* dst = this->data(r);
for (size_t i = m_discard; i < total; i++) {
dst[i] = src[i - offset];
}
memcpy(dst + m_discard, src + ind.discard(),
sizeof(IndicatorImp::value_t) * (total - m_discard));
}
return;

Expand All @@ -72,13 +90,23 @@ void IAlign::_calculate(const Indicator& ind) {
}

// 其它有上下文日期对应的指标数据
size_t ind_idx = 0;
// 1. 如果没有刚好相等的日期,则取小于对应日期且最靠近对应日期的数据
// 2. 如果有对应的日期,取对应日期的数据
size_t ind_idx = ind.discard();
for (size_t i = 0; i < total; i++) {
if (ind_idx >= ind_total) {
if (!use_null) {
size_t pos = ind_total - 1;
for (size_t r = 0; r < m_result_num; r++) {
for (size_t j = i; j < total; j++) {
_set(ind.get(pos, r), j, r);
}
}
}
break;
}

Datetime ind_date = ind.getDatetime(ind_idx);
const Datetime& ind_date = ind_dates[ind_idx];
if (ind_date == dates[i]) {
for (size_t r = 0; r < m_result_num; r++) {
_set(ind.get(ind_idx, r), i, r);
Expand All @@ -87,12 +115,12 @@ void IAlign::_calculate(const Indicator& ind) {

} else if (ind_date < dates[i]) {
size_t j = ind_idx + 1;
while (j < ind_total && ind.getDatetime(j) < dates[i]) {
while (j < ind_total && ind_dates[j] < dates[i]) {
j++;
}

if (j >= ind_total) {
if (i >= 1) {
if (!use_null) {
for (size_t r = 0; r < m_result_num; r++) {
price_t val = ind.get(j - 1, r);
for (; i < total; i++) {
Expand All @@ -103,36 +131,52 @@ void IAlign::_calculate(const Indicator& ind) {
break;
}

if (ind.getDatetime(j) == dates[i]) {
if (ind_dates[j] == dates[i]) {
for (size_t r = 0; r < m_result_num; r++) {
_set(ind.get(j, r), i, r);
}
} else if (!use_null && j < ind_total) {
for (size_t r = 0; r < m_result_num; r++) {
_set(ind.get(j - 1, r), i, r);
}
}

ind_idx = j + 1;
}
}

m_discard = total;
for (size_t i = 0; i < total; i++) {
bool all_not_null = true;
if (use_null) {
m_discard = total;
}
size_t i = 0;
while (i < total) {
size_t not_null_count = 0;
for (size_t r = 0; r < m_result_num; r++) {
if (std::isnan(get(i, r))) {
all_not_null = false;
break;
if (!std::isnan(get(i, r))) {
not_null_count++;
}
}

if (all_not_null) {
if (not_null_count == m_result_num) {
m_discard = i;
break;
}
i++;
}
if (i == total) {
m_discard = total;
}
}

Indicator HKU_API ALIGN(bool use_null) {
IndicatorImpPtr p = make_shared<IAlign>();
p->setParam<bool>("use_null", use_null);
return Indicator(p);
}

Indicator HKU_API ALIGN(const DatetimeList& ref) {
Indicator HKU_API ALIGN(const DatetimeList& ref, bool use_null) {
IndicatorImpPtr p = make_shared<IAlign>();
p->setParam<DatetimeList>("align_date_list", ref);
p->setParam<bool>("use_null", use_null);
return Indicator(p);
}

Expand Down

0 comments on commit 5467245

Please sign in to comment.