hikyuu 2.6.8.3__py3-none-manylinux2014_x86_64.whl → 2.6.9__py3-none-manylinux2014_x86_64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (198) hide show
  1. hikyuu/__init__.py +5 -12
  2. hikyuu/__init__.pyi +612 -587
  3. hikyuu/analysis/__init__.pyi +589 -563
  4. hikyuu/analysis/analysis.pyi +590 -564
  5. hikyuu/core.py +2 -0
  6. hikyuu/core.pyi +591 -565
  7. hikyuu/cpp/__init__.pyi +2 -2
  8. hikyuu/cpp/core310.pyi +446 -13
  9. hikyuu/cpp/core310.so +0 -0
  10. hikyuu/cpp/core311.pyi +440 -13
  11. hikyuu/cpp/core311.so +0 -0
  12. hikyuu/cpp/core312.pyi +440 -13
  13. hikyuu/cpp/core312.so +0 -0
  14. hikyuu/cpp/core313.pyi +446 -13
  15. hikyuu/cpp/core313.so +0 -0
  16. hikyuu/cpp/i18n/zh_CN/hikyuu.mo +0 -0
  17. hikyuu/cpp/libboost_charconv-mt.so +0 -0
  18. hikyuu/cpp/libboost_charconv-mt.so.1.88.0 +0 -0
  19. hikyuu/cpp/libboost_chrono-mt.so +0 -0
  20. hikyuu/cpp/libboost_chrono-mt.so.1.88.0 +0 -0
  21. hikyuu/cpp/libboost_date_time-mt.so +0 -0
  22. hikyuu/cpp/libboost_date_time-mt.so.1.88.0 +0 -0
  23. hikyuu/cpp/libboost_serialization-mt.so +0 -0
  24. hikyuu/cpp/libboost_serialization-mt.so.1.88.0 +0 -0
  25. hikyuu/cpp/libboost_system-mt.so +0 -0
  26. hikyuu/cpp/libboost_system-mt.so.1.88.0 +0 -0
  27. hikyuu/cpp/libboost_thread-mt.so +0 -0
  28. hikyuu/cpp/libboost_thread-mt.so.1.88.0 +0 -0
  29. hikyuu/cpp/libboost_wserialization-mt.so +0 -0
  30. hikyuu/cpp/libboost_wserialization-mt.so.1.88.0 +0 -0
  31. hikyuu/cpp/libhikyuu.so +0 -0
  32. hikyuu/cpp/libsqlite3.so +0 -0
  33. hikyuu/data/clickhouse_upgrade/createdb.sql +105 -105
  34. hikyuu/data/common.py +3 -3
  35. hikyuu/data/common_clickhouse.py +1 -1
  36. hikyuu/data/download_block.py +318 -0
  37. hikyuu/data/em_block_to_clickhouse.py +26 -74
  38. hikyuu/data/em_block_to_mysql.py +25 -75
  39. hikyuu/data/em_block_to_sqlite.py +26 -78
  40. hikyuu/data/hku_config_template.py +3 -3
  41. hikyuu/data/pytdx_to_clickhouse.py +15 -11
  42. hikyuu/data/pytdx_to_h5.py +6 -2
  43. hikyuu/data/pytdx_to_mysql.py +5 -1
  44. hikyuu/data/pytdx_weight_to_clickhouse.py +1 -1
  45. hikyuu/data/pytdx_weight_to_mysql.py +1 -1
  46. hikyuu/data/pytdx_weight_to_sqlite.py +1 -1
  47. hikyuu/data/zh_bond10_to_clickhouse.py +1 -1
  48. hikyuu/draw/drawplot/__init__.pyi +8 -8
  49. hikyuu/draw/drawplot/bokeh_draw.pyi +603 -578
  50. hikyuu/draw/drawplot/common.pyi +1 -1
  51. hikyuu/draw/drawplot/echarts_draw.pyi +605 -580
  52. hikyuu/draw/drawplot/matplotlib_draw.py +4 -74
  53. hikyuu/draw/drawplot/matplotlib_draw.pyi +615 -590
  54. hikyuu/draw/elder.pyi +11 -11
  55. hikyuu/draw/kaufman.pyi +18 -18
  56. hikyuu/draw/volume.pyi +10 -10
  57. hikyuu/examples/notebook/Demo/Demo1.ipynb +48 -33
  58. hikyuu/extend.pyi +599 -573
  59. hikyuu/fetcher/stock/zh_block_em.py +50 -18
  60. hikyuu/gui/HikyuuTDX.py +81 -30
  61. hikyuu/gui/data/CollectSpotThread.py +1 -1
  62. hikyuu/gui/data/EscapetimeThread.py +8 -14
  63. hikyuu/gui/data/ImportBlockInfoTask.py +3 -10
  64. hikyuu/gui/data/MainWindow.py +1168 -715
  65. hikyuu/gui/data/SchedImportThread.py +2 -2
  66. hikyuu/gui/data/UsePytdxImportToH5Thread.py +3 -3
  67. hikyuu/gui/data/UseQmtImportToH5Thread.py +2 -2
  68. hikyuu/gui/data/UseTdxImportToH5Thread.py +3 -3
  69. hikyuu/gui/data/tool.py +32 -25
  70. hikyuu/gui/dataserver.py +5 -3
  71. hikyuu/gui/importdata.py +4 -0
  72. hikyuu/hub.pyi +6 -6
  73. hikyuu/include/hikyuu/DataType.h +4 -16
  74. hikyuu/include/hikyuu/KData.h +6 -3
  75. hikyuu/include/hikyuu/KDataPrivatedBufferImp.h +1 -1
  76. hikyuu/include/hikyuu/KDataSharedBufferImp.h +1 -1
  77. hikyuu/include/hikyuu/KQuery.h +2 -2
  78. hikyuu/include/hikyuu/Stock.h +3 -0
  79. hikyuu/include/hikyuu/StockManager.h +13 -3
  80. hikyuu/include/hikyuu/config.h +3 -0
  81. hikyuu/include/hikyuu/data_driver/BaseInfoDriver.h +8 -0
  82. hikyuu/include/hikyuu/data_driver/BlockInfoDriver.h +6 -0
  83. hikyuu/include/hikyuu/data_driver/KDataDriver.h +26 -1
  84. hikyuu/include/hikyuu/data_driver/base_info/mysql/MySQLBaseInfoDriver.h +1 -1
  85. hikyuu/include/hikyuu/data_driver/base_info/sqlite/SQLiteBaseInfoDriver.h +1 -1
  86. hikyuu/include/hikyuu/data_driver/block_info/mysql/MySQLBlockInfoDriver.h +2 -1
  87. hikyuu/include/hikyuu/data_driver/block_info/qianlong/QLBlockInfoDriver.h +2 -1
  88. hikyuu/include/hikyuu/data_driver/block_info/sqlite/SQLiteBlockInfoDriver.h +2 -1
  89. hikyuu/include/hikyuu/data_driver/kdata/DoNothingKDataDriver.h +1 -1
  90. hikyuu/include/hikyuu/data_driver/kdata/cvs/KDataTempCsvDriver.h +1 -1
  91. hikyuu/include/hikyuu/data_driver/kdata/hdf5/H5KDataDriver.h +1 -1
  92. hikyuu/include/hikyuu/data_driver/kdata/mysql/MySQLKDataDriver.h +1 -1
  93. hikyuu/include/hikyuu/data_driver/kdata/sqlite/SQLiteKDataDriver.h +1 -1
  94. hikyuu/include/hikyuu/data_driver/kdata/tdx/TdxKDataDriver.h +1 -1
  95. hikyuu/include/hikyuu/hikyuu.h +1 -1
  96. hikyuu/include/hikyuu/indicator/build_in.h +1 -0
  97. hikyuu/include/hikyuu/indicator/crt/CYCLE.h +4 -4
  98. hikyuu/include/hikyuu/indicator/crt/HSL.h +2 -2
  99. hikyuu/include/hikyuu/indicator/crt/QUANTILE_TRUNC.h +30 -0
  100. hikyuu/include/hikyuu/indicator/crt/TURNOVER.h +1 -0
  101. hikyuu/include/hikyuu/indicator/crt/ZSCORE.h +2 -2
  102. hikyuu/include/hikyuu/indicator/imp/IQuantileTrunc.h +25 -0
  103. hikyuu/include/hikyuu/lang.h +15 -2
  104. hikyuu/include/hikyuu/misc.h +38 -0
  105. hikyuu/include/hikyuu/plugin/dataserver.h +2 -1
  106. hikyuu/include/hikyuu/plugin/extind.h +37 -0
  107. hikyuu/include/hikyuu/plugin/hkuextra.h +0 -18
  108. hikyuu/include/hikyuu/plugin/hkuviews.h +36 -0
  109. hikyuu/include/hikyuu/plugin/interface/DataServerPluginInterface.h +2 -2
  110. hikyuu/include/hikyuu/plugin/interface/ExtendIndicatorsPluginInterface.h +12 -0
  111. hikyuu/include/hikyuu/plugin/interface/HkuExtraPluginInterface.h +0 -14
  112. hikyuu/include/hikyuu/plugin/interface/HkuViewsPluginInterface.h +34 -0
  113. hikyuu/include/hikyuu/plugin/interface/plugins.h +8 -1
  114. hikyuu/include/hikyuu/python/pybind_utils.h +8 -3
  115. hikyuu/include/hikyuu/strategy/RunSystemInStrategy.h +3 -0
  116. hikyuu/include/hikyuu/trade_manage/Performance.h +4 -4
  117. hikyuu/include/hikyuu/trade_manage/TradeManagerBase.h +10 -1
  118. hikyuu/include/hikyuu/trade_sys/moneymanager/imp/FixedCapitalFundsMM.h +0 -4
  119. hikyuu/include/hikyuu/trade_sys/multifactor/MultiFactorBase.h +36 -3
  120. hikyuu/include/hikyuu/trade_sys/multifactor/NormalizeBase.h +125 -0
  121. hikyuu/include/hikyuu/trade_sys/multifactor/ScoresFilterBase.h +125 -0
  122. hikyuu/include/hikyuu/trade_sys/multifactor/build_in.h +3 -0
  123. hikyuu/include/hikyuu/trade_sys/multifactor/buildin_norm.h +36 -0
  124. hikyuu/include/hikyuu/trade_sys/multifactor/buildin_scfilter.h +51 -0
  125. hikyuu/include/hikyuu/trade_sys/multifactor/filter/GroupSCFilter.h +24 -0
  126. hikyuu/include/hikyuu/trade_sys/multifactor/filter/IgnoreLessOrEqualValueSCFilter.h +24 -0
  127. hikyuu/include/hikyuu/trade_sys/multifactor/filter/IgnoreNanSCFilter.h +24 -0
  128. hikyuu/include/hikyuu/trade_sys/multifactor/filter/MinAmountPercentSCFilter.h +25 -0
  129. hikyuu/include/hikyuu/trade_sys/multifactor/filter/PriceSCFilter.h +24 -0
  130. hikyuu/include/hikyuu/trade_sys/multifactor/filter/TopNSCFilter.h +24 -0
  131. hikyuu/include/hikyuu/trade_sys/multifactor/filter/__init__.py +1 -0
  132. hikyuu/include/hikyuu/trade_sys/multifactor/imp/EqualWeightMultiFactor.h +1 -1
  133. hikyuu/include/hikyuu/trade_sys/multifactor/imp/ICIRMultiFactor.h +1 -1
  134. hikyuu/include/hikyuu/trade_sys/multifactor/imp/ICMultiFactor.h +1 -1
  135. hikyuu/include/hikyuu/trade_sys/multifactor/imp/WeightMultiFactor.h +1 -1
  136. hikyuu/include/hikyuu/trade_sys/multifactor/normalize/NormMinMax.h +23 -0
  137. hikyuu/include/hikyuu/trade_sys/multifactor/normalize/NormQuantile.h +28 -0
  138. hikyuu/include/hikyuu/trade_sys/multifactor/normalize/NormQuantileUniform.h +28 -0
  139. hikyuu/include/hikyuu/trade_sys/multifactor/normalize/NormZScore.h +25 -0
  140. hikyuu/include/hikyuu/trade_sys/multifactor/normalize/__init__.py +1 -0
  141. hikyuu/include/hikyuu/trade_sys/multifactor/normalize/quantile_trunc.h +16 -0
  142. hikyuu/include/hikyuu/trade_sys/portfolio/Portfolio.h +7 -0
  143. hikyuu/include/hikyuu/trade_sys/portfolio/imp/SimplePortfolio.h +7 -0
  144. hikyuu/include/hikyuu/trade_sys/portfolio/imp/WithoutAFPortfolio.h +7 -0
  145. hikyuu/include/hikyuu/trade_sys/selector/SelectorBase.h +49 -0
  146. hikyuu/include/hikyuu/trade_sys/selector/build_in.h +1 -0
  147. hikyuu/include/hikyuu/trade_sys/selector/crt/SE_MultiFactor2.h +40 -0
  148. hikyuu/include/hikyuu/trade_sys/selector/imp/MultiFactorSelector.h +0 -3
  149. hikyuu/include/hikyuu/trade_sys/selector/imp/MultiFactorSelector2.h +49 -0
  150. hikyuu/include/hikyuu/trade_sys/selector/imp/logic/OperatorSelector.h +1 -1
  151. hikyuu/include/hikyuu/trade_sys/selector/imp/logic/OperatorValueSelector.h +1 -1
  152. hikyuu/include/hikyuu/trade_sys/signal/imp/BandSignal2.h +0 -4
  153. hikyuu/include/hikyuu/trade_sys/signal/imp/logic/AddValueSignal.h +2 -2
  154. hikyuu/include/hikyuu/trade_sys/signal/imp/logic/DivValueSignal.h +2 -2
  155. hikyuu/include/hikyuu/trade_sys/signal/imp/logic/MulValueSignal.h +2 -2
  156. hikyuu/include/hikyuu/trade_sys/signal/imp/logic/OperatorSignal.h +1 -1
  157. hikyuu/include/hikyuu/trade_sys/signal/imp/logic/OperatorValueSignal.h +4 -4
  158. hikyuu/include/hikyuu/trade_sys/signal/imp/logic/SubValueSignal.h +2 -2
  159. hikyuu/include/hikyuu/trade_sys/system/System.h +14 -1
  160. hikyuu/include/hikyuu/utilities/SpendTimer.h +17 -7
  161. hikyuu/include/hikyuu/utilities/arithmetic.h +55 -0
  162. hikyuu/include/hikyuu/utilities/db_connect/mysql/MySQLConnect.h +1 -1
  163. hikyuu/include/hikyuu/utilities/db_connect/mysql/MySQLStatement.h +1 -1
  164. hikyuu/include/hikyuu/utilities/db_connect/sqlite/SQLiteConnect.h +1 -1
  165. hikyuu/include/hikyuu/utilities/db_connect/sqlite/SQLiteStatement.h +1 -1
  166. hikyuu/include/hikyuu/utilities/plugin/PluginLoader.h +4 -1
  167. hikyuu/include/hikyuu/version.h +4 -4
  168. hikyuu/plugin/libbacktest.so +0 -0
  169. hikyuu/plugin/libclickhousedriver.so +0 -0
  170. hikyuu/plugin/libdataserver.so +0 -0
  171. hikyuu/plugin/libdevice.so +0 -0
  172. hikyuu/plugin/libextind.so +0 -0
  173. hikyuu/plugin/libhkuextra.so +0 -0
  174. hikyuu/plugin/libhkuviews.so +0 -0
  175. hikyuu/plugin/libimport2hdf5.so +0 -0
  176. hikyuu/plugin/libtmreport.so +0 -0
  177. hikyuu/trade_manage/__init__.pyi +602 -577
  178. hikyuu/trade_manage/broker.pyi +3 -3
  179. hikyuu/trade_manage/broker_easytrader.pyi +1 -1
  180. hikyuu/trade_manage/trade.pyi +602 -577
  181. hikyuu/util/__init__.pyi +1 -1
  182. hikyuu/util/singleton.pyi +1 -1
  183. {hikyuu-2.6.8.3.dist-info → hikyuu-2.6.9.dist-info}/METADATA +13 -13
  184. {hikyuu-2.6.8.3.dist-info → hikyuu-2.6.9.dist-info}/RECORD +187 -158
  185. {hikyuu-2.6.8.3.dist-info → hikyuu-2.6.9.dist-info}/top_level.txt +2 -1
  186. hikyuu/cpp/core39.pyi +0 -14385
  187. hikyuu/cpp/core39.so +0 -0
  188. hikyuu/data_driver/__init__.py +0 -49
  189. hikyuu/data_driver/jqdata_data_driver.py +0 -277
  190. hikyuu/data_driver/pytdx_data_driver.py +0 -292
  191. hikyuu/fetcher/stock/zh_stock_a_huatai.py +0 -51
  192. hikyuu/fetcher/stock/zh_stock_a_pytdx.py +0 -129
  193. hikyuu/gui/data/CollectToMemThread.py +0 -123
  194. hikyuu/gui/data/CollectToMySQLThread.py +0 -178
  195. hikyuu/gui/start_huatai_insight.py +0 -510
  196. hikyuu/tools/update_block_info.py +0 -168
  197. {hikyuu-2.6.8.3.dist-info → hikyuu-2.6.9.dist-info}/WHEEL +0 -0
  198. {hikyuu-2.6.8.3.dist-info → hikyuu-2.6.9.dist-info}/entry_points.txt +0 -0
@@ -17,7 +17,7 @@ from hikyuu.util import *
17
17
  em_num_per_page = 100
18
18
 
19
19
 
20
- @hku_catch(ret=[], trace=True)
20
+ @hku_catch(ret=[], trace=False)
21
21
  def get_hybk_names():
22
22
  """获取所有行业(板块代码,板块名称)列表"""
23
23
  url = "https://19.push2.eastmoney.com/api/qt/clist/get"
@@ -50,7 +50,7 @@ def get_hybk_names():
50
50
  return ret
51
51
 
52
52
 
53
- @hku_catch(ret=[], trace=True)
53
+ @hku_catch(ret=[], trace=False)
54
54
  def get_hybk_cons_code(blk_code):
55
55
  "获取指定行业板块成分代码列表"
56
56
  url = "http://30.push2.eastmoney.com/api/qt/clist/get"
@@ -83,16 +83,19 @@ def get_hybk_cons_code(blk_code):
83
83
  return ret
84
84
 
85
85
 
86
- @hku_catch(ret={}, trace=True)
86
+ @hku_catch(ret={}, trace=False)
87
87
  def get_all_hybk_info(code_market_dict, sep=""):
88
88
  """获取所有行业板块列表"""
89
89
  blk_list = get_hybk_names()
90
+ time.sleep(random.uniform(1, 3))
90
91
  ret = {}
91
- for blk in blk_list:
92
+ total = len(blk_list)
93
+ for i, blk in enumerate(blk_list):
92
94
  stk_codes = get_hybk_cons_code(blk[0])
93
- hku_info(f"获取行业板块{blk[1]}成分: {len(stk_codes)}")
95
+ hku_info(f"{i}|{total} 获取行业板块{blk[1]}成分: {len(stk_codes)}")
94
96
  ret[blk[1]] = [
95
97
  f"{code_market_dict[stk_code]}{sep}{stk_code}" for stk_code in stk_codes if stk_code in code_market_dict]
98
+ time.sleep(random.uniform(1, 3))
96
99
  return ret
97
100
 
98
101
 
@@ -431,21 +434,23 @@ def stock_board_concept_cons_em(symbol: str = "融资融券") -> pd.DataFrame:
431
434
  return temp_df
432
435
 
433
436
 
434
- @hku_catch(ret={}, trace=True)
437
+ @hku_catch(ret={}, trace=False)
435
438
  def get_all_gnbk_info(code_market_dict, sep=""):
436
439
  """获取所有概念版本列表"""
437
440
  blk_names = stock_board_concept_name_em()['板块名称']
438
441
  ret = {}
442
+ total = len(blk_names)
439
443
  for i, blk_name in enumerate(blk_names):
440
444
  stk_codes = stock_board_concept_cons_em(blk_name)
441
445
  stk_codes = stk_codes['代码'].to_list()
442
- hku_info(f"{i} 获取概念板块{blk_name}成分: {len(stk_codes)}")
446
+ hku_info(f"{i}|{total} 获取概念板块{blk_name}成分: {len(stk_codes)}")
443
447
  ret[blk_name] = [
444
448
  f"{code_market_dict[stk_code]}{sep}{stk_code}" for stk_code in stk_codes if stk_code in code_market_dict]
449
+ time.sleep(random.uniform(1, 3))
445
450
  return ret
446
451
 
447
452
 
448
- @hku_catch(ret=[], trace=True)
453
+ @hku_catch(ret=[], trace=False)
449
454
  def get_dybk_names():
450
455
  """获取所有地域板块名称列表"""
451
456
  url = "http://13.push2.eastmoney.com/api/qt/clist/get"
@@ -478,7 +483,7 @@ def get_dybk_names():
478
483
  return ret
479
484
 
480
485
 
481
- @hku_catch(ret={}, trace=True)
486
+ @hku_catch(ret={}, trace=False)
482
487
  def get_all_dybk_info(code_market_dict, sep=""):
483
488
  """获取所有地域板块列表"""
484
489
  blk_list = get_dybk_names()
@@ -499,10 +504,12 @@ def get_all_dybk_info(code_market_dict, sep=""):
499
504
  }
500
505
 
501
506
  ret = {}
502
- for v in blk_list:
507
+ total = len(blk_list)
508
+ for i, v in enumerate(blk_list):
503
509
  blk_code, blk_name = v[0], v[1]
504
510
  params["fs"] = f"b:{blk_code} f:!50"
505
511
  params["pn"] = 1
512
+ time.sleep(random.uniform(1, 3))
506
513
  r = requests.get(url, params=params, timeout=15)
507
514
  data = r.json()
508
515
  if data["data"] is None:
@@ -522,15 +529,34 @@ def get_all_dybk_info(code_market_dict, sep=""):
522
529
  ret[blk_name].extend(
523
530
  [f"{code_market_dict[v['f12']]}{sep}{v['f12']}" for v in stk_json if v["f12"] in code_market_dict])
524
531
  time.sleep(random.uniform(1, 3))
525
- hku_info(f'获取地域板块{blk_name}成分: {len(ret[blk_name])}')
532
+ hku_info(f'{i}|{total} 获取地域板块{blk_name}成分: {len(ret[blk_name])}')
526
533
 
527
534
  return ret
528
535
 
529
536
 
530
- @hku_catch(ret={}, trace=True)
537
+ @hku_catch(ret={}, trace=False)
531
538
  def get_all_zsbk_info(code_market_dict, sep=""):
532
539
  """获取所有指数成分股列表"""
533
540
  blk_info = ak.index_stock_info()
541
+ blk_info['index_code'] = blk_info['index_code'].astype(str) # 确保是字符串类型
542
+ df_000 = blk_info[blk_info['index_code'].str.startswith('000')].reset_index(drop=True) # 000前缀
543
+ df_399 = blk_info[blk_info['index_code'].str.startswith('399')].reset_index(drop=True) # 399前缀
544
+
545
+ # 2. 交替合并两个DataFrame
546
+ merged_rows = []
547
+ max_length = max(len(df_000), len(df_399)) # 取两个DataFrame的最大长度
548
+
549
+ for i in range(max_length):
550
+ # 先加000前缀的行(如果存在)
551
+ if i < len(df_000):
552
+ merged_rows.append(df_000.iloc[i])
553
+ # 再加399前缀的行(如果存在)
554
+ if i < len(df_399):
555
+ merged_rows.append(df_399.iloc[i])
556
+
557
+ # 3. 转换为DataFrame
558
+ blk_info = pd.DataFrame(merged_rows).reset_index(drop=True)
559
+
534
560
  blk_codes = blk_info["index_code"]
535
561
  blk_names = blk_info["display_name"]
536
562
  ret = {}
@@ -542,17 +568,23 @@ def get_all_zsbk_info(code_market_dict, sep=""):
542
568
  # 沪深指数有重复,避免深指覆盖
543
569
  if blk_name in ret:
544
570
  continue
571
+
572
+ time.sleep(random.uniform(1, 3))
545
573
  try:
546
- stk_codes = ak.index_stock_cons_csindex(symbol=blk_code)
547
- stk_codes = stk_codes['成分券代码'].to_list()
548
- hku_info("{} 获取指数板块{}成分: {}", i, blk_name, len(stk_codes))
574
+ if blk_code[:3] == "399":
575
+ stk_codes = ak.index_stock_cons(symbol=blk_code)
576
+ stk_codes = stk_codes['品种代码'].to_list()
577
+ else:
578
+ stk_codes = ak.index_stock_cons_csindex(symbol=blk_code)
579
+ stk_codes = stk_codes['成分券代码'].to_list()
580
+ hku_info("{}|{} 获取指数板块 {}|{} 成分: {}", i, total, blk_code, blk_name, len(stk_codes))
549
581
  ret[blk_name] = [
550
582
  f"{code_market_dict[stk_code]}{sep}{stk_code}" for stk_code in stk_codes if stk_code in code_market_dict]
551
583
  except KeyboardInterrupt:
552
584
  break
553
- except:
554
- # print("Failed!", blk_code, blk_name)
555
- pass
585
+ except Exception as e:
586
+ print(f"Failed! {i}, {blk_code}, {blk_name}")
587
+ # raise e
556
588
  return ret
557
589
 
558
590
 
hikyuu/gui/HikyuuTDX.py CHANGED
@@ -12,11 +12,10 @@ from logging.handlers import QueueListener
12
12
  # 优先加载,处理 VS 17.10 升级后依赖 dll 不兼容问题
13
13
  import hikyuu
14
14
 
15
- import PyQt5
16
-
17
- from PyQt5.QtWidgets import QApplication, QMainWindow, QFileDialog, QMessageBox
18
- from PyQt5.QtCore import pyqtSlot, QObject, pyqtSignal
19
- from PyQt5.QtGui import QIcon, QTextCursor, QFont, QPalette, QPixmap
15
+ # 替换PyQt5导入为PySide6
16
+ from PySide6.QtWidgets import QApplication, QMainWindow, QFileDialog, QMessageBox
17
+ from PySide6.QtCore import Slot, QObject, Signal
18
+ from PySide6.QtGui import QIcon, QTextCursor, QFont, QPalette, QPixmap
20
19
 
21
20
  import mysql.connector
22
21
  from mysql.connector import errorcode
@@ -43,7 +42,7 @@ from hikyuu.util import *
43
42
 
44
43
  class EmittingStream(QObject):
45
44
  """输出重定向至QT"""
46
- textWritten = pyqtSignal(str)
45
+ textWritten = Signal(str)
47
46
 
48
47
  def write(self, text):
49
48
  self.textWritten.emit(str(text))
@@ -249,7 +248,7 @@ class MyMainWindow(QMainWindow, Ui_MainWindow):
249
248
  except:
250
249
  pass
251
250
 
252
- @pyqtSlot()
251
+ @Slot()
253
252
  def on_save_pushButton_clicked(self):
254
253
  try:
255
254
  self.saveConfig()
@@ -333,7 +332,22 @@ class MyMainWindow(QMainWindow, Ui_MainWindow):
333
332
  icon = QIcon(f"{current_dir}/images/hikyuu_small.png")
334
333
  star_img = QPixmap(f"{current_dir}/images/star.png")
335
334
  self.label_44.setPixmap(star_img)
335
+ # 修改 label_46 的 HTML 文本,直接在 HTML 中设置字体大小
336
+
337
+ label_46_txt = """<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
338
+ <html><head><meta name="qrichtext" content="1" /><meta charset="utf-8" /><style type="text/css">
339
+ p, li { white-space: pre-wrap; }
340
+ hr { height: 1px; border-width: 0; }
341
+ li.unchecked::marker { content: "\2610"; }
342
+ li.checked::marker { content: "\2612"; }
343
+ </style></head><body style="font-weight:400; font-style:normal;">
344
+ <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span>Hikyuu </span><span style="font-weight:700;">专注于量化交易领域的核心技术构建,涵盖交易模型开发、极速计算引擎、高效回测框架及实盘拓展能力</span><span>,定位为量化交易计算引擎,为量化交易爱好者提供高性能底层架构支持。随着社区规模扩大,分散了作者在策略研究上的精力。为保障项目的可持续性,现对捐赠用户提供部分额外功能作为回馈,感谢社区伙伴的支持!</span></p>
345
+ <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span>捐赠功能以插件的方式提供,采用独立授权许可,完全在 hikyuu 之外,对喜欢自行编译扩展的朋友没有影响。因插件许可授权需要采集硬件信息,如有疑虑只要不申请试用许可和正式许可授权,不会触发硬件信息采集,如申请,视为同意采集。</span></p>
346
+ <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span>详情参见:</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>
347
+ """
348
+ self.label_46.setText(label_46_txt)
336
349
  self.label_46.setOpenExternalLinks(True)
350
+
337
351
  self.label_license.setText(view_license())
338
352
  self.fetch_trial_pushButton.setEnabled(not is_valid_license())
339
353
 
@@ -434,6 +448,7 @@ class MyMainWindow(QMainWindow, Ui_MainWindow):
434
448
  if (not is_valid_license()) or hdf5_enable or mysql_enable:
435
449
  clickhouse_enable = False
436
450
  self.enable_clickhouse_radioButton.setChecked(clickhouse_enable)
451
+ self.enable_clickhouse_radioButton.setEnabled(is_valid_license())
437
452
  self.clickhouse_tmpdir_lineEdit.setText(import_config.get('clickhouse', 'tmpdir', fallback='d:/stock'))
438
453
  self.clickhouse_tmpdir_pushButton.setEnabled(clickhouse_enable)
439
454
  clickhouse_ip = import_config.get('clickhouse', 'host', fallback='127.0.0.1')
@@ -618,7 +633,7 @@ class MyMainWindow(QMainWindow, Ui_MainWindow):
618
633
  '5MIN': self.hdf5_5min_progressBar
619
634
  }
620
635
 
621
- @pyqtSlot()
636
+ @Slot()
622
637
  def on_fetch_trial_pushButton_clicked(self):
623
638
  email = self.email_lineEdit.text()
624
639
  info = fetch_trial_license(email)
@@ -626,7 +641,7 @@ class MyMainWindow(QMainWindow, Ui_MainWindow):
626
641
  self.label_license.setText(view_license())
627
642
  self.fetch_trial_pushButton.setEnabled(not is_valid_license())
628
643
 
629
- @pyqtSlot()
644
+ @Slot()
630
645
  def on_pytdx_radioButton_clicked(self):
631
646
  if self.pytdx_radioButton.isChecked():
632
647
  self.tdx_radioButton.setChecked(False)
@@ -634,7 +649,7 @@ class MyMainWindow(QMainWindow, Ui_MainWindow):
634
649
  self.use_download = 'pytdx'
635
650
  self.on_tdx_or_pytdx_toggled()
636
651
 
637
- @pyqtSlot()
652
+ @Slot()
638
653
  def on_tdx_radioButton_clicked(self):
639
654
  if self.tdx_radioButton.isChecked():
640
655
  self.pytdx_radioButton.setChecked(False)
@@ -642,6 +657,7 @@ class MyMainWindow(QMainWindow, Ui_MainWindow):
642
657
  self.use_download = 'tdx'
643
658
  self.on_tdx_or_pytdx_toggled()
644
659
 
660
+ @Slot()
645
661
  def on_qmt_radioButton_clicked(self):
646
662
  if self.qmt_radioButton.isChecked():
647
663
  self.tdx_radioButton.setChecked(False)
@@ -675,7 +691,7 @@ class MyMainWindow(QMainWindow, Ui_MainWindow):
675
691
  self.time_start_dateEdit.setEnabled(False)
676
692
  self.use_tdx_number_spinBox.setEnabled(False)
677
693
 
678
- @pyqtSlot()
694
+ @Slot()
679
695
  def on_select_tdx_dir_pushButton_clicked(self):
680
696
  dlg = QFileDialog()
681
697
  dlg.setFileMode(QFileDialog.Directory)
@@ -685,7 +701,7 @@ class MyMainWindow(QMainWindow, Ui_MainWindow):
685
701
  dirname = dlg.selectedFiles()
686
702
  self.tdx_dir_lineEdit.setText(dirname[0])
687
703
 
688
- @pyqtSlot()
704
+ @Slot()
689
705
  def on_hdf5_dir_pushButton_clicked(self):
690
706
  dlg = QFileDialog()
691
707
  dlg.setFileMode(QFileDialog.Directory)
@@ -695,21 +711,21 @@ class MyMainWindow(QMainWindow, Ui_MainWindow):
695
711
  dirname = dlg.selectedFiles()
696
712
  self.hdf5_dir_lineEdit.setText(dirname[0])
697
713
 
698
- @pyqtSlot()
714
+ @Slot()
699
715
  def on_enable_hdf55_radioButton_clicked(self):
700
716
  if self.enable_hdf55_radioButton.isChecked():
701
717
  self.enable_mysql_radioButton.setChecked(False)
702
718
  self.enable_clickhouse_radioButton.setChecked(False)
703
719
  self.on_enable_database_toggled(hdf5=True, mysql=False, clickhouse=False)
704
720
 
705
- @pyqtSlot()
721
+ @Slot()
706
722
  def on_enable_mysql_radioButton_clicked(self):
707
723
  if self.enable_mysql_radioButton.isChecked():
708
724
  self.enable_hdf55_radioButton.setChecked(False)
709
725
  self.enable_clickhouse_radioButton.setChecked(False)
710
726
  self.on_enable_database_toggled(hdf5=False, mysql=True, clickhouse=False)
711
727
 
712
- @pyqtSlot()
728
+ @Slot()
713
729
  def on_enable_clickhouse_radioButton_clicked(self):
714
730
  if self.enable_clickhouse_radioButton.isChecked():
715
731
  self.enable_hdf55_radioButton.setChecked(False)
@@ -732,7 +748,7 @@ class MyMainWindow(QMainWindow, Ui_MainWindow):
732
748
  self.clickhouse_test_pushButton.setEnabled(clickhouse)
733
749
  self.clickhouse_tmpdir_pushButton.setEnabled(clickhouse)
734
750
 
735
- @pyqtSlot()
751
+ @Slot()
736
752
  def on_mysql_tmpdir_pushButton_clicked(self):
737
753
  dlg = QFileDialog()
738
754
  dlg.setFileMode(QFileDialog.Directory)
@@ -742,7 +758,7 @@ class MyMainWindow(QMainWindow, Ui_MainWindow):
742
758
  dirname = dlg.selectedFiles()
743
759
  self.mysql_tmpdir_lineEdit.setText(dirname[0])
744
760
 
745
- @pyqtSlot()
761
+ @Slot()
746
762
  def on_clickhouse_tmpdir_pushButton_clicked(self):
747
763
  if not is_valid_license():
748
764
  QMessageBox.critical(self, "clickhouse引擎", "需要捐赠授权才能使用clickhouse引擎")
@@ -756,7 +772,7 @@ class MyMainWindow(QMainWindow, Ui_MainWindow):
756
772
  dirname = dlg.selectedFiles()
757
773
  self.clickhouse_tmpdir_lineEdit.setText(dirname[0])
758
774
 
759
- @pyqtSlot()
775
+ @Slot()
760
776
  def on_mysql_test_pushButton_clicked(self):
761
777
  """测试数据库连接"""
762
778
  db_config = {
@@ -780,7 +796,7 @@ class MyMainWindow(QMainWindow, Ui_MainWindow):
780
796
 
781
797
  QMessageBox.about(self, "测试数据库连接", " 连接成功!")
782
798
 
783
- @pyqtSlot()
799
+ @Slot()
784
800
  def on_clickhouse_test_pushButton_clicked(self):
785
801
  """测试数据库连接"""
786
802
  db_config = {
@@ -821,7 +837,8 @@ class MyMainWindow(QMainWindow, Ui_MainWindow):
821
837
  if msg_name == 'ESCAPE_TIME':
822
838
  self.escape_time = msg_task_name
823
839
  self.import_status_label.setText(
824
- "耗时:{:>.2f} 秒 ({:>.2f}分钟) {}".format(self.escape_time, self.escape_time / 60, datetime.datetime.now())
840
+ "耗时:{:>.2f} 秒 ({:>.2f}分钟) {}".format(
841
+ self.escape_time, self.escape_time / 60, datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
825
842
  )
826
843
 
827
844
  elif msg_name == 'HDF5_IMPORT':
@@ -890,7 +907,7 @@ class MyMainWindow(QMainWindow, Ui_MainWindow):
890
907
  if msg[2] != 'FINISHED':
891
908
  self.import_detail_textEdit.append(msg[2])
892
909
 
893
- @pyqtSlot()
910
+ @Slot()
894
911
  def on_start_import_pushButton_clicked(self):
895
912
  try:
896
913
  self.saveConfig()
@@ -965,7 +982,7 @@ class MyMainWindow(QMainWindow, Ui_MainWindow):
965
982
  self.escape_time_thread.message.connect(self.on_message_from_thread)
966
983
  self.escape_time_thread.start()
967
984
 
968
- @pyqtSlot()
985
+ @Slot()
969
986
  def on_sched_import_pushButton_clicked(self):
970
987
  self.sched_import_pushButton.setEnabled(False)
971
988
  if self._is_sched_import_running:
@@ -993,7 +1010,7 @@ class MyMainWindow(QMainWindow, Ui_MainWindow):
993
1010
  self.sched_import_pushButton.setText("停止定时导入")
994
1011
  self.sched_import_pushButton.setEnabled(True)
995
1012
 
996
- @pyqtSlot()
1013
+ @Slot()
997
1014
  def on_collect_start_pushButton_clicked(self):
998
1015
  if self._is_collect_running:
999
1016
  if self.collect_spot_thread is not None and self.collect_spot_thread.isRunning():
@@ -1033,6 +1050,41 @@ def start():
1033
1050
  sys.exit(app.exec())
1034
1051
 
1035
1052
 
1053
+ def is_font_installed(font_name):
1054
+ """检查字体是否安装"""
1055
+ if sys.platform == "win32":
1056
+ try:
1057
+ import winreg
1058
+ # 打开注册表中的字体项
1059
+ key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, r"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts")
1060
+ i = 0
1061
+ while True:
1062
+ try:
1063
+ name, value, _ = winreg.EnumValue(key, i)
1064
+ if font_name in name:
1065
+ winreg.CloseKey(key)
1066
+ return True
1067
+ i += 1
1068
+ except WindowsError:
1069
+ break
1070
+ winreg.CloseKey(key)
1071
+ except:
1072
+ # 如果注册表检查失败,则尝试创建字体对象
1073
+ try:
1074
+ f = QFont(font_name)
1075
+ return f.exactMatch()
1076
+ except:
1077
+ pass
1078
+ return False
1079
+ else:
1080
+ # 非Windows系统简单检查
1081
+ try:
1082
+ f = QFont(font_name)
1083
+ return f.exactMatch()
1084
+ except:
1085
+ return False
1086
+
1087
+
1036
1088
  if __name__ == "__main__":
1037
1089
  import requests
1038
1090
  import urllib
@@ -1040,14 +1092,13 @@ if __name__ == "__main__":
1040
1092
  logging.getLogger("urllib3").setLevel(logging.WARNING)
1041
1093
  logging.getLogger("pytdx").setLevel(logging.WARNING)
1042
1094
 
1043
- # 自适应分辨率,防止字体显示不全
1044
- QtWidgets.QApplication.setAttribute(QtCore.Qt.AA_UseHighDpiPixmaps)
1045
- QtWidgets.QApplication.setAttribute(QtCore.Qt.AA_EnableHighDpiScaling)
1046
-
1047
1095
  app = QApplication(sys.argv)
1048
- f = QFont('SimSun')
1049
- f.setPixelSize(12)
1050
- app.setFont(f)
1096
+ if sys.platform == 'win32':
1097
+ # 检查Microsoft YaHei字体是否存在
1098
+ if is_font_installed('Microsoft YaHei'):
1099
+ f = QFont('Microsoft YaHei')
1100
+ f.setPixelSize(12)
1101
+ app.setFont(f)
1051
1102
 
1052
1103
  if (len(sys.argv) > 1 and sys.argv[1] == '0'):
1053
1104
  FORMAT = '%(asctime)-15s [%(levelname)s]: %(message)s [%(name)s::%(funcName)s]'
@@ -6,7 +6,7 @@ import logging
6
6
  import time
7
7
  import datetime
8
8
  from math import ceil
9
- from PyQt5.QtCore import QThread, QWaitCondition, QMutex
9
+ from PySide6.QtCore import QThread, QWaitCondition, QMutex
10
10
 
11
11
  from hikyuu.util import *
12
12
  from hikyuu.gui.spot_server import collect, release_nng_senders
@@ -3,10 +3,10 @@
3
3
  # cp936
4
4
 
5
5
  import time
6
- from PyQt5.QtCore import QThread, pyqtSignal
6
+ from PySide6.QtCore import QThread, Signal
7
7
 
8
8
  class EscapetimeThread(QThread):
9
- message = pyqtSignal(list)
9
+ message = Signal(list)
10
10
 
11
11
  def __init__(self):
12
12
  super(self.__class__, self).__init__()
@@ -14,19 +14,13 @@ class EscapetimeThread(QThread):
14
14
  self.msg_name = 'ESCAPE_TIME'
15
15
  self.init_time = time.time()
16
16
 
17
- def __del__(self):
18
- self.working = False
19
- #print("EscapetimeThread", "__del__", time.time() - self.init_time)
20
- self.wait()
21
-
22
- def send_message(self, msg):
23
- self.message.emit([self.msg_name] + msg)
17
+ def run(self):
18
+ while self.working:
19
+ time.sleep(1)
20
+ current_time = time.time()
21
+ self.message.emit([self.msg_name, round(current_time - self.init_time, 1)])
24
22
 
25
23
  def stop(self):
26
24
  self.working = False
25
+ self.quit()
27
26
  self.wait()
28
-
29
- def run(self):
30
- while self.working:
31
- self.msleep(10)
32
- self.send_message([(time.time() - self.init_time),])
@@ -6,7 +6,6 @@
6
6
 
7
7
  import sqlite3
8
8
  import mysql.connector
9
- from hikyuu.data.common import MARKET, get_stk_code_name_list
10
9
  from hikyuu.data.em_block_to_mysql import em_import_block_to_mysql
11
10
  from hikyuu.data.em_block_to_sqlite import em_import_block_to_sqlite
12
11
  from hikyuu.data.em_block_to_clickhouse import em_import_block_to_clickhouse
@@ -14,11 +13,10 @@ from hikyuu.util import *
14
13
 
15
14
 
16
15
  class ImportBlockInfoTask:
17
- def __init__(self, log_queue, queue, config, categorys):
16
+ def __init__(self, log_queue, queue, config):
18
17
  self.log_queue = log_queue
19
18
  self.queue = queue
20
19
  self.config = config
21
- self.categorys = categorys
22
20
  self.task_name = 'IMPORT_BLOCKINFO'
23
21
  self.status = "no run"
24
22
 
@@ -52,16 +50,11 @@ class ImportBlockInfoTask:
52
50
 
53
51
  count = 0
54
52
  try:
55
- code_market_dict = {}
56
- for market in (MARKET.SH, MARKET.SZ, MARKET.BJ):
57
- x = get_stk_code_name_list(market)
58
- for v in x:
59
- code_market_dict[v["code"]] = market
60
- count = import_block(connect, code_market_dict, self.categorys)
53
+ count = import_block(connect)
61
54
  except Exception as e:
62
55
  hku_error(str(e))
63
56
 
64
57
  connect.close()
65
58
 
66
- self.queue.put([self.task_name, "BLOCKINFO", f"{self.categorys}板块信息下载完毕: {count}", None, None])
59
+ self.queue.put([self.task_name, "BLOCKINFO", f"板块信息更新完毕: {count}", None, None])
67
60
  self.status = "finished"