看到坛子里多策略摊饼的同学还在苦于画资产分布图,斗胆献下丑,将自用代码贡献一段。
目前是可以实现场内+场外+港股+股指的画图的,但因为和数据库有牵扯,放上来的版本做了简化,仅实现场内部分。
如果自己能算出来市值,那就不受限制了。
excel文件格式和最终效果见附图。
py文件代码见下。
目前是可以实现场内+场外+港股+股指的画图的,但因为和数据库有牵扯,放上来的版本做了简化,仅实现场内部分。
如果自己能算出来市值,那就不受限制了。
excel文件格式和最终效果见附图。
py文件代码见下。
import requests
import pandas as pd
导入plotly库
import plotly.graph_objs as go
import cufflinks as cf
cf.go_offline()
处理代码前辍函数
def code_prefix(code, qmt = False):
"""处理代码前辍
沪市 转债 '11' 股票 '60' '68' 基金 '51' '501' '58'
深市 转债 '12' 股票 '00' '30' 基金 '159' '16'
"""
#场外基金的要自己去处理
#场内的只分沪市SH和深市SZ
#场外基金的没去处理,jj开头
sh_prefix = ['11', '60' ,'68', '51', '501','58']
if_prefix = ['IM','IF','IH']
sz_prefix = ['12', '00' ,'30', '159', '16' ]
#腾讯接口的代码格式处理
if not qmt:
if len(code)==5: #code.startswith(tuple(hk_prefix))
code = 'hk' + code
elif code.startswith(tuple(sh_prefix)):
code = 'sh' + code
else:
code = 'sz' + code
#qmt接口的代码格式处理
elif qmt:
if len(code)==5: #code.startswith(tuple(hk_prefix))
code = code + '.HK'
elif code.startswith(tuple(if_prefix)):
code = code + '.IF'
elif code.startswith(tuple(sh_prefix)):
code = code + '.SH'
else:
code = code + '.SZ'
return code
def get_stock_prices(keys, prefix = False) ->dict:
"""
腾讯行情接口
0: 未知
1: 股票名字
2: 股票代码
3: 当前价格
4: 昨收
5: 今开
6: 成交量(手)
7: 外盘
8: 内盘
9: 买一
10: 买一量(手)
11-18: 买二 买五
19: 卖一
20: 卖一量
21-28: 卖二 卖五
29: 最近逐笔成交
30: 时间
31: 涨跌
32: 涨跌%
33: 最高
34: 最低
35: 价格/成交量(手)/成交额
36: 成交量(手)
37: 成交额(万)
38: 换手率
39: 市盈率
40:
41: 最高
42: 最低
43: 振幅
44: 流通市值
45: 总市值
46: 市净率
47: 涨停价
48: 跌停价
"""
#股指期货的前缀,例如IM2409
keys_if = [k for k in keys if k.startswith(('IM','IF','IH','IC'))]
keys = [k for k in keys if not k in keys_if]
if prefix:
if type(prefix) == str:
keys = [prefix + str(i) for i in keys ]
else:
keys = [code_prefix(i) for i in keys ]
#场外基金的没去处理,jj开头
keys_str = ','.join(keys)
res = requests.get(url = 'http://qt.gtimg.cn/q=%s'%keys_str)
res_list = res.text.replace('\n','').strip().split(';')
stocks = {}
for i in range(len(res_list)):
row = res_list[i]
# print(row,i)
if len(row) == 0:
continue
code = row.split('=')[0].split('_')[-1]
row = row.split('=')[-1].replace('"','').split('~')
# print(code, keys[i], row)
if prefix == 'jj':
stocks[code] = {
'名称': row[1],
'现价': float(row[5]),
'累计': float(row[6]),
'涨跌': float(row[7]),
#'日期': parse(row[8]),
}
else:
stocks[code] = {
'名称': row[1],
'现价': float(row[3]),
'昨收': float(row[4]),
'今开': float(row[5]),
'涨跌': float(row[31]),
'涨幅': round(float(row[32])/100,4),
}
#股指
for k in keys_if:
pre_code = k[0:2]
code = k
from io import StringIO
headers={
'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36',
}
txt = requests.get(f'http://www.cffex.com.cn/quote_{pre_code}.txt', headers=headers).text
df_im = pd.read_csv(StringIO(txt)).set_index('instrument')
if not ( k in df_im.index):
continue
row = pd.read_csv(StringIO(txt)).set_index('instrument').loc[k]
# with G_C.duck:
# df = G_C.duck.conn.sql(f"""select * from stock_k_data
# where code='{code}.IF'
# order by date desc limit 1
# """).df()
# if not df.empty:
# last_price = df['close'][0]
# else:
last_price = row['lastprice'] - row['updown']
stocks[code] = {
'名称': code,
'现价': row['lastprice'],
'昨收': last_price,
'今开': row['openprice'],
'涨跌': row['lastprice'] - last_price,
'涨幅': round((row['lastprice'] - last_price)/last_price ,4),
}
return stocks
df_hold = pd.read_excel('持仓.xlsx', dtype={'证券代码':str})
pie_stock = df_hold[~df_hold['证券代码'].isna()].set_index('证券代码')
cash = df_hold.query("小类=='现金'")['持仓市值'].iloc[0]
codes = pie_stock.index.to_list()
表格中如果算好了持仓市值,以下自动获取市值的代码就是多余的
prices = pd.DataFrame.from_dict(get_stock_prices(codes),orient= 'index')
prices.index = prices.index.map(lambda x: x[2:])
pie_stock['现价'] = prices['现价']
pie_stock['持仓市值'] = pie_stock['持仓数量']*pie_stock['现价']
print(pie_stock)
df_fig_pie = pie_stock.append({'证券名称':'现金','小类':'现金+固收','持仓市值':cash},
ignore_index=True)
df_fig_pie['持仓市值'] = df_fig_pie['持仓市值'].fillna(0).astype(int)
按饼图层次逐级计算值
pie_level0 = pd.DataFrame.from_dict({'证券名称':['我的持仓'],'小类':[''],'持仓市值':[df_fig_pie['持仓市值'].sum()]})
pie_level1 = df_fig_pie.groupby('大类').sum().reset_index().rename(columns={'大类':'证券名称'})
pie_level1['小类'] = '我的持仓'
pie_level2 = df_fig_pie.fillna('我的持仓').groupby('小类').agg({'持仓市值':'sum','大类':'first'}).reset_index().rename(columns={'小类':'证券名称','大类':'小类'})
df_fig_pie_sum = pd.concat([df_fig_pie, pie_level0, pie_level1, pie_level2])
print(df_fig_pie_sum)
if df_fig_pie_sum['证券名称'].duplicated().any():
print('证券名称不唯一')
print(df_fig_pie_sum[df_fig_pie_sum['证券名称'].duplicated()])
fig_sun =go.Figure(go.Sunburst(
labels = df_fig_pie_sum['证券名称'],
parents = df_fig_pie_sum['小类'],
values= df_fig_pie_sum['持仓市值'],
branchvalues="total",
texttemplate = "%{label}<br>%{percentEntry:.1%}",
hovertemplate = "%{label}<br>%{value:,r}<br>%{percentEntry:.1%}",
name='',
))
total_amount = df_fig_pie['持仓市值'].sum()/10000
fig_sun = fig_sun.update_layout(title = f'资产 {total_amount:.2f}万 ',
margin=dict(t=40, l=1, r=1, b=1) , width = 600, height=600)
fig_sun.show()
fig_json_sun = fig_sun.to_json()