Skip to content

Commit 6a73a46

Browse files
authored
Merge pull request #336 from fasiondog/feature/dev
add TR indicator, fixed ATD
2 parents abea2ad + 1eddab2 commit 6a73a46

File tree

10 files changed

+301
-72
lines changed

10 files changed

+301
-72
lines changed

hikyuu_cpp/hikyuu/indicator/build_in.h

+1
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@
116116
#include "crt/TIME.h"
117117
#include "crt/TIMELINE.h"
118118
#include "crt/TIMELINEVOL.h"
119+
#include "crt/TR.h"
119120
#include "crt/TURNOVER.h"
120121
#include "crt/UPNDAY.h"
121122
#include "crt/VAR.h"

hikyuu_cpp/hikyuu/indicator/crt/ATR.h

+2-13
Original file line numberDiff line numberDiff line change
@@ -14,30 +14,19 @@
1414
namespace hku {
1515

1616
/**
17-
* 平均真实波幅(Average True Range)
17+
* 平均真实波幅(Average True Range), TR 的简单平均值
1818
* @param n 计算均值的周期窗口,必须为大于1的整数
1919
* @ingroup Indicator
2020
*/
2121
Indicator HKU_API ATR(int n = 14);
22-
Indicator HKU_API ATR(const IndParam& n);
2322

2423
/**
2524
* 平均真实波幅(Average True Range)
2625
* @param data 待计算的源数据
2726
* @param n 计算均值的周期窗口,必须为大于1的整数
2827
* @ingroup Indicator
2928
*/
30-
inline Indicator HKU_API ATR(const Indicator& data, int n = 14) {
31-
return ATR(n)(data);
32-
}
33-
34-
inline Indicator HKU_API ATR(const Indicator& data, const IndParam& n) {
35-
return ATR(n)(data);
36-
}
37-
38-
inline Indicator HKU_API ATR(const Indicator& data, const Indicator& n) {
39-
return ATR(IndParam(n))(data);
40-
}
29+
Indicator HKU_API ATR(const KData& kdata, int n = 14);
4130

4231
} // namespace hku
4332

hikyuu_cpp/hikyuu/indicator/crt/TR.h

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/*
2+
* TRG.h
3+
*
4+
* Created on: 2019年3月6日
5+
* Author: fasiondog
6+
*/
7+
8+
#pragma once
9+
#ifndef INDICATOR_CRT_TR_H_
10+
#define INDICATOR_CRT_TR_H_
11+
12+
#include "../Indicator.h"
13+
14+
namespace hku {
15+
16+
/**
17+
* @brief 真实波动幅度(TR)
18+
* @details
19+
* <pre>
20+
* 真实波动幅度(TR)是以下三个值中的最大值:
21+
* 1. 当前周期最高价(H)与最低价(L)之差
22+
* 2. 当前周期最高价与前一周期收盘价(PC)之差的绝对值
23+
* 3. 当前周期最低价与前一周期收盘价之差的绝对值
24+
* </pre>
25+
* @ingroup Indicator
26+
*/
27+
Indicator HKU_API TR();
28+
Indicator HKU_API TR(const KData&);
29+
30+
} // namespace hku
31+
32+
#endif /* INDICATOR_CRT_TR_H_ */

hikyuu_cpp/hikyuu/indicator/imp/IAtr.cpp

+38-23
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,12 @@ IAtr::IAtr() : IndicatorImp("ATR", 1) {
1919
setParam<int>("n", 14);
2020
}
2121

22+
IAtr::IAtr(const KData& k, int n) : IndicatorImp("ATR", 1) {
23+
setParam<int>("n", n);
24+
setParam<KData>("kdata", k);
25+
IAtr::_calculate(Indicator());
26+
}
27+
2228
IAtr::~IAtr() {}
2329

2430
void IAtr::_checkParam(const string& name) const {
@@ -27,45 +33,54 @@ void IAtr::_checkParam(const string& name) const {
2733
}
2834
}
2935

30-
void IAtr::_calculate(const Indicator& indicator) {
31-
size_t total = indicator.size();
32-
m_discard = indicator.discard();
36+
void IAtr::_calculate(const Indicator& data) {
37+
HKU_WARN_IF(!isLeaf() && !data.empty(),
38+
"The input is ignored because {} depends on the context!", m_name);
39+
40+
KData kdata = getContext();
41+
size_t total = kdata.size();
42+
HKU_IF_RETURN(total == 0, void());
43+
44+
_readyBuffer(total, 1);
45+
46+
int n = getParam<int>("n");
47+
m_discard = n + 1;
3348
if (m_discard >= total) {
3449
m_discard = total;
3550
return;
3651
}
3752

38-
int n = getParam<int>("n");
39-
size_t startPos = discard();
53+
auto* k = kdata.data();
54+
vector<value_t> buf(total);
55+
for (size_t i = 1; i < total; ++i) {
56+
value_t v1 = k[i].highPrice - k[i].lowPrice;
57+
value_t v2 = std::abs(k[i].highPrice - k[i - 1].closePrice);
58+
value_t v3 = std::abs(k[i].lowPrice - k[i - 1].closePrice);
59+
buf[i] = std::max(std::max(v1, v2), v3);
60+
}
4061

41-
auto const* src = indicator.data();
42-
auto* dst = this->data();
43-
dst[startPos] = src[startPos];
44-
value_t multiplier = 2.0 / (n + 1);
45-
for (size_t i = startPos + 1; i < total; ++i) {
46-
dst[i] = (src[i] - dst[i - 1]) * multiplier + dst[i - 1];
62+
value_t sum = 0.0;
63+
for (size_t i = 1, end = n + 1; i < end; ++i) {
64+
sum += buf[i];
4765
}
48-
}
4966

50-
void IAtr::_dyn_run_one_step(const Indicator& ind, size_t curPos, size_t step) {
51-
HKU_IF_RETURN(step < 1, void());
52-
Indicator slice = SLICE(ind, 0, curPos + 1);
53-
Indicator atr = ATR(slice, step);
54-
if (atr.size() > 0) {
55-
_set(atr[atr.size() - 1], curPos);
67+
auto* dst = this->data();
68+
dst[n] = sum / n;
69+
70+
for (size_t i = n + 1; i < total; ++i) {
71+
sum = buf[i] + sum - buf[i - n];
72+
dst[i] = sum / n;
5673
}
5774
}
5875

5976
Indicator HKU_API ATR(int n) {
60-
IndicatorImpPtr p = make_shared<IAtr>();
77+
auto p = make_shared<IAtr>();
6178
p->setParam<int>("n", n);
6279
return Indicator(p);
6380
}
6481

65-
Indicator HKU_API ATR(const IndParam& n) {
66-
IndicatorImpPtr p = make_shared<IAtr>();
67-
p->setIndParam("n", n);
68-
return Indicator(p);
82+
Indicator HKU_API ATR(const KData& kdata, int n) {
83+
return Indicator(make_shared<IAtr>(kdata, n));
6984
}
7085

7186
} /* namespace hku */

hikyuu_cpp/hikyuu/indicator/imp/IAtr.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,13 @@
1414
namespace hku {
1515

1616
class IAtr : public IndicatorImp {
17-
INDICATOR_IMP_SUPPORT_DYNAMIC_STEP(IAtr)
17+
INDICATOR_IMP(IAtr)
18+
INDICATOR_NEED_CONTEXT
1819
INDICATOR_IMP_NO_PRIVATE_MEMBER_SERIALIZATION
1920

2021
public:
2122
IAtr();
23+
explicit IAtr(const KData&, int n);
2224
virtual ~IAtr();
2325
virtual void _checkParam(const string& name) const override;
2426
};
+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/*
2+
* Copyright (c) 2025 hikyuu.org
3+
*
4+
* Created on: 2025-03-05
5+
* Author: fasiondog
6+
*/
7+
8+
#include "ITr.h"
9+
10+
#if HKU_SUPPORT_SERIALIZATION
11+
BOOST_CLASS_EXPORT(hku::ITr)
12+
#endif
13+
14+
namespace hku {
15+
16+
ITr::ITr() : IndicatorImp("TR", 1) {}
17+
18+
ITr::~ITr() {}
19+
20+
ITr::ITr(const KData& k) : IndicatorImp("TR", 1) {
21+
setParam<KData>("kdata", k);
22+
ITr::_calculate(Indicator());
23+
}
24+
25+
void ITr::_calculate(const Indicator& data) {
26+
HKU_WARN_IF(!isLeaf() && !data.empty(),
27+
"The input is ignored because {} depends on the context!", m_name);
28+
29+
KData kdata = getContext();
30+
size_t total = kdata.size();
31+
HKU_IF_RETURN(total == 0, void());
32+
33+
_readyBuffer(total, 1);
34+
35+
m_discard = 1;
36+
37+
auto* k = kdata.data();
38+
auto* dst = this->data();
39+
for (size_t i = m_discard; i < total; ++i) {
40+
value_t v1 = k[i].highPrice - k[i].lowPrice;
41+
value_t v2 = std::abs(k[i].highPrice - k[i - 1].closePrice);
42+
value_t v3 = std::abs(k[i].lowPrice - k[i - 1].closePrice);
43+
dst[i] = std::max(std::max(v1, v2), v3);
44+
}
45+
}
46+
47+
Indicator HKU_API TR() {
48+
return make_shared<ITr>()->calculate();
49+
}
50+
51+
Indicator HKU_API TR(const KData& k) {
52+
return Indicator(make_shared<ITr>(k));
53+
}
54+
55+
} /* namespace hku */

hikyuu_cpp/hikyuu/indicator/imp/ITr.h

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/*
2+
* Copyright (c) 2025 hikyuu.org
3+
*
4+
* Created on: 2025-03-05
5+
* Author: fasiondog
6+
*/
7+
8+
#pragma once
9+
#ifndef INDICATOR_IMP_ITR_H_
10+
#define INDICATOR_IMP_ITR_H_
11+
12+
#include "../Indicator.h"
13+
14+
namespace hku {
15+
16+
/*
17+
* 真实波动幅度(TR)是以下三个值中的最大值:
18+
* 1. 当前周期最高价与最低价之差
19+
* 2. 当前周期最高价与前一周期收盘价之差的绝对值
20+
* 3. 当前周期最低价与前一周期收盘价之差的绝对值
21+
*/
22+
class ITr : public IndicatorImp {
23+
INDICATOR_IMP(ITr)
24+
INDICATOR_NEED_CONTEXT
25+
INDICATOR_IMP_NO_PRIVATE_MEMBER_SERIALIZATION
26+
27+
public:
28+
ITr();
29+
explicit ITr(const KData&);
30+
virtual ~ITr();
31+
};
32+
33+
} /* namespace hku */
34+
35+
#endif /* INDICATOR_IMP_ITR_H_ */

hikyuu_cpp/unit_test/hikyuu/indicator/test_ATR.cpp

+14-21
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,10 @@
1111
#include <fstream>
1212
#include <hikyuu/StockManager.h>
1313
#include <hikyuu/indicator/crt/ATR.h>
14+
#include <hikyuu/indicator/crt/TR.h>
15+
#include <hikyuu/indicator/crt/MA.h>
16+
#include <hikyuu/indicator/crt/DISCARD.h>
1417
#include <hikyuu/indicator/crt/KDATA.h>
15-
#include <hikyuu/indicator/crt/PRICELIST.h>
1618

1719
using namespace hku;
1820

@@ -24,24 +26,16 @@ using namespace hku;
2426

2527
/** @par 检测点 */
2628
TEST_CASE("test_ATR") {
27-
Indicator result;
29+
auto k = getKData("sh000001", KQuery(-30));
2830

29-
PriceList a;
30-
for (int i = 0; i < 10; ++i) {
31-
a.push_back(i / 2.);
32-
}
33-
34-
vector<Indicator::value_t> expect = {0., 0.333333, 0.77778, 1.25926, 1.75309,
35-
2.25103, 2.75034, 3.25011, 3.75004, 4.25001};
36-
37-
Indicator data = PRICELIST(a);
31+
auto atr = ATR(k, 10);
32+
CHECK_EQ(atr.name(), "ATR");
33+
CHECK_EQ(atr.size(), k.size());
34+
CHECK_EQ(atr.discard(), 11);
3835

39-
result = ATR(data, 2);
40-
CHECK_EQ(result.name(), "ATR");
41-
CHECK_EQ(result.discard(), 0);
42-
CHECK_EQ(result.size(), data.size());
43-
for (int i = 0, len = data.size(); i < len; ++i) {
44-
CHECK_EQ(result[i], doctest::Approx(expect[i]));
36+
auto expect = DISCARD(MA(TR(), 10), 11)(k);
37+
for (size_t i = atr.discard(); i < atr.size(); ++i) {
38+
CHECK_EQ(atr[i], doctest::Approx(expect[i]));
4539
}
4640
}
4741

@@ -52,15 +46,14 @@ TEST_CASE("test_ATR") {
5246
TEST_CASE("test_ATR_benchmark") {
5347
Stock stock = getStock("sh000001");
5448
KData kdata = stock.getKData(KQuery(0));
55-
Indicator c = kdata.close();
5649
int cycle = 1000; // 测试循环次数
5750

5851
{
59-
BENCHMARK_TIME_MSG(test_ATR_benchmark, cycle, fmt::format("data len: {}", c.size()));
52+
BENCHMARK_TIME_MSG(test_ATR_benchmark, cycle, fmt::format("data len: {}", kdata.size()));
6053
SPEND_TIME_CONTROL(false);
6154
for (int i = 0; i < cycle; i++) {
6255
Indicator ind = ATR();
63-
Indicator result = ind(c);
56+
Indicator result = ind(kdata);
6457
}
6558
}
6659
}
@@ -79,7 +72,7 @@ TEST_CASE("test_ATR_export") {
7972

8073
Stock stock = sm.getStock("sh000001");
8174
KData kdata = stock.getKData(KQuery(-20));
82-
Indicator x1 = ATR(CLOSE(kdata));
75+
Indicator x1 = ATR(kdata);
8376
{
8477
std::ofstream ofs(filename);
8578
boost::archive::xml_oarchive oa(ofs);

0 commit comments

Comments
 (0)