用 Python 快速追蹤基金的收益情況 | Python財(cái)經(jīng)實(shí)踐
來源:Python數(shù)據(jù)之道 (ID:PyDataLab)
作者:陽哥
大家知道,近幾年,不少同學(xué)都是經(jīng)由基金進(jìn)入到股市中的。至于股票和基金到底誰更好,這個(gè)仁者見仁智者見智,恐怕一時(shí)半會兒也說不清楚。
項(xiàng)目定制化需求, 加老表微信: pythonbrief
掃碼即可加我微信
本次內(nèi)容涉及到的Python庫主要是 pandas 和 tushare 。
最終實(shí)現(xiàn)的效果如下:

上面表格中的信息,主要涉及四個(gè)方面:
基金基礎(chǔ)信息,包括基金名稱、基金費(fèi)率、基金公司、基金成立時(shí)間等; 基金經(jīng)理的信息,包括姓名、性別、任職時(shí)間等; 基金規(guī)模,體現(xiàn)出來的是基金金額的規(guī)模,是通過基金份額以及基金凈值計(jì)算出來的; 基金年度收益情況,一般是計(jì)算基金近幾年的收益情況。
上面的這些信息,在財(cái)經(jīng)工具 tushare 中,目前是都已經(jīng)提供了的。因此,咱們有必要稍微介紹下 tushare 。
01tushare 介紹
關(guān)于財(cái)經(jīng)數(shù)據(jù),有多個(gè)Python庫可以供咱們選擇,其中 tushare 是國內(nèi)較早開始發(fā)布財(cái)經(jīng)數(shù)據(jù)的社區(qū),其內(nèi)容比較完善,今天我們使用的就是 tushare 。
Tushare 是一個(gè)金融大數(shù)據(jù)平臺,數(shù)據(jù)內(nèi)容包含股票、指數(shù)、基金、期貨、債券、外匯、行業(yè)大數(shù)據(jù)等,同時(shí)包括了數(shù)字貨幣行情等區(qū)塊鏈數(shù)據(jù),為各類金融投資和研究人員提供適用的數(shù)據(jù)和工具,概覽如下:

使用 Tushare
Tushare 平臺的數(shù)據(jù),已全面升級到 tushare pro 了,通常情況下,還是稱之為 tushare。
想使用 tushare 中的數(shù)據(jù)和功能,首先需要進(jìn)行注冊,獲得一份 token (一串字母和數(shù)字組成的文本),然后才可以獲取到數(shù)據(jù),大家可以通過以下鏈接來注冊(也可以點(diǎn)擊文末的“閱讀原文”):
https://tushare.pro/register?reg=129033
在 tushare 中注冊后,通過 “個(gè)人主頁”——“接口TOKEN” 可以找到自己的 token 值,界面如下:

復(fù)制 token 值,然后在代碼中進(jìn)行如下設(shè)置:
# 設(shè)置 token
# tushare 注冊地址: https://tushare.pro/register?reg=129033
# 以上方法只需要在第一次或者token失效后調(diào)用,完成調(diào)取tushare數(shù)據(jù)憑證的設(shè)置,正常情況下不需要重復(fù)設(shè)置。
ts.set_token('你的token值')
pro = ts.pro_api()
在設(shè)置好 token 值后,我們就可以開始獲取數(shù)據(jù)。
關(guān)于 tushare 的詳細(xì)介紹,請點(diǎn)擊下面的鏈接前往:
02基金信息獲取
首先,導(dǎo)入本次需要用到的 python 庫,并設(shè)置好 tushare ,如下:
import pandas as pd
import datetime
import numpy as np
import tushare as ts
# token='XXXXXXX'
# ts.set_token(token)
pro = ts.pro_api()
需要說明的是,tushare 中不同的數(shù)據(jù)獲取需要的權(quán)限是不一樣的,如果權(quán)限不夠,可能獲取不到數(shù)據(jù)哦。
獲取基金基礎(chǔ)信息
首先,咱們來獲取基金基礎(chǔ)信息,包括基金名稱、基金費(fèi)率、基金公司、基金成立時(shí)間等。在 tushare 中,提供了 fund_basic() 接口來獲取這些信息。

該接口有兩個(gè)參數(shù),咱們主要關(guān)注的是第一個(gè)參數(shù) market,由于基金有場內(nèi)基金(ETF和LOF)和場外基金,因此,全部的基金是這兩者之和。
所有基金的基礎(chǔ)信息獲取代碼如下:
# 獲取基金中文名稱信息
df_e = pro.fund_basic(market='E')
df_o = pro.fund_basic(market='O')
# df_fund_info = df_e.append(df_o)
df_fund_info = pd.concat([df_e,df_o])
df_fund_info = df_fund_info[['ts_code','name', 'management','m_fee', 'c_fee','found_date']]
df_fund_info.columns = ['fund_code','fund_name', 'management','m_fee', 'c_fee','found_date']
df_fund_info = df_fund_info.reset_index(drop=True)
df_fund_info
結(jié)果如下:

這個(gè)數(shù)據(jù)框中,有 1.6萬多支基金,是不是超出你的想象了啊~~~
實(shí)際上,目前整個(gè)市場上總數(shù)應(yīng)該多于這個(gè)數(shù),tushare中有部分信息還沒有納入進(jìn)來。
當(dāng)然了,這是包括了混合型、股票型、債券型、貨幣基金類等全部的基金。
獲取基金經(jīng)理信息
對于主動型基金而言,挑選基金時(shí),選擇一個(gè)好的基金經(jīng)理是很重要的因素,因此,在追蹤基金的收益情況時(shí),是有必要將基金經(jīng)理的信息一并獲取的。
在tushare 中,可通過接口 fund_manager 來獲取某只基金過往基金經(jīng)理的信息。
在獲取基金經(jīng)理信息后,可以跟之前獲取基金基礎(chǔ)信息進(jìn)行合并。
這個(gè)過程,陽哥寫了一個(gè)自定義函數(shù),如下:
# 獲取單個(gè)基金的信息
def get_fund(fund_code,df_fund_info):
# 獲取基金經(jīng)理信息,以及開始管理該基金的日期
df_manager = pro.fund_manager(ts_code=fund_code)
df_manager = df_manager[df_manager['end_date'].isna()]
df_manager = df_manager.sort_values('begin_date',ascending=True).head(1)
begin_date = df_manager['begin_date'].values[0] # 開始管理該基金的日期
df_manager = df_manager[['ts_code', 'name', 'gender','begin_date']]
df_manager.columns = ['fund_code', 'manager_name', 'gender','begin_date']
# 合并
df_fund = pd.merge(df_manager,df_fund_info,how='left',on='fund_code')
return df_fund
假如你想獲取易方達(dá)優(yōu)質(zhì)精選(以前叫易方達(dá)中小盤)的信息,可以基于上面的自定義函數(shù) get_fund ,使用如下的代碼:
# 110011.OF,易方達(dá)優(yōu)質(zhì)精選(易方達(dá)中小盤)
df_fund = get_fund('110011.OF',df_fund_info)
df_fund
獲取的信息如下:

計(jì)算基金規(guī)模和收益情況
接下來,咱們還需要獲取兩個(gè)信息,基金規(guī)模和基金近幾年的收益情況。
基金規(guī)模,可以從一個(gè)角度來觀察該基金在市場上的受歡迎度,一般來說,規(guī)模較大的基金,說明該基金過往的表現(xiàn)應(yīng)該還是可以的。不過這里也有兩點(diǎn)需要注意:
基金過往業(yè)績并不代表未來依然會如此; 基金規(guī)模小,并不一定說明該基金未來表現(xiàn)會不好。
除了基金規(guī)模,另一個(gè)咱們經(jīng)常關(guān)注的,也是基金營銷機(jī)構(gòu)經(jīng)常拿出來宣傳的,就是基金的過往收益情況。
基金規(guī)模的計(jì)算公式如下:
在 tushare 中 基金份額數(shù)量由函數(shù) fund_share 來獲取,基金單位凈值(unit_nav)數(shù)據(jù)由函數(shù) fund_nav 來獲取。
此外,在計(jì)算基金的過往年度收益時(shí),也是基于其累計(jì)凈值(accum_nav)來實(shí)現(xiàn)的。
因此,陽哥將基金規(guī)模獲取過程和基金近幾年收益情況計(jì)算合并在一個(gè)自定義函數(shù)里,代碼如下:
# 獲取單支基金的年度收益,基金規(guī)模等信息
def get_returns(fund_code,start_year):
"""獲取單支基金的年度收益,基金規(guī)模等信息
Keyword arguments:
fund_code -- 基金代碼,如:110011.OF
start_year -- 開始獲取基金數(shù)據(jù)的年份
"""
df_fund_nav = pro.fund_nav(ts_code=fund_code)
df_fund_nav['date'] = pd.to_datetime(df_fund_nav['nav_date'])
df_fund_nav = df_fund_nav.set_index('date').sort_index()
years = df_fund_nav['accum_nav'].resample('AS').sum().to_period('A')
# 獲取年度數(shù)據(jù),類型為 pandas 的 period
years = years.index.tolist()
# 有些基金的開始日期晚于2018年,需要對齊列,補(bǔ)空白
year_list = [yr.year for yr in years if yr.year>=start_year]
# 將 period 時(shí)間數(shù)據(jù)轉(zhuǎn)為 string 的年度數(shù)據(jù)
years = [str(yr.year) for yr in years]
df_yrs_index = pd.DataFrame()
for yr in years:
df_yr_index = df_fund_nav.loc[yr].tail(1)
# df_yrs_index = df_yrs_index.append(df_yr_index) # append 將被替代
df_yrs_index = pd.concat([df_yrs_index,df_yr_index])
# df_yrs = df_fund_nav.head(1).append(df_yrs_index)
df_yrs = pd.concat([df_fund_nav.head(1),df_yrs_index])
# 計(jì)算每年的收益率,即漲跌幅度
df_yrs['returns'] = df_yrs['accum_nav'].pct_change()
# 刪除收益率為 NA 的行 (第1天有數(shù)據(jù)記錄的日期)
df_yrs = df_yrs.dropna(subset=['returns'])
# 篩選自開始年份以來的數(shù)據(jù)
df_yrs = df_yrs.loc[str(start_year):]
df_yrs = df_yrs.reset_index()
df_yrs['year'] = df_yrs['date'].dt.year
# 透視表
df_yr_returns = pd.pivot_table(
df_yrs, index=['ts_code'],
values=['returns'], columns=['year'], fill_value=""
)
# 將多層索引轉(zhuǎn)變?yōu)閱螌铀饕?/span>
df_yr_returns = df_yr_returns['returns']
df_yr_returns = df_yr_returns.reset_index()
df_yr_returns.columns.name = None
df_yr_returns = df_yr_returns.rename(columns={'ts_code':'fund_code'})
# 基金份額
df_fund_share = pro.fund_share(ts_code=fund_code).head(1)
df_fund_share.columns = ['fund_code', 'fd_share_date', 'fd_share', 'fund_type', 'market']
# fd_share,單位是 萬份
fd_share_date = df_fund_share['fd_share_date'].values[0] # 份額對應(yīng)的日期
# 份額日期的凈值數(shù)據(jù)
df_ann_nav = df_fund_nav.loc[fd_share_date:fd_share_date].sort_values('update_flag',ascending=False).head(1)
df_ann_nav = df_ann_nav[['ts_code', 'accum_nav','unit_nav']]
df_ann_nav.columns = ['fund_code', 'accum_nav','unit_nav']
# 計(jì)算基金規(guī)模,amount,單位:億元
df_fund_amount = pd.merge(df_fund_share,df_ann_nav,how='left',on='fund_code')
df_fund_amount['amount'] = df_fund_amount['fd_share'] * df_fund_amount['unit_nav']/10000
df_fund_amount = df_fund_amount[['fund_code','amount','fd_share_date']]
# 合并數(shù)據(jù)
df_yr_returns = pd.merge(df_fund_amount,df_yr_returns,how='left',on='fund_code')
for yr in year_list:
if yr not in df_yr_returns.columns.tolist():
df_yr_returns[yr]=np.nan
return df_yr_returns
假如你想獲取易方達(dá)優(yōu)質(zhì)精選基金的2018年以來的收益情況信息,可以基于上面的自定義函數(shù) get_returns ,使用如下的代碼:
df_return = get_returns('110011.OF',2018)
df_return
獲取的信息如下:

同時(shí)獲取多只基金的信息
上面已經(jīng)實(shí)現(xiàn)了獲取單只基金所需要的信息,接下來,咱們需要拼接之前獲取的信息。
同時(shí),我們一般會同時(shí)關(guān)注多只基金,因此同時(shí)獲取多只基金的信息,也是基本必備的需求。
實(shí)現(xiàn)的代碼如下:
# 獲取多只基金的信息
def get_data_fund(df_fund_info,fund_code_short,start_year):
df_filter_info = pd.DataFrame()
for code in fund_code_short:
df_tmp = df_fund_info[df_fund_info['fund_code'].str.contains(code)].head(1)
# df_filter_info = df_filter_info.append(df_tmp)
df_filter_info = pd.concat([df_filter_info,df_tmp])
df_filter_info = df_filter_info.reset_index(drop=True)
fund_codes = df_filter_info['fund_code'].tolist()
# fund_codes
# df = pd.DataFrame()
frames = [] # 用來裝載 df_fund_merge
i=0
for code in fund_codes:
print(f'i:{i},code:{code}')
if i<78:
# print(code)
# print(f'i:{i},code:{code}')
df_fund = get_fund(code,df_fund_info)
df_return = get_returns(code,start_year)
df_fund_merge = pd.merge(df_fund,df_return,how='left',on='fund_code')
frames.append(df_fund_merge)
i +=1
else:
i=0
time.sleep(61)
# df = df.append(df_fund_merge)
df = pd.concat(frames)
df = df.reset_index(drop=True)
df = df.rename(columns={
'fund_code':'基金代碼','manager_name':'基金經(jīng)理',
'gender':'性別','begin_date':'上任日期',
'fund_name':'基金名稱','management':'基金公司',
'm_fee':'管理費(fèi)','c_fee':'托管費(fèi)',
'found_date':'成立時(shí)間','amount':'基金規(guī)模(億元)',
'fd_share_date':'規(guī)模對應(yīng)日期'
})
# 調(diào)整列的排序
cols = df.columns.tolist()
col_1 = cols[:4]
col_2 = cols[4:5]
col_3 = cols[5:]
cols = col_2 + col_1 + col_3
df = df[cols]
return df
在上面的函數(shù) get_data_fund 中,還對最后顯示的列的順序也進(jìn)行了調(diào)整,該過程的實(shí)現(xiàn)的詳細(xì)內(nèi)容,可以在下面的鏈接中來了解:
基于自定義函數(shù) get_data_fund,設(shè)置好函數(shù)所需要的參數(shù)后,就可以獲取多只基金的信息了,具體參數(shù)如下:
# 需要獲取的基金代碼簡稱列表
fund_code_short = ['001938', '162605', '005911', '005827','007119',
'110011', '161005', '000800', '519736', '163402',
'003095', '163406', '002190', '164908', '000772']
# 設(shè)置基金收益開始的年份
start_year = 2018
# 設(shè)置基金收益截止的年份
end_year = 2022
year_list = list(range(start_year,end_year+1))
df_fund_final = get_data_fund(df_fund_info,fund_code_short,start_year)
df = df_fund_final.sort_values('基金經(jīng)理',ascending=True,ignore_index=True)
# df.to_csv('./data/fund_manager.csv',index=False)
df
得到的結(jié)果如下:

Pandas 中,可以通過 Style 對表格樣式進(jìn)行設(shè)置,對收益情況進(jìn)行紅漲綠跌的設(shè)置。
代碼如下:
def color_returns(val):
if val >=0:
color = '#EE7621' # light red
elif val <0:
color = '#99ff66' # light green
else:
color = '#FFFAFA' # ligth gray
return f'background-color: {color}'
format_dict = {'基金規(guī)模(億元)': '¥{0:.1f}',
'管理費(fèi)': '{0:.1f}',
'托管費(fèi)': '{0:.2f}',
2017: '{0:.1%}',
2018: '{0:.1%}',
2019: '{0:.1%}',
2020: '{0:.1%}',
2021: '{0:.1%}',
2022: '{0:.1%}',
}
df.style.hide(axis='index')\
.hide(['規(guī)模對應(yīng)日期','成立時(shí)間'],axis='columns')\
.format(format_dict)\
.applymap(color_returns,subset=year_list)\
.background_gradient(subset=['基金規(guī)模(億元)'],cmap='Blues')
得到的結(jié)果如下:

關(guān)于 Pandas 中表格樣式設(shè)置,陽哥之前分享了一份詳細(xì)的內(nèi)容,有興趣的同學(xué)可以前往查看:
03小結(jié)
至此,咱們就獲取了本次想要得到的信息,這個(gè)表格可以定期更新,用于給其他人員分享基金的基本信息以及年度收益情況。
在今天的這個(gè)財(cái)經(jīng)案例里,需求其實(shí)是很常見的。在這個(gè)案例里,主要用到的是 Pandas 和 Tushare 工具。
對于 Pandas 而言,用到的知識點(diǎn)還是挺多的,包括數(shù)據(jù)篩選、數(shù)據(jù)合并、數(shù)據(jù)排序、數(shù)據(jù)透視表、樣式設(shè)置等,雖然都是基礎(chǔ)知識點(diǎn),但要做到熟練運(yùn)用,也是需要一定功底的。
圖書推薦:
點(diǎn)擊小程序卡片,優(yōu)惠購買
《uni-app跨平臺開發(fā)與應(yīng)用從入門到實(shí)踐》
本書以“零基礎(chǔ)”為起點(diǎn),系統(tǒng)地介紹了uni-app的跨平臺開發(fā)與應(yīng)用。全書內(nèi)容分為3篇,共12章,具體安排如下。
第一篇:基礎(chǔ)篇,包括第1~4章,主要介紹了uni-app的特點(diǎn)和優(yōu)勢、環(huán)境搭建、HBuilderX開發(fā)工具的安裝和使用,以及uni-app的一些基礎(chǔ)知識。
第二篇:進(jìn)階篇,包括第5~9章,主要介紹了uni-app的基礎(chǔ)配置、相關(guān)組件、導(dǎo)航欄、高效開發(fā)技巧,以及uniCloud云開發(fā)平臺。
第三篇:實(shí)戰(zhàn)篇,包括第10~12章,通過第一個(gè)實(shí)戰(zhàn),介紹了如何使用uni-app開發(fā)小程序;通過第二個(gè)實(shí)戰(zhàn),介紹了如何使用uni-app進(jìn)行跨平臺開發(fā);通過第三個(gè)實(shí)戰(zhàn),介紹了如何使用uniCloud云開發(fā)。
留言就贈書:
點(diǎn)贊+留言第 8、18位可以分別獲得贈書一本。
注意:僅限關(guān)注本公眾號18天及以上且之前未獲得過贈書的讀者參與。
1、想領(lǐng)取贈書,加我微信,朋友圈不定期送書;
2、想咨詢學(xué)習(xí),加我微信,每次咨詢僅9.9元;
3、更多需求(學(xué)習(xí) 代碼 視頻剪輯),都可以加我微信,歡迎咨詢。
掃碼即可加我微信
分享
收藏
點(diǎn)贊
在看




