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.
- hikyuu/cpp/core312.pyd +0 -0
- hikyuu/cpp/hikyuu.dll +0 -0
- hikyuu/data/em_block_to_mysql.py +45 -31
- hikyuu/data/em_block_to_sqlite.py +48 -33
- hikyuu/data/mysql_upgrade/0019.sql +6 -0
- hikyuu/data/mysql_upgrade/0020.sql +4 -0
- hikyuu/data/mysql_upgrade/0021.sql +4 -0
- hikyuu/data/pytdx_to_h5.py +21 -15
- hikyuu/data/pytdx_to_mysql.py +20 -2
- hikyuu/data/pytdx_weight_to_mysql.py +1 -1
- hikyuu/data/pytdx_weight_to_sqlite.py +1 -1
- hikyuu/data/sqlite_upgrade/0020.sql +4 -0
- hikyuu/data/sqlite_upgrade/0021.sql +6 -0
- hikyuu/data/sqlite_upgrade/0022.sql +6 -0
- hikyuu/fetcher/stock/zh_stock_a_pytdx.py +56 -8
- hikyuu/fetcher/stock/zh_stock_a_qmt.py +49 -40
- hikyuu/fetcher/stock/zh_stock_a_sina_qq.py +15 -5
- hikyuu/gui/HikyuuTDX.py +1 -1
- hikyuu/gui/data/ImportWeightToSqliteTask.py +18 -27
- hikyuu/gui/data/UsePytdxImportToH5Thread.py +17 -6
- hikyuu/gui/data/UseTdxImportToH5Thread.py +30 -6
- hikyuu/gui/spot_server.py +3 -1
- hikyuu/include/hikyuu/KQuery.h +5 -2
- hikyuu/include/hikyuu/KRecord.h +1 -1
- hikyuu/include/hikyuu/Stock.h +1 -1
- hikyuu/include/hikyuu/StockManager.h +26 -20
- hikyuu/include/hikyuu/StrategyContext.h +66 -25
- hikyuu/include/hikyuu/data_driver/BaseInfoDriver.h +1 -0
- hikyuu/include/hikyuu/doc.h +1 -1
- hikyuu/include/hikyuu/global/GlobalSpotAgent.h +5 -2
- hikyuu/include/hikyuu/global/agent/SpotAgent.h +28 -6
- hikyuu/include/hikyuu/hikyuu.h +13 -0
- hikyuu/include/hikyuu/indicator/crt/AMA.h +1 -1
- hikyuu/include/hikyuu/indicator/crt/CORR.h +1 -1
- hikyuu/include/hikyuu/indicator/crt/ICIR.h +1 -0
- hikyuu/include/hikyuu/indicator/crt/SMA.h +1 -1
- hikyuu/include/hikyuu/indicator/crt/SPEARMAN.h +1 -1
- hikyuu/include/hikyuu/strategy/BrokerTradeManager.h +1 -2
- hikyuu/include/hikyuu/strategy/RunPortfolioInStrategy.h +1 -1
- hikyuu/include/hikyuu/strategy/Strategy.h +18 -4
- hikyuu/include/hikyuu/trade_manage/OrderBrokerBase.h +3 -0
- hikyuu/include/hikyuu/trade_manage/TradeManagerBase.h +1 -2
- hikyuu/include/hikyuu/trade_sys/allocatefunds/AllocateFundsBase.h +0 -1
- hikyuu/include/hikyuu/trade_sys/condition/ConditionBase.h +1 -0
- hikyuu/include/hikyuu/trade_sys/portfolio/Portfolio.h +1 -0
- hikyuu/include/hikyuu/trade_sys/selector/imp/FixedSelector.h +1 -1
- hikyuu/include/hikyuu/trade_sys/selector/imp/OperatorSelector.h +11 -2
- hikyuu/include/hikyuu/trade_sys/selector/imp/OperatorValueSelector.h +19 -2
- hikyuu/include/hikyuu/utilities/Parameter.h +1 -1
- hikyuu/include/hikyuu/utilities/TimerManager.h +2 -2
- hikyuu/include/hikyuu/utilities/arithmetic.h +4 -4
- hikyuu/include/hikyuu/utilities/base64.h +1 -2
- hikyuu/include/hikyuu/utilities/config.h +1 -1
- hikyuu/include/hikyuu/utilities/mo/moFileReader.h +2 -2
- hikyuu/include/hikyuu/utilities/node/NodeMessage.h +1 -3
- hikyuu/include/hikyuu/utilities/thread/MQStealThreadPool.h +6 -7
- hikyuu/include/hikyuu/version.h +4 -4
- hikyuu/interactive.py +55 -131
- {hikyuu-2.1.2.dist-info → hikyuu-2.1.4.dist-info}/METADATA +1 -1
- {hikyuu-2.1.2.dist-info → hikyuu-2.1.4.dist-info}/RECORD +64 -60
- hikyuu/include/hikyuu/global/GlobalTaskGroup.h +0 -44
- hikyuu/puppet.py +0 -297
- {hikyuu-2.1.2.dist-info → hikyuu-2.1.4.dist-info}/LICENSE +0 -0
- {hikyuu-2.1.2.dist-info → hikyuu-2.1.4.dist-info}/WHEEL +0 -0
- {hikyuu-2.1.2.dist-info → hikyuu-2.1.4.dist-info}/entry_points.txt +0 -0
- {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
|
hikyuu/data/em_block_to_mysql.py
CHANGED
|
@@ -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
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
if
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
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
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
if
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
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
|
-
|
|
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;
|
hikyuu/data/pytdx_to_h5.py
CHANGED
|
@@ -101,27 +101,33 @@ def import_stock_name(connect, api, market, quotations=None):
|
|
|
101
101
|
"""
|
|
102
102
|
cur = connect.cursor()
|
|
103
103
|
|
|
104
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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'])
|
|
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
|
hikyuu/data/pytdx_to_mysql.py
CHANGED
|
@@ -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
|
-
|
|
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;
|
|
@@ -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
|
-
|
|
31
|
-
result['
|
|
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
|
-
|
|
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
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
batch_func
|
|
49
|
-
|
|
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
|
-
|
|
68
|
-
|
|
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
|
-
|
|
107
|
-
|
|
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] == '导入通达信财务信息完毕!':
|