hikyuu 2.1.3__cp312-none-win_amd64.whl → 2.1.5__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 (67) 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/0020.sql +4 -0
  6. hikyuu/data/mysql_upgrade/0021.sql +4 -0
  7. hikyuu/data/mysql_upgrade/0022.sql +5 -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/0021.sql +6 -0
  13. hikyuu/data/sqlite_upgrade/0022.sql +6 -0
  14. hikyuu/data/sqlite_upgrade/0023.sql +7 -0
  15. hikyuu/fetcher/stock/zh_stock_a_pytdx.py +57 -9
  16. hikyuu/fetcher/stock/zh_stock_a_qmt.py +3 -3
  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/gui/start_qmt.py +99 -13
  24. hikyuu/include/hikyuu/KQuery.h +5 -2
  25. hikyuu/include/hikyuu/KRecord.h +1 -1
  26. hikyuu/include/hikyuu/Stock.h +1 -1
  27. hikyuu/include/hikyuu/StockManager.h +26 -20
  28. hikyuu/include/hikyuu/StrategyContext.h +66 -25
  29. hikyuu/include/hikyuu/data_driver/BaseInfoDriver.h +1 -0
  30. hikyuu/include/hikyuu/doc.h +1 -1
  31. hikyuu/include/hikyuu/global/GlobalSpotAgent.h +5 -2
  32. hikyuu/include/hikyuu/global/agent/SpotAgent.h +28 -6
  33. hikyuu/include/hikyuu/hikyuu.h +13 -0
  34. hikyuu/include/hikyuu/indicator/crt/AMA.h +1 -1
  35. hikyuu/include/hikyuu/indicator/crt/CORR.h +1 -1
  36. hikyuu/include/hikyuu/indicator/crt/DMA.h +1 -7
  37. hikyuu/include/hikyuu/indicator/crt/ICIR.h +1 -0
  38. hikyuu/include/hikyuu/indicator/crt/SMA.h +1 -1
  39. hikyuu/include/hikyuu/indicator/crt/SPEARMAN.h +1 -1
  40. hikyuu/include/hikyuu/indicator/imp/IDma.h +47 -0
  41. hikyuu/include/hikyuu/strategy/BrokerTradeManager.h +1 -2
  42. hikyuu/include/hikyuu/strategy/Strategy.h +15 -4
  43. hikyuu/include/hikyuu/trade_manage/OrderBrokerBase.h +3 -0
  44. hikyuu/include/hikyuu/trade_manage/TradeManagerBase.h +1 -2
  45. hikyuu/include/hikyuu/trade_sys/allocatefunds/AllocateFundsBase.h +0 -1
  46. hikyuu/include/hikyuu/trade_sys/condition/ConditionBase.h +1 -0
  47. hikyuu/include/hikyuu/trade_sys/portfolio/Portfolio.h +1 -0
  48. hikyuu/include/hikyuu/trade_sys/selector/imp/FixedSelector.h +1 -1
  49. hikyuu/include/hikyuu/trade_sys/selector/imp/OperatorSelector.h +11 -2
  50. hikyuu/include/hikyuu/trade_sys/selector/imp/OperatorValueSelector.h +19 -2
  51. hikyuu/include/hikyuu/utilities/Parameter.h +1 -1
  52. hikyuu/include/hikyuu/utilities/TimerManager.h +2 -2
  53. hikyuu/include/hikyuu/utilities/arithmetic.h +4 -4
  54. hikyuu/include/hikyuu/utilities/base64.h +1 -2
  55. hikyuu/include/hikyuu/utilities/mo/moFileReader.h +2 -2
  56. hikyuu/include/hikyuu/utilities/node/NodeMessage.h +1 -3
  57. hikyuu/include/hikyuu/utilities/thread/MQStealThreadPool.h +6 -7
  58. hikyuu/include/hikyuu/version.h +4 -4
  59. hikyuu/interactive.py +55 -135
  60. {hikyuu-2.1.3.dist-info → hikyuu-2.1.5.dist-info}/METADATA +1 -1
  61. {hikyuu-2.1.3.dist-info → hikyuu-2.1.5.dist-info}/RECORD +65 -60
  62. hikyuu/include/hikyuu/global/GlobalTaskGroup.h +0 -44
  63. hikyuu/puppet.py +0 -297
  64. {hikyuu-2.1.3.dist-info → hikyuu-2.1.5.dist-info}/LICENSE +0 -0
  65. {hikyuu-2.1.3.dist-info → hikyuu-2.1.5.dist-info}/WHEEL +0 -0
  66. {hikyuu-2.1.3.dist-info → hikyuu-2.1.5.dist-info}/entry_points.txt +0 -0
  67. {hikyuu-2.1.3.dist-info → hikyuu-2.1.5.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,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;
@@ -0,0 +1,5 @@
1
+ DELETE FROM `hku_base`.`stkweight`;
2
+ UPDATE `hku_base`.`coderuletype` SET `codepre`=51 WHERE `codepre`=510 AND `marketid`=1;
3
+ UPDATE `hku_base`.`coderuletype` SET `codepre`=50 WHERE `codepre`=500 AND `marketid`=1;
4
+ UPDATE `hku_base`.`coderuletype` SET `codepre`=20 WHERE `codepre`=200 AND `marketid`=2;
5
+ UPDATE `hku_base`.`version` set `version` = 22;
@@ -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,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;
@@ -0,0 +1,7 @@
1
+ BEGIN TRANSACTION;
2
+ DELETE FROM `stkWeight`;
3
+ UPDATE `coderuletype` SET `codepre`=51 WHERE `codepre`=510 AND `marketid`=1;
4
+ UPDATE `coderuletype` SET `codepre`=50 WHERE `codepre`=500 AND `marketid`=1;
5
+ UPDATE `coderuletype` SET `codepre`=20 WHERE `codepre`=200 AND `marketid`=2;
6
+ UPDATE `version` set `version` = 23;
7
+ 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,7 +72,8 @@ 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
 
66
- def get_spot(stocklist, ip, port, batch_func=None):
75
+ @hku_catch(ret=([], []))
76
+ def inner_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))
69
79
 
@@ -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_spot(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 = inner_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
@@ -30,7 +30,7 @@ try:
30
30
  result['high'] = data['high']
31
31
  result['low'] = data['low']
32
32
  result['close'] = data['lastPrice']
33
- result['amount'] = data['amount'] * 0.001 # 转千元
33
+ result['amount'] = data['amount'] * 0.0001 # 转千元
34
34
  result['volume'] = data['pvolume'] * 0.01 # 转手数
35
35
 
36
36
  for i in range(5):
@@ -40,7 +40,7 @@ try:
40
40
  result[f'ask{i+1}_amount'] = data['askVol'][i]
41
41
  return result
42
42
 
43
- def get_spot(stocklist, unused1, unused2, batch_func=None):
43
+ def get_spot(stocklist, unused1=None, unused2=None, batch_func=None):
44
44
  code_list = [f'{s.code}.{s.market}' for s in stocklist]
45
45
  full_tick = xtdata.get_full_tick(code_list)
46
46
  records = [parse_one_result_qmt(code, data) for code, data in full_tick.items()]
@@ -53,6 +53,6 @@ except:
53
53
  hku_error("Not fount xtquant")
54
54
  return dict()
55
55
 
56
- def get_spot(stocklist, unused1, unused2, batch_func=None):
56
+ def get_spot(stocklist, unused1=None, unused2=None, batch_func=None):
57
57
  hku_error("Not fount xtquant")
58
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] == '导入通达信财务信息完毕!':
@@ -42,7 +42,7 @@ from hikyuu.util.check import hku_catch, hku_check
42
42
 
43
43
 
44
44
  class ImportWeightToSqliteTask:
45
- def __init__(self, log_queue, queue, config, dest_dir):
45
+ def __init__(self, log_queue, queue, config, dest_dir, market, cmd, host, port):
46
46
  self.logger = logging.getLogger(self.__class__.__name__)
47
47
  self.log_queue = log_queue
48
48
  self.queue = queue
@@ -50,6 +50,10 @@ class ImportWeightToSqliteTask:
50
50
  self.dest_dir = dest_dir
51
51
  self.msg_name = 'IMPORT_WEIGHT'
52
52
  self.status = "no run"
53
+ self.market = market
54
+ self.cmd = cmd # "weight" | "finance"
55
+ self.host = host
56
+ self.port = port
53
57
 
54
58
  @hku_catch(trace=True)
55
59
  def __call__(self):
@@ -76,44 +80,31 @@ class ImportWeightToSqliteTask:
76
80
  self.logger.debug('use mysql import weight')
77
81
 
78
82
  except Exception as e:
79
- #self.queue.put([self.msg_name, str(e), -1, 0, total_count])
83
+ # self.queue.put([self.msg_name, str(e), -1, 0, total_count])
80
84
  self.queue.put([self.msg_name, 'INFO', str(e), 0, 0])
81
85
  self.queue.put([self.msg_name, '', 0, None, total_count])
82
86
  self.status = "failure"
83
87
  return
84
88
 
85
89
  try:
86
- hosts = search_best_tdx()
87
90
  api = TdxHq_API()
88
- hku_check(api.connect(hosts[0][2], hosts[0][3]), "failed connect pytdx {}:{}!", hosts[0][2], hosts[0][3])
89
-
90
- self.logger.info('正在导入权息数据')
91
- self.queue.put([self.msg_name, '正在导入权息数据...', 0, 0, 0])
92
-
93
- total_count = 0
94
- for market in g_market_list:
95
- count = pytdx_import_weight(api, connect, market)
96
- self.logger.info("导入 {} 权息记录数: {}".format(market, count))
97
- total_count += count
98
-
99
- self.queue.put([self.msg_name, '导入权息数据完毕!', 0, 0, total_count])
100
- self.logger.info('导入权息数据完毕')
101
-
102
- self.queue.put([self.msg_name, '下载通达信财务信息(上证)...', 0, 0, 0])
103
- x = pytdx_import_finance(connect, api, "SH")
104
-
105
- self.queue.put([self.msg_name, '下载通达信财务信息(深证)...', 0, 0, 0])
106
- x += pytdx_import_finance(connect, api, "SZ")
107
-
108
- self.queue.put([self.msg_name, '下载通达信财务信息(北证)...', 0, 0, 0])
109
- x += pytdx_import_finance(connect, api, "BJ")
110
- self.queue.put([self.msg_name, '导入通达信财务信息完毕!', 0, 0, x])
91
+ hku_check(api.connect(self.host, self.port), "failed connect pytdx {}:{}!", self.host, self.port)
92
+
93
+ if self.cmd == 'weight':
94
+ count = pytdx_import_weight(api, connect, self.market)
95
+ self.logger.info("导入 {} 权息记录数: {}".format(self.market, count))
96
+ self.queue.put([self.msg_name, '导入权息数据完毕!', 0, 0, f'{self.market} {total_count}'])
97
+ elif self.cmd == 'finance':
98
+ self.queue.put([self.msg_name, f'下载通达信当前财务信息({self.market})...', 0, 0, 0])
99
+ x = pytdx_import_finance(connect, api, self.market)
100
+ self.logger.info(f'导入 {self.market} 通达信当前财务信息数: {x}')
101
+ self.queue.put([self.msg_name, '导入通达信财务信息完毕!', 0, 0, f'{self.market} {x}'])
111
102
 
112
103
  api.disconnect()
113
104
 
114
105
  except Exception as e:
115
106
  self.logger.error(e)
116
- #self.queue.put([self.msg_name, str(e), -1, 0, total_count])
107
+ # self.queue.put([self.msg_name, str(e), -1, 0, total_count])
117
108
  self.queue.put([self.msg_name, 'INFO', str(e), 0, 0])
118
109
  finally:
119
110
  connect.commit()