rquote 0.3.4__py3-none-any.whl → 0.3.5__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.
- rquote/__init__.py +53 -5
- rquote/api/__init__.py +32 -0
- rquote/api/lists.py +175 -0
- rquote/api/price.py +73 -0
- rquote/api/stock_info.py +49 -0
- rquote/api/tick.py +47 -0
- rquote/cache/__init__.py +9 -0
- rquote/cache/base.py +26 -0
- rquote/cache/memory.py +77 -0
- rquote/config.py +42 -0
- rquote/data_sources/__init__.py +10 -0
- rquote/data_sources/base.py +21 -0
- rquote/data_sources/sina.py +92 -0
- rquote/data_sources/tencent.py +90 -0
- rquote/exceptions.py +40 -0
- rquote/factors/__init__.py +8 -0
- rquote/factors/technical.py +150 -0
- rquote/markets/__init__.py +14 -0
- rquote/markets/base.py +49 -0
- rquote/markets/cn_stock.py +186 -0
- rquote/markets/factory.py +82 -0
- rquote/markets/future.py +92 -0
- rquote/markets/hk_stock.py +46 -0
- rquote/markets/us_stock.py +69 -0
- rquote/parsers/__init__.py +8 -0
- rquote/parsers/kline.py +104 -0
- rquote/plots.py +1 -1
- rquote/utils/__init__.py +13 -0
- rquote/utils/date.py +40 -0
- rquote/utils/helpers.py +23 -0
- rquote/utils/http.py +112 -0
- rquote/utils/logging.py +25 -0
- rquote/utils/web.py +104 -0
- rquote/utils.py +9 -195
- rquote-0.3.5.dist-info/METADATA +486 -0
- rquote-0.3.5.dist-info/RECORD +38 -0
- rquote/main.py +0 -503
- rquote-0.3.4.dist-info/METADATA +0 -286
- rquote-0.3.4.dist-info/RECORD +0 -8
- {rquote-0.3.4.dist-info → rquote-0.3.5.dist-info}/WHEEL +0 -0
- {rquote-0.3.4.dist-info → rquote-0.3.5.dist-info}/top_level.txt +0 -0
rquote/main.py
DELETED
|
@@ -1,503 +0,0 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
|
-
|
|
3
|
-
import json
|
|
4
|
-
import time
|
|
5
|
-
import re
|
|
6
|
-
import base64
|
|
7
|
-
import pandas as pd
|
|
8
|
-
from .utils import WebUtils, hget, logger
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
def get_cn_stock_list(money_min=2e8):
|
|
13
|
-
ret = []
|
|
14
|
-
try:
|
|
15
|
-
ret = get_cn_stock_list_qq(money_min)
|
|
16
|
-
except Exception as e:
|
|
17
|
-
ret = get_cn_stock_list_eastmoney(money_min)
|
|
18
|
-
return ret
|
|
19
|
-
|
|
20
|
-
def get_cn_stock_list_eastmoney(money_min=2e8):
|
|
21
|
-
'''
|
|
22
|
-
Return sorted stock list ordered by latest amount of money, cut at `money_min`
|
|
23
|
-
item in returned list are [code, name, change, amount, mktcap]
|
|
24
|
-
'''
|
|
25
|
-
a = hget(
|
|
26
|
-
base64.b64decode('aHR0cDovLzM4LnB1c2gyLmVhc3Rtb25leS5jb20vYXBpL3F0L2Ns'+
|
|
27
|
-
'aXN0L2dldD9jYj1qUXVlcnkxMTI0MDk0NTg3NjE4NDQzNzQ4MDFfMTYyNzI4ODQ4O'+
|
|
28
|
-
'Tk2MSZwbj0xJnB6PTEwMDAwJnBvPTEmbnA9MSZ1dD1iZDFkOWRkYjA0MDg5NzAwY2'+
|
|
29
|
-
'Y5YzI3ZjZmNzQyNjI4MSZmbHR0PTImaW52dD0yJmZpZD1mNiZmcz1tOjArdDo2LG0'+
|
|
30
|
-
'6MCt0OjgwLG06MSt0OjIsbToxK3Q6MjMmZmllbGRzPWYxMixmMTQsZjMsZjYsZjIxJl89'
|
|
31
|
-
).decode() + str(int(time.time()*1e3))
|
|
32
|
-
)
|
|
33
|
-
if a:
|
|
34
|
-
a = json.loads(a.text.split(
|
|
35
|
-
'jQuery112409458761844374801_1627288489961(')[1][:-2])
|
|
36
|
-
a = [ ['sh'+i['f12'] if i['f12'][0]=='6' else 'sz'+i['f12'],
|
|
37
|
-
i['f14'], i['f3'], i['f6'], i['f21']] for i in a['data']['diff']
|
|
38
|
-
if i['f6']!='-' and float(i['f6']) > money_min]
|
|
39
|
-
#cands=[(i.code,i.name) for i in a[['code','name']].itertuples()]
|
|
40
|
-
return a
|
|
41
|
-
|
|
42
|
-
def get_cn_stock_list_qq(money_min=2e8):
|
|
43
|
-
offset = 0
|
|
44
|
-
count = 200 # max, or error
|
|
45
|
-
df = []
|
|
46
|
-
while not df or float(df[-1]['turnover'])*1e4 > money_min:
|
|
47
|
-
a = hget(
|
|
48
|
-
'https://proxy.finance.qq.com/cgi/cgi-bin/rank/hs/getBoardRankList?_appver=11.17.0'+
|
|
49
|
-
f'&board_code=aStock&sort_type=turnover&direct=down&offset={offset}&count={count}'
|
|
50
|
-
)
|
|
51
|
-
if a:
|
|
52
|
-
a = json.loads(a.text)
|
|
53
|
-
if a['data']['rank_list']:
|
|
54
|
-
df.extend(a['data']['rank_list'])
|
|
55
|
-
offset += count
|
|
56
|
-
else:
|
|
57
|
-
break
|
|
58
|
-
return df
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
def get_hk_stocks_500():
|
|
62
|
-
a = hget(
|
|
63
|
-
'https://stock.gtimg.cn/data/hk_rank.php?board=main_all&metric=amount&' +
|
|
64
|
-
'pageSize=500&reqPage=1&order=desc&var_name=list_data').text
|
|
65
|
-
if a:
|
|
66
|
-
a = [i.split('~') for i in json.loads(a.split('list_data=')[1])['data']['page_data']]
|
|
67
|
-
return a
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
def get_us_stocks(k=100):
|
|
71
|
-
# return list of [symbol, name, price, volume, mktcap, pe]
|
|
72
|
-
uscands = []
|
|
73
|
-
page_n = k//20 + 1
|
|
74
|
-
for page in range(1, page_n+1):
|
|
75
|
-
a = hget(
|
|
76
|
-
"https://stock.finance.sina.com.cn/usstock/api/jsonp.php/IO.XSRV2."+
|
|
77
|
-
f"CallbackList['f0j3ltzVzdo2Fo4p']/US_CategoryService.getList?page={page}"+
|
|
78
|
-
"&num=20&sort=&asc=0&market=&id=").text
|
|
79
|
-
if a:
|
|
80
|
-
uslist = json.loads(a.split('(',1)[1][:-2])['data']
|
|
81
|
-
uscands.extend(uslist)
|
|
82
|
-
return uscands
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
def get_cn_fund_list():
|
|
86
|
-
'''
|
|
87
|
-
Return sorted etf list (ordered by latest amount of money),
|
|
88
|
-
of [code, name, change, amount, price]
|
|
89
|
-
'''
|
|
90
|
-
a = hget(base64.b64decode('aHR0cDovL3ZpcC5zdG9jay5maW5hbmNlLnNpbmEuY29tL'+
|
|
91
|
-
'mNuL3F1b3Rlc19zZXJ2aWNlL2FwaS9qc29ucC5waHAvSU8uWFNSVjIuQ2FsbGJhY2tMaX'+
|
|
92
|
-
'N0WydrMldhekswNk5Rd2xoeVh2J10vTWFya2V0X0NlbnRlci5nZXRIUU5vZGVEYXRhU2l'+
|
|
93
|
-
'tcGxlP3BhZ2U9MSZudW09MTAwMCZzb3J0PWFtb3VudCZhc2M9MCZub2RlPWV0Zl9ocV9m'+
|
|
94
|
-
'dW5kJiU1Qm9iamVjdCUyMEhUTUxEaXZFbGVtZW50JTVEPXhtNGkw').decode()).text
|
|
95
|
-
if a:
|
|
96
|
-
fundcands = [[i['symbol'], i['name'], i['changepercent'], i['amount'], i['trade']]
|
|
97
|
-
for i in json.loads(a.split('k2WazK06NQwlhyXv')[1][3:-2])]
|
|
98
|
-
return fundcands
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
def get_cn_future_list():
|
|
102
|
-
'''
|
|
103
|
-
Return cn future id list, with prefix of `fu`
|
|
104
|
-
e.g. ['fuSC2109',
|
|
105
|
-
'fuRB2110',
|
|
106
|
-
'fuHC2110',
|
|
107
|
-
'fuFU2109',
|
|
108
|
-
...]
|
|
109
|
-
'''
|
|
110
|
-
a = hget('https://finance.sina.com.cn/futuremarket/').text
|
|
111
|
-
if a:
|
|
112
|
-
futurelist_active = [
|
|
113
|
-
'fu' + i for i in re.findall(r'quotes/(.*?\d+).shtml', a)]
|
|
114
|
-
return futurelist_active
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
def _check_date_format(date_str):
|
|
118
|
-
# 允许格式: 2099-01-01
|
|
119
|
-
if not re.match(r'^\d{4}-\d{2}-\d{2}$', date_str):
|
|
120
|
-
# 尝试转换
|
|
121
|
-
try:
|
|
122
|
-
# 常见格式尝试
|
|
123
|
-
t_struct = None
|
|
124
|
-
for fmt in ("%Y/%m/%d", "%Y%m%d", "%Y.%m.%d", "%Y_%m_%d", "%Y-%m-%d"):
|
|
125
|
-
try:
|
|
126
|
-
t_struct = time.strptime(date_str, fmt)
|
|
127
|
-
break
|
|
128
|
-
except Exception:
|
|
129
|
-
continue
|
|
130
|
-
if t_struct is None:
|
|
131
|
-
raise ValueError(f"date format not recognized: {date_str}")
|
|
132
|
-
# 转换为标准格式
|
|
133
|
-
date_str_std = time.strftime("%Y-%m-%d", t_struct)
|
|
134
|
-
return date_str_std
|
|
135
|
-
except Exception as e:
|
|
136
|
-
raise ValueError(f"date format error: {date_str}, {e}")
|
|
137
|
-
return date_str
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
def load_js_var_json(url):
|
|
141
|
-
a = hget(url)
|
|
142
|
-
if a:
|
|
143
|
-
a = json.loads(a.text.split('(')[1].split(')')[0])
|
|
144
|
-
return a
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
def get_price(i, sdate='', edate='', freq='day', days=320, fq='qfq',
|
|
148
|
-
dd=None) -> (str, str, pd.DataFrame):
|
|
149
|
-
'''
|
|
150
|
-
Args:
|
|
151
|
-
sdate: start date
|
|
152
|
-
edate: end date
|
|
153
|
-
dd: data dictionary, any local cache with get/put methods
|
|
154
|
-
days: day length of fetching, overwriting sdate
|
|
155
|
-
fq: qfq for non
|
|
156
|
-
'''
|
|
157
|
-
if dd is not None:
|
|
158
|
-
a = dd.get(i)
|
|
159
|
-
if a:
|
|
160
|
-
n, d = a
|
|
161
|
-
logger.debug('loading price from dd {}'.format(i))
|
|
162
|
-
return i, n, d
|
|
163
|
-
logger.debug('fetching price of {}'.format(i))
|
|
164
|
-
|
|
165
|
-
# 检查sdate和edate格式
|
|
166
|
-
sdate = _check_date_format(sdate) if sdate else ''
|
|
167
|
-
edate = _check_date_format(edate) if edate else ''
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
qtimg_stock = 'http://web.ifzq.gtimg.cn/appstock/app/newfqkline/get?param=' + \
|
|
171
|
-
'{},{},{},{},{},{}'
|
|
172
|
-
qtimg_stock_hk = 'http://web.ifzq.gtimg.cn/appstock/app/hkfqkline/get?' + \
|
|
173
|
-
'param={},{},{},{},{},{}'
|
|
174
|
-
qtimg_stock_us = 'http://web.ifzq.gtimg.cn/appstock/app/usfqkline/get?' + \
|
|
175
|
-
'param={},{},{},{},{},{}'
|
|
176
|
-
qtimg_stock_us_min = 'https://web.ifzq.gtimg.cn/appstock/app/UsMinute/query?' + \
|
|
177
|
-
'_var=min_data_{}&code={}'
|
|
178
|
-
sina_future_d = 'https://stock2.finance.sina.com.cn/futures/api/jsonp.php/' + \
|
|
179
|
-
'var%20t1nf_{}=/InnerFuturesNewService.getDailyKLine?symbol={}'
|
|
180
|
-
sina_future_min = 'https://stock2.finance.sina.com.cn/futures/api/jsonp.php/' + \
|
|
181
|
-
'var%20t1nf_{}=/InnerFuturesNewService.getMinLine?symbol={}'
|
|
182
|
-
sina_btc = 'https://quotes.sina.cn/fx/api/openapi.php/BtcService.getDayKLine?' + \
|
|
183
|
-
'symbol=btcbtcusd'
|
|
184
|
-
|
|
185
|
-
# sina_future_d.format('FB0','FB0')
|
|
186
|
-
|
|
187
|
-
if i[:2] == 'BK':
|
|
188
|
-
try:
|
|
189
|
-
a = hget(base64.b64decode('aHR0cDovL3B1c2gyaGlzLmVhc3' +
|
|
190
|
-
'Rtb25leS5jb20vYXBpL3F0L3N0b2NrL2tsaW5lL2dldD9jYj1qUX' +
|
|
191
|
-
'VlcnkxMTI0MDIyNTY2NDQ1ODczNzY2OTcyXzE2MTc4NjQ1NjgxMz' +
|
|
192
|
-
'Emc2VjaWQ9OTAu').decode() + i +
|
|
193
|
-
'&fields1=f1%2Cf2%2Cf3%2Cf4%2Cf5' +
|
|
194
|
-
'&fields2=f51%2Cf52%2Cf53%2Cf54%2Cf55%2Cf56%2Cf57%2Cf58' +
|
|
195
|
-
'&klt=101&fqt=0&beg=19900101&end=20990101&_=1')
|
|
196
|
-
if not a:
|
|
197
|
-
logger.warning('{} hget failed: {}'.format(i, a))
|
|
198
|
-
return i, 'None', pd.DataFrame([])
|
|
199
|
-
a = json.loads(a.text.split(
|
|
200
|
-
'jQuery1124022566445873766972_1617864568131(')[1][:-2])
|
|
201
|
-
if not a['data']:
|
|
202
|
-
logger.warning('{} data empty: {}'.format(i, a))
|
|
203
|
-
return i, 'None', pd.DataFrame([])
|
|
204
|
-
name = a['data']['name']
|
|
205
|
-
d = pd.DataFrame([i.split(',') for i in a['data']['klines']], columns=[
|
|
206
|
-
'date', 'open', 'close', 'high', 'low', 'vol', 'money', 'p'])
|
|
207
|
-
d = d.set_index(['date']).astype(float)
|
|
208
|
-
# d.index = pd.DatetimeIndex(d.index)
|
|
209
|
-
return i, name, d
|
|
210
|
-
except Exception as e:
|
|
211
|
-
logger.warning('error fetching {}, err: {}'.format(i, e))
|
|
212
|
-
return i, 'None', pd.DataFrame([])
|
|
213
|
-
|
|
214
|
-
if i[:2] == 'fu':
|
|
215
|
-
try:
|
|
216
|
-
if i[2:5].lower() == 'btc':
|
|
217
|
-
url = sina_btc
|
|
218
|
-
d = json.loads(hget(url).text)['result']['data'].split('|')
|
|
219
|
-
d = pd.DataFrame([i.split(',') for i in d],
|
|
220
|
-
columns=['date', 'open', 'high', 'low', 'close', 'vol', 'amount'])
|
|
221
|
-
for col in ['open','high','low','close','vol','amount']:
|
|
222
|
-
d[col] = pd.to_numeric(d[col], errors='coerce')
|
|
223
|
-
return i, 'BTC', d
|
|
224
|
-
else:
|
|
225
|
-
ix = i[2:]
|
|
226
|
-
if freq in ('min', '1min', 'minute'):
|
|
227
|
-
url = sina_future_min.format(ix, ix)
|
|
228
|
-
# rtext = hget(url).text
|
|
229
|
-
# d = pd.DataFrame(json.loads(rtext.split(i[2:])[1][2:-2]))
|
|
230
|
-
d = pd.DataFrame(load_js_var_json(url))
|
|
231
|
-
d.columns = ['dtime', 'close', 'avg', 'vol', 'hold','last_close','cur_date']
|
|
232
|
-
for col in ['close','avg','vol','hold']:
|
|
233
|
-
d[col] = pd.to_numeric(d[col], errors='coerce')
|
|
234
|
-
d = d.set_index(['dtime'])
|
|
235
|
-
return i[2:], i[2:], d
|
|
236
|
-
else:
|
|
237
|
-
# d = pd.DataFrame(json.loads(hget(sina_future_d.format(
|
|
238
|
-
# ix, ix)).text.split('(')[1][:-2]))
|
|
239
|
-
d = pd.DataFrame(load_js_var_json(sina_future_d.format(ix, ix)))
|
|
240
|
-
d.columns = ['date', 'open', 'high', 'low', 'close', 'vol', 'p', 's']
|
|
241
|
-
for col in ['open','high','low','close','vol','p','s']:
|
|
242
|
-
d[col] = pd.to_numeric(d[col], errors='coerce')
|
|
243
|
-
d = d.set_index(['date']).astype(float)
|
|
244
|
-
# d.index = pd.DatetimeIndex(d.index)
|
|
245
|
-
return i, ix, d
|
|
246
|
-
except Exception as e:
|
|
247
|
-
logger.warning('error get price {}, err {}'.format(i[2:-4], e))
|
|
248
|
-
return i, 'None', pd.DataFrame([])
|
|
249
|
-
|
|
250
|
-
if i[0] in ['0', '1', '3', '5', '6']:
|
|
251
|
-
i = 'sh'+i if i[0] in ['5', '6'] else 'sz'+i
|
|
252
|
-
if i[:2] in ['sh', 'sz']:
|
|
253
|
-
url = qtimg_stock.format(i, freq, sdate, edate, days, fq)
|
|
254
|
-
elif i[:2] == 'hk':
|
|
255
|
-
url = qtimg_stock_hk.format(i, freq, sdate, edate, days, fq)
|
|
256
|
-
elif i[:2] == 'us':
|
|
257
|
-
if freq in ('min', '1min', 'minute'):
|
|
258
|
-
url = qtimg_stock_us_min.format(i.replace('.', ''), i)
|
|
259
|
-
else:
|
|
260
|
-
url = qtimg_stock_us.format(i, freq, sdate, edate, days, fq)
|
|
261
|
-
else:
|
|
262
|
-
raise ValueError(f'target market not supported: {i}')
|
|
263
|
-
a = hget(url)
|
|
264
|
-
#a = json.loads(a.text.replace('kline_dayqfq=', ''))['data'][i]
|
|
265
|
-
if i[:2] == 'us' and freq in ('min', '1min', 'minute'):
|
|
266
|
-
a = json.loads(a.text.split('=')[1])['data'][i]
|
|
267
|
-
nm = a['qt'][i][1]
|
|
268
|
-
b = pd.DataFrame([i.split() for i in a['data']['data']],
|
|
269
|
-
columns=['minute','price','volume']).set_index(['minute'])
|
|
270
|
-
for col in ['price','volume']:
|
|
271
|
-
b[col] = pd.to_numeric(b[col], errors='coerce')
|
|
272
|
-
return i, nm, b
|
|
273
|
-
a = json.loads(a.text)['data'][i]
|
|
274
|
-
name = ''
|
|
275
|
-
try:
|
|
276
|
-
for tkt in ['day', 'qfqday', 'hfqday', 'week', 'qfqweek', 'hfqweek',
|
|
277
|
-
'month', 'qfqmonth', 'hfqmonth']:
|
|
278
|
-
if tkt in a:
|
|
279
|
-
tk = tkt
|
|
280
|
-
break
|
|
281
|
-
b = pd.DataFrame([j[:6] for j in a[tk]],
|
|
282
|
-
columns=['date','open','close','high','low','vol']
|
|
283
|
-
).set_index(['date'])
|
|
284
|
-
for col in ['open','high','low','close','vol']:
|
|
285
|
-
b[col] = pd.to_numeric(b[col], errors='coerce')
|
|
286
|
-
if 'qt' in a:
|
|
287
|
-
name = a['qt'][i][1]
|
|
288
|
-
except Exception as e:
|
|
289
|
-
raise ValueError('error fetching {}, err: {}'.format(i, e))
|
|
290
|
-
return i, name, b
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
def get_price_longer(i, l=2, dd={}):
|
|
294
|
-
# default get price 320 day, l as years
|
|
295
|
-
_, name, a = get_price(i, dd=dd)
|
|
296
|
-
d1 = a.index.format()[0]
|
|
297
|
-
for y in range(1, l):
|
|
298
|
-
d0 = str(int(d1[:4]) - 1) + d1[4:]
|
|
299
|
-
a = pd.concat((get_price(i, d0, d1)[2], a), 0).drop_duplicates()
|
|
300
|
-
d1 = d0
|
|
301
|
-
return i, name, a
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
def get_tick(tgts=[]):
|
|
305
|
-
'''
|
|
306
|
-
Get quotes of a tick
|
|
307
|
-
tgt list format:
|
|
308
|
-
us stocks like gb_symbol, e.g. gb_aapl, gb_goog
|
|
309
|
-
Return list of dict of given symbols for current timestamp
|
|
310
|
-
'''
|
|
311
|
-
if not tgts:
|
|
312
|
-
return []
|
|
313
|
-
sina_tick = 'https://hq.sinajs.cn/?list='
|
|
314
|
-
head_row = ['name', 'price', 'price_change_rate', 'timesec',
|
|
315
|
-
'price_change', '_', '_', '_', '_', '_', 'volume', '_', '_',
|
|
316
|
-
'_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_',
|
|
317
|
-
'_', 'last_close', '_', '_', '_', 'turnover', '_', '_', '_', '_']
|
|
318
|
-
|
|
319
|
-
if type(tgts) == list:
|
|
320
|
-
tgts = ['gb_' + i.lower() for i in tgts]
|
|
321
|
-
elif type(tgts) == str:
|
|
322
|
-
tgts = ['gb_' + tgts]
|
|
323
|
-
else:
|
|
324
|
-
raise ValueError('tgt should be list or str, e.g. APPL,')
|
|
325
|
-
|
|
326
|
-
a = hget(sina_tick + ','.join(tgts))
|
|
327
|
-
if not a:
|
|
328
|
-
raise ValueError('hget failed {}'.format(tgts))
|
|
329
|
-
|
|
330
|
-
try:
|
|
331
|
-
dat = [i.split('"')[1].split(',') for i in a.text.split(';\n') if ',' in i]
|
|
332
|
-
dat_trim = [{k:i[j] for j,k in enumerate(head_row) if k!='_'} for i in dat]
|
|
333
|
-
except Exception as e:
|
|
334
|
-
raise ValueError('data not complete, check tgt be code str or list without'+
|
|
335
|
-
' prefix, your given: {}'.format(tgts))
|
|
336
|
-
return dat_trim
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
def get_stock_concepts(i) -> []:
|
|
340
|
-
'''
|
|
341
|
-
Return concept id(start with `BK`) list of a stock, from eastmoney
|
|
342
|
-
'''
|
|
343
|
-
f10url = base64.b64decode('aHR0cDovL2YxMC5lYXN0bW9uZXkuY29tLy9Db3JlQ29uY2V' +
|
|
344
|
-
'wdGlvbi9Db3JlQ29uY2VwdGlvbkFqYXg/Y29kZT0=').decode()
|
|
345
|
-
#drop_cons = ['融资融券', '创业板综', '深股通', '沪股通', '深成500', '长江三角']
|
|
346
|
-
#drop_tails = ['板块', '概念', '0_', '成份', '重仓']
|
|
347
|
-
url = f10url + i
|
|
348
|
-
try:
|
|
349
|
-
concepts = json.loads(hget(url).text)[
|
|
350
|
-
'hxtc'][0]['ydnr'].split()
|
|
351
|
-
except Exception as e:
|
|
352
|
-
raise ValueError(f'error fetching concepts of {i}, err: {e}')
|
|
353
|
-
#concepts = [i for i in concepts if i not in drop_cons]
|
|
354
|
-
#concepts = [i for i in concepts if i[-2:] not in drop_tails]
|
|
355
|
-
#concepts = [i for i in concepts if '股' not in i]
|
|
356
|
-
return concepts
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
def get_concept_stocks(bkid, dc=None):
|
|
360
|
-
'''
|
|
361
|
-
Return stocks of input bkid, e.g. BK0420, BK0900
|
|
362
|
-
dc : dictionary of concepts, local cache with get/put
|
|
363
|
-
'''
|
|
364
|
-
if dc is not None:
|
|
365
|
-
a = dc.get(bkid)
|
|
366
|
-
if a:
|
|
367
|
-
return a
|
|
368
|
-
bkid = bkid if isinstance(bkid, str) else 'BK' + str(bkid).zfill(4)
|
|
369
|
-
a = hget(
|
|
370
|
-
base64.b64decode('aHR0cDovL3B1c2gyLmVhc3Rtb25leS5jb20vYXBpL3F0L2NsaXN0' +
|
|
371
|
-
'L2dldD9jYj1qUXVlcnkxMTIzMDQwNTcwNTM4NTY5NDcwMTA1XzE2MTgwNDc5OTA2O' +
|
|
372
|
-
'TAmZmlkPWY2MiZwbz0xJnB6PTUwMCZwbj0xJm5wPTEmZmx0dD0yJmludnQ9MiZmcz' +
|
|
373
|
-
'1iJTNB').decode() +
|
|
374
|
-
bkid +
|
|
375
|
-
'&fields=f3%2Cf6%2Cf12%2Cf14%2Cf21').text
|
|
376
|
-
a = json.loads(
|
|
377
|
-
a.split('jQuery1123040570538569470105_1618047990690(')[1][:-2])['data']['diff']
|
|
378
|
-
logger.debug('get fresh conc {}'.format(bkid))
|
|
379
|
-
a = [ ['sh'+i['f12'] if i['f12'][0]=='6' else 'sz'+i['f12'],
|
|
380
|
-
i['f14'], i['f3'], i['f6'], i['f21']] for i in a]
|
|
381
|
-
return a
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
def _east_list_fmt(burl, api_name):
|
|
385
|
-
'''
|
|
386
|
-
formatter of eastmoney api
|
|
387
|
-
Return list of list:
|
|
388
|
-
[sid, name, rise, amount, mkt]
|
|
389
|
-
'''
|
|
390
|
-
a = hget(base64.b64decode(burl).decode() +
|
|
391
|
-
str(int(time.time()*1e3)))
|
|
392
|
-
if a:
|
|
393
|
-
a = a.text
|
|
394
|
-
else:
|
|
395
|
-
return
|
|
396
|
-
a = json.loads(a.split(api_name+'(')[1][:-2])['data']['diff']
|
|
397
|
-
a = [ [i['f12'],i['f14'], i['f3'], i['f6'], i['f20']] for i in a]
|
|
398
|
-
return a
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
def get_all_industries():
|
|
402
|
-
'''
|
|
403
|
-
Return sorted industry item list ordered by latest amount of money,
|
|
404
|
-
item in returned list are [code, name, change, amount, price]
|
|
405
|
-
'''
|
|
406
|
-
a = _east_list_fmt('aHR0cHM6Ly84Ny5wdXNoMi5lYXN0bW9uZXkuY29tL2FwaS9xdC9jbGl'+
|
|
407
|
-
'zdC9nZXQ/Y2I9alF1ZXJ5MTEyNDAzNzExNzU2NTU3MTk3MTM0NV8xNjI3MDQ3MTg4NTk5'+
|
|
408
|
-
'JnBuPTEmcHo9MTAwJnBvPTEmbnA9MSZ1dD1iZDFkOWRkYjA0MDg5NzAwY2Y5YzI3ZjZmN'+
|
|
409
|
-
'zQyNjI4MSZmbHR0PTImaW52dD0yJmZpZD1mMyZmcz1tOjkwK3Q6MitmOiE1MCZmaWVsZH'+
|
|
410
|
-
'M9ZjMsZjYsZjEyLGYxNCxmMjAsZjEwNCxmMTA1Jl89',
|
|
411
|
-
'jQuery1124037117565571971345_1627047188599')
|
|
412
|
-
logger.debug('get industries {}'.format(len(a)))
|
|
413
|
-
return a
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
def get_all_concepts():
|
|
417
|
-
'''
|
|
418
|
-
Return sorted concept item list ordered by latest amount of money,
|
|
419
|
-
item in returned list are [code, name, change, amount, price]
|
|
420
|
-
'''
|
|
421
|
-
a = _east_list_fmt('aHR0cHM6Ly8yMi5wdXNoMi5lYXN0bW9uZXkuY29tL2FwaS9xdC9jbGl'+
|
|
422
|
-
'zdC9nZXQ/Y2I9alF1ZXJ5MTEyNDA3MzI5ODQxOTMwNzY4OTc5XzE2MjcxMDk0NjA2MzMm'+
|
|
423
|
-
'cG49MSZwej00MDAmcG89MSZucD0xJnV0PWJkMWQ5ZGRiMDQwODk3MDBjZjljMjdmNmY3N'+
|
|
424
|
-
'DI2MjgxJmZsdHQ9MiZpbnZ0PTImZmlkPWYzJmZzPW06OTArdDozK2Y6ITUwJmZpZWxkcz'+
|
|
425
|
-
'1mMyxmNixmMTIsZjE0LGYyMCxmMTA0LGYxMDUmXz0='
|
|
426
|
-
,'jQuery112407329841930768979_1627109460633')
|
|
427
|
-
logger.debug('get concepts {}'.format(len(a)))
|
|
428
|
-
return a
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
def get_bk_stocks(bkid):
|
|
432
|
-
'''
|
|
433
|
-
Return stock item list of given bk id,
|
|
434
|
-
item in returned list are [code, name, change, amount, price]
|
|
435
|
-
'''
|
|
436
|
-
url = base64.b64decode('aHR0cDovLzgyLnB1c2gyLmVhc3Rtb25leS5jb20vYXBpL3F0L2'+
|
|
437
|
-
'NsaXN0L2dldD9jYj1qUXVlcnkxMTI0MDQ4Njk5NjMwMDk1MTM3NzE0XzE2Mjc0Nzc0OTU'+
|
|
438
|
-
'wNjQmcG49MSZwej0yMDAwJnBvPTAmbnA9MSZ1dD1iZDFkOWRkYjA0MDg5NzAwY2Y5YzI3'+
|
|
439
|
-
'ZjZmNzQyNjI4MSZmbHR0PTImaW52dD0yJmZpZD1mNiZmcz1iOg==').decode()+ \
|
|
440
|
-
bkid + '+f:!50&fields=f3,f6,f12,f14,f20&_='
|
|
441
|
-
a = _east_list_fmt(base64.b64encode(bytes(url, encoding='utf-8')),
|
|
442
|
-
'jQuery1124048699630095137714_1627477495064')
|
|
443
|
-
logger.debug('get bk stocks {}'.format(len(a)))
|
|
444
|
-
return a
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
def get_industry_stocks(bkid):
|
|
448
|
-
'''
|
|
449
|
-
Return sorted industry item list ordered by latest amount of money,
|
|
450
|
-
item in returned list are [code, name, change, amount, price]
|
|
451
|
-
'''
|
|
452
|
-
url = base64.b64decode('aHR0cHM6Ly82Mi5wdXNoMi5lYXN0bW9uZXkuY29tL2FwaS9xdC'+
|
|
453
|
-
'9jbGlzdC9nZXQ/Y2I9alF1ZXJ5MTEyNDA4Mzc4MjAwMDc0NDQ0MzA5XzE2Mjc4MjQ2MDM'+
|
|
454
|
-
'1NjImcG49MSZwej0yMDAwJnBvPTAmbnA9MSZ1dD1iZDFkOWRkYjA0MDg5NzAwY2Y5YzI3'+
|
|
455
|
-
'ZjZmNzQyNjI4MSZmbHR0PTImaW52dD0yJmZpZD1mNiZmcz1iOg==').decode()+ \
|
|
456
|
-
bkid + '+f:!50&fields=f3,f6,f12,f14,f20&_='
|
|
457
|
-
a = _east_list_fmt(base64.b64encode(bytes(url, encoding='utf-8')),
|
|
458
|
-
'jQuery112408378200074444309_1627824603562')
|
|
459
|
-
logger.debug('get industry stocks {}'.format(len(a)))
|
|
460
|
-
return a
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
def get_hk_stocks_ggt():
|
|
464
|
-
'''
|
|
465
|
-
Return sorted stock item list in GangGuTong, ordered by amount of money,
|
|
466
|
-
item in returned list are [code, name, change, amount, price]
|
|
467
|
-
'''
|
|
468
|
-
a = _east_list_fmt('aHR0cHM6Ly8yLnB1c2gyLmVhc3Rtb25leS5jb20vYXBpL3F0L2NsaX'+
|
|
469
|
-
'N0L2dldD9jYj1qUXVlcnkxMTI0MDI0MzYyMzA4OTA2NjE1MDgyXzE2MjgyNTg5MzEyMjQ'+
|
|
470
|
-
'mcG49MSZwej0xMDAwJnBvPTAmbnA9MSZ1dD1iZDFkOWRkYjA0MDg5NzAwY2Y5YzI3ZjZm'+
|
|
471
|
-
'NzQyNjI4MSZmbHR0PTImaW52dD0yJmZpZD1mNiZmcz1iOkRMTUswMTQ2LGI6RExNSzAxN'+
|
|
472
|
-
'DQmZmllbGRzPWYzLGY2LGYxMixmMTQsZjIwJl89',
|
|
473
|
-
'jQuery1124024362308906615082_1628258931224')
|
|
474
|
-
a = [ ['hk'+i[0], i[1], i[2], i[3], i[4]] for i in a]
|
|
475
|
-
logger.debug('get hk stocks GangGuTong {}'.format(len(a)))
|
|
476
|
-
return a
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
def get_hk_stocks_hsi():
|
|
480
|
-
'''
|
|
481
|
-
Return sorted stock item list in HSI, ordered by amount of money,
|
|
482
|
-
item in returned list are [code, name, change, amount, price]
|
|
483
|
-
'''
|
|
484
|
-
a = _east_list_fmt('aHR0cHM6Ly81Ni5wdXNoMi5lYXN0bW9uZXkuY29tL2FwaS9xdC9jbG'+
|
|
485
|
-
'lzdC9nZXQ/Y2I9alF1ZXJ5MTEyNDA3ODg4ODY4NDU5NDc5NzkyXzE2MjgyNTk1NjQ2NzE'+
|
|
486
|
-
'mcG49MSZwej0xMDAwJnBvPTEmbnA9MSZ1dD1iZDFkOWRkYjA0MDg5NzAwY2Y5YzI3ZjZm'+
|
|
487
|
-
'NzQyNjI4MSZmbHR0PTImaW52dD0yJmZpZD1mNiZmcz1iOkRMTUswMTQxJmZpZWxkcz1mM'+
|
|
488
|
-
'yxmNixmMTIsZjE0LGYyMCZfPQ==',
|
|
489
|
-
'jQuery112407888868459479792_1628259564671')
|
|
490
|
-
a = [ ['hk'+i[0], i[1], i[2], i[3], i[4]] for i in a]
|
|
491
|
-
logger.debug('get hk stocks HSI {}'.format(len(a)))
|
|
492
|
-
return a
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
if __name__ == "__main__":
|
|
497
|
-
# print(get_cn_stock_list())
|
|
498
|
-
# print(get_price('fuBTC',sdate='20250101'))
|
|
499
|
-
# print(get_price('fuM2601',sdate='20250101', freq='min'))
|
|
500
|
-
# print(get_price('fuM2601',sdate='2025-01-01'))
|
|
501
|
-
# print(get_price('sz000001', sdate='20240101', edate='20250101'))
|
|
502
|
-
print(get_price('usAMZN.OQ', sdate='20250101', edate='20250101', freq='min'))
|
|
503
|
-
|