hikyuu 2.5.6__py3-none-win_amd64.whl → 2.6.1__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 (118) hide show
  1. hikyuu/__init__.py +33 -49
  2. hikyuu/__init__.pyi +530 -516
  3. hikyuu/analysis/__init__.pyi +498 -490
  4. hikyuu/analysis/analysis.pyi +499 -491
  5. hikyuu/core.pyi +500 -492
  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 +187 -22
  12. hikyuu/cpp/core311.pyd +0 -0
  13. hikyuu/cpp/core311.pyi +187 -22
  14. hikyuu/cpp/core312.pyd +0 -0
  15. hikyuu/cpp/core312.pyi +187 -22
  16. hikyuu/cpp/core313.pyd +0 -0
  17. hikyuu/cpp/core313.pyi +186 -22
  18. hikyuu/cpp/core39.pyd +0 -0
  19. hikyuu/cpp/core39.pyi +187 -22
  20. hikyuu/cpp/hikyuu.dll +0 -0
  21. hikyuu/cpp/hikyuu.lib +0 -0
  22. hikyuu/draw/__init__.pyi +1 -1
  23. hikyuu/draw/drawplot/__init__.py +2 -0
  24. hikyuu/draw/drawplot/__init__.pyi +9 -8
  25. hikyuu/draw/drawplot/bokeh_draw.pyi +519 -506
  26. hikyuu/draw/drawplot/common.pyi +1 -1
  27. hikyuu/draw/drawplot/echarts_draw.pyi +521 -508
  28. hikyuu/draw/drawplot/matplotlib_draw.py +80 -0
  29. hikyuu/draw/drawplot/matplotlib_draw.pyi +540 -517
  30. hikyuu/draw/elder.pyi +11 -11
  31. hikyuu/draw/kaufman.pyi +18 -18
  32. hikyuu/draw/volume.pyi +10 -10
  33. hikyuu/examples/notebook/002-HowToGetStock.ipynb +1 -1
  34. hikyuu/examples/notebook/004-IndicatorOverview.ipynb +117 -52
  35. hikyuu/extend.pyi +507 -500
  36. hikyuu/gui/HikyuuTDX.py +85 -15
  37. hikyuu/gui/data/ImportQmtToH5Task.py +209 -0
  38. hikyuu/gui/data/ImportTdxToH5Task.py +8 -1
  39. hikyuu/gui/data/MainWindow.py +94 -13
  40. hikyuu/gui/data/UseQmtImportToH5Thread.py +316 -0
  41. hikyuu/gui/data/UseTdxImportToH5Thread.py +221 -65
  42. hikyuu/gui/dataserver.py +25 -0
  43. hikyuu/gui/images/star.png +0 -0
  44. hikyuu/gui/importdata.py +24 -11
  45. hikyuu/hub.pyi +6 -6
  46. hikyuu/include/hikyuu/KData.h +5 -0
  47. hikyuu/include/hikyuu/KDataImp.h +4 -0
  48. hikyuu/include/hikyuu/StockManager.h +23 -0
  49. hikyuu/include/hikyuu/data_driver/kdata/mysql/KRecordTable.h +41 -2
  50. hikyuu/include/hikyuu/global/agent/spot_generated.h +3 -3
  51. hikyuu/include/hikyuu/indicator/crt/COUNT.h +3 -3
  52. hikyuu/include/hikyuu/indicator/crt/DISCARD.h +1 -1
  53. hikyuu/include/hikyuu/indicator/crt/ISINF.h +1 -1
  54. hikyuu/include/hikyuu/indicator/crt/ISINFA.h +1 -1
  55. hikyuu/include/hikyuu/indicator/crt/ISNA.h +1 -1
  56. hikyuu/include/hikyuu/indicator/crt/LAST.h +2 -2
  57. hikyuu/include/hikyuu/indicator/crt/MAX.h +1 -1
  58. hikyuu/include/hikyuu/indicator/crt/MIN.h +1 -1
  59. hikyuu/include/hikyuu/indicator/crt/PRICELIST.h +1 -15
  60. hikyuu/include/hikyuu/indicator/crt/SUMBARS.h +1 -1
  61. hikyuu/include/hikyuu/plugin/KDataToHdf5Importer.h +33 -0
  62. hikyuu/include/hikyuu/plugin/__init__.py +1 -0
  63. hikyuu/include/hikyuu/plugin/backtest.h +37 -0
  64. hikyuu/include/hikyuu/plugin/dataserver.h +18 -0
  65. hikyuu/include/hikyuu/plugin/device.h +29 -0
  66. hikyuu/include/hikyuu/plugin/interface/BackTestPluginInterface.h +26 -0
  67. hikyuu/include/hikyuu/plugin/interface/DataServerPluginInterface.h +23 -0
  68. hikyuu/include/hikyuu/plugin/interface/DevicePluginInterface.h +25 -0
  69. hikyuu/include/hikyuu/plugin/interface/ImportKDataToHdf5PluginInterface.h +33 -0
  70. hikyuu/include/hikyuu/plugin/interface/__init__.py +1 -0
  71. hikyuu/include/hikyuu/plugin/interface/plugins.h +22 -0
  72. hikyuu/include/hikyuu/python/pybind_utils.h +8 -0
  73. hikyuu/include/hikyuu/strategy/BrokerTradeManager.h +2 -1
  74. hikyuu/include/hikyuu/strategy/RunPortfolioInStrategy.h +1 -0
  75. hikyuu/include/hikyuu/strategy/Strategy.h +93 -16
  76. hikyuu/include/hikyuu/trade_manage/TradeManagerBase.h +4 -2
  77. hikyuu/include/hikyuu/trade_sys/portfolio/Portfolio.h +2 -1
  78. hikyuu/include/hikyuu/trade_sys/selector/SelectorBase.h +12 -9
  79. hikyuu/include/hikyuu/trade_sys/selector/imp/MultiFactorSelector.h +1 -1
  80. hikyuu/include/hikyuu/trade_sys/selector/imp/logic/OperatorSelector.h +12 -12
  81. hikyuu/include/hikyuu/trade_sys/selector/imp/logic/OperatorValueSelector.h +2 -2
  82. hikyuu/include/hikyuu/trade_sys/selector/imp/optimal/PerformanceOptimalSelector.h +1 -1
  83. hikyuu/include/hikyuu/trade_sys/system/System.h +12 -3
  84. hikyuu/include/hikyuu/trade_sys/system/imp/DelegateSystem.h +0 -1
  85. hikyuu/include/hikyuu/trade_sys/system/imp/WalkForwardSystem.h +0 -1
  86. hikyuu/include/hikyuu/trade_sys/system/imp/WalkForwardTradeManager.h +3 -2
  87. hikyuu/include/hikyuu/utilities/arithmetic.h +32 -22
  88. hikyuu/include/hikyuu/utilities/datetime/Datetime.h +1 -0
  89. hikyuu/include/hikyuu/utilities/plugin/PluginClient.h +2 -2
  90. hikyuu/include/hikyuu/utilities/plugin/PluginLoader.h +66 -13
  91. hikyuu/include/hikyuu/utilities/plugin/PluginManager.h +72 -0
  92. hikyuu/include/hikyuu/version.h +5 -5
  93. hikyuu/plugin/__init__.py +1 -0
  94. hikyuu/plugin/backtest.dll +0 -0
  95. hikyuu/plugin/dataserver.dll +0 -0
  96. hikyuu/plugin/device.dll +0 -0
  97. hikyuu/plugin/import2hdf5.dll +0 -0
  98. hikyuu/strategy/strategy_demo1.py +7 -8
  99. hikyuu/strategy/strategy_demo2.py +1 -1
  100. hikyuu/trade_manage/__init__.pyi +518 -505
  101. hikyuu/trade_manage/broker.pyi +3 -3
  102. hikyuu/trade_manage/broker_easytrader.pyi +1 -1
  103. hikyuu/trade_manage/trade.pyi +518 -505
  104. hikyuu/util/__init__.py +1 -0
  105. hikyuu/util/__init__.pyi +2 -1
  106. hikyuu/util/mylog.py +30 -3
  107. hikyuu/util/mylog.pyi +3 -1
  108. hikyuu/util/singleton.pyi +1 -1
  109. {hikyuu-2.5.6.dist-info → hikyuu-2.6.1.dist-info}/METADATA +6 -2
  110. {hikyuu-2.5.6.dist-info → hikyuu-2.6.1.dist-info}/RECORD +115 -97
  111. {hikyuu-2.5.6.dist-info → hikyuu-2.6.1.dist-info}/entry_points.txt +1 -0
  112. {hikyuu-2.5.6.dist-info → hikyuu-2.6.1.dist-info}/top_level.txt +4 -0
  113. hikyuu/cpp/core38.pyd +0 -0
  114. hikyuu/cpp/core38.pyi +0 -13173
  115. hikyuu/examples/notebook/011-PyechartsDrawplot.ipynb +0 -21821
  116. /hikyuu/gui/{hikyuu_small.png → images/hikyuu_small.png} +0 -0
  117. {hikyuu-2.5.6.dist-info → hikyuu-2.6.1.dist-info}/LICENSE +0 -0
  118. {hikyuu-2.5.6.dist-info → hikyuu-2.6.1.dist-info}/WHEEL +0 -0
hikyuu/gui/HikyuuTDX.py CHANGED
@@ -16,7 +16,7 @@ import PyQt5
16
16
 
17
17
  from PyQt5.QtWidgets import QApplication, QMainWindow, QFileDialog, QMessageBox
18
18
  from PyQt5.QtCore import pyqtSlot, QObject, pyqtSignal
19
- from PyQt5.QtGui import QIcon, QTextCursor, QFont, QPalette
19
+ from PyQt5.QtGui import QIcon, QTextCursor, QFont, QPalette, QPixmap
20
20
 
21
21
  import mysql.connector
22
22
  from mysql.connector import errorcode
@@ -27,13 +27,14 @@ from hikyuu.gui.data.EscapetimeThread import EscapetimeThread
27
27
  from hikyuu.gui.data.UseTdxImportToH5Thread import UseTdxImportToH5Thread
28
28
  from hikyuu.gui.data.ImportTdxToH5Task import ImportTdxToH5Task
29
29
  from hikyuu.gui.data.UsePytdxImportToH5Thread import UsePytdxImportToH5Thread
30
+ from hikyuu.gui.data.UseQmtImportToH5Thread import UseQmtImportToH5Thread
30
31
  # from hikyuu.gui.data.CollectToMySQLThread import CollectToMySQLThread
31
32
  # from hikyuu.gui.data.CollectToMemThread import CollectToMemThread
32
33
  from hikyuu.gui.data.CollectSpotThread import CollectSpotThread
33
34
  from hikyuu.gui.data.SchedImportThread import SchedImportThread
34
35
  from hikyuu.gui.spot_server import release_nng_senders
35
36
 
36
- from hikyuu import can_upgrade, get_last_version
37
+ from hikyuu import can_upgrade, get_last_version, fetch_trial_license, view_license
37
38
  from hikyuu.data import hku_config_template
38
39
  from hikyuu.util import *
39
40
 
@@ -267,7 +268,14 @@ class MyMainWindow(QMainWindow, Ui_MainWindow):
267
268
  self.log_textEdit.document().setMaximumBlockCount(1000)
268
269
 
269
270
  current_dir = os.path.dirname(__file__)
270
- icon = QIcon(f"{current_dir}/hikyuu_small.png")
271
+ icon = QIcon(f"{current_dir}/images/hikyuu_small.png")
272
+ star_img = QPixmap(f"{current_dir}/images/star.png")
273
+ self.label_44.setPixmap(star_img)
274
+ self.label_46.setOpenExternalLinks(True)
275
+ self.label_license.setText(view_license())
276
+ if os.path.exists(self.getUserConfigDir() + '/.hikyuu.lic'):
277
+ self.fetch_trial_pushButton.setEnabled(False)
278
+
271
279
  self.setWindowIcon(icon)
272
280
  QApplication.instance().setWindowIcon(icon)
273
281
  self.import_detail_textEdit.clear()
@@ -309,11 +317,23 @@ class MyMainWindow(QMainWindow, Ui_MainWindow):
309
317
  self.tdx_dir_lineEdit.setEnabled(tdx_enable)
310
318
  self.select_tdx_dir_pushButton.setEnabled(tdx_enable)
311
319
  self.tdx_dir_lineEdit.setText(tdx_dir)
320
+ if tdx_enable:
321
+ self.use_download = 'tdx'
312
322
 
313
323
  # 初始化pytdx配置及显示
314
- self.pytdx_radioButton.setChecked(import_config.getboolean('pytdx', 'enable', fallback=True))
324
+ use_pytdx_download = import_config.getboolean('pytdx', 'enable', fallback=True)
325
+ self.pytdx_radioButton.setChecked(use_pytdx_download)
326
+ if use_pytdx_download:
327
+ self.use_download = 'pytdx'
315
328
  self.use_tdx_number_spinBox.setValue(import_config.getint('pytdx', 'use_tdx_number', fallback=10))
316
329
 
330
+ # 屏蔽,qmt下载缓慢到发指,且容易中断
331
+ # use_qmt_download = import_config.getboolean('qmt', 'enable', fallback=False)
332
+ # self.qmt_radioButton.setChecked(use_qmt_download)
333
+ # if use_qmt_download:
334
+ # self.use_download = 'qmt'
335
+ self.qmt_radioButton.setEnabled(False)
336
+
317
337
  self.on_tdx_or_pytdx_toggled()
318
338
 
319
339
  # 初始化hdf5设置
@@ -427,6 +447,7 @@ class MyMainWindow(QMainWindow, Ui_MainWindow):
427
447
  'enable': self.pytdx_radioButton.isChecked(),
428
448
  'use_tdx_number': self.use_tdx_number_spinBox.value()
429
449
  }
450
+ import_config['qmt'] = {'enable': self.qmt_radioButton.isChecked()}
430
451
  import_config['hdf5'] = {
431
452
  'enable': self.enable_hdf55_radioButton.isChecked(),
432
453
  'dir': self.hdf5_dir_lineEdit.text()
@@ -494,27 +515,63 @@ class MyMainWindow(QMainWindow, Ui_MainWindow):
494
515
  '5MIN': self.hdf5_5min_progressBar
495
516
  }
496
517
 
518
+ @pyqtSlot()
519
+ def on_fetch_trial_pushButton_clicked(self):
520
+ email = self.email_lineEdit.text()
521
+ info = fetch_trial_license(email)
522
+ QMessageBox.about(self, "获取试用许可", info)
523
+ self.label_license.setText(view_license())
524
+ if os.path.exists(self.getUserConfigDir() + '/.hikyuu.lic'):
525
+ self.fetch_trial_pushButton.setEnabled(False)
526
+
497
527
  @pyqtSlot()
498
528
  def on_pytdx_radioButton_clicked(self):
499
529
  if self.pytdx_radioButton.isChecked():
500
530
  self.tdx_radioButton.setChecked(False)
531
+ self.qmt_radioButton.setChecked(False)
532
+ self.use_download = 'pytdx'
501
533
  self.on_tdx_or_pytdx_toggled()
502
534
 
503
535
  @pyqtSlot()
504
536
  def on_tdx_radioButton_clicked(self):
505
537
  if self.tdx_radioButton.isChecked():
506
538
  self.pytdx_radioButton.setChecked(False)
539
+ self.qmt_radioButton.setChecked(False)
540
+ self.use_download = 'tdx'
541
+ self.on_tdx_or_pytdx_toggled()
542
+
543
+ def on_qmt_radioButton_clicked(self):
544
+ if self.qmt_radioButton.isChecked():
545
+ self.tdx_radioButton.setChecked(False)
546
+ self.pytdx_radioButton.setChecked(False)
547
+ self.use_download = 'qmt'
507
548
  self.on_tdx_or_pytdx_toggled()
508
549
 
509
550
  def on_tdx_or_pytdx_toggled(self):
510
- tdx_enable = self.tdx_radioButton.isChecked()
511
- self.tdx_dir_lineEdit.setEnabled(tdx_enable)
512
- self.select_tdx_dir_pushButton.setEnabled(tdx_enable)
513
- self.import_trans_checkBox.setEnabled(not tdx_enable)
514
- self.import_time_checkBox.setEnabled(not tdx_enable)
515
- self.trans_start_dateEdit.setEnabled(not tdx_enable)
516
- self.time_start_dateEdit.setEnabled(not tdx_enable)
517
- self.use_tdx_number_spinBox.setEnabled(not tdx_enable)
551
+ if self.use_download == 'tdx':
552
+ self.tdx_dir_lineEdit.setEnabled(True)
553
+ self.select_tdx_dir_pushButton.setEnabled(True)
554
+ self.import_trans_checkBox.setEnabled(False)
555
+ self.import_time_checkBox.setEnabled(False)
556
+ self.trans_start_dateEdit.setEnabled(False)
557
+ self.time_start_dateEdit.setEnabled(False)
558
+ self.use_tdx_number_spinBox.setEnabled(False)
559
+ elif self.use_download == 'pytdx':
560
+ self.tdx_dir_lineEdit.setEnabled(False)
561
+ self.select_tdx_dir_pushButton.setEnabled(False)
562
+ self.import_trans_checkBox.setEnabled(True)
563
+ self.import_time_checkBox.setEnabled(True)
564
+ self.trans_start_dateEdit.setEnabled(True)
565
+ self.time_start_dateEdit.setEnabled(True)
566
+ self.use_tdx_number_spinBox.setEnabled(True)
567
+ elif self.use_download == 'qmt':
568
+ self.tdx_dir_lineEdit.setEnabled(False)
569
+ self.select_tdx_dir_pushButton.setEnabled(False)
570
+ self.import_trans_checkBox.setEnabled(False)
571
+ self.import_time_checkBox.setEnabled(False)
572
+ self.trans_start_dateEdit.setEnabled(False)
573
+ self.time_start_dateEdit.setEnabled(False)
574
+ self.use_tdx_number_spinBox.setEnabled(False)
518
575
 
519
576
  @pyqtSlot()
520
577
  def on_select_tdx_dir_pushButton_clicked(self):
@@ -646,7 +703,10 @@ class MyMainWindow(QMainWindow, Ui_MainWindow):
646
703
  if ktype != 'FINISHED':
647
704
  self.hdf5_import_progress_bar[ktype].setValue(progress)
648
705
  else:
649
- self.import_detail_textEdit.append('导入 {} {} 记录数:{}'.format(msg[3], msg[4], msg[5]))
706
+ if self.use_download == 'qmt':
707
+ self.import_detail_textEdit.append('导入 {} 记录数:{}'.format(msg[4], msg[5]))
708
+ else:
709
+ self.import_detail_textEdit.append('导入 {} {} 记录数:{}'.format(msg[3], msg[4], msg[5]))
650
710
 
651
711
  elif msg_task_name == 'IMPORT_TRANS':
652
712
  ktype, progress = msg[2:4]
@@ -732,10 +792,20 @@ class MyMainWindow(QMainWindow, Ui_MainWindow):
732
792
  self.import_status_label.setText("正在启动任务....")
733
793
  QApplication.processEvents()
734
794
 
735
- if self.tdx_radioButton.isChecked():
795
+ if self.use_download == 'tdx':
736
796
  self.hdf5_import_thread = UseTdxImportToH5Thread(self, config)
737
- else:
797
+ elif self.use_download == 'pytdx':
738
798
  self.hdf5_import_thread = UsePytdxImportToH5Thread(self, config)
799
+ elif self.use_download == 'qmt':
800
+ if sys.platform != 'win32':
801
+ QMessageBox.about(self, "错误", "qmt导入功能仅支持Windows系统!")
802
+ return
803
+ try:
804
+ import xtquant
805
+ except ImportError:
806
+ QMessageBox.about(self, "错误", "请安装xtquant后再次尝试!")
807
+ return
808
+ self.hdf5_import_thread = UseQmtImportToH5Thread(self, config)
739
809
 
740
810
  self.hdf5_import_thread.message.connect(self.on_message_from_thread)
741
811
  self.hdf5_import_thread.start()
@@ -0,0 +1,209 @@
1
+ # coding:utf-8
2
+ #
3
+ # The MIT License (MIT)
4
+ #
5
+ # Copyright (c) 2010-2017 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 time
26
+ import logging
27
+ import sqlite3
28
+ import mysql.connector
29
+ from hikyuu.util.check import hku_catch
30
+
31
+ from hikyuu.util.mylog import class_logger
32
+ from hikyuu.util import capture_multiprocess_all_logger, get_default_logger
33
+ from hikyuu.data.common import g_market_list
34
+ from hikyuu.data.common_sqlite3 import get_stock_list as sqlite_get_stock_list
35
+ from hikyuu.data.common_mysql import get_stock_list as mysql_get_stock_list
36
+ from hikyuu import KDataToHdf5Importer, Query, KRecord, Datetime, KRecordList
37
+
38
+
39
+ def ktype_to_qmt_period(ktype):
40
+ if ktype == 'DAY':
41
+ return '1d'
42
+ elif ktype == '5MIN':
43
+ return '5m'
44
+ elif ktype == '1MIN':
45
+ return '1m'
46
+ else:
47
+ raise ValueError('ktype must be DAY, 1MIN or 5MIN')
48
+
49
+
50
+ class ProgressBar:
51
+ def __init__(self, src, market, ktype):
52
+ self.src = src
53
+ self.market = market
54
+ self.ktype = ktype
55
+ self.finished = False
56
+ self.total = 0
57
+ self.cur = 0
58
+
59
+ def __call__(self, data):
60
+ print(data)
61
+ self.total = data['total']
62
+ self.cur = data['finished']
63
+ if self.src.queue:
64
+ self.src.queue.put([self.src.task_name, self.market, self.ktype, (self.cur + 1) * 100 // self.total, 0])
65
+ if self.cur == self.total:
66
+ self.finished = True
67
+
68
+
69
+ class ImportQmtToH5Task:
70
+ def __init__(self, log_queue, queue, config, ktype_list, quotations, dest_dir):
71
+ super(ImportQmtToH5Task, self).__init__()
72
+ self.logger = logging.getLogger(self.__class__.__name__)
73
+ self.task_name = 'IMPORT_KDATA'
74
+ self.log_queue = log_queue
75
+ self.queue = queue
76
+ self.config = config
77
+ self.ktype_list = [ktype.upper() for ktype in ktype_list]
78
+ self.quotations = quotations
79
+ self.dest_dir = dest_dir
80
+ self.status = "no run"
81
+
82
+ def __del__(self):
83
+ # print(self.__class__.__name__, self.market, self.ktype, "__del__")
84
+ pass
85
+
86
+ @hku_catch(trace=True)
87
+ def __call__(self):
88
+ self.status = "no run"
89
+ capture_multiprocess_all_logger(self.log_queue)
90
+ use_hdf = False
91
+ if self.config.getboolean('hdf5', 'enable', fallback=True):
92
+ sqlite_file = "{}/stock.db".format(self.config['hdf5']['dir'])
93
+ connect = sqlite3.connect(sqlite_file, timeout=1800)
94
+ get_stock_list = sqlite_get_stock_list
95
+ self.logger.debug('use hdf5 import kdata')
96
+ use_hdf = True
97
+ else:
98
+ db_config = {
99
+ 'user': self.config['mysql']['usr'],
100
+ 'password': self.config['mysql']['pwd'],
101
+ 'host': self.config['mysql']['host'],
102
+ 'port': self.config['mysql']['port']
103
+ }
104
+ connect = mysql.connector.connect(**db_config)
105
+ get_stock_list = mysql_get_stock_list
106
+ self.logger.debug('use mysql import kdata')
107
+
108
+ from xtquant import xtdata
109
+ total = 0
110
+ for ktype in self.ktype_list:
111
+ for market in g_market_list:
112
+ import time
113
+ start_time = time.time()
114
+ process = ProgressBar(self, market, ktype)
115
+ try:
116
+ code_list = []
117
+ only_code_list = []
118
+ stock_list = get_stock_list(connect, market, self.quotations)
119
+ tmp_list = [f'{stock[2]}.{market}' for stock in stock_list]
120
+ code_list.extend(tmp_list)
121
+ tmp_list = [f'{stock[2]}' for stock in stock_list]
122
+ only_code_list.extend(tmp_list)
123
+ xtdata.download_history_data2(code_list[:1], period=ktype_to_qmt_period(ktype), start_time='', end_time='',
124
+ callback=process, incrementally=True)
125
+ except Exception as e:
126
+ self.logger.error(e)
127
+
128
+ while not process.finished:
129
+ time.sleep(0.1)
130
+ end_time = time.time()
131
+ if (end_time - start_time) > 30 and process.total == 0:
132
+ self.logger.error(f'QMT 超时没反应 {market} {ktype}')
133
+ break
134
+
135
+ total += process.total
136
+
137
+ self.import_qmt_to_h5(market, only_code_list[:1], ktype, self.dest_dir)
138
+
139
+ if self.queue:
140
+ self.queue.put([self.task_name, 'ALL', 'ALL', None, total])
141
+
142
+ self.status = "finished"
143
+
144
+ @hku_catch(trace=True)
145
+ def import_qmt_to_h5(self, market, code_list, ktype, dest_dir):
146
+ im = KDataToHdf5Importer()
147
+ if not im.set_config(dest_dir, [market]):
148
+ self.logger.error('KDataToHdf5Importer set config error! Maybe no license!')
149
+ return
150
+ if ktype == '1MIN':
151
+ nktype = Query.MIN
152
+ elif ktype == '5MIN':
153
+ nktype = Query.MIN5
154
+ elif ktype == 'DAY':
155
+ nktype = Query.DAY
156
+ else:
157
+ self.logger.error(f'Error ktype! {ktype}')
158
+ return
159
+ total = len(code_list)
160
+ cnt = 0
161
+ from xtquant import xtdata
162
+ for code in code_list:
163
+ last_date = im.get_last_datetime(market, code, nktype)
164
+ if not last_date.is_null():
165
+ if last_date >= Datetime.today():
166
+ cnt += 1
167
+ print(f"已导入 {cnt}, 总数: {total}, {market}{code}")
168
+ continue
169
+ df = xtdata.get_local_data(field_list=['open', 'high', 'low', 'close', 'amount', 'volume'],
170
+ stock_list=[f"{code}.{market}",], period=ktype_to_qmt_period(ktype),
171
+ start_time=str(last_date.number*100+1),
172
+ end_time='', count=-1, dividend_type='none', fill_data=False)
173
+ else:
174
+ df = xtdata.get_local_data(field_list=['open', 'high', 'low', 'close', 'amount', 'volume'],
175
+ stock_list=[f"{code}.{market}",], period=ktype_to_qmt_period(ktype),
176
+ dividend_type='none', fill_data=False)
177
+
178
+ if df:
179
+ df = df[f"{code}.{market}"]
180
+ ks = KRecordList()
181
+ for index, row in df.iterrows():
182
+ k = KRecord()
183
+ k.datetime = Datetime(index) if ktype == 'DAY' else Datetime(index/100)
184
+ k.open, k.high, k.low, k.close, k.volume, k.amount = row
185
+ ks.append(k)
186
+ if len(ks) > 0:
187
+ im.add_krecord_list(market, code, ks, nktype)
188
+ if nktype in (Query.DAY, Query.MIN5):
189
+ im.update_index(market, code, nktype)
190
+
191
+ cnt += 1
192
+ print(f"导入hikyuu 已完成: {cnt}, 总数: {total}, {market}{code}")
193
+
194
+
195
+ if __name__ == '__main__':
196
+ from hikyuu import *
197
+ from configparser import ConfigParser
198
+ import os
199
+
200
+ filename = os.path.expanduser('~') + '/.hikyuu' + '/importdata-gui.ini'
201
+ import_config = ConfigParser()
202
+ import_config.read(filename, encoding='utf-8')
203
+
204
+ from xtquant import xtdata
205
+ # get_default_logger()
206
+
207
+ # self, log_queue, queue, config, ktype, quotations, dest_dir
208
+ task = ImportQmtToH5Task(None, None, import_config, ['DAY'], ['stock', 'fund'], 'd:\\tmp\\stock')
209
+ task()
@@ -66,11 +66,18 @@ class ImportTdxToH5Task:
66
66
  self.src_dir = src_dir + "/vipdoc/sz/minline"
67
67
  elif self.ktype == '5MIN':
68
68
  self.src_dir = src_dir + "/vipdoc/sz/fzline"
69
+ elif self.market == 'BJ':
70
+ if self.ktype == 'DAY':
71
+ self.src_dir = src_dir + "/vipdoc/bj/lday"
72
+ elif self.ktype == '1MIN':
73
+ self.src_dir = src_dir + "/vipdoc/bj/minline"
74
+ elif self.ktype == '5MIN':
75
+ self.src_dir = src_dir + "/vipdoc/bj/fzline"
69
76
  self.dest_dir = dest_dir
70
77
  self.status = "no run"
71
78
 
72
79
  def __del__(self):
73
- #print(self.__class__.__name__, self.market, self.ktype, "__del__")
80
+ # print(self.__class__.__name__, self.market, self.ktype, "__del__")
74
81
  pass
75
82
 
76
83
  @hku_catch(trace=True)
@@ -14,7 +14,7 @@ from PyQt5 import QtCore, QtGui, QtWidgets
14
14
  class Ui_MainWindow(object):
15
15
  def setupUi(self, MainWindow):
16
16
  MainWindow.setObjectName("MainWindow")
17
- MainWindow.resize(1269, 690)
17
+ MainWindow.resize(1269, 797)
18
18
  self.centralwidget = QtWidgets.QWidget(MainWindow)
19
19
  self.centralwidget.setObjectName("centralwidget")
20
20
  self.horizontalLayout_12 = QtWidgets.QHBoxLayout(self.centralwidget)
@@ -75,6 +75,14 @@ class Ui_MainWindow(object):
75
75
  self.gridLayout_2 = QtWidgets.QGridLayout()
76
76
  self.gridLayout_2.setContentsMargins(10, -1, -1, 10)
77
77
  self.gridLayout_2.setObjectName("gridLayout_2")
78
+ self.select_tdx_dir_pushButton = QtWidgets.QPushButton(self.groupBox_2)
79
+ sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed)
80
+ sizePolicy.setHorizontalStretch(0)
81
+ sizePolicy.setVerticalStretch(0)
82
+ sizePolicy.setHeightForWidth(self.select_tdx_dir_pushButton.sizePolicy().hasHeightForWidth())
83
+ self.select_tdx_dir_pushButton.setSizePolicy(sizePolicy)
84
+ self.select_tdx_dir_pushButton.setObjectName("select_tdx_dir_pushButton")
85
+ self.gridLayout_2.addWidget(self.select_tdx_dir_pushButton, 0, 3, 1, 1)
78
86
  self.label_2 = QtWidgets.QLabel(self.groupBox_2)
79
87
  self.label_2.setObjectName("label_2")
80
88
  self.gridLayout_2.addWidget(self.label_2, 0, 0, 1, 1)
@@ -86,15 +94,14 @@ class Ui_MainWindow(object):
86
94
  self.tdx_dir_lineEdit.setSizePolicy(sizePolicy)
87
95
  self.tdx_dir_lineEdit.setObjectName("tdx_dir_lineEdit")
88
96
  self.gridLayout_2.addWidget(self.tdx_dir_lineEdit, 0, 1, 1, 2)
89
- self.select_tdx_dir_pushButton = QtWidgets.QPushButton(self.groupBox_2)
90
- sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed)
91
- sizePolicy.setHorizontalStretch(0)
92
- sizePolicy.setVerticalStretch(0)
93
- sizePolicy.setHeightForWidth(self.select_tdx_dir_pushButton.sizePolicy().hasHeightForWidth())
94
- self.select_tdx_dir_pushButton.setSizePolicy(sizePolicy)
95
- self.select_tdx_dir_pushButton.setObjectName("select_tdx_dir_pushButton")
96
- self.gridLayout_2.addWidget(self.select_tdx_dir_pushButton, 0, 3, 1, 1)
97
97
  self.verticalLayout_12.addLayout(self.gridLayout_2)
98
+ self.horizontalLayout_24 = QtWidgets.QHBoxLayout()
99
+ self.horizontalLayout_24.setContentsMargins(10, 0, -1, -1)
100
+ self.horizontalLayout_24.setObjectName("horizontalLayout_24")
101
+ self.qmt_radioButton = QtWidgets.QRadioButton(self.groupBox_2)
102
+ self.qmt_radioButton.setObjectName("qmt_radioButton")
103
+ self.horizontalLayout_24.addWidget(self.qmt_radioButton)
104
+ self.verticalLayout_12.addLayout(self.horizontalLayout_24)
98
105
  self.verticalLayout_13.addWidget(self.groupBox_2)
99
106
  spacerItem2 = QtWidgets.QSpacerItem(20, 20, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum)
100
107
  self.verticalLayout_13.addItem(spacerItem2)
@@ -165,7 +172,7 @@ class Ui_MainWindow(object):
165
172
  self.label_6.setObjectName("label_6")
166
173
  self.gridLayout_4.addWidget(self.label_6, 3, 0, 1, 1)
167
174
  self.min5_start_dateEdit = QtWidgets.QDateEdit(self.groupBox_7)
168
- self.min5_start_dateEdit.setMinimumDateTime(QtCore.QDateTime(QtCore.QDate(1989, 12, 30), QtCore.QTime(8, 0, 0)))
175
+ self.min5_start_dateEdit.setMinimumDateTime(QtCore.QDateTime(QtCore.QDate(1989, 12, 27), QtCore.QTime(8, 0, 0)))
169
176
  self.min5_start_dateEdit.setCalendarPopup(True)
170
177
  self.min5_start_dateEdit.setObjectName("min5_start_dateEdit")
171
178
  self.gridLayout_4.addWidget(self.min5_start_dateEdit, 1, 1, 1, 1)
@@ -187,7 +194,7 @@ class Ui_MainWindow(object):
187
194
  self.trans_start_dateEdit.setObjectName("trans_start_dateEdit")
188
195
  self.gridLayout_4.addWidget(self.trans_start_dateEdit, 3, 1, 1, 1)
189
196
  self.day_start_dateEdit = QtWidgets.QDateEdit(self.groupBox_7)
190
- self.day_start_dateEdit.setMinimumDateTime(QtCore.QDateTime(QtCore.QDate(1989, 12, 30), QtCore.QTime(8, 0, 0)))
197
+ self.day_start_dateEdit.setMinimumDateTime(QtCore.QDateTime(QtCore.QDate(1989, 12, 27), QtCore.QTime(8, 0, 0)))
191
198
  self.day_start_dateEdit.setCalendarPopup(True)
192
199
  self.day_start_dateEdit.setObjectName("day_start_dateEdit")
193
200
  self.gridLayout_4.addWidget(self.day_start_dateEdit, 0, 1, 1, 1)
@@ -681,6 +688,71 @@ class Ui_MainWindow(object):
681
688
  self.horizontalLayout_17.addWidget(self.textBrowser)
682
689
  self.verticalLayout_2.addLayout(self.horizontalLayout_17)
683
690
  self.tabWidget.addTab(self.tab, "")
691
+ self.tab_star = QtWidgets.QWidget()
692
+ self.tab_star.setEnabled(True)
693
+ self.tab_star.setObjectName("tab_star")
694
+ self.label_44 = QtWidgets.QLabel(self.tab_star)
695
+ self.label_44.setGeometry(QtCore.QRect(40, 380, 291, 171))
696
+ self.label_44.setText("")
697
+ self.label_44.setPixmap(QtGui.QPixmap("../images/star.png"))
698
+ self.label_44.setScaledContents(True)
699
+ self.label_44.setObjectName("label_44")
700
+ self.label_46 = QtWidgets.QLabel(self.tab_star)
701
+ self.label_46.setGeometry(QtCore.QRect(30, 20, 561, 221))
702
+ self.label_46.setWordWrap(True)
703
+ self.label_46.setObjectName("label_46")
704
+ self.line_2 = QtWidgets.QFrame(self.tab_star)
705
+ self.line_2.setGeometry(QtCore.QRect(30, 240, 531, 16))
706
+ self.line_2.setFrameShape(QtWidgets.QFrame.HLine)
707
+ self.line_2.setFrameShadow(QtWidgets.QFrame.Sunken)
708
+ self.line_2.setObjectName("line_2")
709
+ self.label_47 = QtWidgets.QLabel(self.tab_star)
710
+ self.label_47.setGeometry(QtCore.QRect(40, 260, 151, 16))
711
+ font = QtGui.QFont()
712
+ font.setBold(True)
713
+ self.label_47.setFont(font)
714
+ self.label_47.setObjectName("label_47")
715
+ self.line_3 = QtWidgets.QFrame(self.tab_star)
716
+ self.line_3.setGeometry(QtCore.QRect(30, 330, 531, 16))
717
+ self.line_3.setFrameShape(QtWidgets.QFrame.HLine)
718
+ self.line_3.setFrameShadow(QtWidgets.QFrame.Sunken)
719
+ self.line_3.setObjectName("line_3")
720
+ self.label_48 = QtWidgets.QLabel(self.tab_star)
721
+ self.label_48.setGeometry(QtCore.QRect(40, 356, 331, 16))
722
+ font = QtGui.QFont()
723
+ font.setBold(True)
724
+ self.label_48.setFont(font)
725
+ self.label_48.setObjectName("label_48")
726
+ self.line_4 = QtWidgets.QFrame(self.tab_star)
727
+ self.line_4.setGeometry(QtCore.QRect(30, 560, 531, 16))
728
+ self.line_4.setFrameShape(QtWidgets.QFrame.HLine)
729
+ self.line_4.setFrameShadow(QtWidgets.QFrame.Sunken)
730
+ self.line_4.setObjectName("line_4")
731
+ self.label_49 = QtWidgets.QLabel(self.tab_star)
732
+ self.label_49.setGeometry(QtCore.QRect(40, 580, 81, 16))
733
+ font = QtGui.QFont()
734
+ font.setBold(True)
735
+ self.label_49.setFont(font)
736
+ self.label_49.setObjectName("label_49")
737
+ self.label_license = QtWidgets.QLabel(self.tab_star)
738
+ self.label_license.setGeometry(QtCore.QRect(40, 610, 521, 91))
739
+ self.label_license.setObjectName("label_license")
740
+ self.layoutWidget = QtWidgets.QWidget(self.tab_star)
741
+ self.layoutWidget.setGeometry(QtCore.QRect(40, 290, 511, 33))
742
+ self.layoutWidget.setObjectName("layoutWidget")
743
+ self.horizontalLayout_20 = QtWidgets.QHBoxLayout(self.layoutWidget)
744
+ self.horizontalLayout_20.setContentsMargins(0, 0, 0, 0)
745
+ self.horizontalLayout_20.setObjectName("horizontalLayout_20")
746
+ self.label_45 = QtWidgets.QLabel(self.layoutWidget)
747
+ self.label_45.setObjectName("label_45")
748
+ self.horizontalLayout_20.addWidget(self.label_45)
749
+ self.email_lineEdit = QtWidgets.QLineEdit(self.layoutWidget)
750
+ self.email_lineEdit.setObjectName("email_lineEdit")
751
+ self.horizontalLayout_20.addWidget(self.email_lineEdit)
752
+ self.fetch_trial_pushButton = QtWidgets.QPushButton(self.layoutWidget)
753
+ self.fetch_trial_pushButton.setObjectName("fetch_trial_pushButton")
754
+ self.horizontalLayout_20.addWidget(self.fetch_trial_pushButton)
755
+ self.tabWidget.addTab(self.tab_star, "")
684
756
  self.horizontalLayout_12.addWidget(self.tabWidget)
685
757
  self.verticalLayout_6 = QtWidgets.QVBoxLayout()
686
758
  self.verticalLayout_6.setObjectName("verticalLayout_6")
@@ -703,12 +775,13 @@ class Ui_MainWindow(object):
703
775
  _translate = QtCore.QCoreApplication.translate
704
776
  MainWindow.setWindowTitle(_translate("MainWindow", "数据导入工具"))
705
777
  self.groupBox_2.setTitle(_translate("MainWindow", "数据源设置"))
706
- self.pytdx_radioButton.setText(_translate("MainWindow", "使用Pytdx(推荐)"))
778
+ self.pytdx_radioButton.setText(_translate("MainWindow", "使用Pytdx下载数据"))
707
779
  self.label_16.setText(_translate("MainWindow", "同时使用"))
708
780
  self.label_17.setText(_translate("MainWindow", "个通达信服务器进行下载"))
709
781
  self.tdx_radioButton.setText(_translate("MainWindow", "使用通达信盘后数据(不支持分笔、分时数据,需要配置安装路径)"))
710
- self.label_2.setText(_translate("MainWindow", "通达信安装目录:"))
711
782
  self.select_tdx_dir_pushButton.setText(_translate("MainWindow", "选择"))
783
+ self.label_2.setText(_translate("MainWindow", "通达信安装目录:"))
784
+ self.qmt_radioButton.setText(_translate("MainWindow", "使用 qmt 数据下载(需要 miniqmt)(屏蔽,qmt下载数据太慢,且不稳定)"))
712
785
  self.groupBox_7.setTitle(_translate("MainWindow", "导入设置"))
713
786
  self.import_weight_checkBox.setText(_translate("MainWindow", "下载权息数据"))
714
787
  self.import_stock_checkBox.setText(_translate("MainWindow", "股票"))
@@ -827,4 +900,12 @@ class Ui_MainWindow(object):
827
900
  "<p style=\"-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:\'SimSun\';\"><br /></p>\n"
828
901
  "<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-family:\'SimSun\'; font-weight:696; color:#0000ff;\">3、此处采集为网络采集,更推荐直接运行安装目录下gui子目录下的 start_qmt.py ,使用miniqmt 实时服务。该程序独立运行,不用关闭,和这里的采集效果一样。注意:miniqmt需要QMT交易端配合,且在同一机器上执行。</span></p></body></html>"))
829
902
  self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab), _translate("MainWindow", "行情采集服务"))
903
+ self.label_46.setText(_translate("MainWindow", "<html><head/><body><p>Hikyuu 作为长期持续维护的开源项目,<span style=\" font-weight:700;\">专注于量化交易领域的核心技术构建,涵盖交易模型开发、极速计算引擎、高效回测框架及实盘拓展能力</span>,定位为量化交易的基础设施级计算引擎,为量化交易爱好者和专业提供高性能底层架构支持。随着社区规模扩大,项目持续迭代及技术支持事务逐渐分散了作者在策略研究上的精力。为保障项目的专注度与可持续性,现推出 &quot;VIP计划&quot;,通过提供部分VIP功能作为回馈,构建良性的项目发展生态。诚挚期待社区伙伴的支持,您的参与都将直接助力 Hikyuu 的技术创新,共同推动量化交易基础设施的迭代升级。</p><p>VIP功能以插件的方式提供,采用独立授权许可,完全在 hikyuu 之外,对喜欢自行编译扩展的朋友没有影响。因插件许可授权需要采集硬件信息,如有疑虑只要不申请试用许可和正式许可授权,不会触发硬件信息采集。</p><p><span style=\" font-weight:700;\">正式许可授权除资金支持外,亦可通过其他方式获取,详情参见:</span><a href=\"https://gitee.com/fasiondog/hikyuu/blob/master/vip-plan.md\"><span style=\" font-weight:700; text-decoration: underline; color:#3586ff;\">VIP计划</span></a><span style=\" font-weight:700;\"> 中 &quot;如何获取免费授权和延长授权时间&quot; 章节,已提供的VIP功能亦在其中,可自行查看,感谢大家的支持!</span></p></body></html>"))
904
+ self.label_47.setText(_translate("MainWindow", "申请试用许可(30天试用)"))
905
+ self.label_48.setText(_translate("MainWindow", "加入知识星球,获取星球许可(可同时在3台设备上使用)"))
906
+ self.label_49.setText(_translate("MainWindow", "当前授权信息"))
907
+ self.label_license.setText(_translate("MainWindow", "TextLabel"))
908
+ self.label_45.setText(_translate("MainWindow", "电子邮件地址:"))
909
+ self.fetch_trial_pushButton.setText(_translate("MainWindow", "申请试用许可"))
910
+ self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_star), _translate("MainWindow", "项目VIP"))
830
911
  self.label_41.setText(_translate("MainWindow", "执行日志"))