Table of Contents
近年來開始興起一種投資,叫做環境、社會和治理(ESG)投資,指的是在投資決策時,不再只考慮公司的財務表現,而是額外考慮企業對於環境、社會的影響力,以及公司的行為與準則等。彼此之間不再是抵換關係,而是一種良善的循環,提供公司未來前景的保證,進而為投資者帶來豐富的報酬。
因子投資,即試圖找出幾個關鍵的影響因素,像是文獻常見的規模因子、帳市值比因子、風險因子等等,並預期這些因素能帶來超額報酬。因此本週我們以TEJ資料庫提供的「員工流動率」當作因子,看看ESG投資的成果吧!
本文使用 Windows OS 並以 Jupyter Notebook 作為編輯器
#功能與視覺化模組 import pandas as pd import numpy as np import plotly.express as px import plotly.graph_objects as go
#TEJ import tejapi tejapi.ApiConfig.api_key = 'Your Key' tejapi.ApiConfig.ignoretz = True
turnover = tejapi.get('TWN/ACSR01A', paginate = True, opts = {'columns':['coid','mdate','turn_rate','num_staff']}, chinese_column_name = True)
turnover = turnover[turnover['員工流動率(%)'].isnull() == False]
result = pd.DataFrame() ret_table = pd.DataFrame()
因為員工流動率於年報揭露,為了避免前視偏誤,因此本文以年報最晚公布日 (隔年三月底)作為投組建構日,並持有一年。但由於按照2020年報資訊所建立的投組,投組持有期間為 2021–03–31 ~ 2022–03–31,尚未持滿一年,因此會排除該年。
date_list = sorted(turnover['年度'].unique())[:-1]
接下來以迴圈進行每年報酬率計算,以下內容以第一年 (date = ‘2008–01–01’)的資料處理情形幫助理解,完整迴圈請參考完整程式碼。
#當期資料選取 data = turnover[turnover['年度'] == date].reset_index(drop=True)
#刪除員工人數過少 data = data[data['員工人數'] >= data['員工人數'].quantile(0.1)] #分群 data['group'] = pd.qcut(data['員工流動率(%)'], q=10,labels = [i for i in range(1,11)]) #儲存 result = result.append(data)
首先選取該年資料,並且刪除員工人數過低 (小於十分位數)樣本。接著使用 函數 pd.qcut()
,依員工流動率由小到大形成十個組別,並呈現在group
欄,最後儲存到 result
裡
#投組賣出日期 sell_date = date + pd.Timedelta(days = 365 + 90 + 365) #投組報酬 port_ret = [date]
根據2008年資訊建立的十個投組,都將於 sell_date
(2010–03–31)賣出。而日期 (2008–01–01)與這些投組報酬,將存放於 port_ret
列表
#計算當年各組的投組報酬 for group in range(1,11): #當年,某組的資料 sub_data = data[data['group'] == group].reset_index(drop=True) #報酬率撈取 ret = tejapi.get('TWN/APRCD2', coid = sub_data['公司碼'].tolist(), mdate = {'gte':sell_date - pd.Timedelta(days = 5), 'lte':sell_date}, opts = {'columns':['coid','mdate', 'roi_y']}, paginate = True, chinese_column_name = True) #只需要最後一筆 ret = ret.groupby(by='證券代碼').last().reset_index() #投組報酬(%) port_ret.append(ret['年報酬率 %'].mean())
#表格 ret_table = ret_table.append(pd.DataFrame(data = np.array(port_ret).reshape((1,11)), columns = ['日期'] + [i for i in range(1,11)])).reset_index(drop=True)
接著按照組別由小到大進行迴圈。首先先進一步篩選出某組的資料,然後根據這個組別包含的公司、賣出日期撈取年報酬率(%)。這邊採用的技巧是先撈取靠近賣出日的年報酬率資料,接著取最靠近賣出日期的年報酬,此即為過去完整一年內的報酬率。最後再取平均值,即為該組投組的等權報酬率,各組都計算完成後,再將列表 port_ret
形成表格後存入 ret_table
其他年份一樣重複以上步驟,透過迴圈不斷地去更新 result
與 ret_table
,最後得到以下結果。
cum_ret = ret_table[[i for i in range(1,11)]].apply(lambda x : (x*0.01 + 1)).cumprod() cum_ret.insert(0, '日期', date_list)
先計算這十組投組的累積報酬率,再補上日期,最後再畫出
sharpe_list = [] for i in range(1,11): #年化報酬率 cagr = (cum_ret[i].values[-1]**(1/len(cum_ret)) - 1)*100 #年化標準差 std = ret_table[i].std() #更新list sharpe_list.append(i) sharpe_list.append((cagr-1)/std)
#形成表格 sharpe = pd.DataFrame(np.array(sharpe_list).reshape((10,2)), columns = ["group","夏普比率(%)"])
先計算出夏普比率,再畫出
從累積報酬圖與夏普值可以發現,員工流動率最高的第十組表現最差,即使其在部分年間有好的報酬表現。但這並不意味著員工流動率低,公司的表現就一定會比較好,例如從累積報酬圖來看,第七組是表現最好的,或許這也代表保持一定的員工流動,反而能維持公司的競爭力與創新意識。
整體而言,在市場表現差時,員工流動率較差的公司損失幅度較大,代表ESG因子某種程度提供一定的下行風險保護。如果讀者對於其他ESG資料有興趣,歡迎到 TEJ E-Shop 選擇最適的方案,找出更多創造超額報酬的因子!
電子報訂閱