【量化分析】投資組合風險值

TEJ 台灣經濟新報
TEJ-API 金融資料分析
12 min readMar 1, 2022

以變異數-共變異數法計算風險值

Photo by Scott Graham on Unsplash

本文重點概要

  • 文章難度:★★☆☆☆
  • 投資組合風險值計算&分析
  • 閱讀建議:本文會利用Python實作風險值計算的過程,使用的方法為變異數-共變異數法,需要讀者對投資組合、基礎統計學有基本認識。

前言

風險值的意思基本上就是根據給定的信賴水準以及某特定期間,投資組合可能產生的最大損失。本文計算過程如下:

  1. 投資組合內各標的之每日盈餘風險
  2. 各標的間相關係數
  3. 投資組合風險值

在計算風險值的方面,需要注意各項參數的使用,以及資產報酬率的分佈情形,才能夠將真實的市場波動反映在計算數值上,後續本文將詳細說明完整的執行過程,以及本文所用的「變異數-共變異數法」在應用上的優缺點。

本文所用之風險值名詞如下:

1.每日盈餘風險(Daily Earning at Risk, DEAR):投資標的之單日風險值。

2.相對風險值(Relative VaR):投資標的相對於投資報酬率均值的風險值。

(|-α| * σ) * portfolio value

3.絕對風險值(Absolute VaR):投資標的相對於0的風險值。

(|-α| * σ - mean) * portfolio value

上述α皆為常態分配的臨界值,下文計算會使用99%信心水準的z值,2.33。

編輯環境及模組需求

本文使用 MacOS 並以 Jupyter Notebook 作為編輯器

#基本套件
import numpy as np
import pandas as pd
#繪圖套件
import matplotlib.pyplot as plt
%matplotlib inline
import seaborn as sns
sns.set()
#TEJAPI
import tejapi
tejapi.ApiConfig.api_key = 'Your Key'
tejapi.ApiConfig.ignoretz = True

資料庫使用

  • 證券交易資料表: 資料庫代碼為 ‘TWN/EWPRCD’,提供證券日交易行情資訊,以及還原股價資訊。
  • 報酬率資訊表: 資料庫代碼為 ‘TWN/EWPRCD2’,包含證券與指數之報日、週、月、年酬率資料。

資料處理

Step 1. 股價資料撈取

本文投資組合以傳產、電子、金融及航運各一支標的組成;內文會搭配講解風險值計算的方法和各類型標的報酬率分佈情形,讓讀者更加了解風險值計算上的優缺點。

ticker = ['1476', '2330', '2882', '2603']
# 儒鴻, 台積電, 國泰金, 長榮
df = tejapi.get('TWN/EWPRCD', # 公司交易資料-已調整股價(收盤價)
coid = ticker,
mdate = {'gte':'20200101', 'lte':'20220225'},
opts = {'columns': ['coid', 'mdate', 'close_adj']},
chinese_column_name = True,
paginate = True)
df = df.set_index('日期')

Step 2. 轉置資料表

data = {}for i in ticker:
p = df[df['證券代碼'] == i]
p = p['收盤價(元)']
data.setdefault(i, p)
data = pd.concat(data, axis = 1)

Step 3. 日報酬率資料

本文此處取用報酬率資訊表,確保資料來源的正確性,而資料處理過程與上述價格資料相同。

ret = tejapi.get('TWN/EWPRCD2', 
coid = ticker,
mdate = {'gte':'20200101', 'lte':'20220225'},
opts = {'columns': ['coid', 'mdate', 'roia']},
chinese_column_name = True,
paginate = True)
ret = ret.set_index('日期')
data2 = {}for i in ticker:
r = ret[ret['證券碼'] == i]
r = r['日報酬率(%)']
data2.setdefault(i, r)
data2 = pd.concat(data2, axis = 1)
data2 = data2 * 0.01 #還原報酬率為百分之一單位基準

每日盈餘風險

Step 1. 定義空序列

value = data.iloc[-1] * 1000 Mean = []
STD = []
MAX = []
Min = []
abs_var = []
re_var = []

首先,根據股價資料最後一日計算各項標的價值,本文是以至少持有一張股票為單位;接著,定義各項空list。

Step 2. 計算絕對、相對風險值

for i in ticker:
v = data2[i].std() # Standard Error
mean = data2[i].mean() # Mean
maximum = data2[i].max() # Maximum
minimum = data2[i].min() # Minimum

# Calculate 99% Absolute VaR
var_99_ab = (abs(-2.33)*v - mean) * value[i]
# Calculate 99% Relative VaR
var_99_re = (abs(-2.33)*v) * value[i]

# Append those values in lists
Mean.append(mean)
STD.append(v)
MAX.append(maximum)
Min.append(minimum)
abs_var.append(var_99_ab)
re_var.append(var_99_re)

在迴圈中,先計算各項標的之標準差、平均數及最大最小值;再計算絕對風險值與相對風險值;最後將上述計算各數值回傳至相對應的list。

在風險值的計算中,首先看到本文取用abs(-2.33)為99%信心水準的臨界值,會使用abs()而非直接取用2.33是想提醒讀者:風險值考量的是投資組合下跌風險的價值,所以用-2.33,而風險值表達通常為「正數」,因此加上絕對值。

Step 3. 整理表格

dear = pd.DataFrame({'Mean': Mean, 'STD': STD, 'Maximum': MAX, 'Minimum': Min, '99%絕對VaR': abs_var, '99%相對VaR': re_var},
index = ticker)
# 直接將DEAR命名為絕對、相對VaR,供後續計算使用

標的間相關係數

rho = data2.corr() # Apply ret to avoid spurious regression result

要運用報酬率資料取得標的間相關係數,而非價格資料,才能夠避免假性迴歸導致的錯誤相關係數。

投資組合風險值

Step 1. 表格合併

# 將不需用到的資料剔除。
dear = dear.drop(columns = ['Mean', 'STD', 'Maximum', 'Minimum'])
# 合併 dear 與 rho
portfolio = pd.concat([dear, rho,], axis = 1)
portfolio[['99%絕對VaR', '99%相對VaR']] = portfolio[['99%絕對VaR', '99%相對VaR']]

Step 2. 風險值計算

part1的部分是個別標的本身之風險值;part2則是標的間經相關係數調整的風險值。

part1 = sum(portfolio['99%絕對VaR']**2)

part2 =
2*portfolio.iat[0,3] * portfolio.iat[0,0] * portfolio.iat[1,0] \
+ 2*portfolio.iat[0,4] * portfolio.iat[0,0] * portfolio.iat[2,0] \
+ 2*portfolio.iat[0,5] * portfolio.iat[0,0] * portfolio.iat[3,0] \
+ 2*portfolio.iat[1,4] * portfolio.iat[1,0] * portfolio.iat[2,0] \
+ 2*portfolio.iat[1,5] * portfolio.iat[1,0] * portfolio.iat[3,0] \
+ 2*portfolio.iat[2,5] * portfolio.iat[2,0] * portfolio.iat[3,0]

99%信心水準之絕對風險值為50647.78。

part1 = sum(portfolio['99%相對VaR']**2)

part2 =
2*portfolio.iat[0,3] * portfolio.iat[0,1] * portfolio.iat[1,1] \
+ 2*portfolio.iat[0,4] * portfolio.iat[0,1] * portfolio.iat[2,1] \
+ 2*portfolio.iat[0,5] * portfolio.iat[0,1] * portfolio.iat[3,1] \
+ 2*portfolio.iat[1,4] * portfolio.iat[1,1] * portfolio.iat[2,1] \
+ 2*portfolio.iat[1,5] * portfolio.iat[1,1] * portfolio.iat[3,1] \
+ 2*portfolio.iat[2,5] * portfolio.iat[2,1] * portfolio.iat[3,1]

99%信心水準之相對風險值為52205.86。

根據上述的計算結果,可以推論此投資組合於單一交易日之最大損失金額有99%的機率不會超過5萬2千元;然而,再經過一段時間,市場也會有所變化,因此需要再次計算風險值,才能更準確的評估部位風險。

變異數-共變異數法的缺點

  1. 無法衡量非線性資產(如選擇權)之投資風險值:因為相關係數共的計算結構基本上就設定兩筆資料間為線性關係(相關係數為0則可能是非線性關係),所以此方法不適用於非線性資產。
  2. 忽略厚尾問題:此方法是以常態分配套用在資產上面,但是證券資產通常具有厚尾現象,所以可能會低估風險值。

以下將呈現投資標的之報酬率分配圖,查驗各標的厚尾現象的嚴重程度。

plt.rcParams['font.sans-serif'] = ['Arial Unicode MS']fig, ax =plt.subplots(figsize = (18, 12), nrows = 2, ncols = 2)data2['1476'].plot.hist(ax=ax[0][0], bins = 100,range=(data2['1476'].min(), data2['1476'].max()),  label = '儒鴻')
ax[0][0].legend(loc = 2, fontsize = 30)
data2['2330'].plot.hist(ax=ax[0][1], bins = 100,range=(data2['2330'].min(), data2['2330'].max()), label = '台積電')
ax[0][1].legend(loc = 2, fontsize = 30)
data2['2882'].plot.hist(ax=ax[1][0], bins = 100,range=(data2['2882'].min(), data2['2882'].max()), label = '國泰金')
ax[1][0].legend(loc = 2, fontsize = 30)
data2['2603'].plot.hist(ax=ax[1][1], bins = 100,range=(data2['2603'].min(), data2['2603'].max()), label = '長榮')
ax[1][1].legend(loc = 2, fontsize = 30)
plt.tight_layout()

由上圖可以了解,長榮的厚尾現象最為嚴重,而台積電與儒鴻也有厚尾的現象,國泰金則比較不明顯。

結論

根據本文前述的計算以及分析,相信讀者可以明白風險值(變異數-共變異數法)的計算流程:首先,計算個別標的之每日盈餘風險;接著,計算標的間相關係數;最後,計算整體投資組合的風險值。當然,在文末,本文也說明此方法的局限性,首先是針對線性證券資產;其次為「厚尾」問題,而通過圖表的呈現,讀者也可以了解文中四項標的資產確實具有厚尾現象,至於此問題要如何解決,請持續關注本平台,後續會有其他文章說明。最後,歡迎讀者選購 TEJ E Shop中的方案,就能夠輕鬆地對自己的投資組合進行風險值計算。

完整程式碼

延伸閱讀

相關連結

給我們鼓勵
之後會持續分享更多財金資料庫的應用
如果你的覺得今天的文章不錯,可以幫我們在下面的
掌聲 icon 點 1下
如果覺得超讚,可以按住
掌聲 icon 不放直到 50 下
有任何想法歡迎點選
留言 icon和我們討論

--

--

TEJ 台灣經濟新報
TEJ-API 金融資料分析

TEJ 為台灣本土第一大財經資訊公司,成立於 1990 年,提供金融市場基本分析所需資訊,以及信用風險、法遵科技、資產評價、量化分析及 ESG 等解決方案及顧問服務。鑒於財務金融領域日趨多元與複雜,TEJ 結合實務與學術界的精英人才,致力於開發機器學習、人工智慧 AI 及自然語言處理 NLP 等新技術,持續提供創新服務