hikyuu 2.1.2__cp312-none-win_amd64.whl → 2.1.4__cp312-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 (66) hide show
  1. hikyuu/cpp/core312.pyd +0 -0
  2. hikyuu/cpp/hikyuu.dll +0 -0
  3. hikyuu/data/em_block_to_mysql.py +45 -31
  4. hikyuu/data/em_block_to_sqlite.py +48 -33
  5. hikyuu/data/mysql_upgrade/0019.sql +6 -0
  6. hikyuu/data/mysql_upgrade/0020.sql +4 -0
  7. hikyuu/data/mysql_upgrade/0021.sql +4 -0
  8. hikyuu/data/pytdx_to_h5.py +21 -15
  9. hikyuu/data/pytdx_to_mysql.py +20 -2
  10. hikyuu/data/pytdx_weight_to_mysql.py +1 -1
  11. hikyuu/data/pytdx_weight_to_sqlite.py +1 -1
  12. hikyuu/data/sqlite_upgrade/0020.sql +4 -0
  13. hikyuu/data/sqlite_upgrade/0021.sql +6 -0
  14. hikyuu/data/sqlite_upgrade/0022.sql +6 -0
  15. hikyuu/fetcher/stock/zh_stock_a_pytdx.py +56 -8
  16. hikyuu/fetcher/stock/zh_stock_a_qmt.py +49 -40
  17. hikyuu/fetcher/stock/zh_stock_a_sina_qq.py +15 -5
  18. hikyuu/gui/HikyuuTDX.py +1 -1
  19. hikyuu/gui/data/ImportWeightToSqliteTask.py +18 -27
  20. hikyuu/gui/data/UsePytdxImportToH5Thread.py +17 -6
  21. hikyuu/gui/data/UseTdxImportToH5Thread.py +30 -6
  22. hikyuu/gui/spot_server.py +3 -1
  23. hikyuu/include/hikyuu/KQuery.h +5 -2
  24. hikyuu/include/hikyuu/KRecord.h +1 -1
  25. hikyuu/include/hikyuu/Stock.h +1 -1
  26. hikyuu/include/hikyuu/StockManager.h +26 -20
  27. hikyuu/include/hikyuu/StrategyContext.h +66 -25
  28. hikyuu/include/hikyuu/data_driver/BaseInfoDriver.h +1 -0
  29. hikyuu/include/hikyuu/doc.h +1 -1
  30. hikyuu/include/hikyuu/global/GlobalSpotAgent.h +5 -2
  31. hikyuu/include/hikyuu/global/agent/SpotAgent.h +28 -6
  32. hikyuu/include/hikyuu/hikyuu.h +13 -0
  33. hikyuu/include/hikyuu/indicator/crt/AMA.h +1 -1
  34. hikyuu/include/hikyuu/indicator/crt/CORR.h +1 -1
  35. hikyuu/include/hikyuu/indicator/crt/ICIR.h +1 -0
  36. hikyuu/include/hikyuu/indicator/crt/SMA.h +1 -1
  37. hikyuu/include/hikyuu/indicator/crt/SPEARMAN.h +1 -1
  38. hikyuu/include/hikyuu/strategy/BrokerTradeManager.h +1 -2
  39. hikyuu/include/hikyuu/strategy/RunPortfolioInStrategy.h +1 -1
  40. hikyuu/include/hikyuu/strategy/Strategy.h +18 -4
  41. hikyuu/include/hikyuu/trade_manage/OrderBrokerBase.h +3 -0
  42. hikyuu/include/hikyuu/trade_manage/TradeManagerBase.h +1 -2
  43. hikyuu/include/hikyuu/trade_sys/allocatefunds/AllocateFundsBase.h +0 -1
  44. hikyuu/include/hikyuu/trade_sys/condition/ConditionBase.h +1 -0
  45. hikyuu/include/hikyuu/trade_sys/portfolio/Portfolio.h +1 -0
  46. hikyuu/include/hikyuu/trade_sys/selector/imp/FixedSelector.h +1 -1
  47. hikyuu/include/hikyuu/trade_sys/selector/imp/OperatorSelector.h +11 -2
  48. hikyuu/include/hikyuu/trade_sys/selector/imp/OperatorValueSelector.h +19 -2
  49. hikyuu/include/hikyuu/utilities/Parameter.h +1 -1
  50. hikyuu/include/hikyuu/utilities/TimerManager.h +2 -2
  51. hikyuu/include/hikyuu/utilities/arithmetic.h +4 -4
  52. hikyuu/include/hikyuu/utilities/base64.h +1 -2
  53. hikyuu/include/hikyuu/utilities/config.h +1 -1
  54. hikyuu/include/hikyuu/utilities/mo/moFileReader.h +2 -2
  55. hikyuu/include/hikyuu/utilities/node/NodeMessage.h +1 -3
  56. hikyuu/include/hikyuu/utilities/thread/MQStealThreadPool.h +6 -7
  57. hikyuu/include/hikyuu/version.h +4 -4
  58. hikyuu/interactive.py +55 -131
  59. {hikyuu-2.1.2.dist-info → hikyuu-2.1.4.dist-info}/METADATA +1 -1
  60. {hikyuu-2.1.2.dist-info → hikyuu-2.1.4.dist-info}/RECORD +64 -60
  61. hikyuu/include/hikyuu/global/GlobalTaskGroup.h +0 -44
  62. hikyuu/puppet.py +0 -297
  63. {hikyuu-2.1.2.dist-info → hikyuu-2.1.4.dist-info}/LICENSE +0 -0
  64. {hikyuu-2.1.2.dist-info → hikyuu-2.1.4.dist-info}/WHEEL +0 -0
  65. {hikyuu-2.1.2.dist-info → hikyuu-2.1.4.dist-info}/entry_points.txt +0 -0
  66. {hikyuu-2.1.2.dist-info → hikyuu-2.1.4.dist-info}/top_level.txt +0 -0
hikyuu/cpp/core312.pyd CHANGED
Binary file
hikyuu/cpp/hikyuu.dll CHANGED
Binary file
@@ -4,6 +4,7 @@
4
4
  # Create on: 20240102
5
5
  # Author: fasiondog
6
6
 
7
+ from concurrent.futures import ThreadPoolExecutor
7
8
  from hikyuu.data.common import MARKET, get_stk_code_name_list
8
9
  from hikyuu.util import *
9
10
  from hikyuu.fetcher.stock.zh_block_em import *
@@ -12,37 +13,50 @@ from hikyuu.fetcher.stock.zh_block_em import *
12
13
  def em_import_block_to_mysql(connect, code_market_dict, categorys=('行业板块', '概念板块', '地域板块', '指数板块')):
13
14
  all_block_info = {}
14
15
 
15
- success_fetch_hy = False
16
- if '行业板块' in categorys:
17
- hku_info("获取行业板块信息")
18
- x = get_all_hybk_info(code_market_dict)
19
- if x:
20
- all_block_info["行业板块"] = x
21
- success_fetch_hy = True
22
-
23
- success_fetch_gn = False
24
- if '概念板块' in categorys:
25
- hku_info("获取概念板块信息")
26
- x = get_all_gnbk_info(code_market_dict)
27
- if x:
28
- all_block_info["概念板块"] = x
29
- success_fetch_gn = True
30
-
31
- success_fetch_dy = False
32
- if '地域板块' in categorys:
33
- hku_info("获取地域板块信息")
34
- x = get_all_dybk_info(code_market_dict)
35
- if x:
36
- all_block_info["地域板块"] = x
37
- success_fetch_dy = True
38
-
39
- success_fetch_zs = False
40
- if '指数板块' in categorys:
41
- hku_info("获取指数板块信息")
42
- x = get_all_zsbk_info(code_market_dict)
43
- if x:
44
- all_block_info["指数板块"] = x
45
- success_fetch_zs = True
16
+ with ThreadPoolExecutor(4) as executor:
17
+ if '行业板块' in categorys:
18
+ t1 = executor.submit(get_all_hybk_info, code_market_dict)
19
+
20
+ if '概念板块' in categorys:
21
+ t2 = executor.submit(get_all_gnbk_info, code_market_dict)
22
+
23
+ if '地域板块' in categorys:
24
+ t3 = executor.submit(get_all_dybk_info, code_market_dict)
25
+
26
+ if '指数板块' in categorys:
27
+ t4 = executor.submit(get_all_zsbk_info, code_market_dict)
28
+
29
+ success_fetch_hy = False
30
+ if '行业板块' in categorys:
31
+ x = t1.result()
32
+ hku_info("获取行业板块信息完毕")
33
+ if x:
34
+ all_block_info["行业板块"] = x
35
+ success_fetch_hy = True
36
+
37
+ success_fetch_gn = False
38
+ if '概念板块' in categorys:
39
+ x = t2.result()
40
+ hku_info("获取概念板块信息完毕")
41
+ if x:
42
+ all_block_info["概念板块"] = x
43
+ success_fetch_gn = True
44
+
45
+ success_fetch_dy = False
46
+ if '地域板块' in categorys:
47
+ x = t3.result()
48
+ hku_info("获取地域板块信息完毕")
49
+ if x:
50
+ all_block_info["地域板块"] = x
51
+ success_fetch_dy = True
52
+
53
+ success_fetch_zs = False
54
+ if '指数板块' in categorys:
55
+ x = t4.result()
56
+ hku_info("获取指数板块信息完毕")
57
+ if x:
58
+ all_block_info["指数板块"] = x
59
+ success_fetch_zs = True
46
60
 
47
61
  blks = []
48
62
  if success_fetch_hy:
@@ -4,45 +4,60 @@
4
4
  # Create on: 20240102
5
5
  # Author: fasiondog
6
6
 
7
+ from concurrent.futures import ThreadPoolExecutor
7
8
  from hikyuu.data.common import MARKET, get_stk_code_name_list
8
9
  from hikyuu.util import *
9
10
  from hikyuu.fetcher.stock.zh_block_em import *
10
11
 
11
12
 
13
+ @spend_time
12
14
  def em_import_block_to_sqlite(connect, code_market_dict, categorys=('行业板块', '概念板块', '地域板块', '指数板块')):
13
15
  all_block_info = {}
14
16
 
15
- success_fetch_hy = False
16
- if '行业板块' in categorys:
17
- hku_info("获取行业板块信息")
18
- x = get_all_hybk_info(code_market_dict)
19
- if x:
20
- all_block_info["行业板块"] = x
21
- success_fetch_hy = True
22
-
23
- success_fetch_gn = False
24
- if '概念板块' in categorys:
25
- hku_info("获取概念板块信息")
26
- x = get_all_gnbk_info(code_market_dict)
27
- if x:
28
- all_block_info["概念板块"] = x
29
- success_fetch_gn = True
30
-
31
- success_fetch_dy = False
32
- if '地域板块' in categorys:
33
- hku_info("获取地域板块信息")
34
- x = get_all_dybk_info(code_market_dict)
35
- if x:
36
- all_block_info["地域板块"] = x
37
- success_fetch_dy = True
38
-
39
- success_fetch_zs = False
40
- if '指数板块' in categorys:
41
- hku_info("获取指数板块信息")
42
- x = get_all_zsbk_info(code_market_dict)
43
- if x:
44
- all_block_info["指数板块"] = x
45
- success_fetch_zs = True
17
+ with ThreadPoolExecutor(4) as executor:
18
+ if '行业板块' in categorys:
19
+ t1 = executor.submit(get_all_hybk_info, code_market_dict)
20
+
21
+ if '概念板块' in categorys:
22
+ t2 = executor.submit(get_all_gnbk_info, code_market_dict)
23
+
24
+ if '地域板块' in categorys:
25
+ t3 = executor.submit(get_all_dybk_info, code_market_dict)
26
+
27
+ if '指数板块' in categorys:
28
+ t4 = executor.submit(get_all_zsbk_info, code_market_dict)
29
+
30
+ success_fetch_hy = False
31
+ if '行业板块' in categorys:
32
+ x = t1.result()
33
+ hku_info("获取行业板块信息完毕")
34
+ if x:
35
+ all_block_info["行业板块"] = x
36
+ success_fetch_hy = True
37
+
38
+ success_fetch_gn = False
39
+ if '概念板块' in categorys:
40
+ x = t2.result()
41
+ hku_info("获取概念板块信息完毕")
42
+ if x:
43
+ all_block_info["概念板块"] = x
44
+ success_fetch_gn = True
45
+
46
+ success_fetch_dy = False
47
+ if '地域板块' in categorys:
48
+ x = t3.result()
49
+ hku_info("获取地域板块信息完毕")
50
+ if x:
51
+ all_block_info["地域板块"] = x
52
+ success_fetch_dy = True
53
+
54
+ success_fetch_zs = False
55
+ if '指数板块' in categorys:
56
+ x = t4.result()
57
+ hku_info("获取指数板块信息完毕")
58
+ if x:
59
+ all_block_info["指数板块"] = x
60
+ success_fetch_zs = True
46
61
 
47
62
  blks = []
48
63
  if success_fetch_hy:
@@ -85,8 +100,8 @@ if __name__ == "__main__":
85
100
  import sqlite3
86
101
  from hikyuu.data.common_sqlite3 import create_database
87
102
 
88
- dest_dir = "/home/fasiondog/stock"
89
- # dest_dir = "d:\\stock"
103
+ # dest_dir = "/home/fasiondog/stock"
104
+ dest_dir = "d:\\stock"
90
105
 
91
106
  connect = sqlite3.connect(dest_dir + "/stock.db")
92
107
  create_database(connect)
@@ -0,0 +1,6 @@
1
+ UPDATE `hku_base`.`coderuletype` SET `codepre`=510 WHERE `codepre`=51 AND `marketid`=1;
2
+ UPDATE `hku_base`.`coderuletype` SET `codepre`=500 WHERE `codepre`=50 AND `marketid`=1;
3
+ UPDATE `hku_base`.`coderuletype` SET `codepre`=200 WHERE `codepre`=20 AND `marketid`=2;
4
+ INSERT INTO `hku_base`.`coderuletype` (`marketid`, `codepre`, `type`, `description`) VALUES (1, "56", 5, "上证ETF");
5
+ INSERT INTO `hku_base`.`coderuletype` (`marketid`, `codepre`, `type`, `description`) VALUES (1, "58", 5, "上证ETF");
6
+ UPDATE `hku_base`.`version` set `version` = 19;
@@ -0,0 +1,4 @@
1
+ UPDATE `hku_base`.`market` SET `closeTime1`=1135, `closeTime2`=1505 WHERE `marketid`=1;
2
+ UPDATE `hku_base`.`market` SET `closeTime1`=1135, `closeTime2`=1505 WHERE `marketid`=2;
3
+ UPDATE `hku_base`.`market` SET `closeTime1`=1135, `closeTime2`=1505 WHERE `marketid`=3;
4
+ UPDATE `hku_base`.`version` set `version` = 20;
@@ -0,0 +1,4 @@
1
+ UPDATE `hku_base`.`market` SET `closeTime1`=1130, `closeTime2`=1500 WHERE `marketid`=1;
2
+ UPDATE `hku_base`.`market` SET `closeTime1`=1130, `closeTime2`=1500 WHERE `marketid`=2;
3
+ UPDATE `hku_base`.`market` SET `closeTime1`=1130, `closeTime2`=1500 WHERE `marketid`=3;
4
+ UPDATE `hku_base`.`version` set `version` = 21;
@@ -101,27 +101,33 @@ def import_stock_name(connect, api, market, quotations=None):
101
101
  """
102
102
  cur = connect.cursor()
103
103
 
104
- newStockDict = {}
105
- stk_list = get_stk_code_name_list(market)
106
- if not stk_list:
107
- hku_error("获取 {} 股票代码表失败", market)
108
- return 0
109
-
110
- if not quotations or 'fund' in [v.lower() for v in quotations]:
111
- stk_list.extend(get_fund_code_name_list(market))
112
- for stock in stk_list:
113
- newStockDict[str(stock['code'])] = stock['name']
104
+ deSet = set() # 记录退市证券
114
105
  if market == MARKET.SH:
115
106
  df = ak.stock_info_sh_delist()
116
107
  l = df[['公司代码', '公司简称']].to_dict(orient='records') if not df .empty else []
117
108
  for stock in l:
118
- newStockDict[str(stock['公司代码'])] = stock['公司简称']
109
+ code = str(stock['公司代码'])
110
+ deSet.add(code)
119
111
  elif market == MARKET.SZ:
120
112
  for t in ['暂停上市公司', '终止上市公司']:
121
113
  df = ak.stock_info_sz_delist(t)
122
114
  l = df[['证券代码', '证券简称']].to_dict(orient='records') if not df.empty else []
123
115
  for stock in l:
124
- newStockDict[str(stock['证券代码'])] = stock['证券简称']
116
+ code = str(stock['证券代码'])
117
+ deSet.add(code)
118
+
119
+ newStockDict = {}
120
+ stk_list = get_stk_code_name_list(market)
121
+ if not stk_list:
122
+ hku_error("获取 {} 股票代码表失败", market)
123
+ return 0
124
+
125
+ if not quotations or 'fund' in [v.lower() for v in quotations]:
126
+ stk_list.extend(get_fund_code_name_list(market))
127
+ for stock in stk_list:
128
+ code = str(stock['code'])
129
+ if code not in deSet:
130
+ newStockDict[code] = stock['name']
125
131
 
126
132
  marketid = get_marketid(connect, market)
127
133
 
@@ -138,8 +144,8 @@ def import_stock_name(connect, api, market, quotations=None):
138
144
  oldstockid, oldcode, oldname, oldvalid = oldstock[0], oldstock[1], oldstock[2], int(oldstock[3])
139
145
  oldStockDict[oldcode] = oldstockid
140
146
 
141
- # 新的代码表中无此股票,则置为无效
142
- if (oldvalid == 1) and (oldcode not in newStockDict):
147
+ # 新的代码表中无此股票或者已退市,则置为无效
148
+ if (oldvalid == 1) and ((oldcode not in newStockDict) or (oldcode in deSet)):
143
149
  cur.execute("update stock set valid=0 where stockid=%i" % oldstockid)
144
150
 
145
151
  # 股票名称发生变化,更新股票名称;如果原无效,则置为有效
@@ -287,7 +293,7 @@ def import_one_stock_data(connect, api, h5file, market, ktype, stock_record, sta
287
293
  if today_datetime >= bar_datetime > last_datetime \
288
294
  and bar['high'] >= bar['open'] >= bar['low'] > 0 \
289
295
  and bar['high'] >= bar['close'] >= bar['low'] > 0 \
290
- and int(bar['vol']) != 0 and int(bar['amount']*0.001) != 0:
296
+ and int(bar['vol']) >= 0 and int(bar['amount']*0.001) >= 0:
291
297
  try:
292
298
  row['datetime'] = bar_datetime
293
299
  row['openPrice'] = bar['open'] * 1000
@@ -122,6 +122,21 @@ def import_stock_name(connect, api, market, quotations=None):
122
122
  """
123
123
  cur = connect.cursor()
124
124
 
125
+ deSet = set() # 记录退市证券
126
+ if market == MARKET.SH:
127
+ df = ak.stock_info_sh_delist()
128
+ l = df[['公司代码', '公司简称']].to_dict(orient='records') if not df .empty else []
129
+ for stock in l:
130
+ code = str(stock['公司代码'])
131
+ deSet.add(code)
132
+ elif market == MARKET.SZ:
133
+ for t in ['暂停上市公司', '终止上市公司']:
134
+ df = ak.stock_info_sz_delist(t)
135
+ l = df[['证券代码', '证券简称']].to_dict(orient='records') if not df.empty else []
136
+ for stock in l:
137
+ code = str(stock['证券代码'])
138
+ deSet.add(code)
139
+
125
140
  newStockDict = {}
126
141
  stk_list = get_stk_code_name_list(market)
127
142
  if not stk_list:
@@ -131,7 +146,9 @@ def import_stock_name(connect, api, market, quotations=None):
131
146
  if not quotations or "fund" in [v.lower() for v in quotations]:
132
147
  stk_list.extend(get_fund_code_name_list(market))
133
148
  for stock in stk_list:
134
- newStockDict[str(stock["code"])] = stock["name"]
149
+ code = str(stock["code"])
150
+ if code not in deSet:
151
+ newStockDict[code] = stock["name"]
135
152
 
136
153
  marketid = get_marketid(connect, market)
137
154
 
@@ -156,7 +173,8 @@ def import_stock_name(connect, api, market, quotations=None):
156
173
  oldStockDict[oldcode] = oldstockid
157
174
 
158
175
  # 新的代码表中无此股票,则置为无效
159
- if (oldvalid == 1) and (oldcode not in newStockDict):
176
+ # if (oldvalid == 1) and (oldcode not in newStockDict):
177
+ if (oldvalid == 1) and ((oldcode not in newStockDict) or oldcode in deSet):
160
178
  cur.execute(
161
179
  "update `hku_base`.`stock` set valid=0 where stockid=%i" % oldstockid
162
180
  )
@@ -38,7 +38,7 @@ def pytdx_import_weight_to_mysql(pytdx_api, connect, market):
38
38
  pytdx_market = to_pytdx_market(market)
39
39
 
40
40
  total_count = 0
41
- cur.execute("select stockid, code from `hku_base`.`stock` where marketid=%s" % (marketid))
41
+ cur.execute("select stockid, code from `hku_base`.`stock` where marketid=%s and valid=1" % (marketid))
42
42
  stockid_list = [x for x in cur.fetchall()]
43
43
  cur.close()
44
44
 
@@ -35,7 +35,7 @@ def pytdx_import_weight_to_sqlite(pytdx_api, connect, market):
35
35
  pytdx_market = to_pytdx_market(market)
36
36
 
37
37
  total_count = 0
38
- stockid_list = cur.execute("select stockid, code from Stock where marketid=%s" % (marketid))
38
+ stockid_list = cur.execute("select stockid, code from Stock where marketid=%s and valid=1" % (marketid))
39
39
  stockid_list = [x for x in stockid_list]
40
40
  cur.close()
41
41
 
@@ -0,0 +1,4 @@
1
+ BEGIN TRANSACTION;
2
+ UPDATE `coderuletype` SET `codepre`=150 WHERE `codepre`=15 AND `marketid`=2;
3
+ UPDATE `version` set `version` = 20;
4
+ COMMIT;
@@ -0,0 +1,6 @@
1
+ BEGIN TRANSACTION;
2
+ UPDATE `market` SET `closeTime1`=1135, `closeTime2`=1505 WHERE `marketid`=1;
3
+ UPDATE `market` SET `closeTime1`=1135, `closeTime2`=1505 WHERE `marketid`=2;
4
+ UPDATE `market` SET `closeTime1`=1135, `closeTime2`=1505 WHERE `marketid`=3;
5
+ UPDATE `version` set `version` = 21;
6
+ COMMIT;
@@ -0,0 +1,6 @@
1
+ BEGIN TRANSACTION;
2
+ UPDATE `market` SET `closeTime1`=1130, `closeTime2`=1500 WHERE `marketid`=1;
3
+ UPDATE `market` SET `closeTime1`=1130, `closeTime2`=1500 WHERE `marketid`=2;
4
+ UPDATE `market` SET `closeTime1`=1130, `closeTime2`=1500 WHERE `marketid`=3;
5
+ UPDATE `version` set `version` = 22;
6
+ COMMIT;
@@ -6,9 +6,10 @@
6
6
  # Author: fasiondog
7
7
 
8
8
  import datetime
9
+ from concurrent import futures
9
10
  from pytdx.hq import TdxHq_API
10
11
  from hikyuu.data.common_pytdx import search_best_tdx
11
-
12
+ from hikyuu import get_stock, constant
12
13
  from hikyuu.util import *
13
14
 
14
15
 
@@ -16,6 +17,12 @@ from hikyuu.util import *
16
17
  def parse_one_result(quotes):
17
18
  result = {}
18
19
  hku_check_ignore(quotes, "Invalid input param!")
20
+ try:
21
+ result['datetime'] = datetime.datetime.combine(
22
+ datetime.date.today(), datetime.time.fromisoformat(quotes['servertime'])
23
+ )
24
+ except:
25
+ return None
19
26
 
20
27
  result['market'] = 'SH' if quotes['market'] == 1 else 'SZ'
21
28
  result['code'] = quotes['code']
@@ -27,8 +34,13 @@ def parse_one_result(quotes):
27
34
  result['low'] = quotes['low'] # 今日最低价
28
35
  result['bid'] = float(quotes['bid1']) # 竞买价,即“买一”报价
29
36
  result['ask'] = float(quotes['ask1']) # 竞卖价,即“卖一”报价
30
- result['volume'] = float(quotes['vol']) # 成交的股票手数
31
- result['amount'] = round(quotes['amount'] / 1000.0, 2) # 成交金额,单位为“元”,若要以“万元”为成交金额的单位,需要把该值除以一万
37
+ # 指数 volumn 需要乘以 0.01
38
+ stk = get_stock(f"{result['market']}{result['code']}")
39
+ if not stk.is_null() and stk.type == constant.STOCKTYPE_INDEX:
40
+ result['volume'] = float(quotes['vol']) * 0.01
41
+ else:
42
+ result['volume'] = float(quotes['vol']) # 成交的股票手数
43
+ result['amount'] = round(quotes['amount'] * 0.0001, 2) # 成交金额,单位为“元”,若要以“万元”为成交金额的单位,需要把该值除以一万
32
44
  result['bid1_amount'] = float(quotes['bid_vol1']) # “买一”申请4695股,即47手
33
45
  result['bid1'] = float(quotes['bid1']) # “买一”报价
34
46
  result['bid2_amount'] = float(quotes['bid_vol2'])
@@ -49,13 +61,10 @@ def parse_one_result(quotes):
49
61
  result['ask4'] = float(quotes['ask4'])
50
62
  result['ask5_amount'] = float(quotes['ask_vol5'])
51
63
  result['ask5'] = float(quotes['ask5'])
52
- result['datetime'] = datetime.datetime.combine(
53
- datetime.date.today(), datetime.time.fromisoformat(quotes['servertime'])
54
- )
55
64
  return result
56
65
 
57
66
 
58
- @hku_catch(ret=[])
67
+ @ hku_catch(ret=[], trace=True)
59
68
  def request_data(api, stklist, parse_one_result):
60
69
  """请求失败将抛出异常"""
61
70
  quotes_list = api.get_security_quotes(stklist)
@@ -63,6 +72,7 @@ def request_data(api, stklist, parse_one_result):
63
72
  return [r for r in result if r is not None]
64
73
 
65
74
 
75
+ @hku_catch(ret=([], []))
66
76
  def get_spot(stocklist, ip, port, batch_func=None):
67
77
  api = TdxHq_API()
68
78
  hku_check(api.connect(ip, port), 'Failed connect tdx ({}:{})!'.format(ip, port))
@@ -71,6 +81,7 @@ def get_spot(stocklist, ip, port, batch_func=None):
71
81
  tmplist = []
72
82
  result = []
73
83
  max_size = 80
84
+ err_list = []
74
85
  for stk in stocklist:
75
86
  tmplist.append((1 if stk.market == 'SH' else 0, stk.code))
76
87
  count += 1
@@ -80,6 +91,8 @@ def get_spot(stocklist, ip, port, batch_func=None):
80
91
  result.extend(phase_result)
81
92
  if batch_func:
82
93
  batch_func(phase_result)
94
+ else:
95
+ err_list.extend(tmplist)
83
96
  count = 0
84
97
  tmplist = []
85
98
  if tmplist:
@@ -88,4 +101,39 @@ def get_spot(stocklist, ip, port, batch_func=None):
88
101
  result.extend(phase_result)
89
102
  if batch_func:
90
103
  batch_func(phase_result)
91
- return result
104
+ else:
105
+ err_list.extend(tmplist)
106
+ return result, err_list
107
+
108
+
109
+ @spend_time
110
+ def get_spot2(stocklist, ip, port, batch_func=None):
111
+ hosts = search_best_tdx()
112
+ hosts_cnt = len(hosts)
113
+ num = len(stocklist) // hosts_cnt
114
+ batchslist = []
115
+ for i in range(hosts_cnt):
116
+ batchslist.append([[stk for stk in stocklist[i*num: (i+1)*num]], hosts[i][2], hosts[i][3], batch_func])
117
+ if len(stocklist) % hosts_cnt != 0:
118
+ pos = num * hosts_cnt
119
+ for i in range(hosts_cnt):
120
+ batchslist[i][0].append(stocklist[pos])
121
+ pos += 1
122
+ if pos >= len(stocklist):
123
+ break
124
+
125
+ def do_inner(param):
126
+ ret = get_spot(param[0], param[1], param[2], param[3])
127
+ return ret
128
+
129
+ with futures.ThreadPoolExecutor() as executor:
130
+ res = executor.map(do_inner, batchslist, timeout=10)
131
+
132
+ result = []
133
+ errors = []
134
+ for batch_result in res:
135
+ if batch_result[0]:
136
+ result.extend(batch_result[0])
137
+ if batch_result[1]:
138
+ errors.extend(batch_result[1])
139
+ return result, errors
@@ -4,46 +4,55 @@
4
4
  # Create on: 2024-08-22
5
5
  # Author: fasiondog
6
6
 
7
- from xtquant import xtdata
8
7
  from hikyuu import Datetime
9
8
  from hikyuu.util import *
10
9
 
11
-
12
- @hku_catch(trace=True, callback=lambda stk: hku_warn("Failed parse stk: {}", stk))
13
- def parse_one_result_qmt(stk_code: str, data: dict):
14
- '''将 qmt tick 数据转为 spot 数据
15
-
16
- :param str stk_code: qmt 风格的证券编码,如 000001.SZ
17
- :param dict data: 对应的 qmt 全推 tick 数据
18
- '''
19
- result = {}
20
- code, market = stk_code.split('.')
21
- result['market'] = market
22
- result['code'] = code
23
- result['name'] = ''
24
- result['datetime'] = Datetime(data['timetag']) if 'timetag' in data else xtdata.timetag_to_datetime(
25
- data['time'], "%Y-%m-%d %H:%M:%S")
26
-
27
- result['yesterday_close'] = data['lastClose']
28
- result['open'] = data['open']
29
- result['high'] = data['high']
30
- result['low'] = data['low']
31
- result['close'] = data['lastPrice']
32
- result['amount'] = data['amount'] * 0.001 # 转千元
33
- result['volume'] = data['pvolume'] * 0.01 # 转手数
34
-
35
- for i in range(5):
36
- result[f'bid{i+1}'] = data['bidPrice'][i]
37
- result[f'bid{i+1}_amount'] = data['bidVol'][i]
38
- result[f'ask{i+1}'] = data['askPrice'][i]
39
- result[f'ask{i+1}_amount'] = data['askVol'][i]
40
- return result
41
-
42
-
43
- def get_spot(stocklist, unused1, unused2, batch_func=None):
44
- code_list = [f'{s.code}.{s.market}' for s in stocklist]
45
- full_tick = xtdata.get_full_tick(code_list)
46
- records = [parse_one_result_qmt(code, data) for code, data in full_tick.items()]
47
- if batch_func is not None:
48
- batch_func(records)
49
- return records
10
+ try:
11
+ from xtquant import xtdata
12
+
13
+ @hku_catch(trace=True, callback=lambda stk: hku_warn("Failed parse stk: {}", stk))
14
+ def parse_one_result_qmt(stk_code: str, data: dict):
15
+ '''将 qmt tick 数据转为 spot 数据
16
+
17
+ :param str stk_code: qmt 风格的证券编码,如 000001.SZ
18
+ :param dict data: 对应的 qmt 全推 tick 数据
19
+ '''
20
+ result = {}
21
+ code, market = stk_code.split('.')
22
+ result['market'] = market
23
+ result['code'] = code
24
+ result['name'] = ''
25
+ result['datetime'] = Datetime(data['timetag']) if 'timetag' in data else xtdata.timetag_to_datetime(
26
+ data['time'], "%Y-%m-%d %H:%M:%S")
27
+
28
+ result['yesterday_close'] = data['lastClose']
29
+ result['open'] = data['open']
30
+ result['high'] = data['high']
31
+ result['low'] = data['low']
32
+ result['close'] = data['lastPrice']
33
+ result['amount'] = data['amount'] * 0.0001 # 转千元
34
+ result['volume'] = data['pvolume'] * 0.01 # 转手数
35
+
36
+ for i in range(5):
37
+ result[f'bid{i+1}'] = data['bidPrice'][i]
38
+ result[f'bid{i+1}_amount'] = data['bidVol'][i]
39
+ result[f'ask{i+1}'] = data['askPrice'][i]
40
+ result[f'ask{i+1}_amount'] = data['askVol'][i]
41
+ return result
42
+
43
+ def get_spot(stocklist, unused1=None, unused2=None, batch_func=None):
44
+ code_list = [f'{s.code}.{s.market}' for s in stocklist]
45
+ full_tick = xtdata.get_full_tick(code_list)
46
+ records = [parse_one_result_qmt(code, data) for code, data in full_tick.items()]
47
+ if batch_func is not None:
48
+ batch_func(records)
49
+ return records
50
+
51
+ except:
52
+ def parse_one_result_qmt(stk_code: str, data: dict):
53
+ hku_error("Not fount xtquant")
54
+ return dict()
55
+
56
+ def get_spot(stocklist, unused1=None, unused2=None, batch_func=None):
57
+ hku_error("Not fount xtquant")
58
+ return list()
@@ -61,11 +61,18 @@ def parse_one_result_sina(resultstr):
61
61
  def parse_one_result_qq(resultstr):
62
62
  result = {}
63
63
  hku_check_ignore(resultstr, "Invalid input param!")
64
- hku_check_ignore(len(resultstr) > 3 and resultstr[:2] == 'v_', "Invalid input param! {}", resultstr)
64
+ # hku_check_ignore(len(resultstr) > 3 and resultstr[:2] == 'v_', "Invalid input param! {}", resultstr)
65
+ if (len(resultstr) <= 3 or resultstr[:2] != 'v_'):
66
+ return None
65
67
 
66
68
  a = resultstr.split('~')
67
- result['market'] = a[0][2:4]
68
- result['code'] = a[0][4:10]
69
+ if len(a) <= 1:
70
+ return None
71
+ market = a[0][2:4].upper()
72
+ code = a[0][4:10]
73
+ result['market'] = market
74
+ result['code'] = code
75
+
69
76
  result['name'] = a[1]
70
77
  result['close'] = float(a[3]) # 当前价格
71
78
  result['yesterday_close'] = float(a[4]) # 昨日收盘价
@@ -103,8 +110,11 @@ def parse_one_result_qq(resultstr):
103
110
  result['high'] = float(a[33]) # 最高价
104
111
  result['low'] = float(a[34]) # 最低价
105
112
  # 35: 价格/成交量(手)/成交额
106
- result['volume'] = float(a[36]) # 成交量(手)
107
- result['amount'] = float(a[37]) * 10.0 # 成交额(万)
113
+ if (market == 'SZ' and code[:2] == '39') or (market == 'SH' and code[:3] == '000'):
114
+ result['volume'] = float(a[36]) * 0.01 # 成交量(手)
115
+ else:
116
+ result['volume'] = float(a[36]) # 成交量(手)
117
+ result['amount'] = float(a[37]) # 成交额(万)
108
118
  result['turnover_rate'] = float(a[38]) if a[38] else 0.0 # 换手率
109
119
  result['pe'] = float(a[39]) if a[39] else 0.0 # 市盈率 Price Earnings Ratio,简称P/E或PER
110
120
  result['amplitude'] = float(a[43]) if a[43] else 0.0 # 振幅
hikyuu/gui/HikyuuTDX.py CHANGED
@@ -631,6 +631,7 @@ class MyMainWindow(QMainWindow, Ui_MainWindow):
631
631
  self.escape_time_thread = None
632
632
  self.start_import_pushButton.setEnabled(True)
633
633
  self.import_detail_textEdit.append("导入完毕!")
634
+ self.hdf5_weight_label.setText("导入完毕!")
634
635
  if can_upgrade():
635
636
  self.import_detail_textEdit.append("========================================================")
636
637
  self.import_detail_textEdit.append(
@@ -661,7 +662,6 @@ class MyMainWindow(QMainWindow, Ui_MainWindow):
661
662
  self.import_detail_textEdit.append('导入 {} 分时记录数:{}'.format(msg[3], msg[5]))
662
663
 
663
664
  elif msg_task_name == 'IMPORT_WEIGHT':
664
- self.hdf5_weight_label.setText(msg[2])
665
665
  if msg[2] == '导入权息数据完毕!':
666
666
  self.import_detail_textEdit.append('导入权息记录数:{}'.format(msg[3]))
667
667
  elif msg[2] == '导入通达信财务信息完毕!':