ezKit 1.9.2__py3-none-any.whl → 1.9.4__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/cls.py CHANGED
@@ -100,6 +100,15 @@ def latest_data(
100
100
  ) -> list | pd.DataFrame | None:
101
101
  """股票或板块的最新数据"""
102
102
 
103
+ # 热门板块
104
+ # https://www.cls.cn/hotPlate
105
+ # 行业板块
106
+ # https://x-quote.cls.cn/web_quote/plate/plate_list?rever=1&way=change&type=industry
107
+ # 概念板块
108
+ # https://x-quote.cls.cn/web_quote/plate/plate_list?rever=1&way=change&type=concept
109
+ # 地域板块
110
+ # https://x-quote.cls.cn/web_quote/plate/plate_list?rever=1&way=change&type=area
111
+
103
112
  # ----------------------------------------------------------------------------------------------
104
113
 
105
114
  # 判断参数类型
ezKit/database.py CHANGED
@@ -20,7 +20,7 @@ class Database():
20
20
 
21
21
  engine = create_engine('sqlite://')
22
22
 
23
- def __init__(self, target: str, **options):
23
+ def __init__(self, target: str | None = None, **options):
24
24
  """Initiation"""
25
25
  if isinstance(target, str) and utils.isTrue(target, str):
26
26
  if utils.isTrue(options, dict):
ezKit/mongo.py CHANGED
@@ -11,7 +11,7 @@ class Mongo():
11
11
 
12
12
  client = MongoClient()
13
13
 
14
- def __init__(self, target: str | dict):
14
+ def __init__(self, target: str | dict | None = None):
15
15
  """Initiation"""
16
16
  if isinstance(target, str) and utils.isTrue(target, str):
17
17
  self.client = MongoClient(target)
ezKit/redis.py CHANGED
@@ -16,7 +16,7 @@ class Redis:
16
16
  # 这里修改以下参数: host, port, socket_timeout, socket_connect_timeout, charset
17
17
  redis = RedisClient.Redis()
18
18
 
19
- def __init__(self, target: str | dict):
19
+ def __init__(self, target: str | dict | None = None):
20
20
  """Initiation"""
21
21
  if isinstance(target, str) and utils.isTrue(target, str):
22
22
  self.redis = RedisClient.from_url(target)
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
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ezKit
3
- Version: 1.9.2
3
+ Version: 1.9.4
4
4
  Summary: Easy Kit
5
5
  Author: septvean
6
6
  Author-email: septvean@gmail.com
@@ -2,19 +2,19 @@ ezKit/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
2
  ezKit/bottle.py,sha256=usKK1wVaZw4_D-4VwMYmOIc8jtz4TrpM30nck59HMFw,180178
3
3
  ezKit/bottle_extensions.py,sha256=3reEQVZuHklXTl6r7F8kiBFFPb0RaAGc3mYJJnrMDjQ,1129
4
4
  ezKit/cipher.py,sha256=0T_StbjiNI4zgrjVgcfU-ffKgu1waBA9UDudAnqFcNM,2896
5
- ezKit/cls.py,sha256=_MZRcYVvCfvh6aCrIXAUixY6Q9rS9X5ab4fckrP66yQ,10324
6
- ezKit/database.py,sha256=3-kikSVzmAKUFFBf_t6GiGAPqWfx4IsZlZgyAI52JHA,6907
5
+ ezKit/cls.py,sha256=P6cEWf8uVXn5gRAfnNQb6GESp3Hs3gElOoLr7cd3RyM,10705
6
+ ezKit/database.py,sha256=cmFsZ88Ah7LCBAhEcjN_aI_pEuu682wUgi-TJN8a9Wc,6921
7
7
  ezKit/http.py,sha256=i3Kn5AMAMicDMcDjxKKZU7zqEKTU88Ec9_LwCuBJy-0,1801
8
- ezKit/mongo.py,sha256=5KDDYQnOE3lw4QJlLp-EAuzbKM6VzbU0w0GR9iklldA,2379
8
+ ezKit/mongo.py,sha256=dOm_1wXEPp_e8Ml5Qq78M7FDNrQUAZaThzVIiiLJJwk,2393
9
9
  ezKit/qywx.py,sha256=X_H4fzP-iEqeDEbumr7D1bXi6dxczaxfO8iyutzy02s,7171
10
- ezKit/redis.py,sha256=5TQ7s8fkc-ArXuHT5gOlkR0EBgm3Z-9yTTtS1BgI5Qk,1951
10
+ ezKit/redis.py,sha256=g2_V4jvq0djRc20jLZkgeAeF_bYrq-Rbl_kHcCUPZcA,1965
11
11
  ezKit/sendemail.py,sha256=3YyBqFHPDZl9CwgWtmGABubARE_ih8P473mIcEp5VsY,8193
12
- ezKit/stock.py,sha256=_gWighuVzqSub4GRnN-X_9TVY7kUEYvKHKdbYJPYSYE,4001
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.2.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
17
- ezKit-1.9.2.dist-info/METADATA,sha256=ZoiSVL8T2mtsb9ZxR61cHS8dGvixGvGS5lUui0Y5e8M,190
18
- ezKit-1.9.2.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
19
- ezKit-1.9.2.dist-info/top_level.txt,sha256=aYLB_1WODsqNTsTFWcKP-BN0KCTKcV-HZJ4zlHkCFw8,6
20
- ezKit-1.9.2.dist-info/RECORD,,
16
+ ezKit-1.9.4.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
17
+ ezKit-1.9.4.dist-info/METADATA,sha256=AbhlWuNQdHzY5rT--_vSk4-SAwQgNjiSQgbGL7SN_Lg,190
18
+ ezKit-1.9.4.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
19
+ ezKit-1.9.4.dist-info/top_level.txt,sha256=aYLB_1WODsqNTsTFWcKP-BN0KCTKcV-HZJ4zlHkCFw8,6
20
+ ezKit-1.9.4.dist-info/RECORD,,
File without changes
File without changes