ezKit 1.9.2__py3-none-any.whl → 1.9.3__py3-none-any.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.
- ezKit/stock.py +148 -0
- {ezKit-1.9.2.dist-info → ezKit-1.9.3.dist-info}/METADATA +1 -1
- {ezKit-1.9.2.dist-info → ezKit-1.9.3.dist-info}/RECORD +6 -6
- {ezKit-1.9.2.dist-info → ezKit-1.9.3.dist-info}/LICENSE +0 -0
- {ezKit-1.9.2.dist-info → ezKit-1.9.3.dist-info}/WHEEL +0 -0
- {ezKit-1.9.2.dist-info → ezKit-1.9.3.dist-info}/top_level.txt +0 -0
ezKit/stock.py
CHANGED
@@ -2,8 +2,12 @@
|
|
2
2
|
import re
|
3
3
|
from copy import deepcopy
|
4
4
|
|
5
|
+
import akshare as ak
|
6
|
+
import numpy as np
|
7
|
+
import talib as ta
|
5
8
|
from loguru import logger
|
6
9
|
from pandas import DataFrame
|
10
|
+
from sqlalchemy.engine import Engine
|
7
11
|
|
8
12
|
from . import utils
|
9
13
|
|
@@ -111,3 +115,147 @@ def kdj_vector(df: DataFrame, cp: int = 9, sp1: int = 3, sp2: int = 3) -> DataFr
|
|
111
115
|
except Exception as e:
|
112
116
|
logger.exception(e)
|
113
117
|
return None
|
118
|
+
|
119
|
+
|
120
|
+
# --------------------------------------------------------------------------------------------------
|
121
|
+
|
122
|
+
|
123
|
+
def data_vector(
|
124
|
+
df: DataFrame,
|
125
|
+
macd_options: tuple[int, int, int] = (12, 26, 9),
|
126
|
+
kdj_options: tuple[int, int, int] = (9, 3, 3)
|
127
|
+
) -> DataFrame | None:
|
128
|
+
"""数据运算"""
|
129
|
+
|
130
|
+
try:
|
131
|
+
|
132
|
+
# 数据为空
|
133
|
+
if isinstance(df, DataFrame) and df.empty:
|
134
|
+
return None
|
135
|
+
|
136
|
+
# ------------------------------------------------------------------------------------------
|
137
|
+
|
138
|
+
# 计算均线: 3,7日均线
|
139
|
+
# pylint: disable=E1101
|
140
|
+
# df['SMA03'] = ta.SMA(df['close'], timeperiod=3) # type: ignore
|
141
|
+
# df['SMA07'] = ta.SMA(df['close'], timeperiod=7) # type: ignore
|
142
|
+
|
143
|
+
# 3,7日均线金叉: 0 无, 1 金叉, 2 死叉
|
144
|
+
# df['SMA37_X'] = 0
|
145
|
+
# sma37_position = df['SMA03'] > df['SMA07']
|
146
|
+
# df.loc[sma37_position[(sma37_position is True) & (sma37_position.shift() is False)].index, 'SMA37_X'] = 1 # type: ignore
|
147
|
+
# df.loc[sma37_position[(sma37_position is False) & (sma37_position.shift() is True)].index, 'SMA37_X'] = 2 # type: ignore
|
148
|
+
|
149
|
+
# 计算均线: 20,25日均线
|
150
|
+
# df['SMA20'] = ta.SMA(df['close'], timeperiod=20) # type: ignore
|
151
|
+
# df['SMA25'] = ta.SMA(df['close'], timeperiod=25) # type: ignore
|
152
|
+
|
153
|
+
# 20,25日均线金叉: 0 无, 1 金叉, 2 死叉
|
154
|
+
# df['SMA225_X'] = 0
|
155
|
+
# sma225_position = df['SMA20'] > df['SMA25']
|
156
|
+
# df.loc[sma225_position[(sma225_position is True) & (sma225_position.shift() is False)].index, 'SMA225_X'] = 1 # type: ignore
|
157
|
+
# df.loc[sma225_position[(sma225_position is False) & (sma225_position.shift() is True)].index, 'SMA225_X'] = 2 # type: ignore
|
158
|
+
|
159
|
+
# ------------------------------------------------------------------------------------------
|
160
|
+
|
161
|
+
# 计算 MACD: 默认参数 12 26 9
|
162
|
+
macd_dif, macd_dea, macd_bar = ta.MACD(df['close'].values, fastperiod=macd_options[0], slowperiod=macd_options[1], signalperiod=macd_options[2]) # type: ignore
|
163
|
+
macd_dif[np.isnan(macd_dif)], macd_dea[np.isnan(macd_dea)], macd_bar[np.isnan(macd_bar)] = 0, 0, 0
|
164
|
+
|
165
|
+
# https://www.bilibili.com/read/cv10185856
|
166
|
+
df['MACD'] = 2 * (macd_dif - macd_dea)
|
167
|
+
df['MACD_DIF'] = macd_dif
|
168
|
+
df['MACD_DEA'] = macd_dea
|
169
|
+
|
170
|
+
# MACD 金叉死叉: 0 无, 1 金叉, 2 死叉
|
171
|
+
df['MACD_X'] = 0
|
172
|
+
macd_position = df['MACD_DIF'] > df['MACD_DEA']
|
173
|
+
df.loc[macd_position[(macd_position is True) & (macd_position.shift() is False)].index, 'MACD_X'] = 1 # type: ignore
|
174
|
+
df.loc[macd_position[(macd_position is False) & (macd_position.shift() is True)].index, 'MACD_X'] = 2 # type: ignore
|
175
|
+
|
176
|
+
# ------------------------------------------------------------------------------------------
|
177
|
+
|
178
|
+
# 计算 KDJ: : 默认参数 9 3 3
|
179
|
+
kdj_data = kdj_vector(df, kdj_options[0], kdj_options[1], kdj_options[2])
|
180
|
+
|
181
|
+
if kdj_data is not None:
|
182
|
+
|
183
|
+
# KDJ 数据
|
184
|
+
df['K'] = kdj_data['K'].values
|
185
|
+
df['D'] = kdj_data['D'].values
|
186
|
+
df['J'] = kdj_data['J'].values
|
187
|
+
|
188
|
+
# KDJ 金叉死叉: 0 无, 1 金叉, 2 死叉
|
189
|
+
df['KDJ_X'] = 0
|
190
|
+
kdj_position = df['J'] > df['D']
|
191
|
+
df.loc[kdj_position[(kdj_position is True) & (kdj_position.shift() is False)].index, 'KDJ_X'] = 1 # type: ignore
|
192
|
+
df.loc[kdj_position[(kdj_position is False) & (kdj_position.shift() is True)].index, 'KDJ_X'] = 2 # type: ignore
|
193
|
+
|
194
|
+
# ------------------------------------------------------------------------------------------
|
195
|
+
|
196
|
+
return df
|
197
|
+
|
198
|
+
except Exception as e:
|
199
|
+
logger.exception(e)
|
200
|
+
return None
|
201
|
+
|
202
|
+
|
203
|
+
# --------------------------------------------------------------------------------------------------
|
204
|
+
|
205
|
+
|
206
|
+
def get_code_name_from_akshare() -> DataFrame | None:
|
207
|
+
"""获取股票代码和名称"""
|
208
|
+
info = "获取股票代码和名称"
|
209
|
+
try:
|
210
|
+
logger.info(f"{info} ......")
|
211
|
+
df: DataFrame = ak.stock_info_a_code_name()
|
212
|
+
if df.empty:
|
213
|
+
logger.error(f"{info} [失败]")
|
214
|
+
return None
|
215
|
+
# 排除 ST、证券和银行
|
216
|
+
# https://towardsdatascience.com/8-ways-to-filter-pandas-dataframes-d34ba585c1b8
|
217
|
+
df = df[df.code.str.contains("^00|^60") & ~df.name.str.contains("ST|证券|银行")]
|
218
|
+
logger.success(f"{info} [成功]")
|
219
|
+
return df
|
220
|
+
except Exception as e:
|
221
|
+
logger.error(f"{info} [失败]")
|
222
|
+
logger.exception(e)
|
223
|
+
return None
|
224
|
+
|
225
|
+
|
226
|
+
# --------------------------------------------------------------------------------------------------
|
227
|
+
|
228
|
+
|
229
|
+
def get_stock_data_from_akshare(code: str) -> DataFrame | None:
|
230
|
+
"""从 akshare 获取数据"""
|
231
|
+
info = f"获取股票所有数据: {code}"
|
232
|
+
try:
|
233
|
+
logger.info(f"{info} ......")
|
234
|
+
df: DataFrame = ak.stock_zh_a_daily(symbol=code, adjust="qfq")
|
235
|
+
df = df.round({'turnover': 4})
|
236
|
+
logger.success(f"{info} [成功]")
|
237
|
+
return df[['date', 'open', 'close', 'high', 'low', 'volume', 'turnover']].copy()
|
238
|
+
except Exception as e:
|
239
|
+
logger.error(f"{info} [失败]")
|
240
|
+
logger.exception(e)
|
241
|
+
return None
|
242
|
+
|
243
|
+
|
244
|
+
# --------------------------------------------------------------------------------------------------
|
245
|
+
|
246
|
+
|
247
|
+
def save_data_to_database(engine: Engine, code: str) -> bool:
|
248
|
+
"""保存股票数据到数据库"""
|
249
|
+
info: str = "保存股票数据到数据库"
|
250
|
+
try:
|
251
|
+
logger.info(f"{info} ......")
|
252
|
+
df: DataFrame | None = get_stock_data_from_akshare(code)
|
253
|
+
if df is None:
|
254
|
+
return False
|
255
|
+
df.to_sql(name=code, con=engine, if_exists="replace", index=False)
|
256
|
+
logger.success(f"{info} [成功]")
|
257
|
+
return True
|
258
|
+
except Exception as e:
|
259
|
+
logger.success(f"{info} [失败]")
|
260
|
+
logger.exception(e)
|
261
|
+
return False
|
@@ -9,12 +9,12 @@ ezKit/mongo.py,sha256=5KDDYQnOE3lw4QJlLp-EAuzbKM6VzbU0w0GR9iklldA,2379
|
|
9
9
|
ezKit/qywx.py,sha256=X_H4fzP-iEqeDEbumr7D1bXi6dxczaxfO8iyutzy02s,7171
|
10
10
|
ezKit/redis.py,sha256=5TQ7s8fkc-ArXuHT5gOlkR0EBgm3Z-9yTTtS1BgI5Qk,1951
|
11
11
|
ezKit/sendemail.py,sha256=3YyBqFHPDZl9CwgWtmGABubARE_ih8P473mIcEp5VsY,8193
|
12
|
-
ezKit/stock.py,sha256=
|
12
|
+
ezKit/stock.py,sha256=BWs3G2N3xRfva9yf6K40brnH31V2TROeo9pnl8kgEK8,9954
|
13
13
|
ezKit/token.py,sha256=HKREyZj_T2S8-aFoFIrBXTaCKExQq4zE66OHXhGHqQg,1750
|
14
14
|
ezKit/utils.py,sha256=q6DbXJNgC6sqzjqUPmxbiSiiXqiQFCVnI3jp_zi1ujs,42927
|
15
15
|
ezKit/xftp.py,sha256=XyIdr_2rxRVLqPofG6fIYWhAMVsFwTyp46dg5P9FLW4,7774
|
16
|
-
ezKit-1.9.
|
17
|
-
ezKit-1.9.
|
18
|
-
ezKit-1.9.
|
19
|
-
ezKit-1.9.
|
20
|
-
ezKit-1.9.
|
16
|
+
ezKit-1.9.3.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
17
|
+
ezKit-1.9.3.dist-info/METADATA,sha256=i9lzRl59vhpJ4az8LovuKDj_NjDISMpuBQW9zk_gf6w,190
|
18
|
+
ezKit-1.9.3.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
|
19
|
+
ezKit-1.9.3.dist-info/top_level.txt,sha256=aYLB_1WODsqNTsTFWcKP-BN0KCTKcV-HZJ4zlHkCFw8,6
|
20
|
+
ezKit-1.9.3.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|