阿彪帮你画资产大饼图

看到坛子里多策略摊饼的同学还在苦于画资产分布图,斗胆献下丑,将自用代码贡献一段。

目前是可以实现场内+场外+港股+股指的画图的,但因为和数据库有牵扯,放上来的版本做了简化,仅实现场内部分。

如果自己能算出来市值,那就不受限制了。

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()
0

yjh2175

赞同来自:

@xxbiao
这是一段Python代码,还是需要有一定基础能大概看懂代码。

读完持仓.xlsx后,会显示一个网页,可以交互点击的。
谢谢。是将上面代码,复制到txt文本文件,再怎么执行吗?
2024-06-11 16:31 来自浙江 引用
0

hotsosa

赞同来自:

漂亮,学习了
2024-06-11 15:45 来自四川 引用
0

fh33255

赞同来自:

挺漂亮的,先收藏了,谢谢
2024-06-11 12:41 来自加拿大 引用
0

大狗的猴哥

赞同来自:

挺好看
2024-06-11 11:18 来自浙江 引用
0

xxbiao

赞同来自:

@yjh2175
请问下这些代码,放到什么地方运行,可以在EXCEL表中有表与图出来?
这是一段Python代码,还是需要有一定基础能大概看懂代码。

读完持仓.xlsx后,会显示一个网页,可以交互点击的。
2024-06-11 11:14 来自上海 引用
1

yjh2175

赞同来自: 峰峰峰哥

请问下这些代码,放到什么地方运行,可以在EXCEL表中有表与图出来?
2024-06-11 11:02 来自浙江 引用
0

每天都有进步

赞同来自:

@sunzhen739
感谢楼主分享,请问有没有更简单一些的实现方法?
我用的笨办法,从券商下载持仓数据,用excel的旭日图画出来的
2024-06-11 10:18 来自香港 引用
1

sunzhen739

赞同来自: moneyandyouhai

感谢楼主分享,请问有没有更简单一些的实现方法?
2024-06-11 10:00 来自山东 引用
0

没钱个子矮

赞同来自:

做的真不错
2024-06-10 22:10 来自江苏 引用
0

sunhao5573

赞同来自:

万份感谢
2024-06-10 18:00 来自浙江 引用

要回复问题请先登录注册

发起人

问题状态

  • 最新活动: 2024-06-11 16:31
  • 浏览: 2561
  • 关注: 48