hikyuu 2.6.8.4__py3-none-manylinux2014_x86_64.whl → 2.7.0__py3-none-manylinux2014_x86_64.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 (209) hide show
  1. hikyuu/__init__.py +31 -17
  2. hikyuu/__init__.pyi +610 -590
  3. hikyuu/analysis/__init__.pyi +584 -563
  4. hikyuu/analysis/analysis.pyi +585 -564
  5. hikyuu/core.py +2 -0
  6. hikyuu/core.pyi +586 -565
  7. hikyuu/cpp/__init__.pyi +2 -2
  8. hikyuu/cpp/core310.pyi +501 -108
  9. hikyuu/cpp/core310.so +0 -0
  10. hikyuu/cpp/core311.pyi +495 -108
  11. hikyuu/cpp/core311.so +0 -0
  12. hikyuu/cpp/core312.pyi +495 -108
  13. hikyuu/cpp/core312.so +0 -0
  14. hikyuu/cpp/core313.pyi +501 -108
  15. hikyuu/cpp/core313.so +0 -0
  16. hikyuu/cpp/i18n/zh_CN/hikyuu.mo +0 -0
  17. hikyuu/cpp/libboost_charconv-mt.so +0 -0
  18. hikyuu/cpp/libboost_charconv-mt.so.1.88.0 +0 -0
  19. hikyuu/cpp/libboost_chrono-mt.so +0 -0
  20. hikyuu/cpp/libboost_chrono-mt.so.1.88.0 +0 -0
  21. hikyuu/cpp/libboost_date_time-mt.so +0 -0
  22. hikyuu/cpp/libboost_date_time-mt.so.1.88.0 +0 -0
  23. hikyuu/cpp/libboost_serialization-mt.so +0 -0
  24. hikyuu/cpp/libboost_serialization-mt.so.1.88.0 +0 -0
  25. hikyuu/cpp/libboost_system-mt.so +0 -0
  26. hikyuu/cpp/libboost_system-mt.so.1.88.0 +0 -0
  27. hikyuu/cpp/libboost_thread-mt.so +0 -0
  28. hikyuu/cpp/libboost_thread-mt.so.1.88.0 +0 -0
  29. hikyuu/cpp/libboost_wserialization-mt.so +0 -0
  30. hikyuu/cpp/libboost_wserialization-mt.so.1.88.0 +0 -0
  31. hikyuu/cpp/libhikyuu.so +0 -0
  32. hikyuu/cpp/libsqlite3.so +0 -0
  33. hikyuu/data/clickhouse_upgrade/createdb.sql +105 -105
  34. hikyuu/data/common.py +3 -3
  35. hikyuu/data/common_clickhouse.py +1 -1
  36. hikyuu/data/download_block.py +351 -0
  37. hikyuu/data/em_block_to_clickhouse.py +26 -74
  38. hikyuu/data/em_block_to_mysql.py +25 -75
  39. hikyuu/data/em_block_to_sqlite.py +26 -78
  40. hikyuu/data/hku_config_template.py +3 -3
  41. hikyuu/data/pytdx_to_clickhouse.py +15 -11
  42. hikyuu/data/pytdx_to_h5.py +6 -2
  43. hikyuu/data/pytdx_to_mysql.py +5 -1
  44. hikyuu/data/pytdx_weight_to_clickhouse.py +1 -1
  45. hikyuu/data/pytdx_weight_to_mysql.py +1 -1
  46. hikyuu/data/pytdx_weight_to_sqlite.py +1 -1
  47. hikyuu/data/zh_bond10_to_clickhouse.py +1 -1
  48. hikyuu/draw/__init__.pyi +1 -1
  49. hikyuu/draw/drawplot/__init__.pyi +9 -9
  50. hikyuu/draw/drawplot/bokeh_draw.pyi +600 -580
  51. hikyuu/draw/drawplot/common.pyi +1 -1
  52. hikyuu/draw/drawplot/echarts_draw.pyi +602 -582
  53. hikyuu/draw/drawplot/matplotlib_draw.py +4 -74
  54. hikyuu/draw/drawplot/matplotlib_draw.pyi +612 -592
  55. hikyuu/draw/elder.pyi +11 -11
  56. hikyuu/draw/kaufman.pyi +18 -18
  57. hikyuu/draw/volume.pyi +10 -10
  58. hikyuu/examples/notebook/Demo/Demo1.ipynb +48 -33
  59. hikyuu/extend.py +0 -7
  60. hikyuu/extend.pyi +594 -573
  61. hikyuu/fetcher/stock/zh_block_em.py +12 -40
  62. hikyuu/gui/HikyuuTDX.py +99 -31
  63. hikyuu/gui/data/CollectSpotThread.py +1 -1
  64. hikyuu/gui/data/EscapetimeThread.py +8 -14
  65. hikyuu/gui/data/ImportBlockInfoTask.py +3 -10
  66. hikyuu/gui/data/MainWindow.py +1196 -717
  67. hikyuu/gui/data/SchedImportThread.py +2 -2
  68. hikyuu/gui/data/UsePytdxImportToH5Thread.py +3 -3
  69. hikyuu/gui/data/UseQmtImportToH5Thread.py +2 -2
  70. hikyuu/gui/data/UseTdxImportToH5Thread.py +3 -3
  71. hikyuu/gui/data/tool.py +32 -25
  72. hikyuu/gui/dataserver.py +5 -3
  73. hikyuu/gui/images/liandongxiaopu.png +0 -0
  74. hikyuu/hub.pyi +6 -6
  75. hikyuu/include/hikyuu/DataType.h +4 -16
  76. hikyuu/include/hikyuu/KData.h +6 -3
  77. hikyuu/include/hikyuu/KDataPrivatedBufferImp.h +1 -1
  78. hikyuu/include/hikyuu/KDataSharedBufferImp.h +1 -1
  79. hikyuu/include/hikyuu/KQuery.h +2 -2
  80. hikyuu/include/hikyuu/Stock.h +4 -1
  81. hikyuu/include/hikyuu/StockManager.h +13 -3
  82. hikyuu/include/hikyuu/data_driver/BaseInfoDriver.h +8 -0
  83. hikyuu/include/hikyuu/data_driver/BlockInfoDriver.h +6 -0
  84. hikyuu/include/hikyuu/data_driver/KDataDriver.h +26 -1
  85. hikyuu/include/hikyuu/data_driver/base_info/mysql/MySQLBaseInfoDriver.h +1 -1
  86. hikyuu/include/hikyuu/data_driver/base_info/sqlite/SQLiteBaseInfoDriver.h +1 -1
  87. hikyuu/include/hikyuu/data_driver/block_info/mysql/MySQLBlockInfoDriver.h +2 -1
  88. hikyuu/include/hikyuu/data_driver/block_info/qianlong/QLBlockInfoDriver.h +2 -1
  89. hikyuu/include/hikyuu/data_driver/block_info/sqlite/SQLiteBlockInfoDriver.h +2 -1
  90. hikyuu/include/hikyuu/data_driver/kdata/DoNothingKDataDriver.h +1 -1
  91. hikyuu/include/hikyuu/data_driver/kdata/cvs/KDataTempCsvDriver.h +1 -1
  92. hikyuu/include/hikyuu/data_driver/kdata/hdf5/H5KDataDriver.h +1 -1
  93. hikyuu/include/hikyuu/data_driver/kdata/mysql/MySQLKDataDriver.h +1 -1
  94. hikyuu/include/hikyuu/data_driver/kdata/sqlite/SQLiteKDataDriver.h +1 -1
  95. hikyuu/include/hikyuu/data_driver/kdata/tdx/TdxKDataDriver.h +1 -1
  96. hikyuu/include/hikyuu/hikyuu.h +1 -1
  97. hikyuu/include/hikyuu/indicator/build_in.h +1 -0
  98. hikyuu/include/hikyuu/indicator/crt/CYCLE.h +4 -4
  99. hikyuu/include/hikyuu/indicator/crt/HSL.h +2 -2
  100. hikyuu/include/hikyuu/indicator/crt/QUANTILE_TRUNC.h +30 -0
  101. hikyuu/include/hikyuu/indicator/crt/TURNOVER.h +1 -0
  102. hikyuu/include/hikyuu/indicator/crt/ZSCORE.h +2 -2
  103. hikyuu/include/hikyuu/indicator/imp/IQuantileTrunc.h +25 -0
  104. hikyuu/include/hikyuu/misc.h +38 -0
  105. hikyuu/include/hikyuu/plugin/dataserver.h +2 -1
  106. hikyuu/include/hikyuu/plugin/device.h +10 -0
  107. hikyuu/include/hikyuu/plugin/extind.h +37 -0
  108. hikyuu/include/hikyuu/plugin/hkuextra.h +0 -18
  109. hikyuu/include/hikyuu/plugin/interface/DataServerPluginInterface.h +2 -2
  110. hikyuu/include/hikyuu/plugin/interface/DevicePluginInterface.h +2 -0
  111. hikyuu/include/hikyuu/plugin/interface/ExtendIndicatorsPluginInterface.h +12 -0
  112. hikyuu/include/hikyuu/plugin/interface/HkuExtraPluginInterface.h +0 -14
  113. hikyuu/include/hikyuu/plugin/interface/plugins.h +3 -1
  114. hikyuu/include/hikyuu/python/pybind_utils.h +1 -8
  115. hikyuu/include/hikyuu/strategy/RunSystemInStrategy.h +3 -0
  116. hikyuu/include/hikyuu/trade_manage/Performance.h +4 -4
  117. hikyuu/include/hikyuu/trade_manage/TradeManagerBase.h +10 -1
  118. hikyuu/include/hikyuu/trade_sys/moneymanager/imp/FixedCapitalFundsMM.h +0 -4
  119. hikyuu/include/hikyuu/trade_sys/multifactor/MultiFactorBase.h +36 -3
  120. hikyuu/include/hikyuu/trade_sys/multifactor/NormalizeBase.h +125 -0
  121. hikyuu/include/hikyuu/trade_sys/multifactor/ScoresFilterBase.h +125 -0
  122. hikyuu/include/hikyuu/trade_sys/multifactor/build_in.h +3 -0
  123. hikyuu/include/hikyuu/trade_sys/multifactor/buildin_norm.h +36 -0
  124. hikyuu/include/hikyuu/trade_sys/multifactor/buildin_scfilter.h +51 -0
  125. hikyuu/include/hikyuu/trade_sys/multifactor/filter/GroupSCFilter.h +24 -0
  126. hikyuu/include/hikyuu/trade_sys/multifactor/filter/IgnoreLessOrEqualValueSCFilter.h +24 -0
  127. hikyuu/include/hikyuu/trade_sys/multifactor/filter/IgnoreNanSCFilter.h +24 -0
  128. hikyuu/include/hikyuu/trade_sys/multifactor/filter/MinAmountPercentSCFilter.h +25 -0
  129. hikyuu/include/hikyuu/trade_sys/multifactor/filter/PriceSCFilter.h +24 -0
  130. hikyuu/include/hikyuu/trade_sys/multifactor/filter/TopNSCFilter.h +24 -0
  131. hikyuu/include/hikyuu/trade_sys/multifactor/imp/EqualWeightMultiFactor.h +1 -1
  132. hikyuu/include/hikyuu/trade_sys/multifactor/imp/ICIRMultiFactor.h +1 -1
  133. hikyuu/include/hikyuu/trade_sys/multifactor/imp/ICMultiFactor.h +1 -1
  134. hikyuu/include/hikyuu/trade_sys/multifactor/imp/WeightMultiFactor.h +1 -1
  135. hikyuu/include/hikyuu/trade_sys/multifactor/normalize/NormMinMax.h +23 -0
  136. hikyuu/include/hikyuu/trade_sys/multifactor/normalize/NormQuantile.h +28 -0
  137. hikyuu/include/hikyuu/trade_sys/multifactor/normalize/NormQuantileUniform.h +28 -0
  138. hikyuu/include/hikyuu/trade_sys/multifactor/normalize/NormZScore.h +25 -0
  139. hikyuu/include/hikyuu/trade_sys/multifactor/normalize/__init__.py +1 -0
  140. hikyuu/include/hikyuu/trade_sys/multifactor/normalize/quantile_trunc.h +16 -0
  141. hikyuu/include/hikyuu/trade_sys/portfolio/Portfolio.h +7 -0
  142. hikyuu/include/hikyuu/trade_sys/portfolio/imp/SimplePortfolio.h +7 -0
  143. hikyuu/include/hikyuu/trade_sys/portfolio/imp/WithoutAFPortfolio.h +7 -0
  144. hikyuu/include/hikyuu/trade_sys/selector/SelectorBase.h +49 -0
  145. hikyuu/include/hikyuu/trade_sys/selector/build_in.h +1 -0
  146. hikyuu/include/hikyuu/trade_sys/selector/crt/SE_MultiFactor2.h +40 -0
  147. hikyuu/include/hikyuu/trade_sys/selector/imp/MultiFactorSelector.h +0 -3
  148. hikyuu/include/hikyuu/trade_sys/selector/imp/MultiFactorSelector2.h +49 -0
  149. hikyuu/include/hikyuu/trade_sys/selector/imp/logic/OperatorSelector.h +1 -1
  150. hikyuu/include/hikyuu/trade_sys/selector/imp/logic/OperatorValueSelector.h +1 -1
  151. hikyuu/include/hikyuu/trade_sys/signal/imp/BandSignal2.h +0 -4
  152. hikyuu/include/hikyuu/trade_sys/signal/imp/logic/AddValueSignal.h +2 -2
  153. hikyuu/include/hikyuu/trade_sys/signal/imp/logic/DivValueSignal.h +2 -2
  154. hikyuu/include/hikyuu/trade_sys/signal/imp/logic/MulValueSignal.h +2 -2
  155. hikyuu/include/hikyuu/trade_sys/signal/imp/logic/OperatorSignal.h +1 -1
  156. hikyuu/include/hikyuu/trade_sys/signal/imp/logic/OperatorValueSignal.h +4 -4
  157. hikyuu/include/hikyuu/trade_sys/signal/imp/logic/SubValueSignal.h +2 -2
  158. hikyuu/include/hikyuu/trade_sys/slippage/build_in.h +5 -1
  159. hikyuu/include/hikyuu/trade_sys/slippage/crt/SP_LogNormal.h +22 -0
  160. hikyuu/include/hikyuu/trade_sys/slippage/crt/SP_Normal.h +22 -0
  161. hikyuu/include/hikyuu/trade_sys/slippage/crt/SP_TruncNormal.h +25 -0
  162. hikyuu/include/hikyuu/trade_sys/slippage/crt/SP_Uniform.h +23 -0
  163. hikyuu/include/hikyuu/trade_sys/slippage/imp/LogNormalSlippage.h +28 -0
  164. hikyuu/include/hikyuu/trade_sys/slippage/imp/NormalSlippage.h +28 -0
  165. hikyuu/include/hikyuu/trade_sys/slippage/imp/TruncNormalSlippage.h +28 -0
  166. hikyuu/include/hikyuu/trade_sys/slippage/imp/UniformSlippage.h +24 -0
  167. hikyuu/include/hikyuu/trade_sys/system/System.h +14 -1
  168. hikyuu/include/hikyuu/utilities/SpendTimer.h +17 -7
  169. hikyuu/include/hikyuu/utilities/arithmetic.h +55 -0
  170. hikyuu/include/hikyuu/utilities/db_connect/mysql/MySQLConnect.h +1 -1
  171. hikyuu/include/hikyuu/utilities/db_connect/mysql/MySQLStatement.h +1 -1
  172. hikyuu/include/hikyuu/utilities/db_connect/sqlite/SQLiteConnect.h +1 -1
  173. hikyuu/include/hikyuu/utilities/db_connect/sqlite/SQLiteStatement.h +1 -1
  174. hikyuu/include/hikyuu/utilities/plugin/PluginLoader.h +4 -1
  175. hikyuu/include/hikyuu/version.h +5 -5
  176. hikyuu/plugin/libbacktest.so +0 -0
  177. hikyuu/plugin/libclickhousedriver.so +0 -0
  178. hikyuu/plugin/libdataserver.so +0 -0
  179. hikyuu/{cpp/core39.so → plugin/libdataserver_parquet.so} +0 -0
  180. hikyuu/plugin/libdevice.so +0 -0
  181. hikyuu/plugin/libextind.so +0 -0
  182. hikyuu/plugin/libhkuextra.so +0 -0
  183. hikyuu/plugin/libimport2hdf5.so +0 -0
  184. hikyuu/plugin/libtmreport.so +0 -0
  185. hikyuu/trade_manage/__init__.pyi +599 -579
  186. hikyuu/trade_manage/broker.pyi +3 -3
  187. hikyuu/trade_manage/broker_easytrader.pyi +1 -1
  188. hikyuu/trade_manage/trade.py +0 -2
  189. hikyuu/trade_manage/trade.pyi +599 -579
  190. hikyuu/util/__init__.pyi +1 -1
  191. hikyuu/util/singleton.pyi +1 -1
  192. {hikyuu-2.6.8.4.dist-info → hikyuu-2.7.0.dist-info}/METADATA +36 -32
  193. {hikyuu-2.6.8.4.dist-info → hikyuu-2.7.0.dist-info}/RECORD +197 -164
  194. {hikyuu-2.6.8.4.dist-info → hikyuu-2.7.0.dist-info}/top_level.txt +2 -2
  195. hikyuu/cpp/core39.pyi +0 -14385
  196. hikyuu/data_driver/__init__.py +0 -49
  197. hikyuu/data_driver/jqdata_data_driver.py +0 -277
  198. hikyuu/data_driver/pytdx_data_driver.py +0 -292
  199. hikyuu/fetcher/stock/zh_stock_a_huatai.py +0 -51
  200. hikyuu/fetcher/stock/zh_stock_a_pytdx.py +0 -129
  201. hikyuu/gui/data/CollectToMemThread.py +0 -123
  202. hikyuu/gui/data/CollectToMySQLThread.py +0 -178
  203. hikyuu/gui/start_huatai_insight.py +0 -510
  204. hikyuu/include/hikyuu/views/arrow_common.h +0 -38
  205. hikyuu/include/hikyuu/views/arrow_views.h +0 -117
  206. hikyuu/tools/update_block_info.py +0 -168
  207. /hikyuu/include/hikyuu/{views → trade_sys/multifactor/filter}/__init__.py +0 -0
  208. {hikyuu-2.6.8.4.dist-info → hikyuu-2.7.0.dist-info}/WHEEL +0 -0
  209. {hikyuu-2.6.8.4.dist-info → hikyuu-2.7.0.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,351 @@
1
+ #!/usr/bin/python
2
+ # -*- coding: utf8 -*-
3
+ #
4
+ # Create on: 2025-10-05
5
+ # Author: fasiondog
6
+
7
+ from hikyuu.data.common import modifiy_code
8
+ from hikyuu.util import *
9
+ from hikyuu.fetcher.stock.zh_block_em import *
10
+ import os
11
+ from datetime import datetime
12
+
13
+
14
+ def sanitize_filename(filename: str) -> str:
15
+ """
16
+ 将字符串中影响文件创建的相关目录字符替换为下划线
17
+
18
+ Args:
19
+ filename: 输入的文件名字符串
20
+
21
+ Returns:
22
+ 处理后的文件名字符串,其中非法字符已被替换为下划线
23
+ """
24
+ if not filename:
25
+ return filename
26
+
27
+ # 需要替换的非法字符(Windows和Unix系统中的非法字符)
28
+ illegal_chars = '<>:"/\\|?*'
29
+
30
+ # 替换非法字符为下划线
31
+ sanitized = filename
32
+ for char in illegal_chars:
33
+ sanitized = sanitized.replace(char, '_')
34
+
35
+ return sanitized
36
+
37
+
38
+ _BLOCK_SAVE_PATH = os.path.expanduser('~') + '/.hikyuu/downloads/block'
39
+ if not os.path.exists(_BLOCK_SAVE_PATH):
40
+ os.makedirs(_BLOCK_SAVE_PATH)
41
+
42
+
43
+ def read_block_from_path(block_path=_BLOCK_SAVE_PATH):
44
+ """
45
+ 从指定目录下读取block信息
46
+
47
+ :param block_path: block根目录路径,默认为 _BLOCK_SAVE_PATH
48
+ :return: 返回格式类似于 {'block': {'category1': {'name1': [code1, code2]}},
49
+ 'block_info': {'category1: {'name1': 'code1', 'name2': ''}}
50
+ """
51
+ result = {
52
+ 'block': {},
53
+ 'block_info': {}
54
+ }
55
+
56
+ if not os.path.exists(block_path):
57
+ return result
58
+
59
+ # 遍历所有分类目录
60
+ for category in os.listdir(block_path):
61
+ category_path = os.path.join(block_path, category)
62
+ if not os.path.isdir(category_path):
63
+ continue
64
+
65
+ result['block'][category] = {}
66
+ result['block_info'][category] = {}
67
+
68
+ # 遍历分类目录下的所有.txt文件
69
+ for file in os.listdir(category_path):
70
+ if file.endswith('.txt'):
71
+ file_path = os.path.join(category_path, file)
72
+ # 文件名作为板块名称(去掉扩展名)
73
+ block_name = os.path.splitext(file)[0]
74
+
75
+ # 解析文件名,格式为 "code_name" 或 "name"
76
+ if '_' in block_name:
77
+ parts = block_name.split('_', 1) # 只分割第一个下划线
78
+ code_part = parts[0]
79
+ name_part = parts[1]
80
+ # 判断code部分是否为纯数字或字母数字组合
81
+ if code_part.replace('_', '').isalnum():
82
+ result['block_info'][category][name_part] = code_part
83
+ block_key = name_part
84
+ else:
85
+ result['block_info'][category][block_name] = ""
86
+ block_key = block_name
87
+ else:
88
+ result['block_info'][category][block_name] = ""
89
+ block_key = block_name
90
+
91
+ # 读取文件中的股票代码
92
+ codes = []
93
+ with open(file_path, 'r', encoding='utf-8') as f:
94
+ for line in f:
95
+ code = line.strip()
96
+ if code:
97
+ codes.append(code)
98
+
99
+ result['block'][category][block_key] = codes
100
+
101
+ return result
102
+
103
+
104
+ def is_file_can_download(filepath, sec_limit=5 * 24 * 60 * 60):
105
+ """判断文件创建时间是否超过时长限制可以下载"""
106
+ if not os.path.exists(filepath):
107
+ return True
108
+
109
+ file_mtime = os.path.getmtime(filepath)
110
+ file_datetime = datetime.fromtimestamp(file_mtime)
111
+ now = datetime.now()
112
+
113
+ # 计算时间差是否超过时间限制
114
+ return (now - file_datetime).total_seconds() > sec_limit
115
+
116
+
117
+ @hku_catch()
118
+ def save_block(stkcodes: list, filename: str):
119
+ """将板块数据保存为CSV文件,格式为板块名称/code"""
120
+ with open(filename, 'w', encoding='utf-8') as f:
121
+ for code in stkcodes:
122
+ f.write(f"{code}\n")
123
+ # hku_info(f"已保存至 {filename}")
124
+
125
+
126
+ @hku_catch(trace=False)
127
+ def down_em_all_hybk_info():
128
+ """下载东财所有行业板块列表"""
129
+ save_path = f'{_BLOCK_SAVE_PATH}/行业板块'
130
+ if not os.path.exists(save_path):
131
+ os.makedirs(save_path)
132
+ blk_list = get_hybk_names()
133
+ time.sleep(random.uniform(1, 3))
134
+ total = len(blk_list)
135
+ for i, blk in enumerate(blk_list):
136
+ filename = f"{save_path}/{blk[0]}_{blk[1]}.txt"
137
+ if is_file_can_download(filename, 5 * 24 * 60 * 60):
138
+ try:
139
+ stk_codes = get_hybk_cons_code(blk[0])
140
+ hku_info(f"{i+1}|{total} 获取行业板块{blk[1]}成分: {len(stk_codes)}")
141
+ except (ConnectionError, ConnectionAbortedError, ConnectionResetError, ConnectionRefusedError) as e:
142
+ hku_error(f"ip 封禁! 请至东财官网首页拖动划窗解锁后重试!")
143
+ raise e
144
+ except Exception as e:
145
+ hku_warn(f"Failed! {type(e).__name__}: {str(e)}")
146
+ continue
147
+ stk_codes = [modifiy_code(code) for code in stk_codes]
148
+ stk_codes = [code for code in stk_codes if code is not None]
149
+ save_block(stk_codes, filename)
150
+ time.sleep(random.uniform(1, 3))
151
+
152
+
153
+ @hku_catch(trace=False)
154
+ def down_em_all_gnbk_info():
155
+ """获取所有概念版本列表"""
156
+ save_path = f'{_BLOCK_SAVE_PATH}/概念板块'
157
+ if not os.path.exists(save_path):
158
+ os.makedirs(save_path)
159
+ blk_names = stock_board_concept_name_em()['板块名称']
160
+ not_need_blks = set(["昨日连板_含一字", "昨日涨停_含一字", "昨日涨停"])
161
+ total = len(blk_names)
162
+ for i, blk_name in enumerate(blk_names):
163
+ if blk_name in not_need_blks:
164
+ continue
165
+ filename = f"{save_path}/{sanitize_filename(blk_name)}.txt"
166
+ if is_file_can_download(filename, 30 * 24 * 60 * 60):
167
+ try:
168
+ stk_codes = stock_board_concept_cons_em(blk_name)
169
+ except (ConnectionError, ConnectionAbortedError, ConnectionResetError, ConnectionRefusedError) as e:
170
+ raise e
171
+ except Exception as e:
172
+ hku_warn(f"Failed! {type(e).__name__}: {str(e)}")
173
+ continue
174
+ stk_codes = stk_codes['代码'].to_list()
175
+ stk_codes = [modifiy_code(code) for code in stk_codes]
176
+ stk_codes = [code for code in stk_codes if code is not None]
177
+ hku_info(f"{i+1}|{total} 获取概念板块{blk_name}成分: {len(stk_codes)}")
178
+ save_block(stk_codes, filename)
179
+ time.sleep(random.uniform(1, 3))
180
+
181
+
182
+ @hku_catch(trace=False)
183
+ def down_em_all_dybk_info():
184
+ """获取所有地域板块列表"""
185
+ save_path = f'{_BLOCK_SAVE_PATH}/地域板块'
186
+ if not os.path.exists(save_path):
187
+ os.makedirs(save_path)
188
+ blk_list = get_dybk_names()
189
+
190
+ url = "http://13.push2.eastmoney.com/api/qt/clist/get"
191
+ params = {
192
+ "pn": "1",
193
+ "pz": str(em_num_per_page),
194
+ "po": "1",
195
+ "np": "1",
196
+ "ut": "bd1d9ddb04089700cf9c27f6f7426281",
197
+ "fltt": "2",
198
+ "invt": "2",
199
+ "fid": "f3",
200
+ # "fs": f"b:{stock_board_code} f:!50",
201
+ "fields": "f12",
202
+ "_": "1626081702127",
203
+ }
204
+
205
+ total = len(blk_list)
206
+ for i, v in enumerate(blk_list):
207
+ blk_code, blk_name = v[0], v[1]
208
+ filename = f"{save_path}/{blk_name}.txt"
209
+ if not is_file_can_download(filename, 10 * 24 * 60 * 60):
210
+ continue
211
+
212
+ try:
213
+ params["fs"] = f"b:{blk_code} f:!50"
214
+ params["pn"] = 1
215
+ time.sleep(random.uniform(1, 3))
216
+ r = requests.get(url, params=params, timeout=15)
217
+ data = r.json()
218
+ if data["data"] is None:
219
+ continue
220
+
221
+ stk_json = r.json()
222
+ stk_json = stk_json["data"]["diff"]
223
+ stk_codes = []
224
+
225
+ total_page = math.ceil(data["data"]["total"] / em_num_per_page)
226
+ for page in range(2, total_page + 1):
227
+ params["pn"] = page
228
+ r = requests.get(url, params=params, timeout=15)
229
+ stk_json = r.json()
230
+ stk_json = stk_json["data"]["diff"]
231
+ stk_codes.extend([f"{v['f12']}" for v in stk_json])
232
+ time.sleep(random.uniform(1, 3))
233
+ except (ConnectionError, ConnectionAbortedError, ConnectionResetError, ConnectionRefusedError):
234
+ raise e
235
+ except Exception as e:
236
+ hku_warn(f"Failed! {type(e).__name__}: {str(e)}")
237
+ continue
238
+
239
+ stk_codes = [modifiy_code(code) for code in stk_codes]
240
+ stk_codes = [code for code in stk_codes if code is not None]
241
+ save_block(stk_codes, filename)
242
+ hku_info(f'{i+1}|{total} 获取地域板块{blk_name}成分: {len(stk_codes)}')
243
+
244
+
245
+ @hku_catch(trace=False)
246
+ def download_all_zsbk_info():
247
+ """获取所有指数成分股列表"""
248
+ save_path = f'{_BLOCK_SAVE_PATH}/指数板块'
249
+ if not os.path.exists(save_path):
250
+ os.makedirs(save_path)
251
+
252
+ blk_info = ak.index_stock_info()
253
+ time.sleep(random.uniform(1, 3))
254
+
255
+ blk_info['index_code'] = blk_info['index_code'].astype(str) # 确保是字符串类型
256
+ df_000 = blk_info[blk_info['index_code'].str.startswith('000')].reset_index(drop=True) # 000前缀
257
+ df_399 = blk_info[blk_info['index_code'].str.startswith('399')].reset_index(drop=True) # 399前缀
258
+
259
+ # 2. 交替合并两个DataFrame
260
+ merged_rows = []
261
+ max_length = max(len(df_000), len(df_399)) # 取两个DataFrame的最大长度
262
+
263
+ for i in range(max_length):
264
+ # 先加000前缀的行(如果存在)
265
+ if i < len(df_000):
266
+ merged_rows.append(df_000.iloc[i])
267
+ # 再加399前缀的行(如果存在)
268
+ if i < len(df_399):
269
+ merged_rows.append(df_399.iloc[i])
270
+
271
+ # 3. 转换为DataFrame
272
+ blk_info = pd.DataFrame(merged_rows).reset_index(drop=True)
273
+
274
+ not_need_blks = set(["000012", "000013", "000022", "000061", "000101", "000188",
275
+ "000817", "000847", "000849", "000850", "000851", "000853",
276
+ "000854", "000856", "000857", "000858", "000923", "000973",
277
+ "000974", "000996", "000997", "000999", "399415", "399416"])
278
+
279
+ failed_sina = 0
280
+ failed_csindex = 0
281
+ blk_set = {}
282
+ blk_codes = blk_info["index_code"]
283
+ blk_names = blk_info["display_name"]
284
+ total = len(blk_codes)
285
+ for i in range(total):
286
+ blk_name = blk_names[i]
287
+ blk_code = blk_codes[i]
288
+ # 沪深指数有重复,避免深指覆盖
289
+ if blk_name in blk_set or blk_code in not_need_blks:
290
+ continue
291
+
292
+ market_block_code = f'SH{blk_code}' if blk_code.startswith('0') else f'SZ{blk_code}'
293
+ filename = f"{save_path}/{market_block_code}_{blk_name}.txt"
294
+ if not is_file_can_download(filename, 10 * 24 * 60 * 60):
295
+ continue
296
+
297
+ try:
298
+ if blk_code[:3] == "399":
299
+ if failed_sina > 10:
300
+ continue
301
+ stk_codes = ak.index_stock_cons(symbol=blk_code)
302
+ stk_codes = stk_codes['品种代码'].to_list()
303
+ failed_sina = 0
304
+ else:
305
+ if failed_csindex > 10:
306
+ continue
307
+ stk_codes = ak.index_stock_cons_csindex(symbol=blk_code)
308
+ stk_codes = stk_codes['成分券代码'].to_list()
309
+ failed_csindex = 0
310
+
311
+ stk_codes = [modifiy_code(code) for code in stk_codes]
312
+ stk_codes = [code for code in stk_codes if code is not None]
313
+ save_block(stk_codes, filename)
314
+ hku_info("{}|{} 获取指数板块 {}|{} 成分: {}", i, total, blk_code, blk_name, len(stk_codes))
315
+ blk_set[blk_name] = 1
316
+ except KeyboardInterrupt:
317
+ break
318
+ except (ConnectionError, ConnectionAbortedError, ConnectionResetError, ConnectionRefusedError):
319
+ if blk_code[:3] == "399":
320
+ hku_warn("ConnectionError! Sina closed!")
321
+ failed_sina = 100
322
+ else:
323
+ hku_warn("ConnectionError! CSIndex closed!")
324
+ failed_csindex = 100
325
+ except Exception as e:
326
+ print(f"Failed! {i}, {blk_code}, {blk_name}! {type(e).__name__}: {str(e)}")
327
+ if blk_code[:3] == "399":
328
+ failed_sina += 1
329
+ else:
330
+ failed_csindex += 1
331
+ # raise e
332
+ time.sleep(random.uniform(1, 3))
333
+
334
+
335
+ def download_block_info():
336
+ down_em_all_hybk_info()
337
+ # down_em_all_dybk_info()
338
+ # down_em_all_gnbk_info()
339
+ download_all_zsbk_info()
340
+
341
+
342
+ if __name__ == "__main__":
343
+ # down_em_all_hybk_info()
344
+ # down_em_all_dybk_info()
345
+ # down_em_all_gnbk_info()
346
+ # download_all_zsbk_info()
347
+
348
+ ret = read_block_from_path()
349
+ # print(ret['block'])
350
+ print(ret['block_info'])
351
+ print(tuple(ret['block'].keys()))
@@ -4,85 +4,32 @@
4
4
  # Create on: 20240102
5
5
  # Author: fasiondog
6
6
 
7
- from concurrent.futures import ThreadPoolExecutor
8
- from hikyuu.data.common import MARKET, get_stk_code_name_list
9
7
  from hikyuu.util import *
10
8
  from hikyuu.fetcher.stock.zh_block_em import *
9
+ from hikyuu.data.download_block import *
11
10
 
12
11
 
13
- def em_import_block_to_clickhouse(connect, code_market_dict, categorys=('行业板块', '指数板块')):
14
- all_block_info = {}
15
-
16
- with ThreadPoolExecutor(4) as executor:
17
- if '行业板块' in categorys:
18
- t1 = executor.submit(get_all_hybk_info, code_market_dict)
19
-
20
- if '概念板块' in categorys:
21
- t2 = executor.submit(get_all_gnbk_info, code_market_dict)
22
-
23
- if '地域板块' in categorys:
24
- t3 = executor.submit(get_all_dybk_info, code_market_dict)
25
-
26
- if '指数板块' in categorys:
27
- t4 = executor.submit(get_all_zsbk_info, code_market_dict)
28
-
29
- success_fetch_hy = False
30
- if '行业板块' in categorys:
31
- x = t1.result()
32
- hku_info("获取行业板块信息完毕")
33
- if x:
34
- all_block_info["行业板块"] = x
35
- success_fetch_hy = True
36
-
37
- success_fetch_gn = False
38
- if '概念板块' in categorys:
39
- x = t2.result()
40
- hku_info("获取概念板块信息完毕")
41
- if x:
42
- all_block_info["概念板块"] = x
43
- success_fetch_gn = True
44
-
45
- success_fetch_dy = False
46
- if '地域板块' in categorys:
47
- x = t3.result()
48
- hku_info("获取地域板块信息完毕")
49
- if x:
50
- all_block_info["地域板块"] = x
51
- success_fetch_dy = True
52
-
53
- success_fetch_zs = False
54
- if '指数板块' in categorys:
55
- x = t4.result()
56
- hku_info("获取指数板块信息完毕")
57
- if x:
58
- all_block_info["指数板块"] = x
59
- success_fetch_zs = True
60
-
61
- blks = []
62
- if success_fetch_hy:
63
- blks.append('行业板块')
64
- if success_fetch_gn:
65
- blks.append('概念板块')
66
- if success_fetch_dy:
67
- blks.append('地域板块')
68
- if success_fetch_zs:
69
- blks.append('指数板块')
12
+ def em_import_block_to_clickhouse(connect):
13
+ download_block_info()
14
+
15
+ blocks_info = read_block_from_path()
16
+ blks = blocks_info['block']
17
+ blks_info = blocks_info['block_info']
70
18
 
71
19
  if not blks:
72
- return
20
+ return 0
73
21
 
74
22
  hku_info("更新数据库")
75
- if len(blks) == 1:
76
- sql = f"delete from hku_base.block where category in ('{blks[0]}')"
77
- else:
78
- sql = f"delete from hku_base.block where category in {tuple(blks)}"
23
+ sql = f"delete from hku_base.block where category in {tuple(blks.keys())}"
24
+ connect.command(sql)
25
+ sql = f"delete from hku_base.blockindex where category in {tuple(blks.keys())}"
79
26
  connect.command(sql)
80
27
 
81
28
  insert_records = []
82
29
 
83
- for category in all_block_info:
84
- for name in all_block_info[category]:
85
- for code in all_block_info[category][name]:
30
+ for category, blocks in blks.items():
31
+ for name, codes in blocks.items():
32
+ for code in codes:
86
33
  insert_records.append((category, name, code))
87
34
 
88
35
  if insert_records:
@@ -91,6 +38,17 @@ def em_import_block_to_clickhouse(connect, code_market_dict, categorys=('行业
91
38
  data=insert_records)
92
39
  connect.insert(context=ic)
93
40
 
41
+ index_records = []
42
+ for category, blocks in blks_info.items():
43
+ for name, index_code in blocks.items():
44
+ if len(index_code) == 8:
45
+ index_records.append((category, name, index_code))
46
+ if index_records:
47
+ ic = connect.create_insert_context(table='blockindex', database='hku_base',
48
+ column_names=['category', 'name', 'index_code'],
49
+ data=index_records)
50
+ connect.insert(context=ic)
51
+
94
52
  return len(insert_records)
95
53
 
96
54
 
@@ -109,12 +67,6 @@ if __name__ == "__main__":
109
67
  client = clickhouse_connect.get_client(
110
68
  host=host, username=user, password=password)
111
69
 
112
- x = get_stk_code_name_list(MARKET.SH)
113
- code_market_dict = {}
114
- for v in x:
115
- code_market_dict[v["code"]] = MARKET.SH
116
- # print(code_market_dict)
117
-
118
- em_import_block_to_clickhouse(client, code_market_dict, categorys=('行业板块', ))
70
+ em_import_block_to_clickhouse(client)
119
71
 
120
72
  client.close()
@@ -4,93 +4,49 @@
4
4
  # Create on: 20240102
5
5
  # Author: fasiondog
6
6
 
7
- from concurrent.futures import ThreadPoolExecutor
8
- from hikyuu.data.common import MARKET, get_stk_code_name_list
7
+
9
8
  from hikyuu.util import *
10
9
  from hikyuu.fetcher.stock.zh_block_em import *
10
+ from hikyuu.data.download_block import *
11
+
11
12
 
13
+ def em_import_block_to_mysql(connect):
14
+ download_block_info()
12
15
 
13
- def em_import_block_to_mysql(connect, code_market_dict, categorys=('行业板块', '概念板块', '地域板块', '指数板块')):
14
- all_block_info = {}
15
-
16
- with ThreadPoolExecutor(4) as executor:
17
- if '行业板块' in categorys:
18
- t1 = executor.submit(get_all_hybk_info, code_market_dict)
19
-
20
- if '概念板块' in categorys:
21
- t2 = executor.submit(get_all_gnbk_info, code_market_dict)
22
-
23
- if '地域板块' in categorys:
24
- t3 = executor.submit(get_all_dybk_info, code_market_dict)
25
-
26
- if '指数板块' in categorys:
27
- t4 = executor.submit(get_all_zsbk_info, code_market_dict)
28
-
29
- success_fetch_hy = False
30
- if '行业板块' in categorys:
31
- x = t1.result()
32
- hku_info("获取行业板块信息完毕")
33
- if x:
34
- all_block_info["行业板块"] = x
35
- success_fetch_hy = True
36
-
37
- success_fetch_gn = False
38
- if '概念板块' in categorys:
39
- x = t2.result()
40
- hku_info("获取概念板块信息完毕")
41
- if x:
42
- all_block_info["概念板块"] = x
43
- success_fetch_gn = True
44
-
45
- success_fetch_dy = False
46
- if '地域板块' in categorys:
47
- x = t3.result()
48
- hku_info("获取地域板块信息完毕")
49
- if x:
50
- all_block_info["地域板块"] = x
51
- success_fetch_dy = True
52
-
53
- success_fetch_zs = False
54
- if '指数板块' in categorys:
55
- x = t4.result()
56
- hku_info("获取指数板块信息完毕")
57
- if x:
58
- all_block_info["指数板块"] = x
59
- success_fetch_zs = True
60
-
61
- blks = []
62
- if success_fetch_hy:
63
- blks.append('行业板块')
64
- if success_fetch_gn:
65
- blks.append('概念板块')
66
- if success_fetch_dy:
67
- blks.append('地域板块')
68
- if success_fetch_zs:
69
- blks.append('指数板块')
16
+ blocks_info = read_block_from_path()
17
+ blks = blocks_info['block']
18
+ blks_info = blocks_info['block_info']
70
19
 
71
20
  if not blks:
72
- return
21
+ return 0
73
22
 
74
23
  hku_info("更新数据库")
75
24
  cur = connect.cursor()
76
- if len(blks) == 1:
77
- sql = f"delete from hku_base.block where category in ('{blks[0]}')"
78
- else:
79
- sql = f"delete from hku_base.block where category in {tuple(blks)}"
25
+ sql = f"delete from hku_base.block where category in {tuple(blks.keys())}"
26
+ cur.execute(sql)
27
+ sql = f"delete from hku_base.BlockIndex where category in {tuple(blks.keys())}"
80
28
  cur.execute(sql)
81
29
 
82
30
  insert_records = []
83
31
 
84
- for category in all_block_info:
85
- for name in all_block_info[category]:
86
- for code in all_block_info[category][name]:
32
+ for category, blocks in blks.items():
33
+ for name, codes in blocks.items():
34
+ for code in codes:
87
35
  insert_records.append((category, name, code))
88
36
 
89
37
  if insert_records:
90
38
  sql = "insert into hku_base.block (category, name, market_code) values (%s,%s,%s)"
91
- hku_info(f"insert block records: {len(insert_records)}")
92
39
  cur.executemany(sql, insert_records)
93
40
 
41
+ index_records = []
42
+ for category, blocks in blks_info.items():
43
+ for name, index_code in blocks.items():
44
+ if len(index_code) == 8:
45
+ index_records.append((category, name, index_code))
46
+ if index_records:
47
+ sql = "insert into hku_base.BlockIndex (category, name, market_code) values (%s,%s,%s)"
48
+ cur.executemany(sql, index_records)
49
+
94
50
  connect.commit()
95
51
  cur.close()
96
52
  return len(insert_records)
@@ -111,11 +67,5 @@ if __name__ == "__main__":
111
67
  connect = mysql.connector.connect(user=usr, password=pwd, host=host, port=port)
112
68
  create_database(connect)
113
69
 
114
- x = get_stk_code_name_list(MARKET.SH)
115
- code_market_dict = {}
116
- for v in x:
117
- code_market_dict[v["code"]] = MARKET.SH
118
- # print(code_market_dict)
119
-
120
- em_import_block_to_mysql(connect, code_market_dict)
70
+ em_import_block_to_mysql(connect)
121
71
  connect.close()