hikyuu 2.6.5__py3-none-win_amd64.whl → 2.6.6__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 (108) hide show
  1. hikyuu/__init__.py +6 -0
  2. hikyuu/__init__.pyi +548 -545
  3. hikyuu/analysis/__init__.pyi +519 -518
  4. hikyuu/analysis/analysis.pyi +520 -519
  5. hikyuu/core.pyi +521 -520
  6. hikyuu/cpp/__init__.pyi +2 -2
  7. hikyuu/cpp/boost_date_time-mt.dll +0 -0
  8. hikyuu/cpp/boost_serialization-mt.dll +0 -0
  9. hikyuu/cpp/boost_wserialization-mt.dll +0 -0
  10. hikyuu/cpp/core310.pyd +0 -0
  11. hikyuu/cpp/core310.pyi +35 -25
  12. hikyuu/cpp/core311.pyd +0 -0
  13. hikyuu/cpp/core311.pyi +35 -25
  14. hikyuu/cpp/core312.pyd +0 -0
  15. hikyuu/cpp/core312.pyi +35 -25
  16. hikyuu/cpp/core313.pyd +0 -0
  17. hikyuu/cpp/core313.pyi +35 -25
  18. hikyuu/cpp/core39.pyd +0 -0
  19. hikyuu/cpp/core39.pyi +35 -25
  20. hikyuu/cpp/hikyuu.dll +0 -0
  21. hikyuu/cpp/hikyuu.lib +0 -0
  22. hikyuu/cpp/i18n/__init__.py +0 -0
  23. hikyuu/cpp/i18n/zh_CN.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 +512 -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/zh_bond10_to_clickhouse.py +49 -0
  36. hikyuu/draw/drawplot/__init__.pyi +9 -9
  37. hikyuu/draw/drawplot/bokeh_draw.pyi +537 -534
  38. hikyuu/draw/drawplot/common.pyi +1 -1
  39. hikyuu/draw/drawplot/echarts_draw.pyi +539 -536
  40. hikyuu/draw/drawplot/matplotlib_draw.pyi +549 -546
  41. hikyuu/draw/elder.pyi +11 -11
  42. hikyuu/draw/kaufman.pyi +18 -18
  43. hikyuu/draw/volume.pyi +10 -10
  44. hikyuu/extend.pyi +527 -526
  45. hikyuu/fetcher/stock/zh_stock_a_pytdx.py +9 -20
  46. hikyuu/fetcher/stock/zh_stock_a_qmt.py +4 -5
  47. hikyuu/fetcher/stock/zh_stock_a_sina_qq.py +16 -60
  48. hikyuu/flat/Spot.py +96 -200
  49. hikyuu/gui/HikyuuTDX.py +132 -3
  50. hikyuu/gui/data/ImportBlockInfoTask.py +11 -0
  51. hikyuu/gui/data/ImportHistoryFinanceTask.py +15 -1
  52. hikyuu/gui/data/ImportPytdxTimeToH5Task.py +11 -1
  53. hikyuu/gui/data/ImportPytdxToH5Task.py +13 -1
  54. hikyuu/gui/data/ImportPytdxTransToH5Task.py +11 -1
  55. hikyuu/gui/data/ImportTdxToH5Task.py +13 -1
  56. hikyuu/gui/data/ImportWeightToSqliteTask.py +14 -1
  57. hikyuu/gui/data/ImportZhBond10Task.py +11 -0
  58. hikyuu/gui/data/MainWindow.py +76 -12
  59. hikyuu/gui/data/UsePytdxImportToH5Thread.py +45 -26
  60. hikyuu/gui/data/UseTdxImportToH5Thread.py +19 -1
  61. hikyuu/gui/dataserver.py +12 -4
  62. hikyuu/gui/spot_server.py +30 -40
  63. hikyuu/gui/start_qmt.py +20 -3
  64. hikyuu/hub.pyi +6 -6
  65. hikyuu/include/hikyuu/DataType.h +11 -0
  66. hikyuu/include/hikyuu/StockManager.h +8 -0
  67. hikyuu/include/hikyuu/data_driver/kdata/mysql/KRecordTable.h +1 -0
  68. hikyuu/include/hikyuu/global/GlobalSpotAgent.h +1 -1
  69. hikyuu/include/hikyuu/global/SpotRecord.h +15 -31
  70. hikyuu/include/hikyuu/global/agent/spot_generated.h +48 -232
  71. hikyuu/include/hikyuu/global/schedule/scheduler.h +1 -1
  72. hikyuu/include/hikyuu/plugin/KDataToHdf5Importer.h +3 -0
  73. hikyuu/include/hikyuu/plugin/dataserver.h +26 -1
  74. hikyuu/include/hikyuu/plugin/device.h +2 -1
  75. hikyuu/include/hikyuu/plugin/interface/DataDriverPluginInterface.h +27 -0
  76. hikyuu/include/hikyuu/plugin/interface/DataServerPluginInterface.h +2 -1
  77. hikyuu/include/hikyuu/plugin/interface/DevicePluginInterface.h +1 -1
  78. hikyuu/include/hikyuu/plugin/interface/ImportKDataToHdf5PluginInterface.h +3 -0
  79. hikyuu/include/hikyuu/plugin/interface/plugins.h +2 -0
  80. hikyuu/include/hikyuu/strategy/Strategy.h +0 -9
  81. hikyuu/include/hikyuu/utilities/config.h +1 -1
  82. hikyuu/include/hikyuu/utilities/mo/mo.h +30 -14
  83. hikyuu/include/hikyuu/utilities/os.h +6 -0
  84. hikyuu/include/hikyuu/version.h +4 -4
  85. hikyuu/plugin/backtest.dll +0 -0
  86. hikyuu/plugin/clickhousedriver.dll +0 -0
  87. hikyuu/plugin/dataserver.dll +0 -0
  88. hikyuu/plugin/device.dll +0 -0
  89. hikyuu/plugin/extind.dll +0 -0
  90. hikyuu/plugin/import2hdf5.dll +0 -0
  91. hikyuu/plugin/tmreport.dll +0 -0
  92. hikyuu/trade_manage/__init__.pyi +537 -534
  93. hikyuu/trade_manage/broker.pyi +3 -3
  94. hikyuu/trade_manage/broker_easytrader.pyi +1 -1
  95. hikyuu/trade_manage/trade.pyi +537 -534
  96. hikyuu/util/__init__.py +1 -0
  97. hikyuu/util/__init__.pyi +4 -3
  98. hikyuu/util/check.py +8 -0
  99. hikyuu/util/check.pyi +5 -1
  100. hikyuu/util/singleton.pyi +1 -1
  101. {hikyuu-2.6.5.dist-info → hikyuu-2.6.6.dist-info}/METADATA +2 -2
  102. {hikyuu-2.6.5.dist-info → hikyuu-2.6.6.dist-info}/RECORD +106 -95
  103. {hikyuu-2.6.5.dist-info → hikyuu-2.6.6.dist-info}/top_level.txt +2 -2
  104. hikyuu/include/hikyuu/global/agent/hikyuu/__init__.py +0 -1
  105. hikyuu/include/hikyuu/global/agent/hikyuu/flat/__init__.py +0 -1
  106. {hikyuu-2.6.5.dist-info → hikyuu-2.6.6.dist-info}/LICENSE +0 -0
  107. {hikyuu-2.6.5.dist-info → hikyuu-2.6.6.dist-info}/WHEEL +0 -0
  108. {hikyuu-2.6.5.dist-info → hikyuu-2.6.6.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,512 @@
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
+ connect.command(f"create database if not exists hku_data")
140
+ if nktype == 'timeline':
141
+ sql = f"""
142
+ CREATE table if not exists hku_data.timeline (
143
+ `market` String,
144
+ `code` String,
145
+ `date` DateTime,
146
+ `price` DOUBLE,
147
+ `vol` DOUBLE
148
+ )
149
+ ENGINE = MergeTree()
150
+ PRIMARY KEY (market, code, date);
151
+ """
152
+ # print(sql)
153
+ connect.command(sql)
154
+ return (f'hku_data.timeline', market.upper(), code.upper())
155
+
156
+ elif nktype == 'transdata':
157
+ sql = f"""
158
+ CREATE table if not exists hku_data.transdata (
159
+ `market` String,
160
+ `code` String,
161
+ `date` DateTime,
162
+ `price` DOUBLE,
163
+ `vol` DOUBLE,
164
+ `buyorsell` int
165
+ )
166
+ ENGINE = MergeTree()
167
+ PRIMARY KEY (market, code, date);
168
+ """
169
+ # print(sql)
170
+ connect.command(sql)
171
+ return (f'hku_data.transdata', market.upper(), code.upper())
172
+
173
+ else:
174
+ sql = f"""
175
+ CREATE table if not exists hku_data.{nktype}_k (
176
+ `market` String,
177
+ `code` String,
178
+ `date` DateTime,
179
+ `open` DOUBLE,
180
+ `high` DOUBLE,
181
+ `low` DOUBLE,
182
+ `close` DOUBLE,
183
+ `amount` DOUBLE,
184
+ `volume` DOUBLE
185
+ )
186
+ ENGINE = MergeTree()
187
+ PRIMARY KEY (market, code, date);
188
+ """
189
+ # print(sql)
190
+ connect.command(sql)
191
+ return (f'hku_data.{nktype}_k', market.upper(), code.upper())
192
+
193
+
194
+ @hku_catch(ret=Datetime(1970, 1, 1))
195
+ def get_lastdatetime(connect, tablename):
196
+ tmp = connect.command("select max(date) from {} where market='{}' and code='{}'".format(
197
+ tablename[0], tablename[1], tablename[2]))
198
+ tmp = Datetime(tmp)
199
+ return None if tmp == Datetime(1970, 1, 1) else tmp + UTCOffset()
200
+
201
+
202
+ def get_last_krecord(connect, tablename):
203
+ """获取最后一条K线记录
204
+ 返回:(date, open, close, high, low, amount, volume)
205
+ """
206
+ try:
207
+ a = connect.query(
208
+ "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})
209
+ a = a.result_rows
210
+ # hku_info(f"{tablename} {a}")
211
+ if not a:
212
+ return None
213
+ 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])
214
+ except:
215
+ return None
216
+
217
+
218
+ def getWeekDate(olddate):
219
+ y = olddate // 100000000
220
+ m = olddate // 1000000 - y * 100
221
+ d = olddate // 10000 - (y * 10000 + m * 100)
222
+ tempdate = datetime.date(y, m, d)
223
+ # python中周一是第0天,周五的第4天
224
+ startdate = tempdate + datetime.timedelta(0 - tempdate.weekday())
225
+ enddate = tempdate + datetime.timedelta(4 - tempdate.weekday())
226
+ return (
227
+ startdate.year * 100000000 + startdate.month * 1000000 + startdate.day * 10000,
228
+ enddate.year * 100000000 + enddate.month * 1000000 + enddate.day * 10000
229
+ )
230
+
231
+
232
+ def getMonthDate(olddate):
233
+ y = olddate // 100000000
234
+ m = olddate // 1000000 - y * 100
235
+ import calendar
236
+ _, d = calendar.monthrange(y, m)
237
+ return (y * 100000000 + m * 1000000 + 10000, y * 100000000 + m * 1000000 + d * 10000)
238
+
239
+
240
+ def getQuarterDate(olddate):
241
+ 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}
242
+ 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}
243
+ d_dict = {3: 310000, 6: 300000, 9: 300000, 12: 310000}
244
+ y = olddate // 100000000
245
+ m = olddate // 1000000 - y * 100
246
+ start_m = startDict[m]
247
+ end_m = endDict[m]
248
+ return (y * 100000000 + start_m * 1000000 + 10000, y * 100000000 + end_m * 1000000 + d_dict[end_m])
249
+
250
+
251
+ def getHalfyearDate(olddate):
252
+ y = olddate // 100000000
253
+ m = olddate // 1000000 - y * 100
254
+ return (y * 100000000 + (1010000 if m < 7 else 7010000), y * 100000000 + (6300000 if m < 7 else 12310000))
255
+
256
+
257
+ def getYearDate(olddate):
258
+ y = olddate // 100000000
259
+ return (y * 100000000 + 1010000, y * 100000000 + 12310000)
260
+
261
+
262
+ def getMin60Date(olddate):
263
+ mint = olddate - olddate // 10000 * 10000
264
+ newdate = olddate // 10000 * 10000
265
+ if mint <= 1030:
266
+ startdate = newdate + 931
267
+ enddate = newdate + 1030
268
+ elif mint <= 1130:
269
+ startdate = newdate + 1031
270
+ enddate = newdate + 1130
271
+ elif mint <= 1400:
272
+ startdate = newdate + 1301
273
+ enddate = newdate + 1400
274
+ else:
275
+ startdate = newdate + 1401
276
+ enddate = newdate + 1500
277
+ return (startdate, enddate)
278
+
279
+
280
+ def getHour2Date(olddate):
281
+ mint = olddate - olddate // 10000 * 10000
282
+ newdate = olddate // 10000 * 10000
283
+ if mint <= 1130:
284
+ startdate = newdate + 931
285
+ enddate = newdate + 1130
286
+ else:
287
+ startdate = newdate + 1301
288
+ enddate = newdate + 1500
289
+ return (startdate, enddate)
290
+
291
+
292
+ def getMin15Date(olddate):
293
+ mint = olddate - olddate // 10000 * 10000
294
+ newdate = olddate // 10000 * 10000
295
+ if mint <= 945:
296
+ startdate = newdate + 931
297
+ enddate = newdate + 945
298
+ elif mint <= 1000:
299
+ startdate = newdate + 946
300
+ enddate = newdate + 1000
301
+ elif mint <= 1015:
302
+ startdate = newdate + 1001
303
+ enddate = newdate + 1015
304
+ elif mint <= 1030:
305
+ startdate = newdate + 1016
306
+ enddate = newdate + 1030
307
+ elif mint <= 1045:
308
+ startdate = newdate + 1031
309
+ enddate = newdate + 1045
310
+ elif mint <= 1100:
311
+ startdate = newdate + 1046
312
+ enddate = newdate + 1100
313
+ elif mint <= 1115:
314
+ startdate = newdate + 1101
315
+ enddate = newdate + 1115
316
+ elif mint <= 1130:
317
+ startdate = newdate + 1116
318
+ enddate = newdate + 1130
319
+ elif mint <= 1315:
320
+ startdate = newdate + 1301
321
+ enddate = newdate + 1315
322
+ elif mint <= 1330:
323
+ startdate = newdate + 1316
324
+ enddate = newdate + 1330
325
+ elif mint <= 1345:
326
+ startdate = newdate + 1331
327
+ enddate = newdate + 1345
328
+ elif mint <= 1400:
329
+ startdate = newdate + 1346
330
+ enddate = newdate + 1400
331
+ elif mint <= 1415:
332
+ startdate = newdate + 1401
333
+ enddate = newdate + 1415
334
+ elif mint <= 1430:
335
+ startdate = newdate + 1416
336
+ enddate = newdate + 1430
337
+ elif mint <= 1445:
338
+ startdate = newdate + 1431
339
+ enddate = newdate + 1445
340
+ else:
341
+ startdate = newdate + 1446
342
+ enddate = newdate + 1500
343
+ return (startdate, enddate)
344
+
345
+
346
+ def getMin30Date(olddate):
347
+ mint = olddate - olddate // 10000 * 10000
348
+ newdate = olddate // 10000 * 10000
349
+ if mint <= 1000:
350
+ startdate = newdate + 931
351
+ enddate = newdate + 1000
352
+ elif mint <= 1030:
353
+ startdate = newdate + 1001
354
+ enddate = newdate + 1030
355
+ elif mint <= 1100:
356
+ startdate = newdate + 1031
357
+ enddate = newdate + 1100
358
+ elif mint <= 1130:
359
+ startdate = newdate + 1101
360
+ enddate = newdate + 1130
361
+ elif mint <= 1330:
362
+ startdate = newdate + 1301
363
+ enddate = newdate + 1330
364
+ elif mint <= 1400:
365
+ startdate = newdate + 1331
366
+ enddate = newdate + 1400
367
+ elif mint <= 1430:
368
+ startdate = newdate + 1401
369
+ enddate = newdate + 1430
370
+ else:
371
+ startdate = newdate + 1431
372
+ enddate = newdate + 1500
373
+ return (startdate, enddate)
374
+
375
+
376
+ def getNewDate(index_type, olddate):
377
+ if index_type == 'week':
378
+ return getWeekDate(olddate)
379
+ elif index_type == 'month':
380
+ return getMonthDate(olddate)
381
+ elif index_type == 'quarter':
382
+ return getQuarterDate(olddate)
383
+ elif index_type == 'halfyear':
384
+ return getHalfyearDate(olddate)
385
+ elif index_type == 'year':
386
+ return getYearDate(olddate)
387
+ elif index_type == 'min15':
388
+ return getMin15Date(olddate)
389
+ elif index_type == 'min30':
390
+ return getMin30Date(olddate)
391
+ elif index_type == 'min60':
392
+ return getMin60Date(olddate)
393
+ elif index_type == 'hour2':
394
+ return getHour2Date(olddate)
395
+ else:
396
+ return None
397
+
398
+
399
+ @hku_catch(ret={'week': [], 'month': [], 'quarter': [], 'halfyear': [], 'year': [], 'min15': [], 'min30': [], 'min60': [], 'hour2': []}, trace=True)
400
+ def update_extern_data(connect, market, code, data_type):
401
+ """更新周线、月线、15分钟线等扩展数据索引"""
402
+ if data_type.lower() == 'day':
403
+ index_list = ('week', 'month', 'quarter', 'halfyear', 'year')
404
+ base_table = get_table(connect, market, code, 'day')
405
+ else:
406
+ index_list = ('min15', 'min30', 'min60', 'hour2')
407
+ base_table = get_table(connect, market, code, 'min5')
408
+
409
+ index_data = {}
410
+ for index_type in index_list:
411
+ index_data[index_type] = []
412
+
413
+ base_lastdate = get_lastdatetime(connect, base_table)
414
+ if base_lastdate is None:
415
+ return index_data
416
+
417
+ for index_type in index_list:
418
+ hku_debug("{}{} update {} index".format(market, code, index_type))
419
+ index_table = get_table(connect, market, code, index_type)
420
+ index_last_date = get_lastdatetime(connect, index_table)
421
+
422
+ # 获取当前日期大于等于索引表最大日期的基础表日期列表
423
+ if index_last_date is None:
424
+ 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"
425
+ else:
426
+ index_last_date = index_last_date.ymdhm
427
+ start_date, _ = getNewDate(index_type, index_last_date)
428
+ start_date = Datetime(start_date).timestamp_utc() // 1000000
429
+ 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"
430
+ a = connect.query(sql, settings={'optimize_skip_merged_partitions': 1})
431
+ base_list = a.result_rows
432
+
433
+ last_start_date = 199012010000
434
+ last_end_date = 199012010000
435
+
436
+ insert_buffer = index_data[index_type]
437
+ length_base_all = len(base_list)
438
+ for x in range(length_base_all):
439
+ current_date = Datetime.from_timestamp_utc(base_list[x][0] * 1000000).ymdhm
440
+ if current_date <= last_end_date:
441
+ continue
442
+ last_start_date, last_end_date = getNewDate(index_type, current_date)
443
+
444
+ base_record_list = []
445
+ start_ix = x
446
+ ix_date = current_date
447
+ while start_ix < length_base_all and \
448
+ ix_date >= last_start_date and ix_date <= last_end_date:
449
+ base_record_list.append(base_list[start_ix])
450
+ ix_date = Datetime.from_timestamp_utc(base_list[start_ix][0]*1000000).ymdhm
451
+ start_ix += 1
452
+
453
+ if not base_record_list:
454
+ continue
455
+
456
+ length = len(base_record_list)
457
+ open_price = base_record_list[0][1]
458
+ high_price = base_record_list[0][2]
459
+ low_price = base_record_list[0][3]
460
+ close_price = base_record_list[length - 1][4]
461
+ amount = base_record_list[0][5]
462
+ count = base_record_list[0][6]
463
+ for i in range(1, length):
464
+ if base_record_list[i][2] > high_price:
465
+ high_price = base_record_list[i][2]
466
+ if base_record_list[i][3] < low_price:
467
+ low_price = base_record_list[i][3]
468
+ amount += base_record_list[i][5]
469
+ count += base_record_list[i][6]
470
+
471
+ last_timestamp = Datetime(last_end_date).timestamp_utc()//1000000
472
+ if last_end_date != index_last_date:
473
+ insert_buffer.append((index_table[1], index_table[2], last_timestamp, open_price,
474
+ high_price, low_price, close_price, amount, count))
475
+
476
+ if len(insert_buffer) > 200000:
477
+ hku_info(f"写入 {market} {index_table[0]} 扩展数据: {len(insert_buffer)} ...")
478
+ ic = connect.create_insert_context(table=index_table[0],
479
+ data=insert_buffer)
480
+ connect.insert(context=ic, settings={"prefer_warmed_unmerged_parts_seconds": 86400})
481
+ insert_buffer.clear()
482
+ return index_data
483
+
484
+
485
+ if __name__ == '__main__':
486
+ from configparser import ConfigParser
487
+ dev_config = ConfigParser()
488
+ dev_config.read(os.path.expanduser("~") + '/workspace/dev.ini')
489
+ # dev_config.read('d:/workspace/dev.ini')
490
+ db = 'clickhouse54-http'
491
+ user = dev_config.get(db, 'user')
492
+ password = dev_config.get(db, 'pwd')
493
+ host = dev_config.get(db, 'host')
494
+ port = dev_config.getint(db, 'port')
495
+
496
+ import clickhouse_connect
497
+ client = clickhouse_connect.get_client(
498
+ host=host, username=user, password=password)
499
+
500
+ print(is_exist_db(client))
501
+ create_database(client)
502
+ print(is_exist_db(client))
503
+
504
+ # x = get_codepre_list(client, 'SH', ['stock', 'fund'])
505
+ # print(x)
506
+
507
+ # import_new_holidays(client)
508
+ x = get_last_krecord(client, ('hku_data.min_k', 'SH', '000001'))
509
+ print(x)
510
+
511
+ update_extern_data(client, 'BJ', '430017', 'DAY')
512
+ 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()