hikyuu 2.1.3__cp311-none-win_amd64.whl → 2.1.5__cp311-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/core311.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/0020.sql +4 -0
- hikyuu/data/mysql_upgrade/0021.sql +4 -0
- hikyuu/data/mysql_upgrade/0022.sql +5 -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/0021.sql +6 -0
- hikyuu/data/sqlite_upgrade/0022.sql +6 -0
- hikyuu/data/sqlite_upgrade/0023.sql +7 -0
- hikyuu/fetcher/stock/zh_stock_a_pytdx.py +57 -9
- hikyuu/fetcher/stock/zh_stock_a_qmt.py +3 -3
- 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/gui/start_qmt.py +99 -13
- 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/DMA.h +1 -7
- 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/indicator/imp/IDma.h +47 -0
- hikyuu/include/hikyuu/strategy/BrokerTradeManager.h +1 -2
- hikyuu/include/hikyuu/strategy/Strategy.h +15 -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/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 -135
- {hikyuu-2.1.3.dist-info → hikyuu-2.1.5.dist-info}/METADATA +1 -1
- {hikyuu-2.1.3.dist-info → hikyuu-2.1.5.dist-info}/RECORD +65 -60
- hikyuu/include/hikyuu/global/GlobalTaskGroup.h +0 -44
- hikyuu/puppet.py +0 -297
- {hikyuu-2.1.3.dist-info → hikyuu-2.1.5.dist-info}/LICENSE +0 -0
- {hikyuu-2.1.3.dist-info → hikyuu-2.1.5.dist-info}/WHEEL +0 -0
- {hikyuu-2.1.3.dist-info → hikyuu-2.1.5.dist-info}/entry_points.txt +0 -0
- {hikyuu-2.1.3.dist-info → hikyuu-2.1.5.dist-info}/top_level.txt +0 -0
hikyuu/cpp/core311.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,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;
|
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;
|
|
@@ -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
|
-
|
|
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,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
|
-
|
|
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
|
-
|
|
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.
|
|
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
|
-
|
|
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] == '导入通达信财务信息完毕!':
|
|
@@ -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(
|
|
89
|
-
|
|
90
|
-
self.
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
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()
|