投资组合风险值

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中的方案,就能够轻松地对自己的投资组合进行风险值计算。

完整程式码

延伸阅读

相关连结

返回总览页