hikyuu 2.5.6__py3-none-win_amd64.whl → 2.6.1__py3-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/__init__.py +33 -49
- hikyuu/__init__.pyi +530 -516
- hikyuu/analysis/__init__.pyi +498 -490
- hikyuu/analysis/analysis.pyi +499 -491
- hikyuu/core.pyi +500 -492
- hikyuu/cpp/__init__.pyi +2 -2
- hikyuu/cpp/boost_date_time-mt.dll +0 -0
- hikyuu/cpp/boost_serialization-mt.dll +0 -0
- hikyuu/cpp/boost_wserialization-mt.dll +0 -0
- hikyuu/cpp/core310.pyd +0 -0
- hikyuu/cpp/core310.pyi +187 -22
- hikyuu/cpp/core311.pyd +0 -0
- hikyuu/cpp/core311.pyi +187 -22
- hikyuu/cpp/core312.pyd +0 -0
- hikyuu/cpp/core312.pyi +187 -22
- hikyuu/cpp/core313.pyd +0 -0
- hikyuu/cpp/core313.pyi +186 -22
- hikyuu/cpp/core39.pyd +0 -0
- hikyuu/cpp/core39.pyi +187 -22
- hikyuu/cpp/hikyuu.dll +0 -0
- hikyuu/cpp/hikyuu.lib +0 -0
- hikyuu/draw/__init__.pyi +1 -1
- hikyuu/draw/drawplot/__init__.py +2 -0
- hikyuu/draw/drawplot/__init__.pyi +9 -8
- hikyuu/draw/drawplot/bokeh_draw.pyi +519 -506
- hikyuu/draw/drawplot/common.pyi +1 -1
- hikyuu/draw/drawplot/echarts_draw.pyi +521 -508
- hikyuu/draw/drawplot/matplotlib_draw.py +80 -0
- hikyuu/draw/drawplot/matplotlib_draw.pyi +540 -517
- hikyuu/draw/elder.pyi +11 -11
- hikyuu/draw/kaufman.pyi +18 -18
- hikyuu/draw/volume.pyi +10 -10
- hikyuu/examples/notebook/002-HowToGetStock.ipynb +1 -1
- hikyuu/examples/notebook/004-IndicatorOverview.ipynb +117 -52
- hikyuu/extend.pyi +507 -500
- hikyuu/gui/HikyuuTDX.py +85 -15
- hikyuu/gui/data/ImportQmtToH5Task.py +209 -0
- hikyuu/gui/data/ImportTdxToH5Task.py +8 -1
- hikyuu/gui/data/MainWindow.py +94 -13
- hikyuu/gui/data/UseQmtImportToH5Thread.py +316 -0
- hikyuu/gui/data/UseTdxImportToH5Thread.py +221 -65
- hikyuu/gui/dataserver.py +25 -0
- hikyuu/gui/images/star.png +0 -0
- hikyuu/gui/importdata.py +24 -11
- hikyuu/hub.pyi +6 -6
- hikyuu/include/hikyuu/KData.h +5 -0
- hikyuu/include/hikyuu/KDataImp.h +4 -0
- hikyuu/include/hikyuu/StockManager.h +23 -0
- hikyuu/include/hikyuu/data_driver/kdata/mysql/KRecordTable.h +41 -2
- hikyuu/include/hikyuu/global/agent/spot_generated.h +3 -3
- hikyuu/include/hikyuu/indicator/crt/COUNT.h +3 -3
- hikyuu/include/hikyuu/indicator/crt/DISCARD.h +1 -1
- hikyuu/include/hikyuu/indicator/crt/ISINF.h +1 -1
- hikyuu/include/hikyuu/indicator/crt/ISINFA.h +1 -1
- hikyuu/include/hikyuu/indicator/crt/ISNA.h +1 -1
- hikyuu/include/hikyuu/indicator/crt/LAST.h +2 -2
- hikyuu/include/hikyuu/indicator/crt/MAX.h +1 -1
- hikyuu/include/hikyuu/indicator/crt/MIN.h +1 -1
- hikyuu/include/hikyuu/indicator/crt/PRICELIST.h +1 -15
- hikyuu/include/hikyuu/indicator/crt/SUMBARS.h +1 -1
- hikyuu/include/hikyuu/plugin/KDataToHdf5Importer.h +33 -0
- hikyuu/include/hikyuu/plugin/__init__.py +1 -0
- hikyuu/include/hikyuu/plugin/backtest.h +37 -0
- hikyuu/include/hikyuu/plugin/dataserver.h +18 -0
- hikyuu/include/hikyuu/plugin/device.h +29 -0
- hikyuu/include/hikyuu/plugin/interface/BackTestPluginInterface.h +26 -0
- hikyuu/include/hikyuu/plugin/interface/DataServerPluginInterface.h +23 -0
- hikyuu/include/hikyuu/plugin/interface/DevicePluginInterface.h +25 -0
- hikyuu/include/hikyuu/plugin/interface/ImportKDataToHdf5PluginInterface.h +33 -0
- hikyuu/include/hikyuu/plugin/interface/__init__.py +1 -0
- hikyuu/include/hikyuu/plugin/interface/plugins.h +22 -0
- hikyuu/include/hikyuu/python/pybind_utils.h +8 -0
- hikyuu/include/hikyuu/strategy/BrokerTradeManager.h +2 -1
- hikyuu/include/hikyuu/strategy/RunPortfolioInStrategy.h +1 -0
- hikyuu/include/hikyuu/strategy/Strategy.h +93 -16
- hikyuu/include/hikyuu/trade_manage/TradeManagerBase.h +4 -2
- hikyuu/include/hikyuu/trade_sys/portfolio/Portfolio.h +2 -1
- hikyuu/include/hikyuu/trade_sys/selector/SelectorBase.h +12 -9
- hikyuu/include/hikyuu/trade_sys/selector/imp/MultiFactorSelector.h +1 -1
- hikyuu/include/hikyuu/trade_sys/selector/imp/logic/OperatorSelector.h +12 -12
- hikyuu/include/hikyuu/trade_sys/selector/imp/logic/OperatorValueSelector.h +2 -2
- hikyuu/include/hikyuu/trade_sys/selector/imp/optimal/PerformanceOptimalSelector.h +1 -1
- hikyuu/include/hikyuu/trade_sys/system/System.h +12 -3
- hikyuu/include/hikyuu/trade_sys/system/imp/DelegateSystem.h +0 -1
- hikyuu/include/hikyuu/trade_sys/system/imp/WalkForwardSystem.h +0 -1
- hikyuu/include/hikyuu/trade_sys/system/imp/WalkForwardTradeManager.h +3 -2
- hikyuu/include/hikyuu/utilities/arithmetic.h +32 -22
- hikyuu/include/hikyuu/utilities/datetime/Datetime.h +1 -0
- hikyuu/include/hikyuu/utilities/plugin/PluginClient.h +2 -2
- hikyuu/include/hikyuu/utilities/plugin/PluginLoader.h +66 -13
- hikyuu/include/hikyuu/utilities/plugin/PluginManager.h +72 -0
- hikyuu/include/hikyuu/version.h +5 -5
- hikyuu/plugin/__init__.py +1 -0
- hikyuu/plugin/backtest.dll +0 -0
- hikyuu/plugin/dataserver.dll +0 -0
- hikyuu/plugin/device.dll +0 -0
- hikyuu/plugin/import2hdf5.dll +0 -0
- hikyuu/strategy/strategy_demo1.py +7 -8
- hikyuu/strategy/strategy_demo2.py +1 -1
- hikyuu/trade_manage/__init__.pyi +518 -505
- hikyuu/trade_manage/broker.pyi +3 -3
- hikyuu/trade_manage/broker_easytrader.pyi +1 -1
- hikyuu/trade_manage/trade.pyi +518 -505
- hikyuu/util/__init__.py +1 -0
- hikyuu/util/__init__.pyi +2 -1
- hikyuu/util/mylog.py +30 -3
- hikyuu/util/mylog.pyi +3 -1
- hikyuu/util/singleton.pyi +1 -1
- {hikyuu-2.5.6.dist-info → hikyuu-2.6.1.dist-info}/METADATA +6 -2
- {hikyuu-2.5.6.dist-info → hikyuu-2.6.1.dist-info}/RECORD +115 -97
- {hikyuu-2.5.6.dist-info → hikyuu-2.6.1.dist-info}/entry_points.txt +1 -0
- {hikyuu-2.5.6.dist-info → hikyuu-2.6.1.dist-info}/top_level.txt +4 -0
- hikyuu/cpp/core38.pyd +0 -0
- hikyuu/cpp/core38.pyi +0 -13173
- hikyuu/examples/notebook/011-PyechartsDrawplot.ipynb +0 -21821
- /hikyuu/gui/{hikyuu_small.png → images/hikyuu_small.png} +0 -0
- {hikyuu-2.5.6.dist-info → hikyuu-2.6.1.dist-info}/LICENSE +0 -0
- {hikyuu-2.5.6.dist-info → hikyuu-2.6.1.dist-info}/WHEEL +0 -0
|
@@ -24,18 +24,30 @@
|
|
|
24
24
|
|
|
25
25
|
import logging
|
|
26
26
|
import sqlite3
|
|
27
|
+
import datetime
|
|
28
|
+
import mysql.connector
|
|
29
|
+
import queue
|
|
27
30
|
from multiprocessing import Queue, Process
|
|
28
31
|
from PyQt5.QtCore import QThread, pyqtSignal
|
|
29
32
|
from hikyuu.gui.data.ImportTdxToH5Task import ImportTdxToH5Task
|
|
30
33
|
from hikyuu.gui.data.ImportWeightToSqliteTask import ImportWeightToSqliteTask
|
|
34
|
+
from hikyuu.gui.data.ImportTdxToH5Task import ImportTdxToH5Task
|
|
31
35
|
from hikyuu.gui.data.ImportHistoryFinanceTask import ImportHistoryFinanceTask
|
|
32
|
-
|
|
36
|
+
from hikyuu.gui.data.ImportBlockInfoTask import ImportBlockInfoTask
|
|
37
|
+
from hikyuu.gui.data.ImportZhBond10Task import ImportZhBond10Task
|
|
33
38
|
from pytdx.hq import TdxHq_API
|
|
34
|
-
from hikyuu.data.common import g_market_list
|
|
35
|
-
from hikyuu.data.common_sqlite3 import create_database
|
|
36
39
|
from hikyuu.data.common_pytdx import search_best_tdx
|
|
37
|
-
|
|
38
|
-
from hikyuu.
|
|
40
|
+
|
|
41
|
+
from hikyuu.data.common import *
|
|
42
|
+
from hikyuu.data.common_sqlite3 import import_new_holidays as sqlite_import_new_holidays
|
|
43
|
+
from hikyuu.data.common_sqlite3 import create_database as sqlite_create_database
|
|
44
|
+
from hikyuu.data.pytdx_to_h5 import import_index_name as sqlite_import_index_name
|
|
45
|
+
from hikyuu.data.pytdx_to_h5 import import_stock_name as sqlite_import_stock_name
|
|
46
|
+
from hikyuu.data.common_mysql import create_database as mysql_create_database
|
|
47
|
+
from hikyuu.data.common_mysql import import_new_holidays as mysql_import_new_holidays
|
|
48
|
+
from hikyuu.data.pytdx_to_mysql import import_index_name as mysql_import_index_name
|
|
49
|
+
from hikyuu.data.pytdx_to_mysql import import_stock_name as mysql_import_stock_name
|
|
50
|
+
from hikyuu.util.mylog import class_logger
|
|
39
51
|
|
|
40
52
|
|
|
41
53
|
class UseTdxImportToH5Thread(QThread):
|
|
@@ -43,66 +55,120 @@ class UseTdxImportToH5Thread(QThread):
|
|
|
43
55
|
|
|
44
56
|
def __init__(self, parent, config):
|
|
45
57
|
super(UseTdxImportToH5Thread, self).__init__()
|
|
46
|
-
self.logger = logging.getLogger(self.__class__.__name__)
|
|
47
58
|
self.parent = parent
|
|
48
59
|
self.log_queue = parent.mp_log_q if parent is not None else None
|
|
49
60
|
self.config = config
|
|
50
61
|
self.msg_name = 'HDF5_IMPORT'
|
|
51
62
|
|
|
52
63
|
self.process_list = []
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
dest_dir = config['hdf5']['dir']
|
|
56
|
-
sqlite_file_name = dest_dir + "/stock.db"
|
|
64
|
+
self.hosts = []
|
|
65
|
+
self.tasks = []
|
|
57
66
|
|
|
58
67
|
self.quotations = []
|
|
59
68
|
if self.config['quotation']['stock']:
|
|
60
69
|
self.quotations.append('stock')
|
|
61
70
|
if self.config['quotation']['fund']:
|
|
62
71
|
self.quotations.append('fund')
|
|
63
|
-
# if self.config['quotation']['future']:
|
|
64
|
-
# self.quotations.append('future')
|
|
65
72
|
|
|
66
|
-
|
|
67
|
-
# 每个债券本身的数据很少但债券种类太多占用空间和时间太多,用途较少不再考虑导入
|
|
68
|
-
# if self.config['quotation']['bond']:
|
|
69
|
-
# self.quotations.append('bond')
|
|
73
|
+
self.queue = Queue()
|
|
70
74
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
75
|
+
def __del__(self):
|
|
76
|
+
for p in self.process_list:
|
|
77
|
+
if p.is_alive():
|
|
78
|
+
p.terminate()
|
|
79
|
+
|
|
80
|
+
def send_message(self, msg):
|
|
81
|
+
self.message.emit([self.msg_name] + msg)
|
|
82
|
+
|
|
83
|
+
def init_task(self):
|
|
84
|
+
config = self.config
|
|
85
|
+
src_dir = config['tdx']['dir']
|
|
86
|
+
dest_dir = config['hdf5']['dir']
|
|
74
87
|
|
|
75
|
-
self.queue = Queue()
|
|
76
88
|
self.tasks = []
|
|
89
|
+
if self.config.getboolean('finance', 'enable', fallback=True):
|
|
90
|
+
self.tasks.append(
|
|
91
|
+
ImportHistoryFinanceTask(self.log_queue, self.queue, self.config, dest_dir))
|
|
92
|
+
|
|
93
|
+
self.tasks.append(ImportBlockInfoTask(self.log_queue, self.queue,
|
|
94
|
+
self.config, ('行业板块', '概念板块', '地域板块', '指数板块')))
|
|
95
|
+
self.tasks.append(ImportZhBond10Task(self.log_queue, self.queue, self.config))
|
|
96
|
+
|
|
97
|
+
task_count = 0
|
|
98
|
+
market_count = len(g_market_list)
|
|
99
|
+
if self.config.getboolean('ktype', 'day', fallback=False):
|
|
100
|
+
task_count += market_count
|
|
101
|
+
if self.config.getboolean('ktype', 'min5', fallback=False):
|
|
102
|
+
task_count += market_count
|
|
103
|
+
if self.config.getboolean('ktype', 'min', fallback=False):
|
|
104
|
+
task_count += market_count
|
|
105
|
+
# 本地暂不支持分时和分笔导入
|
|
106
|
+
# if self.config.getboolean('ktype', 'trans', fallback=False):
|
|
107
|
+
# task_count += market_count
|
|
108
|
+
# if self.config.getboolean('ktype', 'time', fallback=False):
|
|
109
|
+
# task_count += market_count
|
|
110
|
+
if self.config.getboolean('weight', 'enable', fallback=False):
|
|
111
|
+
task_count += (market_count*2)
|
|
112
|
+
|
|
113
|
+
self.logger.info('搜索通达信服务器')
|
|
114
|
+
self.send_message(['INFO', '搜索通达信服务器'])
|
|
115
|
+
self.hosts = search_best_tdx()
|
|
116
|
+
if not self.hosts:
|
|
117
|
+
self.logger.warn('无法连接通达信行情服务器!请检查网络设置!')
|
|
118
|
+
self.send_message(['INFO', '无法连接通达信行情服务器!请检查网络设置!'])
|
|
119
|
+
return
|
|
120
|
+
|
|
121
|
+
if task_count == 0:
|
|
122
|
+
self.send_message(['INFO', '未选择需要导入的行情数据!'])
|
|
123
|
+
return
|
|
124
|
+
|
|
125
|
+
use_tdx_number = min(
|
|
126
|
+
task_count, len(self.hosts),
|
|
127
|
+
self.config.getint('pytdx', 'use_tdx_number', fallback=10))
|
|
128
|
+
split = task_count // use_tdx_number
|
|
129
|
+
use_hosts = []
|
|
130
|
+
for i in range(use_tdx_number):
|
|
131
|
+
for j in range(split):
|
|
132
|
+
use_hosts.append((self.hosts[i][2], self.hosts[i][3]))
|
|
133
|
+
if len(use_hosts) < task_count:
|
|
134
|
+
for i in range(task_count - len(use_hosts)):
|
|
135
|
+
use_hosts.insert(0, (self.hosts[0][2], self.hosts[0][3]))
|
|
136
|
+
# for i in range(len(use_hosts)):
|
|
137
|
+
# print(i, use_hosts[i])
|
|
77
138
|
|
|
78
139
|
cur_host = 0
|
|
79
140
|
if self.config.getboolean('weight', 'enable', fallback=False):
|
|
80
141
|
for market in g_market_list:
|
|
81
142
|
self.tasks.append(
|
|
82
143
|
ImportWeightToSqliteTask(self.log_queue, self.queue,
|
|
83
|
-
self.config, dest_dir, market, 'weight', hosts[cur_host][2],
|
|
84
|
-
hosts[cur_host][3]))
|
|
144
|
+
self.config, dest_dir, market, 'weight', self.hosts[cur_host][2],
|
|
145
|
+
self.hosts[cur_host][3]))
|
|
85
146
|
cur_host += 1
|
|
86
|
-
if cur_host >= len(hosts):
|
|
147
|
+
if cur_host >= len(self.hosts):
|
|
87
148
|
cur_host = 0
|
|
88
149
|
self.tasks.append(
|
|
89
150
|
ImportWeightToSqliteTask(self.log_queue, self.queue,
|
|
90
|
-
self.config, dest_dir, market, 'finance', hosts[cur_host][2],
|
|
91
|
-
hosts[cur_host][3]))
|
|
151
|
+
self.config, dest_dir, market, 'finance', self.hosts[cur_host][2],
|
|
152
|
+
self.hosts[cur_host][3]))
|
|
92
153
|
cur_host += 1
|
|
93
|
-
if cur_host >= len(hosts):
|
|
154
|
+
if cur_host >= len(self.hosts):
|
|
94
155
|
cur_host = 0
|
|
95
156
|
|
|
96
|
-
if self.config.getboolean('finance', 'enable', fallback=True):
|
|
97
|
-
self.tasks.append(ImportHistoryFinanceTask(self.log_queue, self.queue, self.config, dest_dir))
|
|
98
157
|
if self.config.getboolean('ktype', 'day', fallback=False):
|
|
158
|
+
self.tasks.append(
|
|
159
|
+
ImportTdxToH5Task(self.log_queue, self.queue, config, 'BJ', 'DAY', self.quotations, src_dir, dest_dir)
|
|
160
|
+
)
|
|
99
161
|
self.tasks.append(
|
|
100
162
|
ImportTdxToH5Task(self.log_queue, self.queue, config, 'SH', 'DAY', self.quotations, src_dir, dest_dir)
|
|
101
163
|
)
|
|
102
164
|
self.tasks.append(
|
|
103
165
|
ImportTdxToH5Task(self.log_queue, self.queue, config, 'SZ', 'DAY', self.quotations, src_dir, dest_dir)
|
|
104
166
|
)
|
|
167
|
+
|
|
105
168
|
if self.config.getboolean('ktype', 'min5', fallback=False):
|
|
169
|
+
self.tasks.append(
|
|
170
|
+
ImportTdxToH5Task(self.log_queue, self.queue, config, 'BJ', '5MIN', self.quotations, src_dir, dest_dir)
|
|
171
|
+
)
|
|
106
172
|
self.tasks.append(
|
|
107
173
|
ImportTdxToH5Task(self.log_queue, self.queue, config, 'SH', '5MIN', self.quotations, src_dir, dest_dir)
|
|
108
174
|
)
|
|
@@ -110,6 +176,9 @@ class UseTdxImportToH5Thread(QThread):
|
|
|
110
176
|
ImportTdxToH5Task(self.log_queue, self.queue, config, 'SZ', '5MIN', self.quotations, src_dir, dest_dir)
|
|
111
177
|
)
|
|
112
178
|
if self.config.getboolean('ktype', 'min', fallback=False):
|
|
179
|
+
self.tasks.append(
|
|
180
|
+
ImportTdxToH5Task(self.log_queue, self.queue, config, 'BJ', '1MIN', self.quotations, src_dir, dest_dir)
|
|
181
|
+
)
|
|
113
182
|
self.tasks.append(
|
|
114
183
|
ImportTdxToH5Task(self.log_queue, self.queue, config, 'SH', '1MIN', self.quotations, src_dir, dest_dir)
|
|
115
184
|
)
|
|
@@ -117,38 +186,71 @@ class UseTdxImportToH5Thread(QThread):
|
|
|
117
186
|
ImportTdxToH5Task(self.log_queue, self.queue, config, 'SZ', '1MIN', self.quotations, src_dir, dest_dir)
|
|
118
187
|
)
|
|
119
188
|
|
|
120
|
-
def __del__(self):
|
|
121
|
-
for p in self.process_list:
|
|
122
|
-
if p.is_alive():
|
|
123
|
-
p.terminate()
|
|
124
|
-
|
|
125
|
-
def send_message(self, msg):
|
|
126
|
-
self.message.emit([self.msg_name] + msg)
|
|
127
|
-
|
|
128
189
|
def run(self):
|
|
129
190
|
try:
|
|
191
|
+
self.init_task()
|
|
130
192
|
self._run()
|
|
131
193
|
except Exception as e:
|
|
194
|
+
self.logger.error(str(e))
|
|
132
195
|
self.send_message(['THREAD', 'FAILURE', str(e)])
|
|
133
196
|
else:
|
|
197
|
+
self.logger.info('导入完毕')
|
|
134
198
|
self.send_message(['THREAD', 'FINISHED'])
|
|
135
199
|
|
|
136
200
|
@hku_catch(trace=True, re_raise=True)
|
|
137
201
|
def _run(self):
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
202
|
+
hdf5_import_progress = {}
|
|
203
|
+
trans_progress = {}
|
|
204
|
+
time_progress = {}
|
|
205
|
+
for market in g_market_list:
|
|
206
|
+
hdf5_import_progress[market] = {'DAY': 0, '1MIN': 0, '5MIN': 0}
|
|
207
|
+
trans_progress[market] = 0
|
|
208
|
+
time_progress[market] = 0
|
|
141
209
|
|
|
142
210
|
# 正在导入代码表
|
|
143
|
-
self.
|
|
211
|
+
self.logger.info('导入股票代码表')
|
|
212
|
+
self.send_message(['INFO', '导入股票代码表'])
|
|
213
|
+
|
|
214
|
+
if self.config.getboolean('hdf5', 'enable', fallback=True):
|
|
215
|
+
connect = sqlite3.connect("{}/stock.db".format(
|
|
216
|
+
self.config['hdf5']['dir']))
|
|
217
|
+
create_database = sqlite_create_database
|
|
218
|
+
import_new_holidays = sqlite_import_new_holidays
|
|
219
|
+
import_index_name = sqlite_import_index_name
|
|
220
|
+
import_stock_name = sqlite_import_stock_name
|
|
221
|
+
else:
|
|
222
|
+
db_config = {
|
|
223
|
+
'user': self.config['mysql']['usr'],
|
|
224
|
+
'password': self.config['mysql']['pwd'],
|
|
225
|
+
'host': self.config['mysql']['host'],
|
|
226
|
+
'port': self.config['mysql']['port']
|
|
227
|
+
}
|
|
228
|
+
connect = mysql.connector.connect(**db_config)
|
|
229
|
+
create_database = mysql_create_database
|
|
230
|
+
import_new_holidays = mysql_import_new_holidays
|
|
231
|
+
import_index_name = mysql_import_index_name
|
|
232
|
+
import_stock_name = mysql_import_stock_name
|
|
144
233
|
|
|
145
|
-
connect = sqlite3.connect(dest_dir + "/stock.db")
|
|
146
234
|
create_database(connect)
|
|
147
235
|
|
|
148
|
-
|
|
149
|
-
|
|
236
|
+
pytdx_api = TdxHq_API()
|
|
237
|
+
hku_check(pytdx_api.connect(self.hosts[0][2], self.hosts[0][3]),
|
|
238
|
+
"failed connect pytdx {}:{}", self.hosts[0][2],
|
|
239
|
+
self.hosts[0][3])
|
|
150
240
|
|
|
151
|
-
self.
|
|
241
|
+
self.logger.info("导入交易所休假日历")
|
|
242
|
+
import_new_holidays(connect)
|
|
243
|
+
|
|
244
|
+
count = import_index_name(connect)
|
|
245
|
+
self.logger.info("指数数量: {}".format(count))
|
|
246
|
+
|
|
247
|
+
for market in g_market_list:
|
|
248
|
+
count = import_stock_name(connect, pytdx_api, market,
|
|
249
|
+
self.quotations)
|
|
250
|
+
if count > 0:
|
|
251
|
+
self.logger.info("{} 新增股票数: {}".format(market, count))
|
|
252
|
+
self.send_message(
|
|
253
|
+
['INFO', '{} 新增股票数:{}'.format(market, count)])
|
|
152
254
|
|
|
153
255
|
self.process_list.clear()
|
|
154
256
|
for task in self.tasks:
|
|
@@ -157,26 +259,80 @@ class UseTdxImportToH5Thread(QThread):
|
|
|
157
259
|
p.start()
|
|
158
260
|
|
|
159
261
|
finished_count = len(self.tasks)
|
|
262
|
+
market_count = len(g_market_list)
|
|
160
263
|
while finished_count > 0:
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
264
|
+
try:
|
|
265
|
+
message = self.queue.get(timeout=10)
|
|
266
|
+
taskname, market, ktype, progress, total = message
|
|
267
|
+
if progress is None:
|
|
268
|
+
finished_count -= 1
|
|
269
|
+
if taskname in ('IMPORT_KDATA', 'IMPORT_TRANS',
|
|
270
|
+
'IMPORT_TIME'):
|
|
271
|
+
self.send_message(
|
|
272
|
+
[taskname, 'FINISHED', market, ktype, total])
|
|
273
|
+
elif taskname == 'IMPORT_BLOCKINFO':
|
|
274
|
+
self.send_message([taskname, ktype])
|
|
275
|
+
elif taskname == 'IMPORT_ZH_BOND10':
|
|
276
|
+
self.send_message([taskname, ktype])
|
|
277
|
+
elif taskname == 'IMPORT_WEIGHT':
|
|
278
|
+
pass
|
|
279
|
+
else:
|
|
280
|
+
self.send_message([taskname, 'FINISHED'])
|
|
281
|
+
continue
|
|
282
|
+
|
|
283
|
+
if taskname == 'IMPORT_WEIGHT':
|
|
284
|
+
if market == 'INFO':
|
|
285
|
+
self.send_message(['INFO', ktype])
|
|
286
|
+
self.send_message([taskname, market, total])
|
|
287
|
+
elif taskname == 'IMPORT_FINANCE':
|
|
288
|
+
self.send_message([taskname, progress])
|
|
289
|
+
elif taskname == 'IMPORT_KDATA':
|
|
290
|
+
hdf5_import_progress[market][ktype] = progress
|
|
291
|
+
current_progress = 0
|
|
292
|
+
for market in g_market_list:
|
|
293
|
+
current_progress += hdf5_import_progress[market][ktype]
|
|
294
|
+
current_progress = current_progress // market_count
|
|
295
|
+
self.send_message([taskname, ktype, current_progress])
|
|
296
|
+
elif taskname == 'IMPORT_TRANS':
|
|
297
|
+
trans_progress[market] = progress
|
|
298
|
+
current_progress = 0
|
|
299
|
+
for market in g_market_list:
|
|
300
|
+
current_progress += trans_progress[market]
|
|
301
|
+
current_progress = current_progress // market_count
|
|
302
|
+
self.send_message([taskname, ktype, current_progress])
|
|
303
|
+
elif taskname == 'IMPORT_TIME':
|
|
304
|
+
time_progress[market] = progress
|
|
305
|
+
current_progress = 0
|
|
306
|
+
for market in g_market_list:
|
|
307
|
+
current_progress += time_progress[market]
|
|
308
|
+
current_progress = current_progress // market_count
|
|
309
|
+
self.send_message([taskname, ktype, current_progress])
|
|
310
|
+
elif taskname == 'IMPORT_BLOCKINFO':
|
|
311
|
+
self.send_message([taskname, market, ktype])
|
|
167
312
|
else:
|
|
168
|
-
self.
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
313
|
+
self.logger.error("Unknow task: {}".format(taskname))
|
|
314
|
+
except queue.Empty:
|
|
315
|
+
if finished_count > 0:
|
|
316
|
+
ok = False
|
|
317
|
+
for p in self.process_list:
|
|
318
|
+
if p.is_alive():
|
|
319
|
+
ok = True
|
|
320
|
+
break
|
|
321
|
+
if not ok:
|
|
322
|
+
for task in self.tasks:
|
|
323
|
+
self.logger.info(
|
|
324
|
+
f"task ({task.__class__.__name__}) status: {task.status}!"
|
|
325
|
+
)
|
|
326
|
+
for p in self.process_list:
|
|
327
|
+
self.logger.info(
|
|
328
|
+
f"Process exit code: {p.exitcode}")
|
|
329
|
+
finished_count = 0
|
|
330
|
+
self.logger.error(
|
|
331
|
+
"All process is finished, but some tasks are running!"
|
|
332
|
+
)
|
|
333
|
+
|
|
334
|
+
except Exception as e:
|
|
335
|
+
self.logger.error(str(e))
|
|
336
|
+
|
|
337
|
+
|
|
338
|
+
class_logger(UseTdxImportToH5Thread)
|
hikyuu/gui/dataserver.py
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
#!/usr/bin/python
|
|
2
|
+
# -*- coding: utf8 -*-
|
|
3
|
+
#
|
|
4
|
+
# Create on: 2025-04-15
|
|
5
|
+
# Author: fasiondog
|
|
6
|
+
|
|
7
|
+
from hikyuu import start_data_server, stop_data_server
|
|
8
|
+
import time
|
|
9
|
+
import sys
|
|
10
|
+
|
|
11
|
+
if __name__ == "__main__":
|
|
12
|
+
data_server_addr = "tcp://0.0.0.0:9201" if len(sys.argv) <= 1 else sys.argv[1]
|
|
13
|
+
work_num = 2 if len(sys.argv) <= 2 else int(sys.argv[2])
|
|
14
|
+
|
|
15
|
+
try:
|
|
16
|
+
start_data_server(data_server_addr, work_num)
|
|
17
|
+
|
|
18
|
+
while True:
|
|
19
|
+
try:
|
|
20
|
+
time.sleep(1)
|
|
21
|
+
except KeyboardInterrupt:
|
|
22
|
+
break
|
|
23
|
+
|
|
24
|
+
finally:
|
|
25
|
+
stop_data_server()
|
|
Binary file
|
hikyuu/gui/importdata.py
CHANGED
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
# cp936
|
|
4
4
|
|
|
5
5
|
import os.path
|
|
6
|
-
import sys
|
|
6
|
+
import sys
|
|
7
|
+
import time
|
|
7
8
|
from configparser import ConfigParser
|
|
8
9
|
|
|
9
10
|
from hikyuu.data.weight_to_sqlite import qianlong_import_weight
|
|
@@ -14,7 +15,8 @@ from hikyuu.gui.data.UsePytdxImportToH5Thread import UsePytdxImportToH5Thread
|
|
|
14
15
|
|
|
15
16
|
|
|
16
17
|
class HKUImportDataCMD:
|
|
17
|
-
def __init__(self):
|
|
18
|
+
def __init__(self, ignore_kdata=False):
|
|
19
|
+
self.ignore_kdata = ignore_kdata # 忽略K线数据导入
|
|
18
20
|
self.initThreads()
|
|
19
21
|
|
|
20
22
|
def getUserConfigDir(self):
|
|
@@ -25,6 +27,12 @@ class HKUImportDataCMD:
|
|
|
25
27
|
this_dir = self.getUserConfigDir()
|
|
26
28
|
import_config = ConfigParser()
|
|
27
29
|
import_config.read(this_dir + '/importdata-gui.ini', encoding='utf-8')
|
|
30
|
+
if self.ignore_kdata:
|
|
31
|
+
import_config.set('ktype', 'day', 'False')
|
|
32
|
+
import_config.set('ktype', 'min', 'False')
|
|
33
|
+
import_config.set('ktype', 'min5', 'False')
|
|
34
|
+
import_config.set('ktype', 'trans', 'False')
|
|
35
|
+
import_config.set('ktype', 'time', 'False')
|
|
28
36
|
return import_config
|
|
29
37
|
|
|
30
38
|
def initThreads(self):
|
|
@@ -46,7 +54,8 @@ class HKUImportDataCMD:
|
|
|
46
54
|
def print_progress(self, ktype, progress):
|
|
47
55
|
if progress != self.progress[ktype]:
|
|
48
56
|
print(
|
|
49
|
-
'import progress: {}% - {} - 已耗时 {:>.2f} 分钟'.format(progress,
|
|
57
|
+
'import progress: {}% - {} - 已耗时 {:>.2f} 分钟'.format(progress,
|
|
58
|
+
self.info_type[ktype], self.time_escaped())
|
|
50
59
|
)
|
|
51
60
|
self.progress[ktype] = progress
|
|
52
61
|
|
|
@@ -65,11 +74,12 @@ class HKUImportDataCMD:
|
|
|
65
74
|
if status == 'FAILURE':
|
|
66
75
|
self.details.append(msg[3])
|
|
67
76
|
print("\n导入完毕, 共耗时 {:>.2f} 分钟".format(self.time_escaped()))
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
77
|
+
if not self.ignore_kdata:
|
|
78
|
+
print('\n=========================================================')
|
|
79
|
+
print("导入详情:")
|
|
80
|
+
for info in self.details:
|
|
81
|
+
print(info)
|
|
82
|
+
print('=========================================================')
|
|
73
83
|
self.import_running = False
|
|
74
84
|
|
|
75
85
|
elif msg_task_name == 'IMPORT_KDATA':
|
|
@@ -144,10 +154,13 @@ class HKUImportDataCMD:
|
|
|
144
154
|
self.hdf5_import_thread.run()
|
|
145
155
|
|
|
146
156
|
|
|
147
|
-
def main():
|
|
148
|
-
x = HKUImportDataCMD()
|
|
157
|
+
def main(ignore_kdata=False):
|
|
158
|
+
x = HKUImportDataCMD(ignore_kdata=ignore_kdata)
|
|
149
159
|
x.start_import_data()
|
|
150
160
|
|
|
151
161
|
|
|
152
162
|
if __name__ == '__main__':
|
|
153
|
-
|
|
163
|
+
if len(sys.argv) > 1 and sys.argv[1] == '--ignore-kdata':
|
|
164
|
+
main(ignore_kdata=True)
|
|
165
|
+
else:
|
|
166
|
+
main(ignore_kdata=False)
|
hikyuu/hub.pyi
CHANGED
|
@@ -28,11 +28,11 @@ import sys as sys
|
|
|
28
28
|
import typing
|
|
29
29
|
__all__: list = ['add_remote_hub', 'add_local_hub', 'update_hub', 'remove_hub', 'build_hub', 'help_part', 'get_part', 'get_part_list', 'get_hub_path', 'get_part_info', 'get_part_module', 'print_part_info', 'get_hub_name_list', 'get_part_name_list', 'get_current_hub', 'search_part']
|
|
30
30
|
class ConfigModel(sqlalchemy.orm.decl_api.Base):
|
|
31
|
-
__mapper__: typing.ClassVar[sqlalchemy.orm.mapper.Mapper] # value = <Mapper at
|
|
31
|
+
__mapper__: typing.ClassVar[sqlalchemy.orm.mapper.Mapper] # value = <Mapper at 0x1dfa5a64520; ConfigModel>
|
|
32
32
|
__table__: typing.ClassVar[sqlalchemy.sql.schema.Table] # value = Table('hub_config', MetaData(), Column('id', Integer(), table=<hub_config>, primary_key=True, nullable=False, default=Sequence('config_id_seq', metadata=MetaData())), Column('key', String(), table=<hub_config>), Column('value', String(), table=<hub_config>), schema=None)
|
|
33
33
|
__table_args__: typing.ClassVar[tuple] # value = (UniqueConstraint(Column('key', String(), table=<hub_config>)))
|
|
34
34
|
__tablename__: typing.ClassVar[str] = 'hub_config'
|
|
35
|
-
_sa_class_manager: typing.ClassVar[sqlalchemy.orm.instrumentation.ClassManager] # value = <ClassManager of <class 'hikyuu.hub.ConfigModel'> at
|
|
35
|
+
_sa_class_manager: typing.ClassVar[sqlalchemy.orm.instrumentation.ClassManager] # value = <ClassManager of <class 'hikyuu.hub.ConfigModel'> at 1dfa5abce50>
|
|
36
36
|
def __init__(self, **kwargs):
|
|
37
37
|
"""
|
|
38
38
|
A simple constructor that allows initialization from kwargs.
|
|
@@ -109,11 +109,11 @@ class HubManager:
|
|
|
109
109
|
def print_part_info(self, name):
|
|
110
110
|
...
|
|
111
111
|
class HubModel(sqlalchemy.orm.decl_api.Base):
|
|
112
|
-
__mapper__: typing.ClassVar[sqlalchemy.orm.mapper.Mapper] # value = <Mapper at
|
|
112
|
+
__mapper__: typing.ClassVar[sqlalchemy.orm.mapper.Mapper] # value = <Mapper at 0x1dfa5adee20; HubModel>
|
|
113
113
|
__table__: typing.ClassVar[sqlalchemy.sql.schema.Table] # value = Table('hub_repo', MetaData(), Column('id', Integer(), table=<hub_repo>, primary_key=True, nullable=False, default=Sequence('remote_id_seq', metadata=MetaData())), Column('name', String(), table=<hub_repo>), Column('hub_type', String(), table=<hub_repo>), Column('local_base', String(), table=<hub_repo>), Column('local', String(), table=<hub_repo>), Column('url', String(), table=<hub_repo>), Column('branch', String(), table=<hub_repo>), schema=None)
|
|
114
114
|
__table_args__: typing.ClassVar[tuple] # value = (UniqueConstraint(Column('name', String(), table=<hub_repo>)))
|
|
115
115
|
__tablename__: typing.ClassVar[str] = 'hub_repo'
|
|
116
|
-
_sa_class_manager: typing.ClassVar[sqlalchemy.orm.instrumentation.ClassManager] # value = <ClassManager of <class 'hikyuu.hub.HubModel'> at
|
|
116
|
+
_sa_class_manager: typing.ClassVar[sqlalchemy.orm.instrumentation.ClassManager] # value = <ClassManager of <class 'hikyuu.hub.HubModel'> at 1dfa5af0900>
|
|
117
117
|
def __init__(self, **kwargs):
|
|
118
118
|
"""
|
|
119
119
|
A simple constructor that allows initialization from kwargs.
|
|
@@ -146,11 +146,11 @@ class ModuleConflictError(Exception):
|
|
|
146
146
|
def __str__(self):
|
|
147
147
|
...
|
|
148
148
|
class PartModel(sqlalchemy.orm.decl_api.Base):
|
|
149
|
-
__mapper__: typing.ClassVar[sqlalchemy.orm.mapper.Mapper] # value = <Mapper at
|
|
149
|
+
__mapper__: typing.ClassVar[sqlalchemy.orm.mapper.Mapper] # value = <Mapper at 0x1dfa5b044f0; PartModel>
|
|
150
150
|
__table__: typing.ClassVar[sqlalchemy.sql.schema.Table] # value = Table('hub_part', MetaData(), Column('id', Integer(), table=<hub_part>, primary_key=True, nullable=False, default=Sequence('part_id_seq', metadata=MetaData())), Column('hub_name', String(), table=<hub_part>), Column('part', String(), table=<hub_part>), Column('name', String(), table=<hub_part>), Column('author', String(), table=<hub_part>), Column('version', String(), table=<hub_part>), Column('doc', String(), table=<hub_part>), Column('module_name', String(), table=<hub_part>), Column('label', String(), table=<hub_part>), schema=None)
|
|
151
151
|
__table_args__: typing.ClassVar[tuple] # value = (UniqueConstraint(Column('name', String(), table=<hub_part>)))
|
|
152
152
|
__tablename__: typing.ClassVar[str] = 'hub_part'
|
|
153
|
-
_sa_class_manager: typing.ClassVar[sqlalchemy.orm.instrumentation.ClassManager] # value = <ClassManager of <class 'hikyuu.hub.PartModel'> at
|
|
153
|
+
_sa_class_manager: typing.ClassVar[sqlalchemy.orm.instrumentation.ClassManager] # value = <ClassManager of <class 'hikyuu.hub.PartModel'> at 1dfa5afd3b0>
|
|
154
154
|
def __init__(self, **kwargs):
|
|
155
155
|
"""
|
|
156
156
|
A simple constructor that allows initialization from kwargs.
|
hikyuu/include/hikyuu/KData.h
CHANGED
|
@@ -117,6 +117,7 @@ public:
|
|
|
117
117
|
const_iterator cbegin() const;
|
|
118
118
|
const_iterator cend() const;
|
|
119
119
|
const KRecord* data() const;
|
|
120
|
+
KRecord* data(); // 谨慎使用(用于强制调整数据)
|
|
120
121
|
|
|
121
122
|
private:
|
|
122
123
|
static KRecord ms_null_krecord;
|
|
@@ -261,6 +262,10 @@ inline const KRecord* KData::data() const {
|
|
|
261
262
|
return m_imp->data();
|
|
262
263
|
}
|
|
263
264
|
|
|
265
|
+
inline KRecord* KData::data() {
|
|
266
|
+
return m_imp->data();
|
|
267
|
+
}
|
|
268
|
+
|
|
264
269
|
} /* namespace hku */
|
|
265
270
|
|
|
266
271
|
#if FMT_VERSION >= 90000
|
hikyuu/include/hikyuu/KDataImp.h
CHANGED
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
#include <thread>
|
|
14
14
|
#include "hikyuu/utilities/Parameter.h"
|
|
15
15
|
#include "hikyuu/utilities/thread/thread.h"
|
|
16
|
+
#include "hikyuu/utilities/plugin/PluginManager.h"
|
|
16
17
|
#include "hikyuu/data_driver/DataDriverFactory.h"
|
|
17
18
|
#include "Block.h"
|
|
18
19
|
#include "MarketInfo.h"
|
|
@@ -235,6 +236,17 @@ public:
|
|
|
235
236
|
return m_load_tg.get();
|
|
236
237
|
}
|
|
237
238
|
|
|
239
|
+
/** 设置插件路径(仅在初始化之前有效) */
|
|
240
|
+
void setPluginPath(const std::string& path);
|
|
241
|
+
|
|
242
|
+
/** 获取当前插件路径 */
|
|
243
|
+
const string& getPluginPath() const {
|
|
244
|
+
return m_plugin_manager.pluginPath();
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
template <typename PluginInterfaceT>
|
|
248
|
+
PluginInterfaceT* getPlugin(const std::string& pluginname) noexcept;
|
|
249
|
+
|
|
238
250
|
public:
|
|
239
251
|
typedef StockMapIterator const_iterator;
|
|
240
252
|
const_iterator begin() const {
|
|
@@ -312,6 +324,8 @@ private:
|
|
|
312
324
|
StrategyContext m_context;
|
|
313
325
|
|
|
314
326
|
std::unique_ptr<ThreadPool> m_load_tg; // 异步数据加载辅助线程组
|
|
327
|
+
|
|
328
|
+
PluginManager m_plugin_manager;
|
|
315
329
|
};
|
|
316
330
|
|
|
317
331
|
inline size_t StockManager::size() const {
|
|
@@ -367,6 +381,15 @@ inline vector<HistoryFinanceInfo> StockManager::getHistoryFinance(const Stock& s
|
|
|
367
381
|
return m_baseInfoDriver->getHistoryFinance(stk.market(), stk.code(), start, end);
|
|
368
382
|
}
|
|
369
383
|
|
|
384
|
+
inline void StockManager::setPluginPath(const std::string& path) {
|
|
385
|
+
m_plugin_manager.pluginPath(path);
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
template <typename PluginInterfaceT>
|
|
389
|
+
inline PluginInterfaceT* StockManager::getPlugin(const std::string& pluginname) noexcept {
|
|
390
|
+
return m_plugin_manager.getPlugin<PluginInterfaceT>(pluginname);
|
|
391
|
+
}
|
|
392
|
+
|
|
370
393
|
} // namespace hku
|
|
371
394
|
|
|
372
395
|
#endif /* STOCKMANAGER_H_ */
|