hikyuu 2.6.8.4__py3-none-manylinux2014_x86_64.whl → 2.6.9__py3-none-manylinux2014_x86_64.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 +5 -12
- hikyuu/__init__.pyi +612 -587
- hikyuu/analysis/__init__.pyi +589 -563
- hikyuu/analysis/analysis.pyi +590 -564
- hikyuu/core.py +2 -0
- hikyuu/core.pyi +591 -565
- hikyuu/cpp/__init__.pyi +2 -2
- hikyuu/cpp/core310.pyi +446 -13
- hikyuu/cpp/core310.so +0 -0
- hikyuu/cpp/core311.pyi +440 -13
- hikyuu/cpp/core311.so +0 -0
- hikyuu/cpp/core312.pyi +440 -13
- hikyuu/cpp/core312.so +0 -0
- hikyuu/cpp/core313.pyi +446 -13
- hikyuu/cpp/core313.so +0 -0
- hikyuu/cpp/i18n/zh_CN/hikyuu.mo +0 -0
- hikyuu/cpp/libboost_charconv-mt.so +0 -0
- hikyuu/cpp/libboost_charconv-mt.so.1.88.0 +0 -0
- hikyuu/cpp/libboost_chrono-mt.so +0 -0
- hikyuu/cpp/libboost_chrono-mt.so.1.88.0 +0 -0
- hikyuu/cpp/libboost_date_time-mt.so +0 -0
- hikyuu/cpp/libboost_date_time-mt.so.1.88.0 +0 -0
- hikyuu/cpp/libboost_serialization-mt.so +0 -0
- hikyuu/cpp/libboost_serialization-mt.so.1.88.0 +0 -0
- hikyuu/cpp/libboost_system-mt.so +0 -0
- hikyuu/cpp/libboost_system-mt.so.1.88.0 +0 -0
- hikyuu/cpp/libboost_thread-mt.so +0 -0
- hikyuu/cpp/libboost_thread-mt.so.1.88.0 +0 -0
- hikyuu/cpp/libboost_wserialization-mt.so +0 -0
- hikyuu/cpp/libboost_wserialization-mt.so.1.88.0 +0 -0
- hikyuu/cpp/libhikyuu.so +0 -0
- hikyuu/cpp/libsqlite3.so +0 -0
- hikyuu/data/clickhouse_upgrade/createdb.sql +105 -105
- hikyuu/data/common.py +3 -3
- hikyuu/data/common_clickhouse.py +1 -1
- hikyuu/data/download_block.py +318 -0
- hikyuu/data/em_block_to_clickhouse.py +26 -74
- hikyuu/data/em_block_to_mysql.py +25 -75
- hikyuu/data/em_block_to_sqlite.py +26 -78
- hikyuu/data/hku_config_template.py +3 -3
- hikyuu/data/pytdx_to_clickhouse.py +15 -11
- hikyuu/data/pytdx_to_h5.py +6 -2
- hikyuu/data/pytdx_to_mysql.py +5 -1
- hikyuu/data/pytdx_weight_to_clickhouse.py +1 -1
- hikyuu/data/pytdx_weight_to_mysql.py +1 -1
- hikyuu/data/pytdx_weight_to_sqlite.py +1 -1
- hikyuu/data/zh_bond10_to_clickhouse.py +1 -1
- hikyuu/draw/drawplot/__init__.pyi +8 -8
- hikyuu/draw/drawplot/bokeh_draw.pyi +603 -578
- hikyuu/draw/drawplot/common.pyi +1 -1
- hikyuu/draw/drawplot/echarts_draw.pyi +605 -580
- hikyuu/draw/drawplot/matplotlib_draw.py +4 -74
- hikyuu/draw/drawplot/matplotlib_draw.pyi +615 -590
- hikyuu/draw/elder.pyi +11 -11
- hikyuu/draw/kaufman.pyi +18 -18
- hikyuu/draw/volume.pyi +10 -10
- hikyuu/examples/notebook/Demo/Demo1.ipynb +48 -33
- hikyuu/extend.pyi +599 -573
- hikyuu/fetcher/stock/zh_block_em.py +50 -18
- hikyuu/gui/HikyuuTDX.py +81 -30
- hikyuu/gui/data/CollectSpotThread.py +1 -1
- hikyuu/gui/data/EscapetimeThread.py +8 -14
- hikyuu/gui/data/ImportBlockInfoTask.py +3 -10
- hikyuu/gui/data/MainWindow.py +1168 -715
- hikyuu/gui/data/SchedImportThread.py +2 -2
- hikyuu/gui/data/UsePytdxImportToH5Thread.py +3 -3
- hikyuu/gui/data/UseQmtImportToH5Thread.py +2 -2
- hikyuu/gui/data/UseTdxImportToH5Thread.py +3 -3
- hikyuu/gui/data/tool.py +32 -25
- hikyuu/gui/dataserver.py +5 -3
- hikyuu/hub.pyi +6 -6
- hikyuu/include/hikyuu/DataType.h +4 -16
- hikyuu/include/hikyuu/KData.h +6 -3
- hikyuu/include/hikyuu/KDataPrivatedBufferImp.h +1 -1
- hikyuu/include/hikyuu/KDataSharedBufferImp.h +1 -1
- hikyuu/include/hikyuu/KQuery.h +2 -2
- hikyuu/include/hikyuu/Stock.h +3 -0
- hikyuu/include/hikyuu/StockManager.h +13 -3
- hikyuu/include/hikyuu/config.h +3 -0
- hikyuu/include/hikyuu/data_driver/BaseInfoDriver.h +8 -0
- hikyuu/include/hikyuu/data_driver/BlockInfoDriver.h +6 -0
- hikyuu/include/hikyuu/data_driver/KDataDriver.h +26 -1
- hikyuu/include/hikyuu/data_driver/base_info/mysql/MySQLBaseInfoDriver.h +1 -1
- hikyuu/include/hikyuu/data_driver/base_info/sqlite/SQLiteBaseInfoDriver.h +1 -1
- hikyuu/include/hikyuu/data_driver/block_info/mysql/MySQLBlockInfoDriver.h +2 -1
- hikyuu/include/hikyuu/data_driver/block_info/qianlong/QLBlockInfoDriver.h +2 -1
- hikyuu/include/hikyuu/data_driver/block_info/sqlite/SQLiteBlockInfoDriver.h +2 -1
- hikyuu/include/hikyuu/data_driver/kdata/DoNothingKDataDriver.h +1 -1
- hikyuu/include/hikyuu/data_driver/kdata/cvs/KDataTempCsvDriver.h +1 -1
- hikyuu/include/hikyuu/data_driver/kdata/hdf5/H5KDataDriver.h +1 -1
- hikyuu/include/hikyuu/data_driver/kdata/mysql/MySQLKDataDriver.h +1 -1
- hikyuu/include/hikyuu/data_driver/kdata/sqlite/SQLiteKDataDriver.h +1 -1
- hikyuu/include/hikyuu/data_driver/kdata/tdx/TdxKDataDriver.h +1 -1
- hikyuu/include/hikyuu/hikyuu.h +1 -1
- hikyuu/include/hikyuu/indicator/build_in.h +1 -0
- hikyuu/include/hikyuu/indicator/crt/CYCLE.h +4 -4
- hikyuu/include/hikyuu/indicator/crt/HSL.h +2 -2
- hikyuu/include/hikyuu/indicator/crt/QUANTILE_TRUNC.h +30 -0
- hikyuu/include/hikyuu/indicator/crt/TURNOVER.h +1 -0
- hikyuu/include/hikyuu/indicator/crt/ZSCORE.h +2 -2
- hikyuu/include/hikyuu/indicator/imp/IQuantileTrunc.h +25 -0
- hikyuu/include/hikyuu/misc.h +38 -0
- hikyuu/include/hikyuu/plugin/dataserver.h +2 -1
- hikyuu/include/hikyuu/plugin/extind.h +37 -0
- hikyuu/include/hikyuu/plugin/hkuextra.h +0 -18
- hikyuu/include/hikyuu/plugin/hkuviews.h +36 -0
- hikyuu/include/hikyuu/plugin/interface/DataServerPluginInterface.h +2 -2
- hikyuu/include/hikyuu/plugin/interface/ExtendIndicatorsPluginInterface.h +12 -0
- hikyuu/include/hikyuu/plugin/interface/HkuExtraPluginInterface.h +0 -14
- hikyuu/include/hikyuu/plugin/interface/HkuViewsPluginInterface.h +34 -0
- hikyuu/include/hikyuu/plugin/interface/plugins.h +8 -1
- hikyuu/include/hikyuu/python/pybind_utils.h +6 -1
- hikyuu/include/hikyuu/strategy/RunSystemInStrategy.h +3 -0
- hikyuu/include/hikyuu/trade_manage/Performance.h +4 -4
- hikyuu/include/hikyuu/trade_manage/TradeManagerBase.h +10 -1
- hikyuu/include/hikyuu/trade_sys/moneymanager/imp/FixedCapitalFundsMM.h +0 -4
- hikyuu/include/hikyuu/trade_sys/multifactor/MultiFactorBase.h +36 -3
- hikyuu/include/hikyuu/trade_sys/multifactor/NormalizeBase.h +125 -0
- hikyuu/include/hikyuu/trade_sys/multifactor/ScoresFilterBase.h +125 -0
- hikyuu/include/hikyuu/trade_sys/multifactor/build_in.h +3 -0
- hikyuu/include/hikyuu/trade_sys/multifactor/buildin_norm.h +36 -0
- hikyuu/include/hikyuu/trade_sys/multifactor/buildin_scfilter.h +51 -0
- hikyuu/include/hikyuu/trade_sys/multifactor/filter/GroupSCFilter.h +24 -0
- hikyuu/include/hikyuu/trade_sys/multifactor/filter/IgnoreLessOrEqualValueSCFilter.h +24 -0
- hikyuu/include/hikyuu/trade_sys/multifactor/filter/IgnoreNanSCFilter.h +24 -0
- hikyuu/include/hikyuu/trade_sys/multifactor/filter/MinAmountPercentSCFilter.h +25 -0
- hikyuu/include/hikyuu/trade_sys/multifactor/filter/PriceSCFilter.h +24 -0
- hikyuu/include/hikyuu/trade_sys/multifactor/filter/TopNSCFilter.h +24 -0
- hikyuu/include/hikyuu/trade_sys/multifactor/filter/__init__.py +1 -0
- hikyuu/include/hikyuu/trade_sys/multifactor/imp/EqualWeightMultiFactor.h +1 -1
- hikyuu/include/hikyuu/trade_sys/multifactor/imp/ICIRMultiFactor.h +1 -1
- hikyuu/include/hikyuu/trade_sys/multifactor/imp/ICMultiFactor.h +1 -1
- hikyuu/include/hikyuu/trade_sys/multifactor/imp/WeightMultiFactor.h +1 -1
- hikyuu/include/hikyuu/trade_sys/multifactor/normalize/NormMinMax.h +23 -0
- hikyuu/include/hikyuu/trade_sys/multifactor/normalize/NormQuantile.h +28 -0
- hikyuu/include/hikyuu/trade_sys/multifactor/normalize/NormQuantileUniform.h +28 -0
- hikyuu/include/hikyuu/trade_sys/multifactor/normalize/NormZScore.h +25 -0
- hikyuu/include/hikyuu/trade_sys/multifactor/normalize/__init__.py +1 -0
- hikyuu/include/hikyuu/trade_sys/multifactor/normalize/quantile_trunc.h +16 -0
- hikyuu/include/hikyuu/trade_sys/portfolio/Portfolio.h +7 -0
- hikyuu/include/hikyuu/trade_sys/portfolio/imp/SimplePortfolio.h +7 -0
- hikyuu/include/hikyuu/trade_sys/portfolio/imp/WithoutAFPortfolio.h +7 -0
- hikyuu/include/hikyuu/trade_sys/selector/SelectorBase.h +49 -0
- hikyuu/include/hikyuu/trade_sys/selector/build_in.h +1 -0
- hikyuu/include/hikyuu/trade_sys/selector/crt/SE_MultiFactor2.h +40 -0
- hikyuu/include/hikyuu/trade_sys/selector/imp/MultiFactorSelector.h +0 -3
- hikyuu/include/hikyuu/trade_sys/selector/imp/MultiFactorSelector2.h +49 -0
- hikyuu/include/hikyuu/trade_sys/selector/imp/logic/OperatorSelector.h +1 -1
- hikyuu/include/hikyuu/trade_sys/selector/imp/logic/OperatorValueSelector.h +1 -1
- hikyuu/include/hikyuu/trade_sys/signal/imp/BandSignal2.h +0 -4
- hikyuu/include/hikyuu/trade_sys/signal/imp/logic/AddValueSignal.h +2 -2
- hikyuu/include/hikyuu/trade_sys/signal/imp/logic/DivValueSignal.h +2 -2
- hikyuu/include/hikyuu/trade_sys/signal/imp/logic/MulValueSignal.h +2 -2
- hikyuu/include/hikyuu/trade_sys/signal/imp/logic/OperatorSignal.h +1 -1
- hikyuu/include/hikyuu/trade_sys/signal/imp/logic/OperatorValueSignal.h +4 -4
- hikyuu/include/hikyuu/trade_sys/signal/imp/logic/SubValueSignal.h +2 -2
- hikyuu/include/hikyuu/trade_sys/system/System.h +14 -1
- hikyuu/include/hikyuu/utilities/SpendTimer.h +17 -7
- hikyuu/include/hikyuu/utilities/arithmetic.h +55 -0
- hikyuu/include/hikyuu/utilities/db_connect/mysql/MySQLConnect.h +1 -1
- hikyuu/include/hikyuu/utilities/db_connect/mysql/MySQLStatement.h +1 -1
- hikyuu/include/hikyuu/utilities/db_connect/sqlite/SQLiteConnect.h +1 -1
- hikyuu/include/hikyuu/utilities/db_connect/sqlite/SQLiteStatement.h +1 -1
- hikyuu/include/hikyuu/utilities/plugin/PluginLoader.h +4 -1
- hikyuu/include/hikyuu/version.h +4 -4
- hikyuu/plugin/libbacktest.so +0 -0
- hikyuu/plugin/libclickhousedriver.so +0 -0
- hikyuu/plugin/libdataserver.so +0 -0
- hikyuu/plugin/libdevice.so +0 -0
- hikyuu/plugin/libextind.so +0 -0
- hikyuu/plugin/libhkuextra.so +0 -0
- hikyuu/plugin/libhkuviews.so +0 -0
- hikyuu/plugin/libimport2hdf5.so +0 -0
- hikyuu/plugin/libtmreport.so +0 -0
- hikyuu/trade_manage/__init__.pyi +603 -578
- hikyuu/trade_manage/broker.pyi +3 -3
- hikyuu/trade_manage/broker_easytrader.pyi +1 -1
- hikyuu/trade_manage/trade.pyi +603 -578
- hikyuu/util/__init__.pyi +2 -2
- hikyuu/util/singleton.pyi +1 -1
- {hikyuu-2.6.8.4.dist-info → hikyuu-2.6.9.dist-info}/METADATA +13 -13
- {hikyuu-2.6.8.4.dist-info → hikyuu-2.6.9.dist-info}/RECORD +185 -156
- {hikyuu-2.6.8.4.dist-info → hikyuu-2.6.9.dist-info}/top_level.txt +2 -1
- hikyuu/cpp/core39.pyi +0 -14385
- hikyuu/cpp/core39.so +0 -0
- hikyuu/data_driver/__init__.py +0 -49
- hikyuu/data_driver/jqdata_data_driver.py +0 -277
- hikyuu/data_driver/pytdx_data_driver.py +0 -292
- hikyuu/fetcher/stock/zh_stock_a_huatai.py +0 -51
- hikyuu/fetcher/stock/zh_stock_a_pytdx.py +0 -129
- hikyuu/gui/data/CollectToMemThread.py +0 -123
- hikyuu/gui/data/CollectToMySQLThread.py +0 -178
- hikyuu/gui/start_huatai_insight.py +0 -510
- hikyuu/tools/update_block_info.py +0 -168
- {hikyuu-2.6.8.4.dist-info → hikyuu-2.6.9.dist-info}/WHEEL +0 -0
- {hikyuu-2.6.8.4.dist-info → hikyuu-2.6.9.dist-info}/entry_points.txt +0 -0
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
#!/usr/bin/python
|
|
2
|
+
# -*- coding: utf8 -*-
|
|
3
|
+
#
|
|
4
|
+
# Create on: 2025-10-05
|
|
5
|
+
# Author: fasiondog
|
|
6
|
+
|
|
7
|
+
from hikyuu.data.common import modifiy_code
|
|
8
|
+
from hikyuu.util import *
|
|
9
|
+
from hikyuu.fetcher.stock.zh_block_em import *
|
|
10
|
+
import os
|
|
11
|
+
from datetime import datetime
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def sanitize_filename(filename: str) -> str:
|
|
15
|
+
"""
|
|
16
|
+
将字符串中影响文件创建的相关目录字符替换为下划线
|
|
17
|
+
|
|
18
|
+
Args:
|
|
19
|
+
filename: 输入的文件名字符串
|
|
20
|
+
|
|
21
|
+
Returns:
|
|
22
|
+
处理后的文件名字符串,其中非法字符已被替换为下划线
|
|
23
|
+
"""
|
|
24
|
+
if not filename:
|
|
25
|
+
return filename
|
|
26
|
+
|
|
27
|
+
# 需要替换的非法字符(Windows和Unix系统中的非法字符)
|
|
28
|
+
illegal_chars = '<>:"/\\|?*'
|
|
29
|
+
|
|
30
|
+
# 替换非法字符为下划线
|
|
31
|
+
sanitized = filename
|
|
32
|
+
for char in illegal_chars:
|
|
33
|
+
sanitized = sanitized.replace(char, '_')
|
|
34
|
+
|
|
35
|
+
return sanitized
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
_BLOCK_SAVE_PATH = os.path.expanduser('~') + '/.hikyuu/downloads/block'
|
|
39
|
+
if not os.path.exists(_BLOCK_SAVE_PATH):
|
|
40
|
+
os.makedirs(_BLOCK_SAVE_PATH)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def read_block_from_path(block_path=_BLOCK_SAVE_PATH):
|
|
44
|
+
"""
|
|
45
|
+
从指定目录下读取block信息
|
|
46
|
+
|
|
47
|
+
:param block_path: block根目录路径,默认为 _BLOCK_SAVE_PATH
|
|
48
|
+
:return: 返回格式类似于 {'block': {'category1': {'name1': [code1, code2]}},
|
|
49
|
+
'block_info': {'category1: {'name1': 'code1', 'name2': ''}}
|
|
50
|
+
"""
|
|
51
|
+
result = {
|
|
52
|
+
'block': {},
|
|
53
|
+
'block_info': {}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if not os.path.exists(block_path):
|
|
57
|
+
return result
|
|
58
|
+
|
|
59
|
+
# 遍历所有分类目录
|
|
60
|
+
for category in os.listdir(block_path):
|
|
61
|
+
category_path = os.path.join(block_path, category)
|
|
62
|
+
if not os.path.isdir(category_path):
|
|
63
|
+
continue
|
|
64
|
+
|
|
65
|
+
result['block'][category] = {}
|
|
66
|
+
result['block_info'][category] = {}
|
|
67
|
+
|
|
68
|
+
# 遍历分类目录下的所有.txt文件
|
|
69
|
+
for file in os.listdir(category_path):
|
|
70
|
+
if file.endswith('.txt'):
|
|
71
|
+
file_path = os.path.join(category_path, file)
|
|
72
|
+
# 文件名作为板块名称(去掉扩展名)
|
|
73
|
+
block_name = os.path.splitext(file)[0]
|
|
74
|
+
|
|
75
|
+
# 解析文件名,格式为 "code_name" 或 "name"
|
|
76
|
+
if '_' in block_name:
|
|
77
|
+
parts = block_name.split('_', 1) # 只分割第一个下划线
|
|
78
|
+
code_part = parts[0]
|
|
79
|
+
name_part = parts[1]
|
|
80
|
+
# 判断code部分是否为纯数字或字母数字组合
|
|
81
|
+
if code_part.replace('_', '').isalnum():
|
|
82
|
+
result['block_info'][category][name_part] = code_part
|
|
83
|
+
block_key = name_part
|
|
84
|
+
else:
|
|
85
|
+
result['block_info'][category][block_name] = ""
|
|
86
|
+
block_key = block_name
|
|
87
|
+
else:
|
|
88
|
+
result['block_info'][category][block_name] = ""
|
|
89
|
+
block_key = block_name
|
|
90
|
+
|
|
91
|
+
# 读取文件中的股票代码
|
|
92
|
+
codes = []
|
|
93
|
+
with open(file_path, 'r', encoding='utf-8') as f:
|
|
94
|
+
for line in f:
|
|
95
|
+
code = line.strip()
|
|
96
|
+
if code:
|
|
97
|
+
codes.append(code)
|
|
98
|
+
|
|
99
|
+
result['block'][category][block_key] = codes
|
|
100
|
+
|
|
101
|
+
return result
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def is_file_can_download(filepath, sec_limit=5 * 24 * 60 * 60):
|
|
105
|
+
"""判断文件创建时间是否超过时长限制可以下载"""
|
|
106
|
+
if not os.path.exists(filepath):
|
|
107
|
+
return True
|
|
108
|
+
|
|
109
|
+
file_mtime = os.path.getmtime(filepath)
|
|
110
|
+
file_datetime = datetime.fromtimestamp(file_mtime)
|
|
111
|
+
now = datetime.now()
|
|
112
|
+
|
|
113
|
+
# 计算时间差是否超过时间限制
|
|
114
|
+
return (now - file_datetime).total_seconds() > sec_limit
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
@hku_catch()
|
|
118
|
+
def save_block(stkcodes: list, filename: str):
|
|
119
|
+
"""将板块数据保存为CSV文件,格式为板块名称/code"""
|
|
120
|
+
with open(filename, 'w', encoding='utf-8') as f:
|
|
121
|
+
for code in stkcodes:
|
|
122
|
+
f.write(f"{code}\n")
|
|
123
|
+
# hku_info(f"已保存至 {filename}")
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
@hku_catch(ret={}, trace=False)
|
|
127
|
+
def down_em_all_hybk_info():
|
|
128
|
+
"""下载东财所有行业板块列表"""
|
|
129
|
+
save_path = f'{_BLOCK_SAVE_PATH}/行业板块'
|
|
130
|
+
if not os.path.exists(save_path):
|
|
131
|
+
os.makedirs(save_path)
|
|
132
|
+
blk_list = get_hybk_names()
|
|
133
|
+
time.sleep(random.uniform(1, 3))
|
|
134
|
+
total = len(blk_list)
|
|
135
|
+
for i, blk in enumerate(blk_list):
|
|
136
|
+
filename = f"{save_path}/{blk[0]}_{blk[1]}.txt"
|
|
137
|
+
if is_file_can_download(filename, 5 * 24 * 60 * 60):
|
|
138
|
+
stk_codes = get_hybk_cons_code(blk[0])
|
|
139
|
+
hku_info(f"{i+1}|{total} 获取行业板块{blk[1]}成分: {len(stk_codes)}")
|
|
140
|
+
stk_codes = [modifiy_code(code) for code in stk_codes]
|
|
141
|
+
stk_codes = [code for code in stk_codes if code is not None]
|
|
142
|
+
save_block(stk_codes, filename)
|
|
143
|
+
time.sleep(random.uniform(1, 3))
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
@hku_catch(ret={}, trace=False)
|
|
147
|
+
def down_em_all_gnbk_info():
|
|
148
|
+
"""获取所有概念版本列表"""
|
|
149
|
+
save_path = f'{_BLOCK_SAVE_PATH}/概念板块'
|
|
150
|
+
if not os.path.exists(save_path):
|
|
151
|
+
os.makedirs(save_path)
|
|
152
|
+
blk_names = stock_board_concept_name_em()['板块名称']
|
|
153
|
+
not_need_blks = set(["昨日连板_含一字", "昨日涨停_含一字", "昨日涨停"])
|
|
154
|
+
total = len(blk_names)
|
|
155
|
+
for i, blk_name in enumerate(blk_names):
|
|
156
|
+
if blk_name in not_need_blks:
|
|
157
|
+
continue
|
|
158
|
+
filename = f"{save_path}/{sanitize_filename(blk_name)}.txt"
|
|
159
|
+
if is_file_can_download(filename, 30 * 24 * 60 * 60):
|
|
160
|
+
stk_codes = stock_board_concept_cons_em(blk_name)
|
|
161
|
+
stk_codes = stk_codes['代码'].to_list()
|
|
162
|
+
stk_codes = [modifiy_code(code) for code in stk_codes]
|
|
163
|
+
stk_codes = [code for code in stk_codes if code is not None]
|
|
164
|
+
hku_info(f"{i+1}|{total} 获取概念板块{blk_name}成分: {len(stk_codes)}")
|
|
165
|
+
save_block(stk_codes, filename)
|
|
166
|
+
time.sleep(random.uniform(1, 3))
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
@hku_catch(ret={}, trace=False)
|
|
170
|
+
def down_em_all_dybk_info():
|
|
171
|
+
"""获取所有地域板块列表"""
|
|
172
|
+
save_path = f'{_BLOCK_SAVE_PATH}/地域板块'
|
|
173
|
+
if not os.path.exists(save_path):
|
|
174
|
+
os.makedirs(save_path)
|
|
175
|
+
blk_list = get_dybk_names()
|
|
176
|
+
|
|
177
|
+
url = "http://13.push2.eastmoney.com/api/qt/clist/get"
|
|
178
|
+
params = {
|
|
179
|
+
"pn": "1",
|
|
180
|
+
"pz": str(em_num_per_page),
|
|
181
|
+
"po": "1",
|
|
182
|
+
"np": "1",
|
|
183
|
+
"ut": "bd1d9ddb04089700cf9c27f6f7426281",
|
|
184
|
+
"fltt": "2",
|
|
185
|
+
"invt": "2",
|
|
186
|
+
"fid": "f3",
|
|
187
|
+
# "fs": f"b:{stock_board_code} f:!50",
|
|
188
|
+
"fields": "f12",
|
|
189
|
+
"_": "1626081702127",
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
total = len(blk_list)
|
|
193
|
+
for i, v in enumerate(blk_list):
|
|
194
|
+
blk_code, blk_name = v[0], v[1]
|
|
195
|
+
filename = f"{save_path}/{blk_name}.txt"
|
|
196
|
+
if not is_file_can_download(filename, 10 * 24 * 60 * 60):
|
|
197
|
+
continue
|
|
198
|
+
|
|
199
|
+
params["fs"] = f"b:{blk_code} f:!50"
|
|
200
|
+
params["pn"] = 1
|
|
201
|
+
time.sleep(random.uniform(1, 3))
|
|
202
|
+
r = requests.get(url, params=params, timeout=15)
|
|
203
|
+
data = r.json()
|
|
204
|
+
if data["data"] is None:
|
|
205
|
+
continue
|
|
206
|
+
|
|
207
|
+
stk_json = r.json()
|
|
208
|
+
stk_json = stk_json["data"]["diff"]
|
|
209
|
+
stk_codes = []
|
|
210
|
+
|
|
211
|
+
total_page = math.ceil(data["data"]["total"] / em_num_per_page)
|
|
212
|
+
for page in range(2, total_page + 1):
|
|
213
|
+
params["pn"] = page
|
|
214
|
+
r = requests.get(url, params=params, timeout=15)
|
|
215
|
+
stk_json = r.json()
|
|
216
|
+
stk_json = stk_json["data"]["diff"]
|
|
217
|
+
stk_codes.extend([f"{v['f12']}" for v in stk_json])
|
|
218
|
+
time.sleep(random.uniform(1, 3))
|
|
219
|
+
|
|
220
|
+
stk_codes = [modifiy_code(code) for code in stk_codes]
|
|
221
|
+
stk_codes = [code for code in stk_codes if code is not None]
|
|
222
|
+
save_block(stk_codes, filename)
|
|
223
|
+
hku_info(f'{i+1}|{total} 获取地域板块{blk_name}成分: {len(stk_codes)}')
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
@hku_catch(ret={}, trace=False)
|
|
227
|
+
def download_all_zsbk_info():
|
|
228
|
+
"""获取所有指数成分股列表"""
|
|
229
|
+
save_path = f'{_BLOCK_SAVE_PATH}/指数板块'
|
|
230
|
+
if not os.path.exists(save_path):
|
|
231
|
+
os.makedirs(save_path)
|
|
232
|
+
|
|
233
|
+
blk_info = ak.index_stock_info()
|
|
234
|
+
time.sleep(random.uniform(1, 3))
|
|
235
|
+
|
|
236
|
+
blk_info['index_code'] = blk_info['index_code'].astype(str) # 确保是字符串类型
|
|
237
|
+
df_000 = blk_info[blk_info['index_code'].str.startswith('000')].reset_index(drop=True) # 000前缀
|
|
238
|
+
df_399 = blk_info[blk_info['index_code'].str.startswith('399')].reset_index(drop=True) # 399前缀
|
|
239
|
+
|
|
240
|
+
# 2. 交替合并两个DataFrame
|
|
241
|
+
merged_rows = []
|
|
242
|
+
max_length = max(len(df_000), len(df_399)) # 取两个DataFrame的最大长度
|
|
243
|
+
|
|
244
|
+
for i in range(max_length):
|
|
245
|
+
# 先加000前缀的行(如果存在)
|
|
246
|
+
if i < len(df_000):
|
|
247
|
+
merged_rows.append(df_000.iloc[i])
|
|
248
|
+
# 再加399前缀的行(如果存在)
|
|
249
|
+
if i < len(df_399):
|
|
250
|
+
merged_rows.append(df_399.iloc[i])
|
|
251
|
+
|
|
252
|
+
# 3. 转换为DataFrame
|
|
253
|
+
blk_info = pd.DataFrame(merged_rows).reset_index(drop=True)
|
|
254
|
+
|
|
255
|
+
not_need_blks = set(["000012", "000013", "000022", "000061", "000101", "000188",
|
|
256
|
+
"000817", "000847", "000849", "000850", "000851", "000853",
|
|
257
|
+
"000854", "000856", "000857", "000858", "000923", "000973",
|
|
258
|
+
"000974", "000996", "000997", "000999", "399415", "399416"])
|
|
259
|
+
|
|
260
|
+
failed_sina = 0
|
|
261
|
+
blk_set = {}
|
|
262
|
+
blk_codes = blk_info["index_code"]
|
|
263
|
+
blk_names = blk_info["display_name"]
|
|
264
|
+
total = len(blk_codes)
|
|
265
|
+
for i in range(total):
|
|
266
|
+
blk_name = blk_names[i]
|
|
267
|
+
blk_code = blk_codes[i]
|
|
268
|
+
# 沪深指数有重复,避免深指覆盖
|
|
269
|
+
if blk_name in blk_set or blk_code in not_need_blks:
|
|
270
|
+
continue
|
|
271
|
+
|
|
272
|
+
market_block_code = f'SH{blk_code}' if blk_code.startswith('0') else f'SZ{blk_code}'
|
|
273
|
+
filename = f"{save_path}/{market_block_code}_{blk_name}.txt"
|
|
274
|
+
if not is_file_can_download(filename, 10 * 24 * 60 * 60):
|
|
275
|
+
continue
|
|
276
|
+
|
|
277
|
+
try:
|
|
278
|
+
if blk_code[:3] == "399":
|
|
279
|
+
if failed_sina >= 5:
|
|
280
|
+
continue
|
|
281
|
+
stk_codes = ak.index_stock_cons(symbol=blk_code)
|
|
282
|
+
stk_codes = stk_codes['品种代码'].to_list()
|
|
283
|
+
else:
|
|
284
|
+
stk_codes = ak.index_stock_cons_csindex(symbol=blk_code)
|
|
285
|
+
stk_codes = stk_codes['成分券代码'].to_list()
|
|
286
|
+
|
|
287
|
+
stk_codes = [modifiy_code(code) for code in stk_codes]
|
|
288
|
+
stk_codes = [code for code in stk_codes if code is not None]
|
|
289
|
+
save_block(stk_codes, filename)
|
|
290
|
+
hku_info("{}|{} 获取指数板块 {}|{} 成分: {}", i, total, blk_code, blk_name, len(stk_codes))
|
|
291
|
+
blk_set[blk_name] = 1
|
|
292
|
+
except KeyboardInterrupt:
|
|
293
|
+
break
|
|
294
|
+
except Exception as e:
|
|
295
|
+
print(f"Failed! {i}, {blk_code}, {blk_name} {str(e)}")
|
|
296
|
+
if blk_code.startswith("399"):
|
|
297
|
+
failed_sina += 1
|
|
298
|
+
# raise e
|
|
299
|
+
time.sleep(random.uniform(1, 3))
|
|
300
|
+
|
|
301
|
+
|
|
302
|
+
def download_block_info():
|
|
303
|
+
down_em_all_hybk_info()
|
|
304
|
+
# down_em_all_dybk_info()
|
|
305
|
+
# down_em_all_gnbk_info()
|
|
306
|
+
download_all_zsbk_info()
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
if __name__ == "__main__":
|
|
310
|
+
# down_em_all_hybk_info()
|
|
311
|
+
# down_em_all_dybk_info()
|
|
312
|
+
# down_em_all_gnbk_info()
|
|
313
|
+
# download_all_zsbk_info()
|
|
314
|
+
|
|
315
|
+
ret = read_block_from_path()
|
|
316
|
+
# print(ret['block'])
|
|
317
|
+
print(ret['block_info'])
|
|
318
|
+
print(tuple(ret['block'].keys()))
|
|
@@ -4,85 +4,32 @@
|
|
|
4
4
|
# Create on: 20240102
|
|
5
5
|
# Author: fasiondog
|
|
6
6
|
|
|
7
|
-
from concurrent.futures import ThreadPoolExecutor
|
|
8
|
-
from hikyuu.data.common import MARKET, get_stk_code_name_list
|
|
9
7
|
from hikyuu.util import *
|
|
10
8
|
from hikyuu.fetcher.stock.zh_block_em import *
|
|
9
|
+
from hikyuu.data.download_block import *
|
|
11
10
|
|
|
12
11
|
|
|
13
|
-
def em_import_block_to_clickhouse(connect
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
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
|
|
60
|
-
|
|
61
|
-
blks = []
|
|
62
|
-
if success_fetch_hy:
|
|
63
|
-
blks.append('行业板块')
|
|
64
|
-
if success_fetch_gn:
|
|
65
|
-
blks.append('概念板块')
|
|
66
|
-
if success_fetch_dy:
|
|
67
|
-
blks.append('地域板块')
|
|
68
|
-
if success_fetch_zs:
|
|
69
|
-
blks.append('指数板块')
|
|
12
|
+
def em_import_block_to_clickhouse(connect):
|
|
13
|
+
download_block_info()
|
|
14
|
+
|
|
15
|
+
blocks_info = read_block_from_path()
|
|
16
|
+
blks = blocks_info['block']
|
|
17
|
+
blks_info = blocks_info['block_info']
|
|
70
18
|
|
|
71
19
|
if not blks:
|
|
72
|
-
return
|
|
20
|
+
return 0
|
|
73
21
|
|
|
74
22
|
hku_info("更新数据库")
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
sql = f"delete from hku_base.block where category in {tuple(blks)}"
|
|
23
|
+
sql = f"delete from hku_base.block where category in {tuple(blks.keys())}"
|
|
24
|
+
connect.command(sql)
|
|
25
|
+
sql = f"delete from hku_base.blockindex where category in {tuple(blks.keys())}"
|
|
79
26
|
connect.command(sql)
|
|
80
27
|
|
|
81
28
|
insert_records = []
|
|
82
29
|
|
|
83
|
-
for category in
|
|
84
|
-
for name in
|
|
85
|
-
for code in
|
|
30
|
+
for category, blocks in blks.items():
|
|
31
|
+
for name, codes in blocks.items():
|
|
32
|
+
for code in codes:
|
|
86
33
|
insert_records.append((category, name, code))
|
|
87
34
|
|
|
88
35
|
if insert_records:
|
|
@@ -91,6 +38,17 @@ def em_import_block_to_clickhouse(connect, code_market_dict, categorys=('行业
|
|
|
91
38
|
data=insert_records)
|
|
92
39
|
connect.insert(context=ic)
|
|
93
40
|
|
|
41
|
+
index_records = []
|
|
42
|
+
for category, blocks in blks_info.items():
|
|
43
|
+
for name, index_code in blocks.items():
|
|
44
|
+
if len(index_code) == 8:
|
|
45
|
+
index_records.append((category, name, index_code))
|
|
46
|
+
if index_records:
|
|
47
|
+
ic = connect.create_insert_context(table='blockindex', database='hku_base',
|
|
48
|
+
column_names=['category', 'name', 'index_code'],
|
|
49
|
+
data=index_records)
|
|
50
|
+
connect.insert(context=ic)
|
|
51
|
+
|
|
94
52
|
return len(insert_records)
|
|
95
53
|
|
|
96
54
|
|
|
@@ -109,12 +67,6 @@ if __name__ == "__main__":
|
|
|
109
67
|
client = clickhouse_connect.get_client(
|
|
110
68
|
host=host, username=user, password=password)
|
|
111
69
|
|
|
112
|
-
|
|
113
|
-
code_market_dict = {}
|
|
114
|
-
for v in x:
|
|
115
|
-
code_market_dict[v["code"]] = MARKET.SH
|
|
116
|
-
# print(code_market_dict)
|
|
117
|
-
|
|
118
|
-
em_import_block_to_clickhouse(client, code_market_dict, categorys=('行业板块', ))
|
|
70
|
+
em_import_block_to_clickhouse(client)
|
|
119
71
|
|
|
120
72
|
client.close()
|
hikyuu/data/em_block_to_mysql.py
CHANGED
|
@@ -4,93 +4,49 @@
|
|
|
4
4
|
# Create on: 20240102
|
|
5
5
|
# Author: fasiondog
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
from hikyuu.data.common import MARKET, get_stk_code_name_list
|
|
7
|
+
|
|
9
8
|
from hikyuu.util import *
|
|
10
9
|
from hikyuu.fetcher.stock.zh_block_em import *
|
|
10
|
+
from hikyuu.data.download_block import *
|
|
11
|
+
|
|
11
12
|
|
|
13
|
+
def em_import_block_to_mysql(connect):
|
|
14
|
+
download_block_info()
|
|
12
15
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
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
|
|
60
|
-
|
|
61
|
-
blks = []
|
|
62
|
-
if success_fetch_hy:
|
|
63
|
-
blks.append('行业板块')
|
|
64
|
-
if success_fetch_gn:
|
|
65
|
-
blks.append('概念板块')
|
|
66
|
-
if success_fetch_dy:
|
|
67
|
-
blks.append('地域板块')
|
|
68
|
-
if success_fetch_zs:
|
|
69
|
-
blks.append('指数板块')
|
|
16
|
+
blocks_info = read_block_from_path()
|
|
17
|
+
blks = blocks_info['block']
|
|
18
|
+
blks_info = blocks_info['block_info']
|
|
70
19
|
|
|
71
20
|
if not blks:
|
|
72
|
-
return
|
|
21
|
+
return 0
|
|
73
22
|
|
|
74
23
|
hku_info("更新数据库")
|
|
75
24
|
cur = connect.cursor()
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
sql = f"delete from hku_base.block where category in {tuple(blks)}"
|
|
25
|
+
sql = f"delete from hku_base.block where category in {tuple(blks.keys())}"
|
|
26
|
+
cur.execute(sql)
|
|
27
|
+
sql = f"delete from hku_base.BlockIndex where category in {tuple(blks.keys())}"
|
|
80
28
|
cur.execute(sql)
|
|
81
29
|
|
|
82
30
|
insert_records = []
|
|
83
31
|
|
|
84
|
-
for category in
|
|
85
|
-
for name in
|
|
86
|
-
for code in
|
|
32
|
+
for category, blocks in blks.items():
|
|
33
|
+
for name, codes in blocks.items():
|
|
34
|
+
for code in codes:
|
|
87
35
|
insert_records.append((category, name, code))
|
|
88
36
|
|
|
89
37
|
if insert_records:
|
|
90
38
|
sql = "insert into hku_base.block (category, name, market_code) values (%s,%s,%s)"
|
|
91
|
-
hku_info(f"insert block records: {len(insert_records)}")
|
|
92
39
|
cur.executemany(sql, insert_records)
|
|
93
40
|
|
|
41
|
+
index_records = []
|
|
42
|
+
for category, blocks in blks_info.items():
|
|
43
|
+
for name, index_code in blocks.items():
|
|
44
|
+
if len(index_code) == 8:
|
|
45
|
+
index_records.append((category, name, index_code))
|
|
46
|
+
if index_records:
|
|
47
|
+
sql = "insert into hku_base.BlockIndex (category, name, market_code) values (%s,%s,%s)"
|
|
48
|
+
cur.executemany(sql, index_records)
|
|
49
|
+
|
|
94
50
|
connect.commit()
|
|
95
51
|
cur.close()
|
|
96
52
|
return len(insert_records)
|
|
@@ -111,11 +67,5 @@ if __name__ == "__main__":
|
|
|
111
67
|
connect = mysql.connector.connect(user=usr, password=pwd, host=host, port=port)
|
|
112
68
|
create_database(connect)
|
|
113
69
|
|
|
114
|
-
|
|
115
|
-
code_market_dict = {}
|
|
116
|
-
for v in x:
|
|
117
|
-
code_market_dict[v["code"]] = MARKET.SH
|
|
118
|
-
# print(code_market_dict)
|
|
119
|
-
|
|
120
|
-
em_import_block_to_mysql(connect, code_market_dict)
|
|
70
|
+
em_import_block_to_mysql(connect)
|
|
121
71
|
connect.close()
|