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.
Files changed (90) hide show
  1. hikyuu/__init__.py +5 -1
  2. hikyuu/__init__.pyi +522 -511
  3. hikyuu/analysis/__init__.pyi +490 -485
  4. hikyuu/analysis/analysis.pyi +491 -486
  5. hikyuu/core.pyi +492 -487
  6. hikyuu/cpp/__init__.pyi +2 -2
  7. hikyuu/cpp/core310.pyd +0 -0
  8. hikyuu/cpp/core310.pyi +249 -26
  9. hikyuu/cpp/core311.pyd +0 -0
  10. hikyuu/cpp/core311.pyi +249 -26
  11. hikyuu/cpp/core312.pyd +0 -0
  12. hikyuu/cpp/core312.pyi +249 -26
  13. hikyuu/cpp/core313.pyd +0 -0
  14. hikyuu/cpp/core313.pyi +243 -26
  15. hikyuu/cpp/core38.pyd +0 -0
  16. hikyuu/cpp/core38.pyi +249 -26
  17. hikyuu/cpp/core39.pyd +0 -0
  18. hikyuu/cpp/core39.pyi +249 -26
  19. hikyuu/cpp/hikyuu.dll +0 -0
  20. hikyuu/cpp/hikyuu.lib +0 -0
  21. hikyuu/data/mysql_upgrade/0027.sql +6 -0
  22. hikyuu/data/pytdx_to_h5.py +7 -4
  23. hikyuu/data/pytdx_to_mysql.py +7 -4
  24. hikyuu/data/sqlite_upgrade/0027.sql +8 -0
  25. hikyuu/draw/drawplot/__init__.py +8 -1
  26. hikyuu/draw/drawplot/__init__.pyi +11 -7
  27. hikyuu/draw/drawplot/bokeh_draw.pyi +509 -500
  28. hikyuu/draw/drawplot/common.pyi +1 -1
  29. hikyuu/draw/drawplot/echarts_draw.pyi +511 -502
  30. hikyuu/draw/drawplot/matplotlib_draw.py +129 -8
  31. hikyuu/draw/drawplot/matplotlib_draw.pyi +571 -515
  32. hikyuu/draw/elder.pyi +11 -11
  33. hikyuu/draw/kaufman.pyi +18 -18
  34. hikyuu/draw/volume.pyi +10 -10
  35. hikyuu/extend.pyi +501 -495
  36. hikyuu/fetcher/stock/zh_block_em.py +18 -7
  37. hikyuu/hub.py +112 -6
  38. hikyuu/hub.pyi +39 -13
  39. hikyuu/include/hikyuu/DataType.h +1 -2
  40. hikyuu/include/hikyuu/StockManager.h +2 -1
  41. hikyuu/include/hikyuu/StrategyContext.h +12 -3
  42. hikyuu/include/hikyuu/indicator/Indicator.h +24 -0
  43. hikyuu/include/hikyuu/indicator/Indicator2InImp.h +1 -0
  44. hikyuu/include/hikyuu/indicator/build_in.h +2 -0
  45. hikyuu/include/hikyuu/indicator/crt/ATR.h +2 -13
  46. hikyuu/include/hikyuu/indicator/crt/BARSSINCE.h +14 -2
  47. hikyuu/include/hikyuu/indicator/crt/KALMAN.h +30 -0
  48. hikyuu/include/hikyuu/indicator/crt/TR.h +32 -0
  49. hikyuu/include/hikyuu/indicator/imp/IAtr.h +3 -1
  50. hikyuu/include/hikyuu/indicator/imp/IBarsSince.h +6 -0
  51. hikyuu/include/hikyuu/indicator/imp/IKalman.h +27 -0
  52. hikyuu/include/hikyuu/indicator/imp/ITr.h +35 -0
  53. hikyuu/include/hikyuu/python/convert_any.h +299 -0
  54. hikyuu/include/hikyuu/trade_manage/PositionRecord.h +5 -4
  55. hikyuu/include/hikyuu/trade_sys/allocatefunds/crt/AF_MultiFactor.h +1 -1
  56. hikyuu/include/hikyuu/trade_sys/allocatefunds/imp/MultiFactorAllocaterFunds.h +3 -0
  57. hikyuu/include/hikyuu/trade_sys/condition/ConditionBase.h +4 -1
  58. hikyuu/include/hikyuu/trade_sys/condition/imp/{SubCondition.h → logic/SubCondition.h} +1 -1
  59. hikyuu/include/hikyuu/trade_sys/environment/EnvironmentBase.h +20 -6
  60. hikyuu/include/hikyuu/trade_sys/environment/build_in.h +1 -0
  61. hikyuu/include/hikyuu/trade_sys/environment/crt/EV_Logic.h +35 -0
  62. hikyuu/include/hikyuu/trade_sys/environment/imp/logic/AddEnvironment.h +42 -0
  63. hikyuu/include/hikyuu/trade_sys/environment/imp/logic/AndEnvironment.h +42 -0
  64. hikyuu/include/hikyuu/trade_sys/environment/imp/logic/DivEnvironment.h +42 -0
  65. hikyuu/include/hikyuu/trade_sys/environment/imp/logic/MultiEnvironment.h +42 -0
  66. hikyuu/include/hikyuu/trade_sys/environment/imp/logic/OrEnvironment.h +42 -0
  67. hikyuu/include/hikyuu/trade_sys/environment/imp/logic/SubEnvironment.h +42 -0
  68. hikyuu/include/hikyuu/trade_sys/environment/imp/logic/__init__.py +1 -0
  69. hikyuu/include/hikyuu/trade_sys/portfolio/Portfolio.h +0 -4
  70. hikyuu/include/hikyuu/trade_sys/signal/crt/SG_Logic.h +68 -7
  71. hikyuu/include/hikyuu/trade_sys/signal/imp/logic/AndSignal.h +19 -0
  72. hikyuu/include/hikyuu/trade_sys/signal/imp/logic/OperatorSignal.h +1 -0
  73. hikyuu/include/hikyuu/trade_sys/signal/imp/logic/OperatorValueSignal.h +1 -0
  74. hikyuu/include/hikyuu/trade_sys/signal/imp/logic/OrSignal.h +19 -0
  75. hikyuu/include/hikyuu/utilities/datetime/Datetime.h +2 -1
  76. hikyuu/include/hikyuu/version.h +4 -4
  77. hikyuu/indicator/indicator.py +1 -0
  78. hikyuu/trade_manage/__init__.pyi +506 -499
  79. hikyuu/trade_manage/broker.pyi +3 -3
  80. hikyuu/trade_manage/broker_easytrader.pyi +1 -1
  81. hikyuu/trade_manage/trade.pyi +506 -499
  82. hikyuu/trade_sys/trade_sys.py +4 -3
  83. hikyuu/util/__init__.pyi +1 -1
  84. hikyuu/util/singleton.pyi +1 -1
  85. {hikyuu-2.5.2.dist-info → hikyuu-2.5.5.dist-info}/METADATA +3 -2
  86. {hikyuu-2.5.2.dist-info → hikyuu-2.5.5.dist-info}/RECORD +90 -73
  87. {hikyuu-2.5.2.dist-info → hikyuu-2.5.5.dist-info}/top_level.txt +1 -0
  88. {hikyuu-2.5.2.dist-info → hikyuu-2.5.5.dist-info}/LICENSE +0 -0
  89. {hikyuu-2.5.2.dist-info → hikyuu-2.5.5.dist-info}/WHEEL +0 -0
  90. {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": "200",
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": "200",
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"] / 200)
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": "200",
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"] / 200)
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": "200",
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"] / 200)
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
- from configparser import ConfigParser
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
- return HubManager().get_part(name, *args, **kwargs)
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 0x18c15d85310; ConfigModel>
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 18c1612aad0>
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 0x18c14f8be90; HubModel>
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 18c1614f2f0>
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 0x18c1612e090; PartModel>
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 18c1614fde0>
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(filename):
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
  """
@@ -149,8 +149,7 @@ using std::isinf;
149
149
  using std::isnan;
150
150
 
151
151
  inline bool iszero(price_t num) {
152
- const price_t epsilon = std::numeric_limits<price_t>::epsilon();
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; // 记录线程id,用于判断Stratege是以独立进程方式还是线程方式运行
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
- 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);
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_ */