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
hikyuu/gui/HikyuuTDX.py CHANGED
@@ -22,6 +22,8 @@ import mysql.connector
22
22
  from mysql.connector import errorcode
23
23
  from mysql.connector.locales.eng import client_error # 此句仅为pyinstaller打包时能够自动引入
24
24
 
25
+ import clickhouse_connect
26
+
25
27
  from hikyuu.gui.data.MainWindow import *
26
28
  from hikyuu.gui.data.EscapetimeThread import EscapetimeThread
27
29
  from hikyuu.gui.data.UseTdxImportToH5Thread import UseTdxImportToH5Thread
@@ -187,6 +189,49 @@ class MyMainWindow(QMainWindow, Ui_MainWindow):
187
189
  hour2_max=current_config.getint('preload', 'hour2_max', fallback=4096),
188
190
  )
189
191
  )
192
+ elif current_config.getboolean('clickhouse', 'enable', fallback=True):
193
+ data_dir = current_config['clickhouse']['tmpdir']
194
+ if not os.path.lexists(data_dir + '/tmp'):
195
+ try:
196
+ os.mkdir(data_dir + '/tmp')
197
+ except:
198
+ pass
199
+ with open(filename, 'w', encoding="utf-8") as f:
200
+ f.write(
201
+ hku_config_template.clickhouse_template.format(
202
+ dir=data_dir,
203
+ quotation_server=current_config.get(
204
+ 'collect', 'quotation_server', fallback='ipc:///tmp/hikyuu_real.ipc'),
205
+ host=current_config['clickhouse']['host'],
206
+ port=current_config['clickhouse']['port'],
207
+ usr=current_config['clickhouse']['usr'],
208
+ pwd=current_config['clickhouse']['pwd'],
209
+ day=current_config.getboolean('preload', 'day', fallback=True),
210
+ week=current_config.getboolean('preload', 'week', fallback=False),
211
+ month=current_config.getboolean('preload', 'month', fallback=False),
212
+ quarter=current_config.getboolean('preload', 'quarter', fallback=False),
213
+ halfyear=current_config.getboolean('preload', 'halfyear', fallback=False),
214
+ year=current_config.getboolean('preload', 'year', fallback=False),
215
+ min1=current_config.getboolean('preload', 'min', fallback=False),
216
+ min5=current_config.getboolean('preload', 'min5', fallback=False),
217
+ min15=current_config.getboolean('preload', 'min15', fallback=False),
218
+ min30=current_config.getboolean('preload', 'min30', fallback=False),
219
+ min60=current_config.getboolean('preload', 'min60', fallback=False),
220
+ hour2=current_config.getboolean('preload', 'hour2', fallback=False),
221
+ day_max=current_config.getint('preload', 'day_max', fallback=100000),
222
+ week_max=current_config.getint('preload', 'week_max', fallback=100000),
223
+ month_max=current_config.getint('preload', 'month_max', fallback=100000),
224
+ quarter_max=current_config.getint('preload', 'quarter_max', fallback=100000),
225
+ halfyear_max=current_config.getint('preload', 'halfyear_max', fallback=100000),
226
+ year_max=current_config.getint('preload', 'year_max', fallback=100000),
227
+ min1_max=current_config.getint('preload', 'min_max', fallback=4096),
228
+ min5_max=current_config.getint('preload', 'min5_max', fallback=4096),
229
+ min15_max=current_config.getint('preload', 'min15_max', fallback=4096),
230
+ min30_max=current_config.getint('preload', 'min30_max', fallback=4096),
231
+ min60_max=current_config.getint('preload', 'min60_max', fallback=4096),
232
+ hour2_max=current_config.getint('preload', 'hour2_max', fallback=4096),
233
+ )
234
+ )
190
235
 
191
236
  try:
192
237
  if not data_dir and not os.path.lexists(data_dir):
@@ -282,6 +327,8 @@ class MyMainWindow(QMainWindow, Ui_MainWindow):
282
327
  sys.stderr = self._stream
283
328
  self.log_textEdit.document().setMaximumBlockCount(1000)
284
329
 
330
+ self.tabWidget.setCurrentIndex(0)
331
+
285
332
  current_dir = os.path.dirname(__file__)
286
333
  icon = QIcon(f"{current_dir}/images/hikyuu_small.png")
287
334
  star_img = QPixmap(f"{current_dir}/images/star.png")
@@ -383,6 +430,30 @@ class MyMainWindow(QMainWindow, Ui_MainWindow):
383
430
  self.mysql_pwd_lineEdit.setEnabled(mysql_enable)
384
431
  self.mysql_test_pushButton.setEnabled(mysql_enable)
385
432
 
433
+ # 初始化clickhouse设置
434
+ clickhouse_enable = import_config.getboolean('clickhouse', 'enable', fallback=False)
435
+ if (not is_valid_license()) or hdf5_enable or mysql_enable:
436
+ clickhouse_enable = False
437
+ self.enable_clickhouse_radioButton.setChecked(clickhouse_enable)
438
+ self.clickhouse_tmpdir_lineEdit.setText(import_config.get('clickhouse', 'tmpdir', fallback='d:/stock'))
439
+ self.clickhouse_tmpdir_pushButton.setEnabled(clickhouse_enable)
440
+ clickhouse_ip = import_config.get('clickhouse', 'host', fallback='127.0.0.1')
441
+ self.clickhouse_ip_lineEdit.setText(clickhouse_ip)
442
+ self.clickhouse_ip_lineEdit.setEnabled(clickhouse_enable)
443
+ clickhouse_port = import_config.get('clickhouse', 'port', fallback='9000')
444
+ self.clickhouse_port_lineEdit.setText(clickhouse_port)
445
+ self.clickhouse_port_lineEdit.setEnabled(clickhouse_enable)
446
+ clickhouse_http_port = import_config.get('clickhouse', 'http_port', fallback='8123')
447
+ self.clickhouse_http_port_lineEdit.setText(clickhouse_http_port)
448
+ self.clickhouse_http_port_lineEdit.setEnabled(clickhouse_enable)
449
+ clickhouse_usr = import_config.get('clickhouse', 'usr', fallback='default')
450
+ self.clickhouse_usr_lineEdit.setText(clickhouse_usr)
451
+ self.clickhouse_usr_lineEdit.setEnabled(clickhouse_enable)
452
+ clickhouse_pwd = import_config.get('clickhouse', 'pwd', fallback='test')
453
+ self.clickhouse_pwd_lineEdit.setText(clickhouse_pwd)
454
+ self.clickhouse_pwd_lineEdit.setEnabled(clickhouse_enable)
455
+ self.clickhouse_test_pushButton.setEnabled(clickhouse_enable)
456
+
386
457
  self.sched_import_timeEdit.setTime(
387
458
  datetime.time.fromisoformat(import_config.get('schec', 'time', fallback='18:00'))
388
459
  )
@@ -484,6 +555,15 @@ class MyMainWindow(QMainWindow, Ui_MainWindow):
484
555
  'usr': self.mysql_usr_lineEdit.text(),
485
556
  'pwd': self.mysql_pwd_lineEdit.text()
486
557
  }
558
+ import_config['clickhouse'] = {
559
+ 'enable': is_valid_license() and self.enable_clickhouse_radioButton.isChecked(),
560
+ 'tmpdir': self.clickhouse_tmpdir_lineEdit.text(),
561
+ 'host': self.clickhouse_ip_lineEdit.text(),
562
+ 'http_port': self.clickhouse_http_port_lineEdit.text(),
563
+ 'port': self.clickhouse_port_lineEdit.text(),
564
+ 'usr': self.clickhouse_usr_lineEdit.text(),
565
+ 'pwd': self.clickhouse_pwd_lineEdit.text()
566
+ }
487
567
  import_config['sched'] = {
488
568
  'time': self.sched_import_timeEdit.time().toString(),
489
569
  }
@@ -621,15 +701,24 @@ class MyMainWindow(QMainWindow, Ui_MainWindow):
621
701
  def on_enable_hdf55_radioButton_clicked(self):
622
702
  if self.enable_hdf55_radioButton.isChecked():
623
703
  self.enable_mysql_radioButton.setChecked(False)
624
- self.on_enable_database_toggled(hdf5=True, mysql=False)
704
+ self.enable_clickhouse_radioButton.setChecked(False)
705
+ self.on_enable_database_toggled(hdf5=True, mysql=False, clickhouse=False)
625
706
 
626
707
  @pyqtSlot()
627
708
  def on_enable_mysql_radioButton_clicked(self):
628
709
  if self.enable_mysql_radioButton.isChecked():
629
710
  self.enable_hdf55_radioButton.setChecked(False)
630
- self.on_enable_database_toggled(hdf5=False, mysql=True)
711
+ self.enable_clickhouse_radioButton.setChecked(False)
712
+ self.on_enable_database_toggled(hdf5=False, mysql=True, clickhouse=False)
631
713
 
632
- def on_enable_database_toggled(self, hdf5, mysql):
714
+ @pyqtSlot()
715
+ def on_enable_clickhouse_radioButton_clicked(self):
716
+ if self.enable_clickhouse_radioButton.isChecked():
717
+ self.enable_hdf55_radioButton.setChecked(False)
718
+ self.enable_mysql_radioButton.setChecked(False)
719
+ self.on_enable_database_toggled(hdf5=False, mysql=False, clickhouse=True)
720
+
721
+ def on_enable_database_toggled(self, hdf5, mysql, clickhouse):
633
722
  self.hdf5_dir_lineEdit.setEnabled(hdf5)
634
723
  self.mysql_ip_lineEdit.setEnabled(mysql)
635
724
  self.mysql_port_lineEdit.setEnabled(mysql)
@@ -637,6 +726,13 @@ class MyMainWindow(QMainWindow, Ui_MainWindow):
637
726
  self.mysql_pwd_lineEdit.setEnabled(mysql)
638
727
  self.mysql_test_pushButton.setEnabled(mysql)
639
728
  self.mysql_tmpdir_pushButton.setEnabled(mysql)
729
+ self.clickhouse_ip_lineEdit.setEnabled(clickhouse)
730
+ self.clickhouse_http_port_lineEdit.setEnabled(clickhouse)
731
+ self.clickhouse_port_lineEdit.setEnabled(clickhouse)
732
+ self.clickhouse_usr_lineEdit.setEnabled(clickhouse)
733
+ self.clickhouse_pwd_lineEdit.setEnabled(clickhouse)
734
+ self.clickhouse_test_pushButton.setEnabled(clickhouse)
735
+ self.clickhouse_tmpdir_pushButton.setEnabled(clickhouse)
640
736
 
641
737
  @pyqtSlot()
642
738
  def on_mysql_tmpdir_pushButton_clicked(self):
@@ -648,6 +744,20 @@ class MyMainWindow(QMainWindow, Ui_MainWindow):
648
744
  dirname = dlg.selectedFiles()
649
745
  self.mysql_tmpdir_lineEdit.setText(dirname[0])
650
746
 
747
+ @pyqtSlot()
748
+ def on_clickhouse_tmpdir_pushButton_clicked(self):
749
+ if not is_valid_license():
750
+ QMessageBox.critical(self, "clickhouse引擎", "需要捐赠授权才能使用clickhouse引擎")
751
+ return
752
+
753
+ dlg = QFileDialog()
754
+ dlg.setFileMode(QFileDialog.Directory)
755
+ config = self.getCurrentConfig()
756
+ dlg.setDirectory(config['clickhouse']['tmpdir'])
757
+ if dlg.exec_():
758
+ dirname = dlg.selectedFiles()
759
+ self.clickhouse_tmpdir_lineEdit.setText(dirname[0])
760
+
651
761
  @pyqtSlot()
652
762
  def on_mysql_test_pushButton_clicked(self):
653
763
  """测试数据库连接"""
@@ -672,6 +782,25 @@ class MyMainWindow(QMainWindow, Ui_MainWindow):
672
782
 
673
783
  QMessageBox.about(self, "测试数据库连接", " 连接成功!")
674
784
 
785
+ @pyqtSlot()
786
+ def on_clickhouse_test_pushButton_clicked(self):
787
+ """测试数据库连接"""
788
+ db_config = {
789
+ 'username': self.clickhouse_usr_lineEdit.text(),
790
+ 'password': self.clickhouse_pwd_lineEdit.text(),
791
+ 'host': self.clickhouse_ip_lineEdit.text(),
792
+ 'port': self.clickhouse_http_port_lineEdit.text()
793
+ }
794
+
795
+ try:
796
+ cnx = clickhouse_connect.get_client(**db_config)
797
+ cnx.close()
798
+ except Exception as err:
799
+ QMessageBox.critical(self, "测试数据库连接失败", str(err))
800
+ return
801
+
802
+ QMessageBox.about(self, "测试数据库连接", " 连接成功!")
803
+
675
804
  def reset_progress_bar(self):
676
805
  self.hdf5_weight_label.setText('')
677
806
  self.hdf5_day_progressBar.setValue(0)
@@ -9,6 +9,7 @@ import mysql.connector
9
9
  from hikyuu.data.common import MARKET, get_stk_code_name_list
10
10
  from hikyuu.data.em_block_to_mysql import em_import_block_to_mysql
11
11
  from hikyuu.data.em_block_to_sqlite import em_import_block_to_sqlite
12
+ from hikyuu.data.em_block_to_clickhouse import em_import_block_to_clickhouse
12
13
  from hikyuu.util import *
13
14
 
14
15
 
@@ -38,6 +39,16 @@ class ImportBlockInfoTask:
38
39
  }
39
40
  connect = mysql.connector.connect(**db_config)
40
41
  import_block = em_import_block_to_mysql
42
+ elif self.config.getboolean('clickhouse', 'enable', fallback=True):
43
+ db_config = {
44
+ 'username': self.config['clickhouse']['usr'],
45
+ 'password': self.config['clickhouse']['pwd'],
46
+ 'host': self.config['clickhouse']['host'],
47
+ 'port': self.config['clickhouse']['http_port']
48
+ }
49
+ import clickhouse_connect
50
+ connect = clickhouse_connect.get_client(**db_config)
51
+ import_block = em_import_block_to_clickhouse
41
52
 
42
53
  count = 0
43
54
  try:
@@ -27,9 +27,11 @@ import shutil
27
27
  import hashlib
28
28
  import sqlite3
29
29
  import mysql.connector
30
+ import clickhouse_connect
30
31
  from pytdx.hq import TdxHq_API
31
32
  from hikyuu.data.pytdx_finance_to_mysql import history_finance_import_mysql
32
33
  from hikyuu.data.pytdx_finance_to_sqlite import history_finance_import_sqlite
34
+ from hikyuu.data.pytdx_finance_to_clickhouse import history_finance_import_clickhouse
33
35
  from hikyuu.util import *
34
36
 
35
37
 
@@ -77,6 +79,16 @@ class ImportHistoryFinanceTask:
77
79
  self.db_connect = mysql.connector.connect(**db_config)
78
80
  self.history_finance_import = history_finance_import_mysql
79
81
  self.engine = 'mysql'
82
+ elif self.config.getboolean('clickhouse', 'enable', fallback=True):
83
+ db_config = {
84
+ 'username': self.config['clickhouse']['usr'],
85
+ 'password': self.config['clickhouse']['pwd'],
86
+ 'host': self.config['clickhouse']['host'],
87
+ 'port': self.config['clickhouse']['http_port']
88
+ }
89
+ self.db_connect = clickhouse_connect.get_client(**db_config)
90
+ self.history_finance_import = history_finance_import_clickhouse
91
+ self.engine = 'clickhouse'
80
92
 
81
93
  def import_to_db(self, filename):
82
94
  try:
@@ -129,6 +141,8 @@ class ImportHistoryFinanceTask:
129
141
  self.queue.put([self.task_name, None, None, int(100 * count / self.total_count), self.total_count])
130
142
  except Exception as e:
131
143
  hku_error(str(e))
144
+ if self.engine == 'clickhouse':
145
+ hku_run_ignore_exception(self.db_connect.command, "OPTIMIZE TABLE hku_base.historyfinance FINAL")
132
146
  self.db_connect.close()
133
147
  self.api.disconnect()
134
148
 
@@ -142,6 +156,6 @@ if __name__ == "__main__":
142
156
  this_dir = os.path.expanduser('~') + '/.hikyuu'
143
157
  import_config = ConfigParser()
144
158
  import_config.read(this_dir + '/importdata-gui.ini', encoding='utf-8')
145
- task = ImportHistoryFinanceTask(None, None, None, "/Users/fasiondog/stock")
159
+ task = ImportHistoryFinanceTask(None, None, import_config, "/Users/fasiondog/stock")
146
160
  task()
147
161
  print("over!")
@@ -25,9 +25,11 @@
25
25
  import logging
26
26
  import sqlite3
27
27
  import mysql.connector
28
+ import clickhouse_connect
28
29
  from pytdx.hq import TdxHq_API
29
30
  from hikyuu.data.pytdx_to_h5 import import_time as h5_import_time
30
31
  from hikyuu.data.pytdx_to_mysql import import_time as mysql_import_time
32
+ from hikyuu.data.pytdx_to_clickhouse import import_time as clickhouse_import_time
31
33
  from hikyuu.util import *
32
34
 
33
35
 
@@ -73,6 +75,15 @@ class ImportPytdxTimeToH5:
73
75
  }
74
76
  connect = mysql.connector.connect(**db_config)
75
77
  import_time = mysql_import_time
78
+ elif self.config.getboolean('clickhouse', 'enable', fallback=True):
79
+ db_config = {
80
+ 'username': self.config['clickhouse']['usr'],
81
+ 'password': self.config['clickhouse']['pwd'],
82
+ 'host': self.config['clickhouse']['host'],
83
+ 'port': self.config['clickhouse']['http_port']
84
+ }
85
+ connect = clickhouse_connect.get_client(**db_config)
86
+ import_time = clickhouse_import_time
76
87
 
77
88
  count = 0
78
89
  try:
@@ -89,7 +100,6 @@ class ImportPytdxTimeToH5:
89
100
  self.logger.error(e)
90
101
  finally:
91
102
  api.close()
92
- connect.commit()
93
103
  connect.close()
94
104
 
95
105
  self.queue.put([self.task_name, self.market, 'TIME', None, count])
@@ -28,6 +28,7 @@ import mysql.connector
28
28
  from pytdx.hq import TdxHq_API
29
29
  from hikyuu.data.pytdx_to_h5 import import_data as h5_import_data
30
30
  from hikyuu.data.pytdx_to_mysql import import_data as mysql_import_data
31
+ from hikyuu.data.pytdx_to_clickhouse import import_data as clickhouse_import_data
31
32
  from hikyuu.util import *
32
33
 
33
34
 
@@ -76,6 +77,18 @@ class ImportPytdxToH5:
76
77
  connect = mysql.connector.connect(**db_config)
77
78
  import_data = mysql_import_data
78
79
  self.logger.debug('use mysql import kdata')
80
+ elif self.config.getboolean('clickhouse', 'enable', fallback=True):
81
+ db_config = {
82
+ 'username': self.config['clickhouse']['usr'],
83
+ 'password': self.config['clickhouse']['pwd'],
84
+ 'host': self.config['clickhouse']['host'],
85
+ 'port': int(self.config['clickhouse']['http_port']),
86
+ 'send_receive_timeout': 60,
87
+ }
88
+ import clickhouse_connect
89
+ connect = clickhouse_connect.get_client(**db_config)
90
+ import_data = clickhouse_import_data
91
+ self.logger.debug('use clickhouse import kdata')
79
92
 
80
93
  count = 0
81
94
  try:
@@ -93,7 +106,6 @@ class ImportPytdxToH5:
93
106
  # self.queue.put([self.task_name, self.market, self.ktype, str(e), count])
94
107
  finally:
95
108
  api.close()
96
- connect.commit()
97
109
  connect.close()
98
110
 
99
111
  self.queue.put([self.task_name, self.market, self.ktype, None, count])
@@ -28,6 +28,7 @@ import mysql.connector
28
28
  from pytdx.hq import TdxHq_API
29
29
  from hikyuu.data.pytdx_to_h5 import import_trans as h5_import_trans
30
30
  from hikyuu.data.pytdx_to_mysql import import_trans as mysql_import_trans
31
+ from hikyuu.data.pytdx_to_clickhouse import import_trans as clickhouse_import_trans
31
32
  from hikyuu.util import *
32
33
 
33
34
 
@@ -73,6 +74,16 @@ class ImportPytdxTransToH5:
73
74
  }
74
75
  connect = mysql.connector.connect(**db_config)
75
76
  import_trans = mysql_import_trans
77
+ elif self.config.getboolean('clickhouse', 'enable', fallback=True):
78
+ db_config = {
79
+ 'username': self.config['clickhouse']['usr'],
80
+ 'password': self.config['clickhouse']['pwd'],
81
+ 'host': self.config['clickhouse']['host'],
82
+ 'port': self.config['clickhouse']['http_port']
83
+ }
84
+ import clickhouse_connect
85
+ connect = clickhouse_connect.get_client(**db_config)
86
+ import_trans = clickhouse_import_trans
76
87
 
77
88
  count = 0
78
89
  try:
@@ -89,7 +100,6 @@ class ImportPytdxTransToH5:
89
100
  self.logger.error(e)
90
101
  finally:
91
102
  api.close()
92
- connect.commit()
93
103
  connect.close()
94
104
 
95
105
  self.queue.put([self.task_name, self.market, 'TRANS', None, count])
@@ -30,6 +30,7 @@ from hikyuu.util.check import hku_catch
30
30
  from hikyuu.util.mylog import class_logger
31
31
  from hikyuu.data.tdx_to_h5 import tdx_import_data as h5_import_data
32
32
  from hikyuu.data.tdx_to_mysql import tdx_import_data as mysql_import_data
33
+ from hikyuu.data.tdx_to_clickhouse import tdx_import_data as clickhouse_import_data
33
34
  from hikyuu.util import capture_multiprocess_all_logger, get_default_logger
34
35
 
35
36
 
@@ -91,7 +92,7 @@ class ImportTdxToH5Task:
91
92
  import_data = h5_import_data
92
93
  self.logger.debug('use hdf5 import kdata')
93
94
  use_hdf = True
94
- else:
95
+ elif self.config.getboolean('mysql', 'enable', fallback=True):
95
96
  db_config = {
96
97
  'user': self.config['mysql']['usr'],
97
98
  'password': self.config['mysql']['pwd'],
@@ -101,6 +102,17 @@ class ImportTdxToH5Task:
101
102
  connect = mysql.connector.connect(**db_config)
102
103
  import_data = mysql_import_data
103
104
  self.logger.debug('use mysql import kdata')
105
+ elif self.config.getboolean('clickhouse', 'enable', fallback=True):
106
+ db_config = {
107
+ 'username': self.config['clickhouse']['usr'],
108
+ 'password': self.config['clickhouse']['pwd'],
109
+ 'host': self.config['clickhouse']['host'],
110
+ 'port': self.config['clickhouse']['http_port']
111
+ }
112
+ import clickhouse_connect
113
+ connect = clickhouse_connect.get_client(**db_config)
114
+ import_data = clickhouse_import_data
115
+ self.logger.debug('use clickhouse import kdata')
104
116
 
105
117
  count = 0
106
118
  try:
@@ -28,6 +28,7 @@ import hashlib
28
28
  import sqlite3
29
29
  import urllib.request
30
30
  import mysql.connector
31
+ import clickhouse_connect
31
32
 
32
33
  from pytdx.hq import TdxHq_API
33
34
  from hikyuu.data.common import MARKET, g_market_list
@@ -37,6 +38,8 @@ from hikyuu.data.pytdx_weight_to_sqlite import pytdx_import_weight_to_sqlite
37
38
  from hikyuu.data.pytdx_weight_to_mysql import pytdx_import_weight_to_mysql
38
39
  from hikyuu.data.pytdx_finance_to_sqlite import pytdx_import_finance_to_sqlite
39
40
  from hikyuu.data.pytdx_finance_to_mysql import pytdx_import_finance_to_mysql
41
+ from hikyuu.data.pytdx_finance_to_clickhouse import pytdx_import_finance_to_clickhouse
42
+ from hikyuu.data.pytdx_weight_to_clickhouse import pytdx_import_weight_to_clickhouse
40
43
  from hikyuu.util import capture_multiprocess_all_logger, get_default_logger
41
44
  from hikyuu.util.check import hku_catch, hku_check
42
45
 
@@ -78,6 +81,17 @@ class ImportWeightToSqliteTask:
78
81
  pytdx_import_weight = pytdx_import_weight_to_mysql
79
82
  pytdx_import_finance = pytdx_import_finance_to_mysql
80
83
  self.logger.debug('use mysql import weight')
84
+ elif self.config.getboolean('clickhouse', 'enable', fallback=True):
85
+ db_config = {
86
+ 'username': self.config['clickhouse']['usr'],
87
+ 'password': self.config['clickhouse']['pwd'],
88
+ 'host': self.config['clickhouse']['host'],
89
+ 'port': self.config['clickhouse']['http_port']
90
+ }
91
+ connect = clickhouse_connect.get_client(**db_config)
92
+ pytdx_import_weight = pytdx_import_weight_to_clickhouse
93
+ pytdx_import_finance = pytdx_import_finance_to_clickhouse
94
+ self.logger.debug('use clickhouse import weight')
81
95
 
82
96
  except Exception as e:
83
97
  # self.queue.put([self.msg_name, str(e), -1, 0, total_count])
@@ -108,7 +122,6 @@ class ImportWeightToSqliteTask:
108
122
  self.queue.put([self.msg_name, 'INFO', str(e), 0, 0])
109
123
  finally:
110
124
  api.close()
111
- connect.commit()
112
125
  connect.close()
113
126
 
114
127
  self.queue.put([self.msg_name, '', 0, None, total_count])
@@ -6,8 +6,10 @@
6
6
 
7
7
  import sqlite3
8
8
  import mysql.connector
9
+ import clickhouse_connect
9
10
  from hikyuu.data.zh_bond10_to_mysql import import_zh_bond10_to_mysql
10
11
  from hikyuu.data.zh_bond10_to_sqlite import import_zh_bond10_to_sqlite
12
+ from hikyuu.data.zh_bond10_to_clickhouse import import_zh_bond10_to_clickhouse
11
13
  from hikyuu.util import *
12
14
 
13
15
 
@@ -36,6 +38,15 @@ class ImportZhBond10Task:
36
38
  }
37
39
  connect = mysql.connector.connect(**db_config)
38
40
  import_zh_bond10 = import_zh_bond10_to_mysql
41
+ elif self.config.getboolean('clickhouse', 'enable', fallback=True):
42
+ db_config = {
43
+ 'username': self.config['clickhouse']['usr'],
44
+ 'password': self.config['clickhouse']['pwd'],
45
+ 'host': self.config['clickhouse']['host'],
46
+ 'port': self.config['clickhouse']['http_port']
47
+ }
48
+ connect = clickhouse_connect.get_client(**db_config)
49
+ import_zh_bond10 = import_zh_bond10_to_clickhouse
39
50
 
40
51
  try:
41
52
  import_zh_bond10(connect)
@@ -178,7 +178,7 @@ class Ui_MainWindow(object):
178
178
  self.label_6.setObjectName("label_6")
179
179
  self.gridLayout_4.addWidget(self.label_6, 3, 0, 1, 1)
180
180
  self.min5_start_dateEdit = QtWidgets.QDateEdit(self.groupBox_7)
181
- self.min5_start_dateEdit.setMinimumDateTime(QtCore.QDateTime(QtCore.QDate(1989, 12, 24), QtCore.QTime(16, 0, 0)))
181
+ self.min5_start_dateEdit.setMinimumDateTime(QtCore.QDateTime(QtCore.QDate(1989, 12, 23), QtCore.QTime(8, 0, 0)))
182
182
  self.min5_start_dateEdit.setCalendarPopup(True)
183
183
  self.min5_start_dateEdit.setObjectName("min5_start_dateEdit")
184
184
  self.gridLayout_4.addWidget(self.min5_start_dateEdit, 1, 1, 1, 1)
@@ -200,7 +200,7 @@ class Ui_MainWindow(object):
200
200
  self.trans_start_dateEdit.setObjectName("trans_start_dateEdit")
201
201
  self.gridLayout_4.addWidget(self.trans_start_dateEdit, 3, 1, 1, 1)
202
202
  self.day_start_dateEdit = QtWidgets.QDateEdit(self.groupBox_7)
203
- self.day_start_dateEdit.setMinimumDateTime(QtCore.QDateTime(QtCore.QDate(1989, 12, 24), QtCore.QTime(16, 0, 0)))
203
+ self.day_start_dateEdit.setMinimumDateTime(QtCore.QDateTime(QtCore.QDate(1989, 12, 23), QtCore.QTime(8, 0, 0)))
204
204
  self.day_start_dateEdit.setCalendarPopup(True)
205
205
  self.day_start_dateEdit.setObjectName("day_start_dateEdit")
206
206
  self.gridLayout_4.addWidget(self.day_start_dateEdit, 0, 1, 1, 1)
@@ -238,6 +238,9 @@ class Ui_MainWindow(object):
238
238
  self.enable_mysql_radioButton = QtWidgets.QRadioButton(self.groupBox_4)
239
239
  self.enable_mysql_radioButton.setObjectName("enable_mysql_radioButton")
240
240
  self.horizontalLayout_19.addWidget(self.enable_mysql_radioButton)
241
+ self.enable_clickhouse_radioButton = QtWidgets.QRadioButton(self.groupBox_4)
242
+ self.enable_clickhouse_radioButton.setObjectName("enable_clickhouse_radioButton")
243
+ self.horizontalLayout_19.addWidget(self.enable_clickhouse_radioButton)
241
244
  spacerItem8 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
242
245
  self.horizontalLayout_19.addItem(spacerItem8)
243
246
  self.verticalLayout_14.addLayout(self.horizontalLayout_19)
@@ -317,8 +320,59 @@ class Ui_MainWindow(object):
317
320
  self.gridLayout_5.addWidget(self.mysql_pwd_lineEdit, 4, 1, 1, 1)
318
321
  self.verticalLayout_8.addLayout(self.gridLayout_5)
319
322
  self.verticalLayout_9.addWidget(self.groupBox)
320
- spacerItem11 = QtWidgets.QSpacerItem(20, 10, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
323
+ spacerItem11 = QtWidgets.QSpacerItem(20, 10, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed)
321
324
  self.verticalLayout_9.addItem(spacerItem11)
325
+ self.groupBox_8 = QtWidgets.QGroupBox(self.tab_3)
326
+ self.groupBox_8.setObjectName("groupBox_8")
327
+ self.layoutWidget_2 = QtWidgets.QWidget(self.groupBox_8)
328
+ self.layoutWidget_2.setGeometry(QtCore.QRect(20, 30, 511, 208))
329
+ self.layoutWidget_2.setObjectName("layoutWidget_2")
330
+ self.gridLayout_7 = QtWidgets.QGridLayout(self.layoutWidget_2)
331
+ self.gridLayout_7.setContentsMargins(10, 10, 0, 10)
332
+ self.gridLayout_7.setObjectName("gridLayout_7")
333
+ self.clickhouse_test_pushButton = QtWidgets.QPushButton(self.layoutWidget_2)
334
+ self.clickhouse_test_pushButton.setObjectName("clickhouse_test_pushButton")
335
+ self.gridLayout_7.addWidget(self.clickhouse_test_pushButton, 2, 2, 1, 1)
336
+ self.label_52 = QtWidgets.QLabel(self.layoutWidget_2)
337
+ self.label_52.setObjectName("label_52")
338
+ self.gridLayout_7.addWidget(self.label_52, 5, 0, 1, 1)
339
+ self.label_54 = QtWidgets.QLabel(self.layoutWidget_2)
340
+ self.label_54.setObjectName("label_54")
341
+ self.gridLayout_7.addWidget(self.label_54, 1, 0, 1, 1)
342
+ self.label_51 = QtWidgets.QLabel(self.layoutWidget_2)
343
+ self.label_51.setObjectName("label_51")
344
+ self.gridLayout_7.addWidget(self.label_51, 2, 0, 1, 1)
345
+ self.label_53 = QtWidgets.QLabel(self.layoutWidget_2)
346
+ self.label_53.setObjectName("label_53")
347
+ self.gridLayout_7.addWidget(self.label_53, 0, 0, 1, 1)
348
+ self.clickhouse_pwd_lineEdit = QtWidgets.QLineEdit(self.layoutWidget_2)
349
+ self.clickhouse_pwd_lineEdit.setObjectName("clickhouse_pwd_lineEdit")
350
+ self.gridLayout_7.addWidget(self.clickhouse_pwd_lineEdit, 5, 1, 1, 1)
351
+ self.clickhouse_http_port_lineEdit = QtWidgets.QLineEdit(self.layoutWidget_2)
352
+ self.clickhouse_http_port_lineEdit.setObjectName("clickhouse_http_port_lineEdit")
353
+ self.gridLayout_7.addWidget(self.clickhouse_http_port_lineEdit, 2, 1, 1, 1)
354
+ self.clickhouse_usr_lineEdit = QtWidgets.QLineEdit(self.layoutWidget_2)
355
+ self.clickhouse_usr_lineEdit.setObjectName("clickhouse_usr_lineEdit")
356
+ self.gridLayout_7.addWidget(self.clickhouse_usr_lineEdit, 4, 1, 1, 1)
357
+ self.clickhouse_tmpdir_lineEdit = QtWidgets.QLineEdit(self.layoutWidget_2)
358
+ self.clickhouse_tmpdir_lineEdit.setObjectName("clickhouse_tmpdir_lineEdit")
359
+ self.gridLayout_7.addWidget(self.clickhouse_tmpdir_lineEdit, 0, 1, 1, 1)
360
+ self.clickhouse_ip_lineEdit = QtWidgets.QLineEdit(self.layoutWidget_2)
361
+ self.clickhouse_ip_lineEdit.setObjectName("clickhouse_ip_lineEdit")
362
+ self.gridLayout_7.addWidget(self.clickhouse_ip_lineEdit, 1, 1, 1, 1)
363
+ self.clickhouse_tmpdir_pushButton = QtWidgets.QPushButton(self.layoutWidget_2)
364
+ self.clickhouse_tmpdir_pushButton.setObjectName("clickhouse_tmpdir_pushButton")
365
+ self.gridLayout_7.addWidget(self.clickhouse_tmpdir_pushButton, 0, 2, 1, 1)
366
+ self.label_50 = QtWidgets.QLabel(self.layoutWidget_2)
367
+ self.label_50.setObjectName("label_50")
368
+ self.gridLayout_7.addWidget(self.label_50, 4, 0, 1, 1)
369
+ self.label_55 = QtWidgets.QLabel(self.layoutWidget_2)
370
+ self.label_55.setObjectName("label_55")
371
+ self.gridLayout_7.addWidget(self.label_55, 3, 0, 1, 1)
372
+ self.clickhouse_port_lineEdit = QtWidgets.QLineEdit(self.layoutWidget_2)
373
+ self.clickhouse_port_lineEdit.setObjectName("clickhouse_port_lineEdit")
374
+ self.gridLayout_7.addWidget(self.clickhouse_port_lineEdit, 3, 1, 1, 1)
375
+ self.verticalLayout_9.addWidget(self.groupBox_8)
322
376
  self.tabWidget.addTab(self.tab_3, "")
323
377
  self.tab_2 = QtWidgets.QWidget()
324
378
  self.tab_2.setObjectName("tab_2")
@@ -774,7 +828,7 @@ class Ui_MainWindow(object):
774
828
  MainWindow.setCentralWidget(self.centralwidget)
775
829
 
776
830
  self.retranslateUi(MainWindow)
777
- self.tabWidget.setCurrentIndex(0)
831
+ self.tabWidget.setCurrentIndex(1)
778
832
  QtCore.QMetaObject.connectSlotsByName(MainWindow)
779
833
 
780
834
  def retranslateUi(self, MainWindow):
@@ -809,6 +863,7 @@ class Ui_MainWindow(object):
809
863
  self.groupBox_4.setTitle(_translate("MainWindow", "存储引擎设置"))
810
864
  self.enable_hdf55_radioButton.setText(_translate("MainWindow", "使用HDF5(推荐)"))
811
865
  self.enable_mysql_radioButton.setText(_translate("MainWindow", "使用MYSQL"))
866
+ self.enable_clickhouse_radioButton.setText(_translate("MainWindow", "使用Clickhouse(捐赠权益)"))
812
867
  self.groupBox_3.setTitle(_translate("MainWindow", "HDF5存储设置"))
813
868
  self.hdf5_dir_pushButton.setText(_translate("MainWindow", "选择"))
814
869
  self.label.setText(_translate("MainWindow", "目标数据(HDF5)存放目录:"))
@@ -818,8 +873,17 @@ class Ui_MainWindow(object):
818
873
  self.label_13.setText(_translate("MainWindow", "密码"))
819
874
  self.mysql_tmpdir_pushButton.setText(_translate("MainWindow", "选择"))
820
875
  self.mysql_test_pushButton.setText(_translate("MainWindow", "测试连接"))
821
- self.label_20.setText(_translate("MainWindow", "临时文件目录:"))
876
+ self.label_20.setText(_translate("MainWindow", "临本机时文件目录:"))
822
877
  self.label_18.setText(_translate("MainWindow", "主机名/IP:"))
878
+ self.groupBox_8.setTitle(_translate("MainWindow", "Clickhouse设置(捐赠权益)"))
879
+ self.clickhouse_test_pushButton.setText(_translate("MainWindow", "测试连接"))
880
+ self.label_52.setText(_translate("MainWindow", "密码"))
881
+ self.label_54.setText(_translate("MainWindow", "主机名/IP:"))
882
+ self.label_51.setText(_translate("MainWindow", "HTTP端口号:"))
883
+ self.label_53.setText(_translate("MainWindow", "本机临时文件目录:"))
884
+ self.clickhouse_tmpdir_pushButton.setText(_translate("MainWindow", "选择"))
885
+ self.label_50.setText(_translate("MainWindow", "用户名:"))
886
+ self.label_55.setText(_translate("MainWindow", "TCP端口号"))
823
887
  self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_3), _translate("MainWindow", "存储设置"))
824
888
  self.label_43.setText(_translate("MainWindow", " 注:HDF5存储导入时,请关闭其他 hikyuu 进程,HDF5不支持同时读写!"))
825
889
  self.sched_import_pushButton.setText(_translate("MainWindow", "启动定时导入"))
@@ -914,13 +978,13 @@ class Ui_MainWindow(object):
914
978
  "hr { height: 1px; border-width: 0; }\n"
915
979
  "li.unchecked::marker { content: \"\\2610\"; }\n"
916
980
  "li.checked::marker { content: \"\\2612\"; }\n"
917
- "</style></head><body style=\" font-family:\'.AppleSystemUIFont\'; font-size:13pt; font-weight:400; font-style:normal;\">\n"
918
- "<p style=\" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">Hikyuu <span style=\" font-weight:700;\">专注于量化交易领域的核心技术构建,涵盖交易模型开发、极速计算引擎、高效回测框架及实盘拓展能力</span>,定位为量化交易的基础设施级计算引擎,为量化交易爱好者和专业提供高性能底层架构支持。随着社区规模扩大,项目持续迭代及技术支持事务逐渐分散了作者在策略研究上的精力。为保障项目的专注度与可持续性,现对捐赠用户提供部分额外功能作为回馈。诚挚期待社区伙伴的支持,您的参与都将直接助力 Hikyuu 的技术创新,共同推动量化交易基础设施的迭代升级。</p>\n"
919
- "<p style=\" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">捐赠功能以插件的方式提供,采用独立授权许可,完全在 hikyuu 之外,对喜欢自行编译扩展的朋友没有影响。因插件许可授权需要采集硬件信息,如有疑虑只要不申请试用许可和正式许可授权,不会触发硬件信息采集,如申请,视为同意采集。</p>\n"
920
- "<p style=\" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-weight:700;\">详情参见:</span><a href=\"https://hikyuu.readthedocs.io/zh-cn/latest/vip/vip-plan.html\"><span style=\" text-decoration: underline; color:#3586ff;\">捐赠权益</span></a><span style=\" font-weight:700;\"> ,感谢大家的支持!</span></p></body></html>"))
921
- self.label_47.setText(_translate("MainWindow", "申请试用许可(30天试用)"))
922
- self.label_48.setText(_translate("MainWindow", "加入知识星球,获取星球许可(可同时在3台设备上使用)"))
923
- self.label_49.setText(_translate("MainWindow", "当前授权信息"))
981
+ "</style></head><body style=\" font-family:\'Microsoft YaHei UI\'; font-size:9pt; font-weight:400; font-style:normal;\">\n"
982
+ "<p style=\" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-family:\'.AppleSystemUIFont\'; font-size:10pt;\">Hikyuu </span><span style=\" font-family:\'.AppleSystemUIFont\'; font-size:10pt; font-weight:700;\">专注于量化交易领域的核心技术构建,涵盖交易模型开发、极速计算引擎、高效回测框架及实盘拓展能力</span><span style=\" font-family:\'.AppleSystemUIFont\'; font-size:10pt;\">,定位为量化交易的基础设施级计算引擎,为量化交易爱好者和专业提供高性能底层架构支持。随着社区规模扩大,项目持续迭代及技术支持事务逐渐分散了作者在策略研究上的精力。为保障项目的专注度与可持续性,现对捐赠用户提供部分额外功能作为回馈。诚挚期待社区伙伴的支持,您的参与都将直接助力 Hikyuu 的技术创新,共同推动量化交易基础设施的迭代升级。</span></p>\n"
983
+ "<p style=\" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-family:\'.AppleSystemUIFont\'; font-size:10pt;\">捐赠功能以插件的方式提供,采用独立授权许可,完全在 hikyuu 之外,对喜欢自行编译扩展的朋友没有影响。因插件许可授权需要采集硬件信息,如有疑虑只要不申请试用许可和正式许可授权,不会触发硬件信息采集,如申请,视为同意采集。</span></p>\n"
984
+ "<p style=\" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-family:\'.AppleSystemUIFont\'; font-size:10pt; font-weight:700;\">详情参见:</span><a href=\"https://hikyuu.readthedocs.io/zh-cn/latest/vip/vip-plan.html\"><span style=\" font-family:\'.AppleSystemUIFont\'; font-size:10pt; text-decoration: underline; color:#3586ff;\">捐赠权益</span></a><span style=\" font-family:\'.AppleSystemUIFont\'; font-size:10pt; font-weight:700;\"> ,感谢大家的支持!</span></p></body></html>"))
985
+ self.label_47.setText(_translate("MainWindow", "申请捐赠试用(30天试用)"))
986
+ self.label_48.setText(_translate("MainWindow", "加入知识星球进行捐赠,可同时在3台设备上使用)"))
987
+ self.label_49.setText(_translate("MainWindow", "当前捐赠授权信息"))
924
988
  self.label_license.setText(_translate("MainWindow", "TextLabel"))
925
989
  self.label_45.setText(_translate("MainWindow", "电子邮件地址:"))
926
990
  self.fetch_trial_pushButton.setText(_translate("MainWindow", "申请试用许可"))