hikyuu 2.5.2__py3-none-win_amd64.whl → 2.5.5__py3-none-win_amd64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- hikyuu/__init__.py +5 -1
- hikyuu/__init__.pyi +522 -511
- hikyuu/analysis/__init__.pyi +490 -485
- hikyuu/analysis/analysis.pyi +491 -486
- hikyuu/core.pyi +492 -487
- hikyuu/cpp/__init__.pyi +2 -2
- hikyuu/cpp/core310.pyd +0 -0
- hikyuu/cpp/core310.pyi +249 -26
- hikyuu/cpp/core311.pyd +0 -0
- hikyuu/cpp/core311.pyi +249 -26
- hikyuu/cpp/core312.pyd +0 -0
- hikyuu/cpp/core312.pyi +249 -26
- hikyuu/cpp/core313.pyd +0 -0
- hikyuu/cpp/core313.pyi +243 -26
- hikyuu/cpp/core38.pyd +0 -0
- hikyuu/cpp/core38.pyi +249 -26
- hikyuu/cpp/core39.pyd +0 -0
- hikyuu/cpp/core39.pyi +249 -26
- hikyuu/cpp/hikyuu.dll +0 -0
- hikyuu/cpp/hikyuu.lib +0 -0
- hikyuu/data/mysql_upgrade/0027.sql +6 -0
- hikyuu/data/pytdx_to_h5.py +7 -4
- hikyuu/data/pytdx_to_mysql.py +7 -4
- hikyuu/data/sqlite_upgrade/0027.sql +8 -0
- hikyuu/draw/drawplot/__init__.py +8 -1
- hikyuu/draw/drawplot/__init__.pyi +11 -7
- hikyuu/draw/drawplot/bokeh_draw.pyi +509 -500
- hikyuu/draw/drawplot/common.pyi +1 -1
- hikyuu/draw/drawplot/echarts_draw.pyi +511 -502
- hikyuu/draw/drawplot/matplotlib_draw.py +129 -8
- hikyuu/draw/drawplot/matplotlib_draw.pyi +571 -515
- hikyuu/draw/elder.pyi +11 -11
- hikyuu/draw/kaufman.pyi +18 -18
- hikyuu/draw/volume.pyi +10 -10
- hikyuu/extend.pyi +501 -495
- hikyuu/fetcher/stock/zh_block_em.py +18 -7
- hikyuu/hub.py +112 -6
- hikyuu/hub.pyi +39 -13
- hikyuu/include/hikyuu/DataType.h +1 -2
- hikyuu/include/hikyuu/StockManager.h +2 -1
- hikyuu/include/hikyuu/StrategyContext.h +12 -3
- hikyuu/include/hikyuu/indicator/Indicator.h +24 -0
- hikyuu/include/hikyuu/indicator/Indicator2InImp.h +1 -0
- hikyuu/include/hikyuu/indicator/build_in.h +2 -0
- hikyuu/include/hikyuu/indicator/crt/ATR.h +2 -13
- hikyuu/include/hikyuu/indicator/crt/BARSSINCE.h +14 -2
- hikyuu/include/hikyuu/indicator/crt/KALMAN.h +30 -0
- hikyuu/include/hikyuu/indicator/crt/TR.h +32 -0
- hikyuu/include/hikyuu/indicator/imp/IAtr.h +3 -1
- hikyuu/include/hikyuu/indicator/imp/IBarsSince.h +6 -0
- hikyuu/include/hikyuu/indicator/imp/IKalman.h +27 -0
- hikyuu/include/hikyuu/indicator/imp/ITr.h +35 -0
- hikyuu/include/hikyuu/python/convert_any.h +299 -0
- hikyuu/include/hikyuu/trade_manage/PositionRecord.h +5 -4
- hikyuu/include/hikyuu/trade_sys/allocatefunds/crt/AF_MultiFactor.h +1 -1
- hikyuu/include/hikyuu/trade_sys/allocatefunds/imp/MultiFactorAllocaterFunds.h +3 -0
- hikyuu/include/hikyuu/trade_sys/condition/ConditionBase.h +4 -1
- hikyuu/include/hikyuu/trade_sys/condition/imp/{SubCondition.h → logic/SubCondition.h} +1 -1
- hikyuu/include/hikyuu/trade_sys/environment/EnvironmentBase.h +20 -6
- hikyuu/include/hikyuu/trade_sys/environment/build_in.h +1 -0
- hikyuu/include/hikyuu/trade_sys/environment/crt/EV_Logic.h +35 -0
- hikyuu/include/hikyuu/trade_sys/environment/imp/logic/AddEnvironment.h +42 -0
- hikyuu/include/hikyuu/trade_sys/environment/imp/logic/AndEnvironment.h +42 -0
- hikyuu/include/hikyuu/trade_sys/environment/imp/logic/DivEnvironment.h +42 -0
- hikyuu/include/hikyuu/trade_sys/environment/imp/logic/MultiEnvironment.h +42 -0
- hikyuu/include/hikyuu/trade_sys/environment/imp/logic/OrEnvironment.h +42 -0
- hikyuu/include/hikyuu/trade_sys/environment/imp/logic/SubEnvironment.h +42 -0
- hikyuu/include/hikyuu/trade_sys/environment/imp/logic/__init__.py +1 -0
- hikyuu/include/hikyuu/trade_sys/portfolio/Portfolio.h +0 -4
- hikyuu/include/hikyuu/trade_sys/signal/crt/SG_Logic.h +68 -7
- hikyuu/include/hikyuu/trade_sys/signal/imp/logic/AndSignal.h +19 -0
- hikyuu/include/hikyuu/trade_sys/signal/imp/logic/OperatorSignal.h +1 -0
- hikyuu/include/hikyuu/trade_sys/signal/imp/logic/OperatorValueSignal.h +1 -0
- hikyuu/include/hikyuu/trade_sys/signal/imp/logic/OrSignal.h +19 -0
- hikyuu/include/hikyuu/utilities/datetime/Datetime.h +2 -1
- hikyuu/include/hikyuu/version.h +4 -4
- hikyuu/indicator/indicator.py +1 -0
- hikyuu/trade_manage/__init__.pyi +506 -499
- hikyuu/trade_manage/broker.pyi +3 -3
- hikyuu/trade_manage/broker_easytrader.pyi +1 -1
- hikyuu/trade_manage/trade.pyi +506 -499
- hikyuu/trade_sys/trade_sys.py +4 -3
- hikyuu/util/__init__.pyi +1 -1
- hikyuu/util/singleton.pyi +1 -1
- {hikyuu-2.5.2.dist-info → hikyuu-2.5.5.dist-info}/METADATA +3 -2
- {hikyuu-2.5.2.dist-info → hikyuu-2.5.5.dist-info}/RECORD +90 -73
- {hikyuu-2.5.2.dist-info → hikyuu-2.5.5.dist-info}/top_level.txt +1 -0
- {hikyuu-2.5.2.dist-info → hikyuu-2.5.5.dist-info}/LICENSE +0 -0
- {hikyuu-2.5.2.dist-info → hikyuu-2.5.5.dist-info}/WHEEL +0 -0
- {hikyuu-2.5.2.dist-info → hikyuu-2.5.5.dist-info}/entry_points.txt +0 -0
|
@@ -10,6 +10,8 @@ import akshare as ak
|
|
|
10
10
|
import pandas as pd
|
|
11
11
|
from hikyuu.util import *
|
|
12
12
|
|
|
13
|
+
em_num_per_page = 100
|
|
14
|
+
|
|
13
15
|
|
|
14
16
|
@hku_catch(ret=[], trace=True)
|
|
15
17
|
def get_hybk_names():
|
|
@@ -17,7 +19,7 @@ def get_hybk_names():
|
|
|
17
19
|
url = "https://19.push2.eastmoney.com/api/qt/clist/get"
|
|
18
20
|
params = {
|
|
19
21
|
"pn": "1",
|
|
20
|
-
"pz":
|
|
22
|
+
"pz": str(em_num_per_page),
|
|
21
23
|
"po": "1",
|
|
22
24
|
"np": "1",
|
|
23
25
|
"ut": "bd1d9ddb04089700cf9c27f6f7426281",
|
|
@@ -31,6 +33,15 @@ def get_hybk_names():
|
|
|
31
33
|
r = requests.get(url, params=params, timeout=15)
|
|
32
34
|
data_json = r.json()
|
|
33
35
|
ret = [(v['f12'], v['f14']) for v in data_json["data"]["diff"]]
|
|
36
|
+
total_page = math.ceil(data_json["data"]["total"] / em_num_per_page)
|
|
37
|
+
for page in range(2, total_page + 1):
|
|
38
|
+
params["pn"] = page
|
|
39
|
+
r = requests.get(url, params=params, timeout=15)
|
|
40
|
+
data_json = r.json()
|
|
41
|
+
if data_json["data"] is None:
|
|
42
|
+
continue
|
|
43
|
+
tmp = [(v['f12'], v['f14']) for v in data_json["data"]["diff"]]
|
|
44
|
+
ret.extend(tmp)
|
|
34
45
|
return ret
|
|
35
46
|
|
|
36
47
|
|
|
@@ -40,7 +51,7 @@ def get_hybk_cons_code(blk_code):
|
|
|
40
51
|
url = "http://30.push2.eastmoney.com/api/qt/clist/get"
|
|
41
52
|
params = {
|
|
42
53
|
"pn": "1",
|
|
43
|
-
"pz":
|
|
54
|
+
"pz": str(em_num_per_page),
|
|
44
55
|
"po": "1",
|
|
45
56
|
"np": "1",
|
|
46
57
|
"ut": "bd1d9ddb04089700cf9c27f6f7426281",
|
|
@@ -54,7 +65,7 @@ def get_hybk_cons_code(blk_code):
|
|
|
54
65
|
r = requests.get(url, params=params, timeout=15)
|
|
55
66
|
data_json = r.json()
|
|
56
67
|
ret = [v['f12'] for v in data_json["data"]["diff"]]
|
|
57
|
-
total_page = math.ceil(data_json["data"]["total"] /
|
|
68
|
+
total_page = math.ceil(data_json["data"]["total"] / em_num_per_page)
|
|
58
69
|
for page in range(2, total_page + 1):
|
|
59
70
|
params["pn"] = page
|
|
60
71
|
r = requests.get(url, params=params, timeout=15)
|
|
@@ -99,7 +110,7 @@ def get_dybk_names():
|
|
|
99
110
|
url = "http://13.push2.eastmoney.com/api/qt/clist/get"
|
|
100
111
|
params = {
|
|
101
112
|
"pn": "1",
|
|
102
|
-
"pz":
|
|
113
|
+
"pz": str(em_num_per_page),
|
|
103
114
|
"po": "1",
|
|
104
115
|
"np": "1",
|
|
105
116
|
"ut": "bd1d9ddb04089700cf9c27f6f7426281",
|
|
@@ -115,7 +126,7 @@ def get_dybk_names():
|
|
|
115
126
|
hku_check(data_json['data'] is not None, "获取地域板块名称列表失败!")
|
|
116
127
|
ret = [(v["f12"], v["f14"]) for v in data_json["data"]["diff"]]
|
|
117
128
|
|
|
118
|
-
total_page = math.ceil(data_json["data"]["total"] /
|
|
129
|
+
total_page = math.ceil(data_json["data"]["total"] / em_num_per_page)
|
|
119
130
|
for page in range(2, total_page + 1):
|
|
120
131
|
params["pn"] = page
|
|
121
132
|
r = requests.get(url, params=params, timeout=15)
|
|
@@ -133,7 +144,7 @@ def get_all_dybk_info(code_market_dict, sep=""):
|
|
|
133
144
|
url = "http://13.push2.eastmoney.com/api/qt/clist/get"
|
|
134
145
|
params = {
|
|
135
146
|
"pn": "1",
|
|
136
|
-
"pz":
|
|
147
|
+
"pz": str(em_num_per_page),
|
|
137
148
|
"po": "1",
|
|
138
149
|
"np": "1",
|
|
139
150
|
"ut": "bd1d9ddb04089700cf9c27f6f7426281",
|
|
@@ -160,7 +171,7 @@ def get_all_dybk_info(code_market_dict, sep=""):
|
|
|
160
171
|
ret[blk_name] = [
|
|
161
172
|
f"{code_market_dict[v['f12']]}{sep}{v['f12']}" for v in stk_json if v['f12'] in code_market_dict]
|
|
162
173
|
|
|
163
|
-
total_page = math.ceil(data["data"]["total"] /
|
|
174
|
+
total_page = math.ceil(data["data"]["total"] / em_num_per_page)
|
|
164
175
|
for page in range(2, total_page + 1):
|
|
165
176
|
params["pn"] = page
|
|
166
177
|
r = requests.get(url, params=params, timeout=15)
|
hikyuu/hub.py
CHANGED
|
@@ -11,6 +11,7 @@ from sqlalchemy.orm import sessionmaker, scoped_session, declarative_base
|
|
|
11
11
|
from sqlalchemy import (create_engine, Sequence, Column, Integer, String, and_, UniqueConstraint)
|
|
12
12
|
from hikyuu.util.singleton import SingletonType
|
|
13
13
|
from hikyuu.util.check import checkif
|
|
14
|
+
from hikyuu.util import hku_info
|
|
14
15
|
import os
|
|
15
16
|
import stat
|
|
16
17
|
import errno
|
|
@@ -19,7 +20,9 @@ import shutil
|
|
|
19
20
|
import pathlib
|
|
20
21
|
import logging
|
|
21
22
|
import importlib
|
|
22
|
-
|
|
23
|
+
import inspect
|
|
24
|
+
import sqlalchemy
|
|
25
|
+
from functools import lru_cache
|
|
23
26
|
|
|
24
27
|
# 引入 git 前需设置环境变量,否则某些情况下会报错失败
|
|
25
28
|
os.environ['GIT_PYTHON_REFRESH'] = 'quiet'
|
|
@@ -79,6 +82,10 @@ class PartModel(Base):
|
|
|
79
82
|
version = Column(String) # 版本
|
|
80
83
|
doc = Column(String) # 帮助说明
|
|
81
84
|
module_name = Column(String) # 实际策略导入模块名
|
|
85
|
+
label = Column(String) # 标签
|
|
86
|
+
__table_args__ = (
|
|
87
|
+
UniqueConstraint('name', name='uq_part_model_name'),
|
|
88
|
+
)
|
|
82
89
|
|
|
83
90
|
def __str__(self):
|
|
84
91
|
return 'PartModel(id={}, hub_name={}, part={}, name={}, author={}, module_name={})'.format(
|
|
@@ -173,6 +180,25 @@ class HubManager(metaclass=SingletonType):
|
|
|
173
180
|
|
|
174
181
|
# 创建仓库数据库
|
|
175
182
|
engine = create_engine("sqlite:///{}/.hikyuu/hub.db".format(usr_dir))
|
|
183
|
+
|
|
184
|
+
inspector = sqlalchemy.inspect(engine)
|
|
185
|
+
if inspector.has_table(PartModel.__tablename__):
|
|
186
|
+
columns = inspector.get_columns(PartModel.__tablename__)
|
|
187
|
+
column_exists = any(column['name'] == 'label' for column in columns)
|
|
188
|
+
if not column_exists:
|
|
189
|
+
add_column_sql = sqlalchemy.text(
|
|
190
|
+
f"ALTER TABLE {PartModel.__tablename__} ADD COLUMN label TEXT;")
|
|
191
|
+
with engine.connect() as connection:
|
|
192
|
+
connection.execute(add_column_sql)
|
|
193
|
+
|
|
194
|
+
indexes = inspector.get_indexes(PartModel.__tablename__)
|
|
195
|
+
index_exists = any(index['name'] == "uq_part_model_name" for index in indexes)
|
|
196
|
+
if not index_exists:
|
|
197
|
+
create_index_sql = sqlalchemy.text(
|
|
198
|
+
f"CREATE INDEX uq_part_model_name ON {PartModel.__tablename__} (name);")
|
|
199
|
+
with engine.connect() as connection:
|
|
200
|
+
connection.execute(create_index_sql)
|
|
201
|
+
|
|
176
202
|
Base.metadata.create_all(engine)
|
|
177
203
|
self._scoped_Session = scoped_session(sessionmaker(autocommit=False, autoflush=False, bind=engine))
|
|
178
204
|
self._session = None
|
|
@@ -365,8 +391,8 @@ class HubManager(metaclass=SingletonType):
|
|
|
365
391
|
except ModuleNotFoundError:
|
|
366
392
|
self.logger.error('{} 缺失 part.py 文件, 位置:"{}"!'.format(module_name, entry.path))
|
|
367
393
|
continue
|
|
368
|
-
except:
|
|
369
|
-
self.logger.error('{} 无法导入该文件: {}'.format(module_name, entry.path))
|
|
394
|
+
except Exception as e:
|
|
395
|
+
self.logger.error('{} 无法导入该文件: {}! {}'.format(module_name, entry.path, str(e)))
|
|
370
396
|
continue
|
|
371
397
|
|
|
372
398
|
module_vars = vars(part_module)
|
|
@@ -386,7 +412,8 @@ class HubManager(metaclass=SingletonType):
|
|
|
386
412
|
module_name=module_name,
|
|
387
413
|
author=part_module.author.strip() if 'author' in module_vars else 'None',
|
|
388
414
|
version=part_module.version.strip() if 'version' in module_vars else 'None',
|
|
389
|
-
doc=part_module.part.__doc__.strip() if part_module.part.__doc__ else "None"
|
|
415
|
+
doc=part_module.part.__doc__.strip() if part_module.part.__doc__ else "None",
|
|
416
|
+
label=part_module.label.strip() if 'label' in module_vars else 'None',
|
|
390
417
|
)
|
|
391
418
|
self._session.add(part_model)
|
|
392
419
|
except Exception as e:
|
|
@@ -462,11 +489,21 @@ class HubManager(metaclass=SingletonType):
|
|
|
462
489
|
part_module = importlib.import_module(part_model.module_name)
|
|
463
490
|
except ModuleNotFoundError:
|
|
464
491
|
raise PartNotFoundError(name, '请检查部件对应路径是否存在')
|
|
492
|
+
signature = inspect.signature(part_module.part)
|
|
493
|
+
func_name = f'\npart("{name}",'
|
|
494
|
+
for param_name, param in signature.parameters.items():
|
|
495
|
+
if param.default is param.empty:
|
|
496
|
+
func_name += f"{param_name}, "
|
|
497
|
+
else:
|
|
498
|
+
default_value = param.default
|
|
499
|
+
func_name += f"{param_name}={default_value}, "
|
|
500
|
+
func_name += ")\n"
|
|
501
|
+
func_name += part_module.part.__doc__
|
|
465
502
|
return {
|
|
466
503
|
'name': name,
|
|
467
504
|
'author': part_model.author,
|
|
468
505
|
'version': part_model.version,
|
|
469
|
-
'doc': part_module.part.__doc__,
|
|
506
|
+
'doc': func_name # part_module.part.__doc__,
|
|
470
507
|
}
|
|
471
508
|
|
|
472
509
|
def print_part_info(self, name):
|
|
@@ -525,6 +562,37 @@ class HubManager(metaclass=SingletonType):
|
|
|
525
562
|
checkif(hub_model is None, local_base, HubNotFoundError)
|
|
526
563
|
return hub_model.name
|
|
527
564
|
|
|
565
|
+
@dbsession
|
|
566
|
+
def search_part(self, name: str = None, hub: str = None, part_type: str = None, label=None):
|
|
567
|
+
"""搜索部件
|
|
568
|
+
:param str name: 部件名称
|
|
569
|
+
:param str hub: 仓库名
|
|
570
|
+
:param str part_type: 部件类型
|
|
571
|
+
:param str label: 标签
|
|
572
|
+
:return: 部件名称列表
|
|
573
|
+
:rtype: list
|
|
574
|
+
"""
|
|
575
|
+
parts = None
|
|
576
|
+
if name is not None:
|
|
577
|
+
parts = self._session.query(PartModel).filter(PartModel.name.like(f'%{name}%'))
|
|
578
|
+
if hub is not None:
|
|
579
|
+
if parts is None:
|
|
580
|
+
parts = self._session.query(PartModel).fileter(PartModel.hub_name.like(f'%{hub}%'))
|
|
581
|
+
else:
|
|
582
|
+
parts = parts.filter(PartModel.hub_name.like(f'%{hub}%'))
|
|
583
|
+
if part_type is not None:
|
|
584
|
+
if parts is None:
|
|
585
|
+
parts = self._session.query(PartModel).filter(PartModel.part.like(f'%{part_type}%'))
|
|
586
|
+
else:
|
|
587
|
+
parts = parts.filter(PartModel.part.like(f'%{part_type}%'))
|
|
588
|
+
if label is not None:
|
|
589
|
+
if parts is None:
|
|
590
|
+
parts = self._session.query(PartModel).filter(PartModel.label.like(f'%{label}%'))
|
|
591
|
+
else:
|
|
592
|
+
parts = parts.filter(PartModel.label.like(f'%{label}%'))
|
|
593
|
+
records = parts.all() if parts is not None else []
|
|
594
|
+
return [record.name for record in records]
|
|
595
|
+
|
|
528
596
|
|
|
529
597
|
def add_remote_hub(name, url, branch='main'):
|
|
530
598
|
"""增加远程策略仓库
|
|
@@ -577,7 +645,29 @@ def get_part(name, *args, **kwargs):
|
|
|
577
645
|
:param args: 其他部件相关参数
|
|
578
646
|
:param kwargs: 其他部件相关参数
|
|
579
647
|
"""
|
|
580
|
-
|
|
648
|
+
@lru_cache
|
|
649
|
+
def _get_part(name, *args, **kwargs):
|
|
650
|
+
return HubManager().get_part(name, *args, **kwargs)
|
|
651
|
+
|
|
652
|
+
try:
|
|
653
|
+
return _get_part(name, *args, **kwargs)
|
|
654
|
+
except TypeError as e:
|
|
655
|
+
if "unhashable type" in str(e):
|
|
656
|
+
hku_info("{}! 该对象不可hash无法缓存, 可考虑优化", str(e))
|
|
657
|
+
return HubManager().get_part(name, *args, **kwargs)
|
|
658
|
+
else:
|
|
659
|
+
raise e
|
|
660
|
+
|
|
661
|
+
|
|
662
|
+
def get_part_list(name_list):
|
|
663
|
+
"""
|
|
664
|
+
获取指定策略部件列表
|
|
665
|
+
|
|
666
|
+
:param list name_list: 部件名称列表
|
|
667
|
+
:return: 部件列表
|
|
668
|
+
:rtype: list
|
|
669
|
+
"""
|
|
670
|
+
return [get_part(name) for name in name_list]
|
|
581
671
|
|
|
582
672
|
|
|
583
673
|
def get_hub_path(name):
|
|
@@ -625,6 +715,7 @@ def get_part_module(part_name: str):
|
|
|
625
715
|
return HubManager().get_part_module(part_name)
|
|
626
716
|
|
|
627
717
|
|
|
718
|
+
@lru_cache
|
|
628
719
|
def get_current_hub(filename):
|
|
629
720
|
"""用于在仓库part.py中获取当前所在的仓库名。
|
|
630
721
|
示例: get_current_hub(__file__)
|
|
@@ -632,6 +723,19 @@ def get_current_hub(filename):
|
|
|
632
723
|
return HubManager().get_current_hub(filename)
|
|
633
724
|
|
|
634
725
|
|
|
726
|
+
def search_part(name: str = None, hub: str = None, part_type: str = None, label: str = None):
|
|
727
|
+
"""搜索部件
|
|
728
|
+
|
|
729
|
+
:param str name: 部件名称
|
|
730
|
+
:param str hub: 仓库名
|
|
731
|
+
:param str part_type: 部件类型
|
|
732
|
+
:param str label: 标签
|
|
733
|
+
:return: 部件名称列表
|
|
734
|
+
:rtype: list
|
|
735
|
+
"""
|
|
736
|
+
return HubManager().search_part(name, hub, part_type, label)
|
|
737
|
+
|
|
738
|
+
|
|
635
739
|
# 初始化仓库
|
|
636
740
|
try:
|
|
637
741
|
HubManager().setup_hub()
|
|
@@ -646,6 +750,7 @@ __all__ = [
|
|
|
646
750
|
'build_hub',
|
|
647
751
|
'help_part',
|
|
648
752
|
'get_part',
|
|
753
|
+
'get_part_list',
|
|
649
754
|
'get_hub_path',
|
|
650
755
|
'get_part_info',
|
|
651
756
|
'get_part_module',
|
|
@@ -653,6 +758,7 @@ __all__ = [
|
|
|
653
758
|
'get_hub_name_list',
|
|
654
759
|
'get_part_name_list',
|
|
655
760
|
'get_current_hub',
|
|
761
|
+
'search_part',
|
|
656
762
|
]
|
|
657
763
|
|
|
658
764
|
if __name__ == "__main__":
|
hikyuu/hub.pyi
CHANGED
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
|
-
from configparser import ConfigParser
|
|
3
2
|
import errno as errno
|
|
3
|
+
from functools import lru_cache
|
|
4
4
|
import git as git
|
|
5
5
|
from hikyuu.util.check import checkif
|
|
6
|
+
from hikyuu.util.mylog import hku_info
|
|
6
7
|
from hikyuu.util.singleton import SingletonType
|
|
7
8
|
import importlib as importlib
|
|
9
|
+
import inspect as inspect
|
|
8
10
|
import logging as logging
|
|
9
11
|
import os as os
|
|
10
12
|
import pathlib as pathlib
|
|
11
13
|
import shutil as shutil
|
|
14
|
+
import sqlalchemy as sqlalchemy
|
|
12
15
|
from sqlalchemy.engine.create import create_engine
|
|
13
16
|
from sqlalchemy.orm.decl_api import Base
|
|
14
17
|
from sqlalchemy.orm.decl_api import declarative_base
|
|
15
|
-
import sqlalchemy.orm.instrumentation
|
|
16
|
-
import sqlalchemy.orm.mapper
|
|
17
18
|
from sqlalchemy.orm.scoping import scoped_session
|
|
18
19
|
from sqlalchemy.orm.session import sessionmaker
|
|
19
20
|
from sqlalchemy.sql._elements_constructors import and_
|
|
20
|
-
import sqlalchemy.sql.schema
|
|
21
21
|
from sqlalchemy.sql.schema import Column
|
|
22
22
|
from sqlalchemy.sql.schema import Sequence
|
|
23
23
|
from sqlalchemy.sql.schema import UniqueConstraint
|
|
@@ -26,13 +26,13 @@ from sqlalchemy.sql.sqltypes import String
|
|
|
26
26
|
import stat as stat
|
|
27
27
|
import sys as sys
|
|
28
28
|
import typing
|
|
29
|
-
__all__: list = ['add_remote_hub', 'add_local_hub', 'update_hub', 'remove_hub', 'build_hub', 'help_part', 'get_part', 'get_hub_path', 'get_part_info', 'get_part_module', 'print_part_info', 'get_hub_name_list', 'get_part_name_list', 'get_current_hub']
|
|
29
|
+
__all__: list = ['add_remote_hub', 'add_local_hub', 'update_hub', 'remove_hub', 'build_hub', 'help_part', 'get_part', 'get_part_list', 'get_hub_path', 'get_part_info', 'get_part_module', 'print_part_info', 'get_hub_name_list', 'get_part_name_list', 'get_current_hub', 'search_part']
|
|
30
30
|
class ConfigModel(sqlalchemy.orm.decl_api.Base):
|
|
31
|
-
__mapper__: typing.ClassVar[sqlalchemy.orm.mapper.Mapper] # value = <Mapper at
|
|
31
|
+
__mapper__: typing.ClassVar[sqlalchemy.orm.mapper.Mapper] # value = <Mapper at 0x289448bfdc0; ConfigModel>
|
|
32
32
|
__table__: typing.ClassVar[sqlalchemy.sql.schema.Table] # value = Table('hub_config', MetaData(), Column('id', Integer(), table=<hub_config>, primary_key=True, nullable=False, default=Sequence('config_id_seq', metadata=MetaData())), Column('key', String(), table=<hub_config>), Column('value', String(), table=<hub_config>), schema=None)
|
|
33
33
|
__table_args__: typing.ClassVar[tuple] # value = (UniqueConstraint(Column('key', String(), table=<hub_config>)))
|
|
34
34
|
__tablename__: typing.ClassVar[str] = 'hub_config'
|
|
35
|
-
_sa_class_manager: typing.ClassVar[sqlalchemy.orm.instrumentation.ClassManager] # value = <ClassManager of <class 'hikyuu.hub.ConfigModel'> at
|
|
35
|
+
_sa_class_manager: typing.ClassVar[sqlalchemy.orm.instrumentation.ClassManager] # value = <ClassManager of <class 'hikyuu.hub.ConfigModel'> at 289448ce8b0>
|
|
36
36
|
def __init__(self, **kwargs):
|
|
37
37
|
"""
|
|
38
38
|
A simple constructor that allows initialization from kwargs.
|
|
@@ -91,6 +91,9 @@ class HubManager:
|
|
|
91
91
|
def remove_hub(*args, **kwargs):
|
|
92
92
|
...
|
|
93
93
|
@staticmethod
|
|
94
|
+
def search_part(*args, **kwargs):
|
|
95
|
+
...
|
|
96
|
+
@staticmethod
|
|
94
97
|
def setup_hub(*args, **kwargs):
|
|
95
98
|
...
|
|
96
99
|
@staticmethod
|
|
@@ -103,11 +106,11 @@ class HubManager:
|
|
|
103
106
|
def print_part_info(self, name):
|
|
104
107
|
...
|
|
105
108
|
class HubModel(sqlalchemy.orm.decl_api.Base):
|
|
106
|
-
__mapper__: typing.ClassVar[sqlalchemy.orm.mapper.Mapper] # value = <Mapper at
|
|
109
|
+
__mapper__: typing.ClassVar[sqlalchemy.orm.mapper.Mapper] # value = <Mapper at 0x28944903460; HubModel>
|
|
107
110
|
__table__: typing.ClassVar[sqlalchemy.sql.schema.Table] # value = Table('hub_repo', MetaData(), Column('id', Integer(), table=<hub_repo>, primary_key=True, nullable=False, default=Sequence('remote_id_seq', metadata=MetaData())), Column('name', String(), table=<hub_repo>), Column('hub_type', String(), table=<hub_repo>), Column('local_base', String(), table=<hub_repo>), Column('local', String(), table=<hub_repo>), Column('url', String(), table=<hub_repo>), Column('branch', String(), table=<hub_repo>), schema=None)
|
|
108
111
|
__table_args__: typing.ClassVar[tuple] # value = (UniqueConstraint(Column('name', String(), table=<hub_repo>)))
|
|
109
112
|
__tablename__: typing.ClassVar[str] = 'hub_repo'
|
|
110
|
-
_sa_class_manager: typing.ClassVar[sqlalchemy.orm.instrumentation.ClassManager] # value = <ClassManager of <class 'hikyuu.hub.HubModel'> at
|
|
113
|
+
_sa_class_manager: typing.ClassVar[sqlalchemy.orm.instrumentation.ClassManager] # value = <ClassManager of <class 'hikyuu.hub.HubModel'> at 289448fd5e0>
|
|
111
114
|
def __init__(self, **kwargs):
|
|
112
115
|
"""
|
|
113
116
|
A simple constructor that allows initialization from kwargs.
|
|
@@ -140,10 +143,11 @@ class ModuleConflictError(Exception):
|
|
|
140
143
|
def __str__(self):
|
|
141
144
|
...
|
|
142
145
|
class PartModel(sqlalchemy.orm.decl_api.Base):
|
|
143
|
-
__mapper__: typing.ClassVar[sqlalchemy.orm.mapper.Mapper] # value = <Mapper at
|
|
144
|
-
__table__: typing.ClassVar[sqlalchemy.sql.schema.Table] # value = Table('hub_part', MetaData(), Column('id', Integer(), table=<hub_part>, primary_key=True, nullable=False, default=Sequence('part_id_seq', metadata=MetaData())), Column('hub_name', String(), table=<hub_part>), Column('part', String(), table=<hub_part>), Column('name', String(), table=<hub_part>), Column('author', String(), table=<hub_part>), Column('version', String(), table=<hub_part>), Column('doc', String(), table=<hub_part>), Column('module_name', String(), table=<hub_part>), schema=None)
|
|
146
|
+
__mapper__: typing.ClassVar[sqlalchemy.orm.mapper.Mapper] # value = <Mapper at 0x28944903df0; PartModel>
|
|
147
|
+
__table__: typing.ClassVar[sqlalchemy.sql.schema.Table] # value = Table('hub_part', MetaData(), Column('id', Integer(), table=<hub_part>, primary_key=True, nullable=False, default=Sequence('part_id_seq', metadata=MetaData())), Column('hub_name', String(), table=<hub_part>), Column('part', String(), table=<hub_part>), Column('name', String(), table=<hub_part>), Column('author', String(), table=<hub_part>), Column('version', String(), table=<hub_part>), Column('doc', String(), table=<hub_part>), Column('module_name', String(), table=<hub_part>), Column('label', String(), table=<hub_part>), schema=None)
|
|
148
|
+
__table_args__: typing.ClassVar[tuple] # value = (UniqueConstraint(Column('name', String(), table=<hub_part>)))
|
|
145
149
|
__tablename__: typing.ClassVar[str] = 'hub_part'
|
|
146
|
-
_sa_class_manager: typing.ClassVar[sqlalchemy.orm.instrumentation.ClassManager] # value = <ClassManager of <class 'hikyuu.hub.PartModel'> at
|
|
150
|
+
_sa_class_manager: typing.ClassVar[sqlalchemy.orm.instrumentation.ClassManager] # value = <ClassManager of <class 'hikyuu.hub.PartModel'> at 2894490d130>
|
|
147
151
|
def __init__(self, **kwargs):
|
|
148
152
|
"""
|
|
149
153
|
A simple constructor that allows initialization from kwargs.
|
|
@@ -197,7 +201,7 @@ def build_hub(name, cmd = 'buildall'):
|
|
|
197
201
|
"""
|
|
198
202
|
def dbsession(func):
|
|
199
203
|
...
|
|
200
|
-
def get_current_hub(
|
|
204
|
+
def get_current_hub(*args, **kwargs):
|
|
201
205
|
"""
|
|
202
206
|
用于在仓库part.py中获取当前所在的仓库名。
|
|
203
207
|
示例: get_current_hub(__file__)
|
|
@@ -229,6 +233,16 @@ def get_part_info(name):
|
|
|
229
233
|
|
|
230
234
|
:param str name: 部件名称
|
|
231
235
|
|
|
236
|
+
"""
|
|
237
|
+
def get_part_list(name_list):
|
|
238
|
+
"""
|
|
239
|
+
|
|
240
|
+
获取指定策略部件列表
|
|
241
|
+
|
|
242
|
+
:param list name_list: 部件名称列表
|
|
243
|
+
:return: 部件列表
|
|
244
|
+
:rtype: list
|
|
245
|
+
|
|
232
246
|
"""
|
|
233
247
|
def get_part_module(part_name: str):
|
|
234
248
|
"""
|
|
@@ -255,6 +269,18 @@ def remove_hub(name):
|
|
|
255
269
|
|
|
256
270
|
:param str name: 仓库名称
|
|
257
271
|
|
|
272
|
+
"""
|
|
273
|
+
def search_part(name: str = None, hub: str = None, part_type: str = None, label: str = None):
|
|
274
|
+
"""
|
|
275
|
+
搜索部件
|
|
276
|
+
|
|
277
|
+
:param str name: 部件名称
|
|
278
|
+
:param str hub: 仓库名
|
|
279
|
+
:param str part_type: 部件类型
|
|
280
|
+
:param str label: 标签
|
|
281
|
+
:return: 部件名称列表
|
|
282
|
+
:rtype: list
|
|
283
|
+
|
|
258
284
|
"""
|
|
259
285
|
def update_hub(name):
|
|
260
286
|
"""
|
hikyuu/include/hikyuu/DataType.h
CHANGED
|
@@ -149,8 +149,7 @@ using std::isinf;
|
|
|
149
149
|
using std::isnan;
|
|
150
150
|
|
|
151
151
|
inline bool iszero(price_t num) {
|
|
152
|
-
|
|
153
|
-
return std::abs(num) < epsilon;
|
|
152
|
+
return std::abs(num) < std::numeric_limits<price_t>::epsilon();
|
|
154
153
|
}
|
|
155
154
|
|
|
156
155
|
using fmt::format;
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* Author: fasiondog
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
+
#pragma once
|
|
8
9
|
#ifndef STOCKMANAGER_H_
|
|
9
10
|
#define STOCKMANAGER_H_
|
|
10
11
|
|
|
@@ -278,7 +279,7 @@ private:
|
|
|
278
279
|
static StockManager* m_sm;
|
|
279
280
|
std::atomic_bool m_initializing;
|
|
280
281
|
std::atomic_bool m_data_ready; // 用于指示是否所有数据准备完毕
|
|
281
|
-
std::thread::id m_thread_id;
|
|
282
|
+
std::thread::id m_thread_id; // 记录线程id,用于判断Stratege是以独立进程方式还是线程方式运行
|
|
282
283
|
string m_tmpdir;
|
|
283
284
|
string m_datadir;
|
|
284
285
|
BaseInfoDriverPtr m_baseInfoDriver;
|
|
@@ -24,7 +24,6 @@ public:
|
|
|
24
24
|
|
|
25
25
|
/**
|
|
26
26
|
* 构造函数
|
|
27
|
-
* @note 未指定 ktypelist 时,默认按预加载参数加载全部
|
|
28
27
|
* @param stockCodeList 指定的证券代码列表,如:如:{"sz000001", "sz000002"}
|
|
29
28
|
*/
|
|
30
29
|
explicit StrategyContext(const vector<string>& stockCodeList);
|
|
@@ -32,11 +31,14 @@ public:
|
|
|
32
31
|
/**
|
|
33
32
|
* 构造函数
|
|
34
33
|
* @note 证券列表中如果包含 ("ALL") 则表示全部证券;
|
|
35
|
-
* 指定K线类型列表同时影响着K
|
|
34
|
+
* 1. 指定K线类型列表同时影响着K线数据的优先加载顺序,靠前的将优先加载。
|
|
35
|
+
* 2. 未指定 ktypelist 或 preloadNum 时,将使用全局配置文件参数
|
|
36
36
|
* @param stockCodeList 指定的证券代码列表,如:{"sh000001", "sz000001"}
|
|
37
37
|
* @param ktypeList 指定的 K线数据列表,如:{"day", "min"}
|
|
38
|
+
* @param preloadNum 指定的预加载数量,如:{{"min_max", 100}, {"day_max", 200}}
|
|
38
39
|
*/
|
|
39
|
-
StrategyContext(const vector<string>& stockCodeList, const vector<KQuery::KType>& ktypeList
|
|
40
|
+
StrategyContext(const vector<string>& stockCodeList, const vector<KQuery::KType>& ktypeList,
|
|
41
|
+
const unordered_map<string, int>& preloadNum = {});
|
|
40
42
|
|
|
41
43
|
// 自定义移动构造与赋值会引起 python 中无法正常退出
|
|
42
44
|
// StrategyContext(const StrategyContext&) = default;
|
|
@@ -75,6 +77,12 @@ public:
|
|
|
75
77
|
return m_ktypeList;
|
|
76
78
|
}
|
|
77
79
|
|
|
80
|
+
void setPreloadNum(const unordered_map<string, int>& preloadNum);
|
|
81
|
+
|
|
82
|
+
const unordered_map<string, int>& getPreloadNum() const noexcept {
|
|
83
|
+
return m_preloadNum;
|
|
84
|
+
}
|
|
85
|
+
|
|
78
86
|
/**
|
|
79
87
|
* 隐含的默认必须被加载的证券列表
|
|
80
88
|
* @note 影响交易日历判断、和某些常被作为默认比较基准的证券,通常被作为某些函数的默认值
|
|
@@ -100,6 +108,7 @@ private:
|
|
|
100
108
|
vector<string> m_mustLoad{"sh000001", "sh000300"}; // 默认必须加载的 stock
|
|
101
109
|
vector<string> m_stockCodeList;
|
|
102
110
|
vector<KQuery::KType> m_ktypeList;
|
|
111
|
+
unordered_map<string, int> m_preloadNum;
|
|
103
112
|
};
|
|
104
113
|
|
|
105
114
|
HKU_API std::ostream& operator<<(std::ostream& os, const StrategyContext& context);
|
|
@@ -198,6 +198,8 @@ public:
|
|
|
198
198
|
return !m_imp && m_imp == other.m_imp;
|
|
199
199
|
}
|
|
200
200
|
|
|
201
|
+
string str() const;
|
|
202
|
+
|
|
201
203
|
protected:
|
|
202
204
|
IndicatorImpPtr m_imp;
|
|
203
205
|
|
|
@@ -383,6 +385,13 @@ HKU_API Indicator operator|(Indicator::value_t, const Indicator&);
|
|
|
383
385
|
*/
|
|
384
386
|
Indicator HKU_API WEAVE(const Indicator& ind1, const Indicator& ind2);
|
|
385
387
|
|
|
388
|
+
template <typename... Args>
|
|
389
|
+
inline Indicator WEAVE(const Indicator& ind1, const Indicator& ind2, const Args&... others) {
|
|
390
|
+
HKU_CHECK(sizeof...(others) <= 4, "WEAVE() only support 6 Indicator!");
|
|
391
|
+
Indicator tmp = WEAVE(ind1, ind2);
|
|
392
|
+
return WEAVE(std::move(tmp), others...);
|
|
393
|
+
}
|
|
394
|
+
|
|
386
395
|
/**
|
|
387
396
|
* 条件函数, 根据条件求不同的值。
|
|
388
397
|
* @details
|
|
@@ -402,6 +411,21 @@ Indicator HKU_API IF(const Indicator& x, Indicator::value_t a, Indicator::value_
|
|
|
402
411
|
|
|
403
412
|
} /* namespace hku */
|
|
404
413
|
|
|
414
|
+
namespace std {
|
|
415
|
+
template <>
|
|
416
|
+
class hash<hku::Indicator> {
|
|
417
|
+
public:
|
|
418
|
+
size_t operator()(hku::Indicator const& ind) const noexcept {
|
|
419
|
+
auto imp = ind.getImp();
|
|
420
|
+
return imp.get() ? std::hash<hku::IndicatorImpPtr>()(imp) : 0;
|
|
421
|
+
}
|
|
422
|
+
};
|
|
423
|
+
|
|
424
|
+
inline string to_string(const hku::Indicator& ind) {
|
|
425
|
+
return ind.str();
|
|
426
|
+
}
|
|
427
|
+
} // namespace std
|
|
428
|
+
|
|
405
429
|
#if FMT_VERSION >= 90000
|
|
406
430
|
template <>
|
|
407
431
|
struct fmt::formatter<hku::Indicator> : ostream_formatter {};
|
|
@@ -47,6 +47,7 @@ private: \
|
|
|
47
47
|
friend class boost::serialization::access; \
|
|
48
48
|
template <class Archive> \
|
|
49
49
|
void serialize(Archive& ar, const unsigned int version) { \
|
|
50
|
+
ar& BOOST_SERIALIZATION_BASE_OBJECT_NVP(IndicatorImp); \
|
|
50
51
|
ar& BOOST_SERIALIZATION_BASE_OBJECT_NVP(Indicator2InImp); \
|
|
51
52
|
}
|
|
52
53
|
#else
|
|
@@ -66,6 +66,7 @@
|
|
|
66
66
|
#include "crt/ISNA.h"
|
|
67
67
|
#include "crt/JUMPUP.h"
|
|
68
68
|
#include "crt/JUMPDOWN.h"
|
|
69
|
+
#include "crt/KALMAN.h"
|
|
69
70
|
#include "crt/LAST.h"
|
|
70
71
|
#include "crt/LASTVALUE.h"
|
|
71
72
|
#include "crt/LIUTONGPAN.h"
|
|
@@ -115,6 +116,7 @@
|
|
|
115
116
|
#include "crt/TIME.h"
|
|
116
117
|
#include "crt/TIMELINE.h"
|
|
117
118
|
#include "crt/TIMELINEVOL.h"
|
|
119
|
+
#include "crt/TR.h"
|
|
118
120
|
#include "crt/TURNOVER.h"
|
|
119
121
|
#include "crt/UPNDAY.h"
|
|
120
122
|
#include "crt/VAR.h"
|
|
@@ -14,12 +14,11 @@
|
|
|
14
14
|
namespace hku {
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
|
-
* 平均真实波幅(Average True Range)
|
|
17
|
+
* 平均真实波幅(Average True Range), TR 的简单平均值
|
|
18
18
|
* @param n 计算均值的周期窗口,必须为大于1的整数
|
|
19
19
|
* @ingroup Indicator
|
|
20
20
|
*/
|
|
21
21
|
Indicator HKU_API ATR(int n = 14);
|
|
22
|
-
Indicator HKU_API ATR(const IndParam& n);
|
|
23
22
|
|
|
24
23
|
/**
|
|
25
24
|
* 平均真实波幅(Average True Range)
|
|
@@ -27,17 +26,7 @@ Indicator HKU_API ATR(const IndParam& n);
|
|
|
27
26
|
* @param n 计算均值的周期窗口,必须为大于1的整数
|
|
28
27
|
* @ingroup Indicator
|
|
29
28
|
*/
|
|
30
|
-
|
|
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);
|
|
41
30
|
|
|
42
31
|
} // namespace hku
|
|
43
32
|
|
|
@@ -25,8 +25,6 @@ namespace hku {
|
|
|
25
25
|
* @ingroup Indicator
|
|
26
26
|
*/
|
|
27
27
|
Indicator HKU_API BARSSINCE();
|
|
28
|
-
Indicator BARSSINCE(Indicator::value_t);
|
|
29
|
-
Indicator BARSSINCE(const Indicator& ind);
|
|
30
28
|
|
|
31
29
|
inline Indicator BARSSINCE(const Indicator& ind) {
|
|
32
30
|
return BARSSINCE()(ind);
|
|
@@ -36,6 +34,20 @@ inline Indicator BARSSINCE(Indicator::value_t val) {
|
|
|
36
34
|
return BARSSINCE(CVAL(val));
|
|
37
35
|
}
|
|
38
36
|
|
|
37
|
+
/**
|
|
38
|
+
* N周期内首个条件成立位置
|
|
39
|
+
* @details N周期内第一个条件成立到当前的周期数
|
|
40
|
+
* <pre>
|
|
41
|
+
* 用法:BARSSINCEN(X,N):N周期内第一次X不为0到现在的周期数,N为常量BARSSINCEN(X,N):
|
|
42
|
+
* 例如:BARSSINCEN(HIGH>10,10)表示10个周期内股价超过10元时到当前的周期数
|
|
43
|
+
* </pre>
|
|
44
|
+
* @ingroup Indicator
|
|
45
|
+
*/
|
|
46
|
+
Indicator HKU_API BARSSINCEN(int n);
|
|
47
|
+
inline Indicator BARSSINCEN(const Indicator& ind, int n) {
|
|
48
|
+
return BARSSINCEN(n)(ind);
|
|
49
|
+
}
|
|
50
|
+
|
|
39
51
|
} // namespace hku
|
|
40
52
|
|
|
41
53
|
#endif /* INDICATOR_CRT_BARSSINCE_H_ */
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2025 hikyuu.org
|
|
3
|
+
*
|
|
4
|
+
* Created on: 2025-03-02
|
|
5
|
+
* Author: fasiondog
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
#pragma once
|
|
9
|
+
#ifndef INDICATOR_CRT_KALMAN_H_
|
|
10
|
+
#define INDICATOR_CRT_KALMAN_H_
|
|
11
|
+
|
|
12
|
+
#include "CVAL.h"
|
|
13
|
+
|
|
14
|
+
namespace hku {
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* 卡尔曼滤波
|
|
18
|
+
* @param q 噪声方差
|
|
19
|
+
* @param r 测量噪声方差
|
|
20
|
+
* @ingroup Indicator
|
|
21
|
+
*/
|
|
22
|
+
Indicator HKU_API KALMAN(double q = 0.01, double r = 0.1);
|
|
23
|
+
|
|
24
|
+
inline Indicator KALMAN(const Indicator& ind, double q = 0.01, double r = 0.1) {
|
|
25
|
+
return KALMAN(q, r)(ind);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
} // namespace hku
|
|
29
|
+
|
|
30
|
+
#endif /* INDICATOR_CRT_KALMAN_H_ */
|