mns-common 1.5.1.8__py3-none-any.whl → 1.5.1.9__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.

Potentially problematic release.


This version of mns-common might be problematic. Click here for more details.

@@ -0,0 +1,422 @@
1
+ import sys
2
+ import os
3
+
4
+ import sys
5
+ import os
6
+
7
+ file_path = os.path.abspath(__file__)
8
+ end = file_path.index('mns') + 14
9
+ project_path = file_path[0:end]
10
+ sys.path.append(project_path)
11
+
12
+ import json
13
+ import akshare as ak
14
+ import pandas as pd
15
+ from loguru import logger
16
+ import requests
17
+ import time
18
+ import numpy as np
19
+ import mns_common.component.proxies.proxy_common_api as proxy_common_api
20
+ from concurrent.futures import ThreadPoolExecutor
21
+ from threading import Lock
22
+ import concurrent.futures
23
+ import mns_common.utils.data_frame_util as data_frame_util
24
+
25
+ # 最大返回条数
26
+ max_number = 600
27
+ # 最小返回条数
28
+ min_number = 500
29
+ # 分页条数
30
+ page_number = 100
31
+
32
+ fields = ("f352,f2,f3,f5,f6,f8,f10,f11,f22,f12,f14,f15,f16,f17,f18,f20,f21,f26,f33,f34,f35,f62,f66,f69,f72,f184,"
33
+ "f211,f212,f232,f233,f234")
34
+
35
+
36
+ def get_kzz_count(pn, proxies, page_size, time_out):
37
+ current_timestamp = str(int(round(time.time() * 1000, 0)))
38
+ url = "https://push2.eastmoney.com/api/qt/clist/get"
39
+
40
+ params = {
41
+ "cb": "jQuery34103608466964799838_" + current_timestamp,
42
+ "pn": str(pn),
43
+ "np": 3,
44
+ "ut": "8a086bfc3570bdde64a6a1c585cccb35",
45
+ "fltt": 1,
46
+ "invt": 1,
47
+ "fs": "m:0+e:11,m:1+e:11,m:1+e:11+s:4194304,m:0+e:11+s:8388608",
48
+ "dpt": "zqsc.zpg",
49
+ "fields": fields,
50
+ "wbp2u": "|0|0|0|wap",
51
+ "fid": "f12",
52
+ "po": 1,
53
+ "pz": str(page_size),
54
+ "_": current_timestamp
55
+ }
56
+ try:
57
+ if proxies is None:
58
+ r = requests.get(url, params, timeout=time_out)
59
+ else:
60
+ r = requests.get(url, params, proxies=proxies, timeout=time_out)
61
+ data_text = r.text
62
+ total_number = int(data_json['data']['total'])
63
+ return total_number
64
+ except Exception as e:
65
+ logger.error("获取可转债列表,实时行情异常:{}", e)
66
+ return 0
67
+
68
+
69
+ #
70
+ # url = https://push2.eastmoney.com/api/qt/clist/get?cb=jQuery34103608466964799838_1718163189869&pn=1&np=1&ut
71
+ # =8a086bfc3570bdde64a6a1c585cccb35&fltt=1&invt=1&fs=m:0+e:11,m:1+e:11,m:1+e:11+s:4194304,
72
+ # m:0+e:11+s:8388608&dpt=zqsc.zpg&fields=f1,f2,f3,f4,f5,f6,f8,f10,f12,f13,f14,f18,f22,f152,
73
+ # f237&wbp2u=|0|0|0|wap&fid=f3&po=1&pz=2000&_=1718163189870
74
+ def get_debt_page_data(pn, proxies, page_size, time_out) -> pd.DataFrame:
75
+ current_timestamp = str(int(round(time.time() * 1000, 0)))
76
+ url = "https://push2.eastmoney.com/api/qt/clist/get"
77
+
78
+ params = {
79
+ "cb": "jQuery34103608466964799838_" + current_timestamp,
80
+ "pn": str(pn),
81
+ "np": 3,
82
+ "ut": "8a086bfc3570bdde64a6a1c585cccb35",
83
+ "fltt": 1,
84
+ "invt": 1,
85
+ "fs": "m:0+e:11,m:1+e:11,m:1+e:11+s:4194304,m:0+e:11+s:8388608",
86
+ "dpt": "zqsc.zpg",
87
+ "fields": fields,
88
+ "wbp2u": "|0|0|0|wap",
89
+ "fid": "f12",
90
+ "po": 1,
91
+ "pz": str(page_size),
92
+ "_": current_timestamp
93
+ }
94
+ try:
95
+ if proxies is None:
96
+ r = requests.get(url, params, timeout=time_out)
97
+ else:
98
+ r = requests.get(url, params, proxies=proxies, timeout=time_out)
99
+ data_text = r.text
100
+
101
+ if pn == 1:
102
+ try:
103
+ begin_index_total = data_text.index('"total":')
104
+
105
+ end_index_total = data_text.index('"diff"')
106
+ global max_number
107
+ max_number = int(data_text[begin_index_total + 8:end_index_total - 1])
108
+ except Exception as e:
109
+ logger.error(f"获取第{pn}页可转债列表异常: {e}")
110
+ return pd.DataFrame()
111
+
112
+ begin_index = data_text.index('[')
113
+ end_index = data_text.index(']')
114
+ data_json = data_text[begin_index:end_index + 1]
115
+ data_json = json.loads(data_json)
116
+ if data_json is None:
117
+ return pd.DataFrame()
118
+ else:
119
+ return pd.DataFrame(data_json)
120
+ except Exception as e:
121
+ logger.error("获取可转债列表,实时行情异常:{}", e)
122
+ return pd.DataFrame()
123
+
124
+
125
+ def all_debt_ticker_data(fields, proxies) -> pd.DataFrame:
126
+ """
127
+ 使用多线程获取所有债券数据
128
+ """
129
+ # 计算总页数,假设总共有1000条数据,每页200条
130
+
131
+ per_page = page_number
132
+ total_pages = (max_number + per_page - 1) // per_page # 向上取整
133
+
134
+ # 创建线程池
135
+ with ThreadPoolExecutor(max_workers=3) as executor:
136
+ # 提交任务,获取每页数据
137
+ futures = [executor.submit(get_debt_page_data, fields, pn, proxies)
138
+ for pn in range(1, total_pages + 1)]
139
+
140
+ # 收集结果
141
+ results = []
142
+ for future in futures:
143
+ result = future.result()
144
+ if not result.empty:
145
+ results.append(result)
146
+
147
+ # 合并所有页面的数据
148
+ if results:
149
+ return pd.concat(results, ignore_index=True)
150
+ else:
151
+ return pd.DataFrame()
152
+
153
+
154
+ def get_debt_real_time_quotes(proxies):
155
+ # 获取第一页数据
156
+ page_one_df = get_debt_page_data(fields, 1, proxies)
157
+ # 数据接口正常返回5600以上的数量
158
+ if page_one_df.shape[0] > min_number:
159
+ page_one_df = rename_real_time_quotes_df(page_one_df)
160
+ page_one_df.drop_duplicates('symbol', keep='last', inplace=True)
161
+ return page_one_df
162
+ else:
163
+ page_df = all_debt_ticker_data(fields, proxies)
164
+ page_df = rename_real_time_quotes_df(page_df)
165
+ page_df.drop_duplicates('symbol', keep='last', inplace=True)
166
+ return page_df
167
+
168
+
169
+ def rename_real_time_quotes_df(temp_df):
170
+ temp_df = temp_df.rename(columns={
171
+ "f2": "now_price",
172
+ "f3": "chg",
173
+ "f5": "volume",
174
+ "f6": "amount",
175
+ "f8": "exchange",
176
+ "f10": "quantity_ratio",
177
+ "f22": "up_speed",
178
+ "f11": "up_speed_05",
179
+ "f12": "symbol",
180
+ "f14": "name",
181
+ "f15": "high",
182
+ "f16": "low",
183
+ "f17": "open",
184
+ "f18": "yesterday_price",
185
+ "f20": "total_mv",
186
+ "f21": "flow_mv",
187
+ "f26": "list_date",
188
+ "f33": "wei_bi",
189
+ "f34": "outer_disk",
190
+ "f35": "inner_disk",
191
+ "f62": "today_main_net_inflow",
192
+ "f66": "super_large_order_net_inflow",
193
+ "f69": "super_large_order_net_inflow_ratio",
194
+ "f72": "large_order_net_inflow",
195
+ # "f78": "medium_order_net_inflow",
196
+ # "f84": "small_order_net_inflow",
197
+ # "f103": "concept",
198
+ "f184": "today_main_net_inflow_ratio",
199
+ "f352": "average_price",
200
+ "f211": "buy_1_num",
201
+ "f212": "sell_1_num",
202
+ "f232": "stock_symbol",
203
+ "f234": "stock_name",
204
+ "f233": "market"
205
+ })
206
+ temp_df.loc[temp_df['buy_1_num'] == '-', 'buy_1_num'] = 0
207
+ temp_df.loc[temp_df['sell_1_num'] == '-', 'sell_1_num'] = 0
208
+ temp_df.loc[temp_df['up_speed_05'] == '-', 'up_speed_05'] = 0
209
+ temp_df.loc[temp_df['up_speed'] == '-', 'up_speed'] = 0
210
+ temp_df.loc[temp_df['average_price'] == '-', 'average_price'] = 0
211
+ temp_df.loc[temp_df['wei_bi'] == '-', 'wei_bi'] = 0
212
+ temp_df.loc[temp_df['yesterday_price'] == '-', 'yesterday_price'] = 0
213
+ temp_df.loc[temp_df['now_price'] == '-', 'now_price'] = 0
214
+ temp_df.loc[temp_df['chg'] == '-', 'chg'] = 0
215
+ temp_df.loc[temp_df['volume'] == '-', 'volume'] = 0
216
+ temp_df.loc[temp_df['amount'] == '-', 'amount'] = 0
217
+ temp_df.loc[temp_df['exchange'] == '-', 'exchange'] = 0
218
+ temp_df.loc[temp_df['quantity_ratio'] == '-', 'quantity_ratio'] = 0
219
+ temp_df.loc[temp_df['high'] == '-', 'high'] = 0
220
+ temp_df.loc[temp_df['low'] == '-', 'low'] = 0
221
+ temp_df.loc[temp_df['open'] == '-', 'open'] = 0
222
+ temp_df.loc[temp_df['total_mv'] == '-', 'total_mv'] = 0
223
+ temp_df.loc[temp_df['flow_mv'] == '-', 'flow_mv'] = 0
224
+ temp_df.loc[temp_df['inner_disk'] == '-', 'inner_disk'] = 0
225
+ temp_df.loc[temp_df['outer_disk'] == '-', 'outer_disk'] = 0
226
+ temp_df.loc[temp_df['today_main_net_inflow_ratio'] == '-', 'today_main_net_inflow_ratio'] = 0
227
+ temp_df.loc[temp_df['today_main_net_inflow'] == '-', 'today_main_net_inflow'] = 0
228
+ temp_df.loc[temp_df['super_large_order_net_inflow'] == '-', 'super_large_order_net_inflow'] = 0
229
+ temp_df.loc[temp_df['super_large_order_net_inflow_ratio'] == '-', 'super_large_order_net_inflow_ratio'] = 0
230
+ temp_df.loc[temp_df['large_order_net_inflow'] == '-', 'large_order_net_inflow'] = 0
231
+ temp_df["list_date"] = pd.to_numeric(temp_df["list_date"], errors="coerce")
232
+ temp_df["wei_bi"] = pd.to_numeric(temp_df["wei_bi"], errors="coerce")
233
+ temp_df["average_price"] = pd.to_numeric(temp_df["average_price"], errors="coerce")
234
+ temp_df["yesterday_price"] = pd.to_numeric(temp_df["yesterday_price"], errors="coerce")
235
+ temp_df["now_price"] = pd.to_numeric(temp_df["now_price"], errors="coerce")
236
+ temp_df["chg"] = pd.to_numeric(temp_df["chg"], errors="coerce")
237
+ temp_df["volume"] = pd.to_numeric(temp_df["volume"], errors="coerce")
238
+ temp_df["amount"] = pd.to_numeric(temp_df["amount"], errors="coerce")
239
+ temp_df["exchange"] = pd.to_numeric(temp_df["exchange"], errors="coerce")
240
+ temp_df["quantity_ratio"] = pd.to_numeric(temp_df["quantity_ratio"], errors="coerce")
241
+ temp_df["high"] = pd.to_numeric(temp_df["high"], errors="coerce")
242
+ temp_df["low"] = pd.to_numeric(temp_df["low"], errors="coerce")
243
+ temp_df["open"] = pd.to_numeric(temp_df["open"], errors="coerce")
244
+ temp_df["total_mv"] = pd.to_numeric(temp_df["total_mv"], errors="coerce")
245
+ temp_df["flow_mv"] = pd.to_numeric(temp_df["flow_mv"], errors="coerce")
246
+ temp_df["outer_disk"] = pd.to_numeric(temp_df["outer_disk"], errors="coerce")
247
+ temp_df["inner_disk"] = pd.to_numeric(temp_df["inner_disk"], errors="coerce")
248
+ temp_df["today_main_net_inflow"] = pd.to_numeric(temp_df["today_main_net_inflow"], errors="coerce")
249
+ temp_df["super_large_order_net_inflow"] = pd.to_numeric(temp_df["super_large_order_net_inflow"],
250
+ errors="coerce")
251
+ temp_df["super_large_order_net_inflow_ratio"] = pd.to_numeric(temp_df["super_large_order_net_inflow_ratio"],
252
+ errors="coerce")
253
+ temp_df["large_order_net_inflow"] = pd.to_numeric(temp_df["large_order_net_inflow"],
254
+ errors="coerce")
255
+ # 大单比例
256
+ temp_df['large_order_net_inflow_ratio'] = round((temp_df['large_order_net_inflow'] / temp_df['amount']) * 100, 2)
257
+
258
+ # 外盘是内盘倍数
259
+ temp_df['disk_ratio'] = round((temp_df['outer_disk'] - temp_df['inner_disk']) / temp_df['inner_disk'], 2)
260
+ # 只有外盘没有内盘
261
+ temp_df.loc[temp_df["inner_disk"] == 0, ['disk_ratio']] = 1688
262
+
263
+ temp_df['now_price'] = round(temp_df['now_price'] / 1000, 3)
264
+ temp_df['chg'] = round(temp_df['chg'] / 100, 2)
265
+ temp_df['exchange'] = round(temp_df['exchange'] / 100, 2)
266
+ temp_df['quantity_ratio'] = round(temp_df['quantity_ratio'] / 100, 2)
267
+
268
+ temp_df['up_speed'] = round(temp_df['up_speed'] / 100, 2)
269
+ temp_df['up_speed_05'] = round(temp_df['up_speed_05'] / 100, 2)
270
+
271
+ temp_df['high'] = round(temp_df['high'] / 1000, 2)
272
+ temp_df['low'] = round(temp_df['low'] / 1000, 2)
273
+
274
+ temp_df['open'] = round(temp_df['open'] / 1000, 2)
275
+ temp_df['yesterday_price'] = round(temp_df['yesterday_price'] / 1000, 2)
276
+ temp_df['wei_bi'] = round(temp_df['wei_bi'] / 100, 2)
277
+ temp_df['super_large_order_net_inflow_ratio'] = round(temp_df['super_large_order_net_inflow_ratio'] / 100, 2)
278
+ temp_df['today_main_net_inflow_ratio'] = round(temp_df['today_main_net_inflow_ratio'] / 100, 2)
279
+ temp_df['average_price'] = round(temp_df['average_price'] / 1000, 2)
280
+
281
+ temp_df.loc[:, 'reference_main_inflow'] = round(
282
+ (temp_df['flow_mv'] * (1 / 1000)), 2)
283
+
284
+ temp_df.loc[:, 'main_inflow_multiple'] = round(
285
+ (temp_df['today_main_net_inflow'] / temp_df['reference_main_inflow']), 2)
286
+
287
+ temp_df.loc[:, 'super_main_inflow_multiple'] = round(
288
+ (temp_df['super_large_order_net_inflow'] / temp_df['reference_main_inflow']), 2)
289
+ temp_df['large_inflow_multiple'] = round(
290
+ (temp_df['large_order_net_inflow'] / temp_df['reference_main_inflow']), 2)
291
+
292
+ # 债权是10
293
+ temp_df['disk_diff_amount'] = round(
294
+ (temp_df['outer_disk'] - temp_df['inner_disk']) * temp_df[
295
+ "average_price"] * 10,
296
+ 2)
297
+
298
+ temp_df['disk_diff_amount_exchange'] = round(
299
+ (temp_df['disk_diff_amount'] / temp_df['reference_main_inflow']), 2)
300
+ temp_df.loc[:, 'sum_main_inflow_disk'] = temp_df['main_inflow_multiple'] + \
301
+ temp_df['disk_diff_amount_exchange']
302
+ temp_df.replace([np.inf, -np.inf], 0, inplace=True)
303
+ temp_df = temp_df.fillna(0)
304
+ return temp_df
305
+
306
+
307
+ # 可转债信息
308
+ def get_kzz_bond_info():
309
+ try:
310
+ bond_zh_cov_info_ths_df = ak.bond_zh_cov_info_ths()
311
+ bond_zh_cov_info_ths_df = bond_zh_cov_info_ths_df.rename(columns={
312
+ "债券代码": "symbol",
313
+ "债券简称": "name",
314
+ "申购日期": "apply_date",
315
+ "申购代码": "apply_code",
316
+ "原股东配售码": "config_code",
317
+ "每股获配额": "per_share_limit",
318
+ "计划发行量": "planned_circulation",
319
+ "实际发行量": "actual_circulation",
320
+ "中签公布日": "winning_date",
321
+ "中签号": "winning_number",
322
+ "上市日期": "list_date",
323
+ "正股代码": "stock_code",
324
+ "正股简称": "stock_name",
325
+ "转股价格": "conversion_price",
326
+ "到期时间": "due_date",
327
+ "中签率": "lot_winning_rate"
328
+ })
329
+ return bond_zh_cov_info_ths_df
330
+ except BaseException as e:
331
+ logger.error("获取可转债信息异常:{}", e)
332
+
333
+
334
+ def repeated_acquisition_ask_etf_async(time_out, max_number, num_threads, pages_per_thread):
335
+ per_page = page_number
336
+ total_pages = (max_number + per_page - 1) // per_page # 向上取整
337
+ result_df = pd.DataFrame()
338
+
339
+ # 创建线程锁以确保线程安全
340
+ df_lock = Lock()
341
+
342
+ # 计算每个线程处理的页数范围
343
+ def process_page_range(start_page, end_page, thread_id):
344
+ nonlocal result_df
345
+ local_df = pd.DataFrame()
346
+ current_page = start_page
347
+ proxy_ip = proxy_common_api.generate_proxy_ip_api(1)
348
+
349
+ while current_page <= end_page and current_page <= total_pages:
350
+ proxies = {"https": proxy_ip, "http": proxy_ip}
351
+ try:
352
+ page_df = get_debt_page_data(current_page, proxies, page_number, time_out)
353
+ if data_frame_util.is_not_empty(page_df):
354
+ local_df = pd.concat([local_df, page_df])
355
+ logger.info("线程{}获取页面数据成功: {}", thread_id, current_page)
356
+ current_page += 1
357
+ else:
358
+ time.sleep(0.2)
359
+ proxy_ip = proxy_common_api.generate_proxy_ip_api(1)
360
+ logger.info("线程{}获取页面数据失败: {}", thread_id, current_page)
361
+ except BaseException as e:
362
+ time.sleep(1)
363
+ proxy_ip = proxy_common_api.generate_proxy_ip_api(1)
364
+ logger.error("线程{}处理页面{}时发生错误: {}", thread_id, current_page, e)
365
+
366
+ with df_lock:
367
+ result_df = pd.concat([result_df, local_df])
368
+ return len(local_df)
369
+
370
+ # 计算每个线程的页面范围
371
+ page_ranges = []
372
+ for i in range(num_threads):
373
+ start_page = i * pages_per_thread + 1
374
+ end_page = (i + 1) * pages_per_thread
375
+ if start_page > total_pages:
376
+ break
377
+ page_ranges.append((start_page, end_page, i + 1))
378
+
379
+ # 使用线程池执行任务
380
+ with concurrent.futures.ThreadPoolExecutor(max_workers=num_threads) as executor:
381
+ # 提交所有任务
382
+ futures = [
383
+ executor.submit(process_page_range, start, end, tid)
384
+ for start, end, tid in page_ranges
385
+ ]
386
+
387
+ # 等待所有任务完成并获取结果
388
+ results = []
389
+ for future in concurrent.futures.as_completed(futures):
390
+ try:
391
+ result = future.result()
392
+ results.append(result)
393
+ except Exception as e:
394
+ logger.error("线程执行出错: {}", e)
395
+
396
+ return rename_real_time_quotes_df(result_df)
397
+
398
+
399
+ def get_kzz_real_time_quotes(time_out, pages_per_thread):
400
+ try_numer = 3
401
+ while try_numer > 0:
402
+ proxy_ip = proxy_common_api.generate_proxy_ip_api(1)
403
+ proxies = {"https": proxy_ip,
404
+ "http": proxy_ip}
405
+
406
+ max_number = get_kzz_count(1, proxies, 20, time_out)
407
+ if max_number > 0:
408
+ break
409
+ try_numer = try_numer - 1
410
+ if max_number == 0:
411
+ return pd.DataFrame()
412
+
413
+ total_pages = (max_number + page_number - 1) // page_number # 向上取整
414
+
415
+ num_threads = int((total_pages / pages_per_thread) + 1)
416
+ return repeated_acquisition_ask_etf_async(time_out, max_number, num_threads, pages_per_thread)
417
+
418
+
419
+ if __name__ == '__main__':
420
+ test_df = get_kzz_real_time_quotes(30, 6)
421
+ print(test_df)
422
+