hikyuu 2.6.5__py3-none-win_amd64.whl → 2.6.7__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 (146) hide show
  1. hikyuu/__init__.py +16 -0
  2. hikyuu/__init__.pyi +484 -474
  3. hikyuu/analysis/__init__.pyi +466 -445
  4. hikyuu/analysis/analysis.pyi +467 -446
  5. hikyuu/core.pyi +468 -447
  6. hikyuu/cpp/boost_date_time-mt.dll +0 -0
  7. hikyuu/cpp/boost_serialization-mt.dll +0 -0
  8. hikyuu/cpp/boost_wserialization-mt.dll +0 -0
  9. hikyuu/cpp/core310.pyd +0 -0
  10. hikyuu/cpp/core310.pyi +1070 -878
  11. hikyuu/cpp/core311.pyd +0 -0
  12. hikyuu/cpp/core311.pyi +1070 -878
  13. hikyuu/cpp/core312.pyd +0 -0
  14. hikyuu/cpp/core312.pyi +1070 -878
  15. hikyuu/cpp/core313.pyd +0 -0
  16. hikyuu/cpp/core313.pyi +1070 -876
  17. hikyuu/cpp/core39.pyd +0 -0
  18. hikyuu/cpp/core39.pyi +1070 -878
  19. hikyuu/cpp/hikyuu.dll +0 -0
  20. hikyuu/cpp/hikyuu.lib +0 -0
  21. hikyuu/cpp/i18n/__init__.py +0 -0
  22. hikyuu/cpp/i18n/zh_CN/__init__.py +0 -0
  23. hikyuu/cpp/i18n/zh_CN/hikyuu.mo +0 -0
  24. hikyuu/cpp/sqlite3.dll +0 -0
  25. hikyuu/data/clickhouse_upgrade/__init__.py +1 -0
  26. hikyuu/data/clickhouse_upgrade/createdb.sql +1085 -0
  27. hikyuu/data/common_clickhouse.py +465 -0
  28. hikyuu/data/em_block_to_clickhouse.py +120 -0
  29. hikyuu/data/hku_config_template.py +58 -3
  30. hikyuu/data/pytdx_finance_to_clickhouse.py +107 -0
  31. hikyuu/data/pytdx_to_clickhouse.py +841 -0
  32. hikyuu/data/pytdx_to_mysql.py +4 -4
  33. hikyuu/data/pytdx_weight_to_clickhouse.py +191 -0
  34. hikyuu/data/tdx_to_clickhouse.py +448 -0
  35. hikyuu/data/tdx_to_h5.py +1 -1
  36. hikyuu/data/zh_bond10_to_clickhouse.py +49 -0
  37. hikyuu/draw/__init__.pyi +1 -1
  38. hikyuu/draw/drawplot/bokeh_draw.pyi +479 -471
  39. hikyuu/draw/drawplot/echarts_draw.py +9 -8
  40. hikyuu/draw/drawplot/echarts_draw.pyi +479 -471
  41. hikyuu/draw/drawplot/matplotlib_draw.py +3 -3
  42. hikyuu/draw/drawplot/matplotlib_draw.pyi +479 -471
  43. hikyuu/draw/elder.pyi +6 -6
  44. hikyuu/draw/kaufman.py +1 -1
  45. hikyuu/draw/kaufman.pyi +10 -10
  46. hikyuu/draw/volume.pyi +5 -5
  47. hikyuu/examples/notebook/000-Index.ipynb +1 -1
  48. hikyuu/examples/notebook/001-overview.ipynb +78 -63
  49. hikyuu/examples/notebook/002-HowToGetStock.ipynb +259 -40
  50. hikyuu/examples/notebook/003-HowToGetKDataAndDraw.ipynb +49 -41
  51. hikyuu/examples/notebook/004-IndicatorOverview.ipynb +29 -29
  52. hikyuu/examples/notebook/005-Drawplot.ipynb +66 -37
  53. hikyuu/examples/notebook/006-TradeManager.ipynb +808 -61
  54. hikyuu/examples/notebook/007-SystemDetails.ipynb +23 -23
  55. hikyuu/examples/notebook/009-RealData.ipynb +3 -3
  56. hikyuu/examples/notebook/010-Portfolio.ipynb +761 -122
  57. hikyuu/extend.py +15 -100
  58. hikyuu/extend.pyi +478 -493
  59. hikyuu/fetcher/stock/zh_stock_a_pytdx.py +9 -20
  60. hikyuu/fetcher/stock/zh_stock_a_qmt.py +4 -5
  61. hikyuu/fetcher/stock/zh_stock_a_sina_qq.py +16 -60
  62. hikyuu/flat/Spot.py +96 -200
  63. hikyuu/gui/HikyuuTDX.py +134 -7
  64. hikyuu/gui/data/ImportBlockInfoTask.py +11 -0
  65. hikyuu/gui/data/ImportHistoryFinanceTask.py +15 -1
  66. hikyuu/gui/data/ImportPytdxTimeToH5Task.py +11 -1
  67. hikyuu/gui/data/ImportPytdxToH5Task.py +13 -1
  68. hikyuu/gui/data/ImportPytdxTransToH5Task.py +11 -1
  69. hikyuu/gui/data/ImportTdxToH5Task.py +13 -1
  70. hikyuu/gui/data/ImportWeightToSqliteTask.py +14 -1
  71. hikyuu/gui/data/ImportZhBond10Task.py +11 -0
  72. hikyuu/gui/data/MainWindow.py +210 -135
  73. hikyuu/gui/data/UsePytdxImportToH5Thread.py +45 -26
  74. hikyuu/gui/data/UseTdxImportToH5Thread.py +19 -1
  75. hikyuu/gui/dataserver.py +12 -4
  76. hikyuu/gui/spot_server.py +30 -40
  77. hikyuu/gui/start_qmt.py +20 -3
  78. hikyuu/hub.pyi +6 -6
  79. hikyuu/include/hikyuu/DataType.h +2 -0
  80. hikyuu/include/hikyuu/KQuery.h +22 -28
  81. hikyuu/include/hikyuu/MarketInfo.h +1 -1
  82. hikyuu/include/hikyuu/Stock.h +15 -3
  83. hikyuu/include/hikyuu/StockManager.h +12 -3
  84. hikyuu/include/hikyuu/StockTypeInfo.h +6 -0
  85. hikyuu/include/hikyuu/TransRecord.h +2 -8
  86. hikyuu/include/hikyuu/data_driver/kdata/mysql/KRecordTable.h +1 -0
  87. hikyuu/include/hikyuu/doc.h +4 -0
  88. hikyuu/include/hikyuu/global/GlobalSpotAgent.h +1 -1
  89. hikyuu/include/hikyuu/global/SpotRecord.h +15 -31
  90. hikyuu/include/hikyuu/global/agent/spot_generated.h +48 -232
  91. hikyuu/include/hikyuu/global/schedule/scheduler.h +1 -1
  92. hikyuu/include/hikyuu/indicator/Indicator.h +37 -0
  93. hikyuu/include/hikyuu/lang.h +27 -0
  94. hikyuu/include/hikyuu/plugin/KDataToHdf5Importer.h +9 -1
  95. hikyuu/include/hikyuu/plugin/dataserver.h +26 -1
  96. hikyuu/include/hikyuu/plugin/device.h +2 -1
  97. hikyuu/include/hikyuu/plugin/hkuextra.h +56 -0
  98. hikyuu/include/hikyuu/plugin/interface/DataDriverPluginInterface.h +27 -0
  99. hikyuu/include/hikyuu/plugin/interface/DataServerPluginInterface.h +2 -1
  100. hikyuu/include/hikyuu/plugin/interface/DevicePluginInterface.h +1 -1
  101. hikyuu/include/hikyuu/plugin/interface/HkuExtraPluginInterface.h +38 -0
  102. hikyuu/include/hikyuu/plugin/interface/ImportKDataToHdf5PluginInterface.h +13 -1
  103. hikyuu/include/hikyuu/plugin/interface/plugins.h +4 -0
  104. hikyuu/include/hikyuu/python/pybind_utils.h +9 -0
  105. hikyuu/include/hikyuu/strategy/Strategy.h +0 -9
  106. hikyuu/include/hikyuu/trade_manage/TradeRecord.h +1 -1
  107. hikyuu/include/hikyuu/utilities/config.h +0 -2
  108. hikyuu/include/hikyuu/utilities/os.h +9 -0
  109. hikyuu/include/hikyuu/utilities/plugin/PluginLoader.h +2 -1
  110. hikyuu/include/hikyuu/version.h +4 -4
  111. hikyuu/include/hikyuu/view/MarketView.h +59 -0
  112. hikyuu/indicator/__init__.py +0 -1
  113. hikyuu/indicator/indicator.py +14 -53
  114. hikyuu/plugin/backtest.dll +0 -0
  115. hikyuu/plugin/clickhousedriver.dll +0 -0
  116. hikyuu/plugin/dataserver.dll +0 -0
  117. hikyuu/plugin/device.dll +0 -0
  118. hikyuu/plugin/extind.dll +0 -0
  119. hikyuu/plugin/hkuextra.dll +0 -0
  120. hikyuu/plugin/import2hdf5.dll +0 -0
  121. hikyuu/plugin/tmreport.dll +0 -0
  122. hikyuu/test/test_init.py +59 -0
  123. hikyuu/test/test_real_tdx_import.py +336 -0
  124. hikyuu/test/test_tdx_import.py +315 -0
  125. hikyuu/test/test_tdx_real_data_import.py +281 -0
  126. hikyuu/trade_manage/__init__.pyi +479 -471
  127. hikyuu/trade_manage/trade.py +4 -65
  128. hikyuu/trade_manage/trade.pyi +479 -483
  129. hikyuu/trade_sys/__init__.py +11 -0
  130. hikyuu/util/__init__.py +1 -0
  131. hikyuu/util/__init__.pyi +4 -4
  132. hikyuu/util/check.py +8 -0
  133. hikyuu/util/check.pyi +5 -1
  134. hikyuu/util/singleton.pyi +1 -1
  135. {hikyuu-2.6.5.dist-info → hikyuu-2.6.7.dist-info}/METADATA +7 -5
  136. {hikyuu-2.6.5.dist-info → hikyuu-2.6.7.dist-info}/RECORD +142 -124
  137. {hikyuu-2.6.5.dist-info → hikyuu-2.6.7.dist-info}/top_level.txt +4 -3
  138. hikyuu/include/hikyuu/global/agent/hikyuu/flat/__init__.py +0 -1
  139. hikyuu/include/hikyuu/utilities/mo/__init__.py +0 -1
  140. hikyuu/include/hikyuu/utilities/mo/mo.h +0 -48
  141. hikyuu/indicator/talib_wrap.py +0 -1273
  142. /hikyuu/include/hikyuu/utilities/{mo/moFileReader.h → moFileReader.h} +0 -0
  143. /hikyuu/include/hikyuu/{global/agent/hikyuu → view}/__init__.py +0 -0
  144. {hikyuu-2.6.5.dist-info → hikyuu-2.6.7.dist-info}/LICENSE +0 -0
  145. {hikyuu-2.6.5.dist-info → hikyuu-2.6.7.dist-info}/WHEEL +0 -0
  146. {hikyuu-2.6.5.dist-info → hikyuu-2.6.7.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,465 @@
1
+ # coding:utf-8
2
+ #
3
+ # The MIT License (MIT)
4
+ #
5
+ # Copyright (c) 2010-2019 fasiondog/hikyuu
6
+ #
7
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ # of this software and associated documentation files (the "Software"), to deal
9
+ # in the Software without restriction, including without limitation the rights
10
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ # copies of the Software, and to permit persons to whom the Software is
12
+ # furnished to do so, subject to the following conditions:
13
+ #
14
+ # The above copyright notice and this permission notice shall be included in all
15
+ # copies or substantial portions of the Software.
16
+ #
17
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23
+ # SOFTWARE.
24
+
25
+ import os
26
+ import datetime
27
+ from pathlib import Path
28
+
29
+ import clickhouse_connect
30
+
31
+ from hikyuu import Datetime, UTCOffset
32
+ from hikyuu.data.common import get_stktype_list, get_new_holidays
33
+ from hikyuu.util import hku_catch, hku_debug, hku_info
34
+
35
+
36
+ def is_exist_db(connect):
37
+ """数据库是否已存在"""
38
+ name = connect.command("SELECT name FROM system.databases WHERE name = 'hku_base'")
39
+ return name == 'hku_base'
40
+
41
+
42
+ @hku_catch(ret=0)
43
+ def get_db_version(connect):
44
+ version = connect.command("select `version` from `hku_base`.`version`")
45
+ return version if type(version) == int else 0
46
+
47
+
48
+ def create_database(connect):
49
+ """创建数据库"""
50
+ sql_dir = os.path.dirname(__file__) + '/clickhouse_upgrade'
51
+ if not is_exist_db(connect):
52
+ filename = sql_dir + "/createdb.sql"
53
+ with open(filename, 'r', encoding='utf8') as f:
54
+ sql_string = f.read()
55
+ statements = sql_string.split(';')
56
+ for stmt in statements:
57
+ stmt = stmt.strip()
58
+ if stmt: # 跳过空语句
59
+ try:
60
+ connect.command(stmt)
61
+ except Exception as e:
62
+ print(f"执行失败: {stmt[:30]}... 错误: {e}")
63
+
64
+ db_version = get_db_version(connect)
65
+ files = [x for x in Path(sql_dir).iterdir()
66
+ if x.is_file()
67
+ and x.name != 'createdb.sql'
68
+ and x.name != '__init__.py'
69
+ and int(x.stem) > db_version and not x.is_dir()]
70
+ files.sort()
71
+ for file in files:
72
+ print(file)
73
+ sql = file.read_text(encoding='utf8')
74
+ statements = sql.split(';')
75
+ for stmt in statements:
76
+ print(stmt)
77
+ stmt = stmt.strip()
78
+ if stmt: # 跳过空语句
79
+ try:
80
+ connect.command(stmt)
81
+ except Exception as e:
82
+ print(f"执行失败: {stmt[:30]}... 错误: {e}")
83
+
84
+
85
+ def get_codepre_list(connect, market, quotations):
86
+ """获取前缀代码表"""
87
+ stktype_list = get_stktype_list(quotations)
88
+ sql = "select codepre, type from `hku_base`.`coderuletype` " \
89
+ "where market='{market}' and type in {type_list} ORDER by length(codepre) DESC"\
90
+ .format(market=market, type_list=stktype_list)
91
+ ret = connect.query(sql)
92
+ return ret.result_rows
93
+
94
+
95
+ def get_stock_list(connect, market, quotations):
96
+ stktype_list = get_stktype_list(quotations)
97
+ sql = "select market, code, valid, type from `hku_base`.`stock` where market='{}' and type in {}"\
98
+ .format(market, stktype_list)
99
+ a = connect.query(sql)
100
+ return a.result_rows
101
+
102
+
103
+ def import_new_holidays(connect):
104
+ """导入新的交易所休假日历"""
105
+ last_date = connect.command("select date from `hku_base`.`holiday` order by date desc limit 1")
106
+ last_date = last_date if type(last_date) == int else 19901219
107
+ holidays = get_new_holidays()
108
+ new_holidays = [(int(v),) for v in holidays if int(v) > last_date]
109
+ if new_holidays:
110
+ ic = connect.create_insert_context(table='holiday', database='hku_base',
111
+ data=new_holidays)
112
+ connect.insert(context=ic)
113
+
114
+
115
+ def get_table(connect, market, code, ktype):
116
+ ktype_dict = {
117
+ 'day': 'day',
118
+ 'week': 'week',
119
+ 'month': 'month',
120
+ 'quarter': 'quarter',
121
+ 'halfyear': 'halfyear',
122
+ 'year': 'year',
123
+ 'min': 'min',
124
+ '1min': 'min',
125
+ '5min': 'min5',
126
+ '15min': 'min15',
127
+ '30min': 'min30',
128
+ '60min': 'min60',
129
+ 'hour2': 'hour2',
130
+ 'min1': 'min',
131
+ 'min5': 'min5',
132
+ 'min15': 'min15',
133
+ 'min30': 'min30',
134
+ 'min60': 'min60',
135
+ 'timeline': 'timeline',
136
+ 'transdata': 'transdata',
137
+ }
138
+ nktype = ktype_dict[ktype.lower()]
139
+ if nktype == 'timeline':
140
+ return (f'hku_data.timeline', market.upper(), code.upper())
141
+ elif nktype == 'transdata':
142
+ return (f'hku_data.transdata', market.upper(), code.upper())
143
+ else:
144
+ return (f'hku_data.{nktype}_k', market.upper(), code.upper())
145
+
146
+
147
+ @hku_catch(ret=Datetime(1970, 1, 1))
148
+ def get_lastdatetime(connect, tablename):
149
+ tmp = connect.command("select max(date) from {} where market='{}' and code='{}'".format(
150
+ tablename[0], tablename[1], tablename[2]))
151
+ tmp = Datetime(tmp)
152
+ return None if tmp == Datetime(1970, 1, 1) else tmp + UTCOffset()
153
+
154
+
155
+ def get_last_krecord(connect, tablename):
156
+ """获取最后一条K线记录
157
+ 返回:(date, open, close, high, low, amount, volume)
158
+ """
159
+ try:
160
+ a = connect.query(
161
+ "select toUInt32(date), open, high, low, close, amount, volume from {} where market='{}' and code='{}' order by date desc limit 1".format(tablename[0], tablename[1], tablename[2]), settings={'optimize_skip_merged_partitions': 1})
162
+ a = a.result_rows
163
+ # hku_info(f"{tablename} {a}")
164
+ if not a:
165
+ return None
166
+ return (Datetime.from_timestamp_utc(a[0][0]*1000000).ymdhm, a[0][1], a[0][2], a[0][3], a[0][4], a[0][5], a[0][6])
167
+ except:
168
+ return None
169
+
170
+
171
+ def getWeekDate(olddate):
172
+ y = olddate // 100000000
173
+ m = olddate // 1000000 - y * 100
174
+ d = olddate // 10000 - (y * 10000 + m * 100)
175
+ tempdate = datetime.date(y, m, d)
176
+ # python中周一是第0天,周五的第4天
177
+ startdate = tempdate + datetime.timedelta(0 - tempdate.weekday())
178
+ enddate = tempdate + datetime.timedelta(4 - tempdate.weekday())
179
+ return (
180
+ startdate.year * 100000000 + startdate.month * 1000000 + startdate.day * 10000,
181
+ enddate.year * 100000000 + enddate.month * 1000000 + enddate.day * 10000
182
+ )
183
+
184
+
185
+ def getMonthDate(olddate):
186
+ y = olddate // 100000000
187
+ m = olddate // 1000000 - y * 100
188
+ import calendar
189
+ _, d = calendar.monthrange(y, m)
190
+ return (y * 100000000 + m * 1000000 + 10000, y * 100000000 + m * 1000000 + d * 10000)
191
+
192
+
193
+ def getQuarterDate(olddate):
194
+ startDict = {1: 1, 2: 1, 3: 1, 4: 4, 5: 4, 6: 4, 7: 7, 8: 7, 9: 7, 10: 10, 11: 10, 12: 10}
195
+ endDict = {1: 3, 2: 3, 3: 3, 4: 6, 5: 6, 6: 6, 7: 9, 8: 9, 9: 9, 10: 12, 11: 12, 12: 12}
196
+ d_dict = {3: 310000, 6: 300000, 9: 300000, 12: 310000}
197
+ y = olddate // 100000000
198
+ m = olddate // 1000000 - y * 100
199
+ start_m = startDict[m]
200
+ end_m = endDict[m]
201
+ return (y * 100000000 + start_m * 1000000 + 10000, y * 100000000 + end_m * 1000000 + d_dict[end_m])
202
+
203
+
204
+ def getHalfyearDate(olddate):
205
+ y = olddate // 100000000
206
+ m = olddate // 1000000 - y * 100
207
+ return (y * 100000000 + (1010000 if m < 7 else 7010000), y * 100000000 + (6300000 if m < 7 else 12310000))
208
+
209
+
210
+ def getYearDate(olddate):
211
+ y = olddate // 100000000
212
+ return (y * 100000000 + 1010000, y * 100000000 + 12310000)
213
+
214
+
215
+ def getMin60Date(olddate):
216
+ mint = olddate - olddate // 10000 * 10000
217
+ newdate = olddate // 10000 * 10000
218
+ if mint <= 1030:
219
+ startdate = newdate + 931
220
+ enddate = newdate + 1030
221
+ elif mint <= 1130:
222
+ startdate = newdate + 1031
223
+ enddate = newdate + 1130
224
+ elif mint <= 1400:
225
+ startdate = newdate + 1301
226
+ enddate = newdate + 1400
227
+ else:
228
+ startdate = newdate + 1401
229
+ enddate = newdate + 1500
230
+ return (startdate, enddate)
231
+
232
+
233
+ def getHour2Date(olddate):
234
+ mint = olddate - olddate // 10000 * 10000
235
+ newdate = olddate // 10000 * 10000
236
+ if mint <= 1130:
237
+ startdate = newdate + 931
238
+ enddate = newdate + 1130
239
+ else:
240
+ startdate = newdate + 1301
241
+ enddate = newdate + 1500
242
+ return (startdate, enddate)
243
+
244
+
245
+ def getMin15Date(olddate):
246
+ mint = olddate - olddate // 10000 * 10000
247
+ newdate = olddate // 10000 * 10000
248
+ if mint <= 945:
249
+ startdate = newdate + 931
250
+ enddate = newdate + 945
251
+ elif mint <= 1000:
252
+ startdate = newdate + 946
253
+ enddate = newdate + 1000
254
+ elif mint <= 1015:
255
+ startdate = newdate + 1001
256
+ enddate = newdate + 1015
257
+ elif mint <= 1030:
258
+ startdate = newdate + 1016
259
+ enddate = newdate + 1030
260
+ elif mint <= 1045:
261
+ startdate = newdate + 1031
262
+ enddate = newdate + 1045
263
+ elif mint <= 1100:
264
+ startdate = newdate + 1046
265
+ enddate = newdate + 1100
266
+ elif mint <= 1115:
267
+ startdate = newdate + 1101
268
+ enddate = newdate + 1115
269
+ elif mint <= 1130:
270
+ startdate = newdate + 1116
271
+ enddate = newdate + 1130
272
+ elif mint <= 1315:
273
+ startdate = newdate + 1301
274
+ enddate = newdate + 1315
275
+ elif mint <= 1330:
276
+ startdate = newdate + 1316
277
+ enddate = newdate + 1330
278
+ elif mint <= 1345:
279
+ startdate = newdate + 1331
280
+ enddate = newdate + 1345
281
+ elif mint <= 1400:
282
+ startdate = newdate + 1346
283
+ enddate = newdate + 1400
284
+ elif mint <= 1415:
285
+ startdate = newdate + 1401
286
+ enddate = newdate + 1415
287
+ elif mint <= 1430:
288
+ startdate = newdate + 1416
289
+ enddate = newdate + 1430
290
+ elif mint <= 1445:
291
+ startdate = newdate + 1431
292
+ enddate = newdate + 1445
293
+ else:
294
+ startdate = newdate + 1446
295
+ enddate = newdate + 1500
296
+ return (startdate, enddate)
297
+
298
+
299
+ def getMin30Date(olddate):
300
+ mint = olddate - olddate // 10000 * 10000
301
+ newdate = olddate // 10000 * 10000
302
+ if mint <= 1000:
303
+ startdate = newdate + 931
304
+ enddate = newdate + 1000
305
+ elif mint <= 1030:
306
+ startdate = newdate + 1001
307
+ enddate = newdate + 1030
308
+ elif mint <= 1100:
309
+ startdate = newdate + 1031
310
+ enddate = newdate + 1100
311
+ elif mint <= 1130:
312
+ startdate = newdate + 1101
313
+ enddate = newdate + 1130
314
+ elif mint <= 1330:
315
+ startdate = newdate + 1301
316
+ enddate = newdate + 1330
317
+ elif mint <= 1400:
318
+ startdate = newdate + 1331
319
+ enddate = newdate + 1400
320
+ elif mint <= 1430:
321
+ startdate = newdate + 1401
322
+ enddate = newdate + 1430
323
+ else:
324
+ startdate = newdate + 1431
325
+ enddate = newdate + 1500
326
+ return (startdate, enddate)
327
+
328
+
329
+ def getNewDate(index_type, olddate):
330
+ if index_type == 'week':
331
+ return getWeekDate(olddate)
332
+ elif index_type == 'month':
333
+ return getMonthDate(olddate)
334
+ elif index_type == 'quarter':
335
+ return getQuarterDate(olddate)
336
+ elif index_type == 'halfyear':
337
+ return getHalfyearDate(olddate)
338
+ elif index_type == 'year':
339
+ return getYearDate(olddate)
340
+ elif index_type == 'min15':
341
+ return getMin15Date(olddate)
342
+ elif index_type == 'min30':
343
+ return getMin30Date(olddate)
344
+ elif index_type == 'min60':
345
+ return getMin60Date(olddate)
346
+ elif index_type == 'hour2':
347
+ return getHour2Date(olddate)
348
+ else:
349
+ return None
350
+
351
+
352
+ @hku_catch(ret={'week': [], 'month': [], 'quarter': [], 'halfyear': [], 'year': [], 'min15': [], 'min30': [], 'min60': [], 'hour2': []}, trace=True)
353
+ def update_extern_data(connect, market, code, data_type):
354
+ """更新周线、月线、15分钟线等扩展数据索引"""
355
+ if data_type.lower() == 'day':
356
+ index_list = ('week', 'month', 'quarter', 'halfyear', 'year')
357
+ base_table = get_table(connect, market, code, 'day')
358
+ else:
359
+ index_list = ('min15', 'min30', 'min60', 'hour2')
360
+ base_table = get_table(connect, market, code, 'min5')
361
+
362
+ index_data = {}
363
+ for index_type in index_list:
364
+ index_data[index_type] = []
365
+
366
+ base_lastdate = get_lastdatetime(connect, base_table)
367
+ if base_lastdate is None:
368
+ return index_data
369
+
370
+ for index_type in index_list:
371
+ hku_debug("{}{} update {} index".format(market, code, index_type))
372
+ index_table = get_table(connect, market, code, index_type)
373
+ index_last_date = get_lastdatetime(connect, index_table)
374
+
375
+ # 获取当前日期大于等于索引表最大日期的基础表日期列表
376
+ if index_last_date is None:
377
+ sql = f"select toUInt32(date), open, high, low, close, amount, volume from {base_table[0]} where market='{base_table[1]}' and code='{base_table[2]}' order by date asc"
378
+ else:
379
+ index_last_date = index_last_date.ymdhm
380
+ start_date, _ = getNewDate(index_type, index_last_date)
381
+ start_date = Datetime(start_date).timestamp_utc() // 1000000
382
+ sql = f"select toUInt32(date), open, high, low, close, amount, volume from {base_table[0]} where market='{base_table[1]}' and code='{base_table[2]}' and date>={start_date} order by date asc"
383
+ a = connect.query(sql, settings={'optimize_skip_merged_partitions': 1})
384
+ base_list = a.result_rows
385
+
386
+ last_start_date = 199012010000
387
+ last_end_date = 199012010000
388
+
389
+ insert_buffer = index_data[index_type]
390
+ length_base_all = len(base_list)
391
+ for x in range(length_base_all):
392
+ current_date = Datetime.from_timestamp_utc(base_list[x][0] * 1000000).ymdhm
393
+ if current_date <= last_end_date:
394
+ continue
395
+ last_start_date, last_end_date = getNewDate(index_type, current_date)
396
+
397
+ base_record_list = []
398
+ start_ix = x
399
+ ix_date = current_date
400
+ while start_ix < length_base_all and \
401
+ ix_date >= last_start_date and ix_date <= last_end_date:
402
+ base_record_list.append(base_list[start_ix])
403
+ ix_date = Datetime.from_timestamp_utc(base_list[start_ix][0]*1000000).ymdhm
404
+ start_ix += 1
405
+
406
+ if not base_record_list:
407
+ continue
408
+
409
+ length = len(base_record_list)
410
+ open_price = base_record_list[0][1]
411
+ high_price = base_record_list[0][2]
412
+ low_price = base_record_list[0][3]
413
+ close_price = base_record_list[length - 1][4]
414
+ amount = base_record_list[0][5]
415
+ count = base_record_list[0][6]
416
+ for i in range(1, length):
417
+ if base_record_list[i][2] > high_price:
418
+ high_price = base_record_list[i][2]
419
+ if base_record_list[i][3] < low_price:
420
+ low_price = base_record_list[i][3]
421
+ amount += base_record_list[i][5]
422
+ count += base_record_list[i][6]
423
+
424
+ last_timestamp = Datetime(last_end_date).timestamp_utc()//1000000
425
+ if last_end_date != index_last_date:
426
+ insert_buffer.append((index_table[1], index_table[2], last_timestamp, open_price,
427
+ high_price, low_price, close_price, amount, count))
428
+
429
+ if len(insert_buffer) > 200000:
430
+ hku_info(f"写入 {market} {index_table[0]} 扩展数据: {len(insert_buffer)} ...")
431
+ ic = connect.create_insert_context(table=index_table[0],
432
+ data=insert_buffer)
433
+ connect.insert(context=ic, settings={"prefer_warmed_unmerged_parts_seconds": 86400})
434
+ insert_buffer.clear()
435
+ return index_data
436
+
437
+
438
+ if __name__ == '__main__':
439
+ from configparser import ConfigParser
440
+ dev_config = ConfigParser()
441
+ dev_config.read(os.path.expanduser("~") + '/workspace/dev.ini')
442
+ # dev_config.read('d:/workspace/dev.ini')
443
+ db = 'clickhouse54-http'
444
+ user = dev_config.get(db, 'user')
445
+ password = dev_config.get(db, 'pwd')
446
+ host = dev_config.get(db, 'host')
447
+ port = dev_config.getint(db, 'port')
448
+
449
+ import clickhouse_connect
450
+ client = clickhouse_connect.get_client(
451
+ host=host, username=user, password=password)
452
+
453
+ print(is_exist_db(client))
454
+ create_database(client)
455
+ print(is_exist_db(client))
456
+
457
+ # x = get_codepre_list(client, 'SH', ['stock', 'fund'])
458
+ # print(x)
459
+
460
+ # import_new_holidays(client)
461
+ x = get_last_krecord(client, ('hku_data.min_k', 'SH', '000001'))
462
+ print(x)
463
+
464
+ update_extern_data(client, 'BJ', '430017', 'DAY')
465
+ client.close()
@@ -0,0 +1,120 @@
1
+ #!/usr/bin/python
2
+ # -*- coding: utf8 -*-
3
+ #
4
+ # Create on: 20240102
5
+ # Author: fasiondog
6
+
7
+ from concurrent.futures import ThreadPoolExecutor
8
+ from hikyuu.data.common import MARKET, get_stk_code_name_list
9
+ from hikyuu.util import *
10
+ from hikyuu.fetcher.stock.zh_block_em import *
11
+
12
+
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('指数板块')
70
+
71
+ if not blks:
72
+ return
73
+
74
+ 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)}"
79
+ connect.command(sql)
80
+
81
+ insert_records = []
82
+
83
+ for category in all_block_info:
84
+ for name in all_block_info[category]:
85
+ for code in all_block_info[category][name]:
86
+ insert_records.append((category, name, code))
87
+
88
+ if insert_records:
89
+ ic = connect.create_insert_context(table='block', database='hku_base',
90
+ column_names=['category', 'name', 'market_code'],
91
+ data=insert_records)
92
+ connect.insert(context=ic)
93
+
94
+ return len(insert_records)
95
+
96
+
97
+ if __name__ == "__main__":
98
+ import os
99
+ from configparser import ConfigParser
100
+ dev_config = ConfigParser()
101
+ dev_config.read(os.path.expanduser("~") + '/workspace/dev.ini')
102
+ db = 'clickhouse54-http'
103
+ user = dev_config.get(db, 'user')
104
+ password = dev_config.get(db, 'pwd')
105
+ host = dev_config.get(db, 'host')
106
+ port = dev_config.getint(db, 'port')
107
+
108
+ import clickhouse_connect
109
+ client = clickhouse_connect.get_client(
110
+ host=host, username=user, password=password)
111
+
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=('行业板块', ))
119
+
120
+ client.close()
@@ -145,6 +145,60 @@ pwd = {pwd}
145
145
 
146
146
  """
147
147
 
148
+ clickhouse_template = """
149
+ [hikyuu]
150
+ tmpdir = {dir}
151
+ datadir = {dir}
152
+ quotation_server = {quotation_server}
153
+
154
+ [block]
155
+ type = clickhouse
156
+ host = {host}
157
+ port = {port}
158
+ usr = {usr}
159
+ pwd = {pwd}
160
+
161
+ [preload]
162
+ day = {day}
163
+ week = {week}
164
+ month = {month}
165
+ quarter = {quarter}
166
+ halfyear = {halfyear}
167
+ year = {year}
168
+ min = {min1}
169
+ min5 = {min5}
170
+ min15 = {min15}
171
+ min30 = {min30}
172
+ min60 = {min60}
173
+ hour2 = {hour2}
174
+ day_max = {day_max}
175
+ week_max = {week_max}
176
+ month_max = {month_max}
177
+ quarter_max = {quarter_max}
178
+ halfyear_max = {halfyear_max}
179
+ year_max = {year_max}
180
+ min_max = {min1_max}
181
+ min5_max = {min5_max}
182
+ min15_max = {min15_max}
183
+ min30_max = {min30_max}
184
+ min60_max = {min60_max}
185
+ hour2_max = {hour2_max}
186
+
187
+ [baseinfo]
188
+ type = clickhouse
189
+ host = {host}
190
+ port = {port}
191
+ usr = {usr}
192
+ pwd = {pwd}
193
+
194
+ [kdata]
195
+ type = clickhouse
196
+ host = {host}
197
+ port = {port}
198
+ usr = {usr}
199
+ pwd = {pwd}
200
+ """
201
+
148
202
 
149
203
  import_config_template = """
150
204
  [quotation]
@@ -187,17 +241,18 @@ dir = {dir}
187
241
 
188
242
  [mysql]
189
243
  enable = False
190
- ;tmpdir = D:/stock
244
+ ;tmpdir = D:/stock/
191
245
  ;host = 127.0.0.1
192
246
  ;port = 3306
193
247
  ;usr = root
194
248
  ;pwd =
195
249
 
196
- [taos]
250
+ [clickhouse]
197
251
  enable = False
198
252
  ;tmpdir = D:/stock
199
253
  ;host = 127.0.0.1
200
- ;port = 6030
254
+ :http_port = 8123
255
+ ;port = 9000
201
256
  ;usr = root
202
257
  ;pwd =
203
258