套件

# 資料整理工具
library(dplyr)

# 繪圖套件
library(plotly)

# 時間序列資料的相關套件
library(xts)

# 財金金融套件
# 安裝 PerformanceAnalytics 之前的準備動作
# sudo apt-get install libblas-dev liblapack-dev
library(PerformanceAnalytics)
library(quantmod)
library(TTR)
setwd("~/TEJ_08170442")

1 前言

動手做:任選兩隻台股(2011~2020),探索其各年的風險係數。

金融-金控:

  • 2880 華南金
  • 2891 中信金

先各別整理兩台股之收益率及風險溢酬,最後再合併同時研究兩台股之差異

為何選擇金融金控產業?

  • 每年領配息、增加現金流
  • 金融股很穩,輸的機率極低
  • 金融股大都是低價股

但是!因為新型冠狀病毒(COVID-19)的關係,重創股價,非常值得探討

為何選擇這兩台股?(2880 華南金、2891 中信金)

資料顯示,台灣六大金融股2020報酬率如下:

前三家為民營股金控銀行,後三家為官股金控銀行,各挑選一家民營股金控、官股金控銀行作為研究,故挑選報酬率最低的2880 華南金以及2891 中信金

2 介紹股票專有名詞

大盤是什麼?

大盤是指台灣股市的整體表現,也可以叫做「加權指數」

例如:

  • 大盤往上漲的,代表今天大部分的股票是上漲的
  • 大盤下跌,我們就可以推估,今天台灣個股整體表現來說是差的

alpha(α)、beta(β)是什麼?

α是總風險扣除系統性風險,額外創造的 超額報酬

例如:

  • α值為1.0 = 該投資表現比大盤好1%
  • α值為-1.0 = 該投資表現比大盤差1%

β是衡量系統性風險及大盤連動性,也就是指數的波動幅度

例如:

  • 高β = 有更高的回報,但相對風險也高
  • 低β = 相對風險小,但回報也較少

通常以1作為臨界點

alpha(α)、beta(β)之間的關係?

低Beta(β)高Alpha(α)的股票往往反映企業有優質且穩定的基本因素,讓投資者即使碰上市況不景亦可做到攻守兼備

α和β是歷史模型估算,過去並不代表將來,所以α和β高低並沒有絕對的好壞,只是一個參考

α和β不能單獨拆開看,必須一起評估,一起看才有意義

3 2880 華南金

3.1 下載資料與整理

# 下載資料
# 大盤指數:^TWII
# 華南金:2880.TW
loadSymbols(Symbols=c("^TWII", "2880.TW"),
            from="2011-01-01", to="2020-12-31",
            auto.assign=TRUE) # 這一定要設定
## 'getSymbols' currently uses auto.assign=TRUE by default, but will
## use auto.assign=FALSE in 0.5-0. You will still be able to use
## 'loadSymbols' to automatically load data. getOption("getSymbols.env")
## and getOption("getSymbols.auto.assign") will still be checked for
## alternate defaults.
## 
## This message is shown once per session and may be disabled by setting 
## options("getSymbols.warning4.0"=FALSE). See ?getSymbols for details.
## Warning: ^TWII contains missing values. Some functions will not work if objects
## contain missing values in the middle of the series. Consider using na.omit(),
## na.approx(), na.fill(), etc to remove or replace them.
## Warning: 2880.TW contains missing values. Some functions will not work if
## objects contain missing values in the middle of the series. Consider using
## na.omit(), na.approx(), na.fill(), etc to remove or replace them.
## [1] "^TWII"   "2880.TW"
# 注意:^TWII 下載後存入 TWII 中
# 轉換成正常的變數名稱
#TWII = get("TWII")
TW2880 = get("2880.TW")
# 處理大盤資料
str(TWII)
## An 'xts' object on 2011-01-03/2020-12-30 containing:
##   Data: num [1:2455, 1:6] 9040 9045 9014 8866 8905 ...
##  - attr(*, "dimnames")=List of 2
##   ..$ : NULL
##   ..$ : chr [1:6] "TWII.Open" "TWII.High" "TWII.Low" "TWII.Close" ...
##   Indexed by objects of class: [Date] TZ: UTC
##   xts Attributes:  
## List of 2
##  $ src    : chr "yahoo"
##  $ updated: POSIXct[1:1], format: "2021-11-14 18:11:42"
# 去掉遺失值
TWII = na.omit(TWII)
colnames(TWII) = c("Open", "High", "Low", "Close", "Volume", "Adjusted")
str(TWII)
## An 'xts' object on 2011-01-03/2020-12-30 containing:
##   Data: num [1:2444, 1:6] 9040 9045 9014 8866 8905 ...
##  - attr(*, "dimnames")=List of 2
##   ..$ : NULL
##   ..$ : chr [1:6] "Open" "High" "Low" "Close" ...
##   Indexed by objects of class: [Date] TZ: UTC
##   xts Attributes:  
## List of 3
##  $ src      : chr "yahoo"
##  $ updated  : POSIXct[1:1], format: "2021-11-14 18:11:42"
##  $ na.action: 'omit' int [1:11] 248 390 1111 1167 1254 1334 1403 1413 1414 1509 ...
##   ..- attr(*, "index")= num [1:11] 1.33e+09 1.34e+09 1.44e+09 1.44e+09 1.45e+09 ...
head(TWII)
##               Open    High     Low   Close  Volume Adjusted
## 2011-01-03 9039.63 9041.32 8994.50 9025.30 5067400 9025.267
## 2011-01-04 9045.11 9046.18 8988.58 8997.19 5270400 8997.157
## 2011-01-05 9014.32 9027.16 8812.36 8846.31 5796600 8846.277
## 2011-01-06 8866.23 8883.21 8813.63 8883.21 4362200 8883.177
## 2011-01-07 8905.25 8907.11 8738.93 8782.72 4500800 8782.688
## 2011-01-10 8798.05 8817.88 8762.50 8817.88 2885200 8817.848
# 轉成資料框
TWII.df = data.frame(Date=index(TWII),coredata(TWII))
head(TWII.df)
##         Date    Open    High     Low   Close  Volume Adjusted
## 1 2011-01-03 9039.63 9041.32 8994.50 9025.30 5067400 9025.267
## 2 2011-01-04 9045.11 9046.18 8988.58 8997.19 5270400 8997.157
## 3 2011-01-05 9014.32 9027.16 8812.36 8846.31 5796600 8846.277
## 4 2011-01-06 8866.23 8883.21 8813.63 8883.21 4362200 8883.177
## 5 2011-01-07 8905.25 8907.11 8738.93 8782.72 4500800 8782.688
## 6 2011-01-10 8798.05 8817.88 8762.50 8817.88 2885200 8817.848
# 處理華南金資料

# 去掉遺失值
TW2880 = na.omit(TW2880)
colnames(TW2880) = c("Open", "High", "Low", "Close", "Volume", "Adjusted")
str(TW2880)
## An 'xts' object on 2011-01-03/2020-12-30 containing:
##   Data: num [1:2450, 1:6] 14.2 14.3 13.9 13.4 13.5 ...
##  - attr(*, "dimnames")=List of 2
##   ..$ : NULL
##   ..$ : chr [1:6] "Open" "High" "Low" "Close" ...
##   Indexed by objects of class: [Date] TZ: UTC
##   xts Attributes:  
## List of 3
##  $ src      : chr "yahoo"
##  $ updated  : POSIXct[1:1], format: "2021-11-14 18:11:43"
##  $ na.action: 'omit' int [1:5] 1254 1334 1403 1509 1578
##   ..- attr(*, "index")= num [1:5] 1.45e+09 1.46e+09 1.47e+09 1.49e+09 1.50e+09
head(TW2880)
##                Open     High      Low    Close   Volume  Adjusted
## 2011-01-03 14.19921 14.34381 14.05462 14.25705 30333029 10.394250
## 2011-01-04 14.25705 14.25705 13.91002 13.93894 20770102 10.162331
## 2011-01-05 13.93894 14.02570 13.30273 13.44732 34703862  9.803907
## 2011-01-06 13.36056 13.56300 13.30273 13.47624 16207353  9.824991
## 2011-01-07 13.47624 13.47624 12.98462 13.10029 24862572  9.550904
## 2011-01-10 13.10029 13.21597 13.01354 13.12921 21482437  9.571988
# 轉成資料框
TW2880.df = data.frame(Date=index(TW2880),coredata(TW2880))
head(TW2880.df)
##         Date     Open     High      Low    Close   Volume  Adjusted
## 1 2011-01-03 14.19921 14.34381 14.05462 14.25705 30333029 10.394250
## 2 2011-01-04 14.25705 14.25705 13.91002 13.93894 20770102 10.162331
## 3 2011-01-05 13.93894 14.02570 13.30273 13.44732 34703862  9.803907
## 4 2011-01-06 13.36056 13.56300 13.30273 13.47624 16207353  9.824991
## 5 2011-01-07 13.47624 13.47624 12.98462 13.10029 24862572  9.550904
## 6 2011-01-10 13.10029 13.21597 13.01354 13.12921 21482437  9.571988
# 算出收益率

# Rm
Rm2880 = quantmod::periodReturn(TWII$Close, period="daily",
                                type='arithmetic')
colnames(Rm2880) = "Rm"
head(Rm2880)
##                      Rm
## 2011-01-03  0.000000000
## 2011-01-04 -0.003114509
## 2011-01-05 -0.016769775
## 2011-01-06  0.004171275
## 2011-01-07 -0.011312379
## 2011-01-10  0.004003333
Rm2880 = Rm2880[-1]
# Rq
Rq2880 = quantmod::periodReturn(TW2880$Close, period="daily",
                                type='arithmetic')
colnames(Rq2880) = "Rq"
head(Rq2880)
##                      Rq
## 2011-01-03  0.000000000
## 2011-01-04 -0.022312327
## 2011-01-05 -0.035269745
## 2011-01-06  0.002150540
## 2011-01-07 -0.027897025
## 2011-01-10  0.002207508
Rq2880 = Rq2880[-1]
# 合併資料,只取共同日期
# all=FALSE ==> 只取共同日期
Ret2880<-merge(Rm2880, Rq2880,all=FALSE) 
head(Ret2880)
##                      Rm           Rq
## 2011-01-04 -0.003114509 -0.022312327
## 2011-01-05 -0.016769775 -0.035269745
## 2011-01-06  0.004171275  0.002150540
## 2011-01-07 -0.011312379 -0.027897025
## 2011-01-10  0.004003333  0.002207508
## 2011-01-11  0.012869360  0.011013228

3.2 無風險收益率

利用台銀一年期存款利率。

# 讀取資料
twRf = read.csv("./ch20_twbank10.csv")
str(twRf)
## 'data.frame':    120 obs. of  2 variables:
##  $ ym : int  10001 10002 10003 10004 10005 10006 10007 10008 10009 10010 ...
##  $ ret: num  1.21 1.21 1.21 1.3 1.3 1.3 1.38 1.38 1.38 1.38 ...
head(twRf)
##      ym  ret
## 1 10001 1.21
## 2 10002 1.21
## 3 10003 1.21
## 4 10004 1.30
## 5 10005 1.30
## 6 10006 1.30
# 資料整理 
# 利率
twRf$ret = twRf$ret*0.01
# 日期
year = as.character(as.numeric(substr(as.character(twRf$ym),1,3))+1911)
head(year)
## [1] "2011" "2011" "2011" "2011" "2011" "2011"
month = substr(as.character(twRf$ym),4,5)
head(month)
## [1] "01" "02" "03" "04" "05" "06"
#
twRf$ym2 = paste(year, month,  sep="-")
head(twRf)
##      ym    ret     ym2
## 1 10001 0.0121 2011-01
## 2 10002 0.0121 2011-02
## 3 10003 0.0121 2011-03
## 4 10004 0.0130 2011-04
## 5 10005 0.0130 2011-05
## 6 10006 0.0130 2011-06

3.3 合併資料

將ret與twRf合併

Ret2880$Rf.month = rep(0, dim(Ret2880)[1])
for (year in seq(2011,2020)){
  
  for (mn in c("01", "02", "03", "04", "05", "06", 
               "07", "08", "09", "10", "11", "12")){
    
    ym = paste(year, mn, sep="-")
    #print(ym)
    #print(twRf[twRf$ym2==ym, "ret"])
    Ret2880$Rf.month[ym] = twRf[twRf$ym2==ym, "ret"]
  }
}

#
head(Ret2880)
##                      Rm           Rq Rf.month
## 2011-01-04 -0.003114509 -0.022312327   0.0121
## 2011-01-05 -0.016769775 -0.035269745   0.0121
## 2011-01-06  0.004171275  0.002150540   0.0121
## 2011-01-07 -0.011312379 -0.027897025   0.0121
## 2011-01-10  0.004003333  0.002207508   0.0121
## 2011-01-11  0.012869360  0.011013228   0.0121
tail(Ret2880)
##                       Rm           Rq Rf.month
## 2020-12-23  0.0032184808 -0.002816847   0.0079
## 2020-12-24  0.0040209567  0.002824804   0.0079
## 2020-12-25  0.0035811376  0.008450771   0.0079
## 2020-12-28  0.0105816724  0.002793299   0.0079
## 2020-12-29 -0.0007609235  0.000000000   0.0079
## 2020-12-30  0.0149011642  0.022284088   0.0079

轉換成日資料

Ret2880$Rf.day = (Ret2880$Rf.month+1)^(1/20)-1
head(Ret2880)
##                      Rm           Rq Rf.month       Rf.day
## 2011-01-04 -0.003114509 -0.022312327   0.0121 0.0006015499
## 2011-01-05 -0.016769775 -0.035269745   0.0121 0.0006015499
## 2011-01-06  0.004171275  0.002150540   0.0121 0.0006015499
## 2011-01-07 -0.011312379 -0.027897025   0.0121 0.0006015499
## 2011-01-10  0.004003333  0.002207508   0.0121 0.0006015499
## 2011-01-11  0.012869360  0.011013228   0.0121 0.0006015499

3.4 繪圖

STEP1:把資料整理成資料框較方便繪圖或建模

head(Ret2880)
##                      Rm           Rq Rf.month       Rf.day
## 2011-01-04 -0.003114509 -0.022312327   0.0121 0.0006015499
## 2011-01-05 -0.016769775 -0.035269745   0.0121 0.0006015499
## 2011-01-06  0.004171275  0.002150540   0.0121 0.0006015499
## 2011-01-07 -0.011312379 -0.027897025   0.0121 0.0006015499
## 2011-01-10  0.004003333  0.002207508   0.0121 0.0006015499
## 2011-01-11  0.012869360  0.011013228   0.0121 0.0006015499
#
Ret2880.df = data.frame(Date=index(Ret2880), coredata(Ret2880))
head(Ret2880.df)
##         Date           Rm           Rq Rf.month       Rf.day
## 1 2011-01-04 -0.003114509 -0.022312327   0.0121 0.0006015499
## 2 2011-01-05 -0.016769775 -0.035269745   0.0121 0.0006015499
## 3 2011-01-06  0.004171275  0.002150540   0.0121 0.0006015499
## 4 2011-01-07 -0.011312379 -0.027897025   0.0121 0.0006015499
## 5 2011-01-10  0.004003333  0.002207508   0.0121 0.0006015499
## 6 2011-01-11  0.012869360  0.011013228   0.0121 0.0006015499

STEP2:計算各風險溢酬

Ret2880.df$Rmf = Ret2880.df$Rm - Ret2880.df$Rf.day
Ret2880.df$Rqf = Ret2880.df$Rq - Ret2880.df$Rf.day
head(Ret2880.df)
##         Date           Rm           Rq Rf.month       Rf.day          Rmf
## 1 2011-01-04 -0.003114509 -0.022312327   0.0121 0.0006015499 -0.003716059
## 2 2011-01-05 -0.016769775 -0.035269745   0.0121 0.0006015499 -0.017371325
## 3 2011-01-06  0.004171275  0.002150540   0.0121 0.0006015499  0.003569725
## 4 2011-01-07 -0.011312379 -0.027897025   0.0121 0.0006015499 -0.011913928
## 5 2011-01-10  0.004003333  0.002207508   0.0121 0.0006015499  0.003401784
## 6 2011-01-11  0.012869360  0.011013228   0.0121 0.0006015499  0.012267810
##            Rqf
## 1 -0.022913876
## 2 -0.035871295
## 3  0.001548990
## 4 -0.028498575
## 5  0.001605958
## 6  0.010411678

STEP3:畫出系統性風險溢酬與投資組合的風險溢酬的散佈圖

plot(Ret2880.df$Rmf, Ret2880.df$Rqf,
     xlab="系統性風險溢酬", ylab="投資風險溢酬",
     main="華南金(2880)十年資料")

plotList2880 = list()

par(mai=c(0.1, 0.1, 0.1, 0.1), mfrow=c(5,2))

for (year in as.character(seq(2011,2020))){
  plotData2880 = Ret2880.df[format(Ret2880.df$Date, "%Y")==year, ]
  
  fig = plot(plotData2880$Rmf, plotData2880$Rqf,
             xlab="系統性風險溢酬", ylab="投資風險溢酬",
             xlim=c(-0.065, 0.065), ylim=c(-0.11, 0.071),
             main=year)
  
  #plotList = list(plotList, fig)
}

par(mfrow=c(1,1))
plotList2880 = list()

for (year in as.character(seq(2011,2020))){
  plotData2880 = Ret2880.df[format(Ret2880.df$Date, "%Y")==year, ]
  
  fig2880 = plotly_build(plot_ly(x=~Rmf, y=~Rqf, data=plotData2880,
                             type="scatter",
                             mode="markers",
                             name=year)) 
  
  plotList2880 = c(plotList2880, list(fig2880))
}

#
plotly::subplot(plotList2880,
                nrows=5,
                shareX=TRUE, shareY=TRUE,
                titleX=FALSE, titleY=FALSE)

3.5 建模

3.5.1 單一年度

算出某一年度的β

year="2020"

anaData2880 = dplyr::filter(Ret2880.df, 
                        format(Date, "%Y")==year)

out2880 = lm(Rqf ~ Rmf, data=anaData2880)
summary(out2880)
## 
## Call:
## lm(formula = Rqf ~ Rmf, data = anaData2880)
## 
## Residuals:
##       Min        1Q    Median        3Q       Max 
## -0.027741 -0.004166 -0.000321  0.004416  0.041411 
## 
## Coefficients:
##               Estimate Std. Error t value Pr(>|t|)    
## (Intercept) -0.0012614  0.0004919  -2.564   0.0109 *  
## Rmf          0.8270838  0.0366705  22.555   <2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.007678 on 242 degrees of freedom
## Multiple R-squared:  0.6776, Adjusted R-squared:  0.6763 
## F-statistic: 508.7 on 1 and 242 DF,  p-value: < 2.2e-16

抓出 α,β,及其統計顯著性

# 只能抓到係數
out2880$coef
##  (Intercept)          Rmf 
## -0.001261361  0.827083796
# 可以抓到細數及其顯著性
summary(out2880)$coef
##                 Estimate   Std. Error  t value     Pr(>|t|)
## (Intercept) -0.001261361 0.0004918834 -2.56435 1.094162e-02
## Rmf          0.827083796 0.0366704515 22.55450 2.009436e-61
# 係數
summary(out2880)$coef[,1]
##  (Intercept)          Rmf 
## -0.001261361  0.827083796
# 顯著性
summary(out2880)$coef[,4]
##  (Intercept)          Rmf 
## 1.094162e-02 2.009436e-61

3.5.2 多個年度

# 抓出年代
Ret2880.df$year = format(Ret2880.df$Date, "%Y")

# 自訂函數
lm.self2880 = function(data){
  out2880 = lm(Rqf ~ Rmf, data=data)
  out2880
}

# 利用 by 分割資料。再將每組資料利用lm.self分析
outT2880 = by(Ret2880.df, Ret2880.df$year, FUN=lm.self2880)

抓出 β與α,與統計顯著性

coef2880 = data.frame()
for (i in seq(1, length(outT2880))){
  coef2880 = rbind(coef2880, 
               c(summary(outT2880[[i]])$coef[,1], 
                 summary(outT2880[[i]])$coef[,4]))
}

colnames(coef2880) = c("alpha", "beta", "p(alpha)", "p(beta)")
coef2880
##            alpha      beta   p(alpha)      p(beta)
## 1  -1.944925e-04 1.0761456 0.76430612 8.436893e-63
## 2  -8.589717e-05 0.8128140 0.83907601 4.436596e-49
## 3  -1.355362e-04 0.8405466 0.73473816 5.902554e-38
## 4  -1.843291e-04 0.7519432 0.69053230 7.886516e-24
## 5  -2.065363e-04 0.7383259 0.62466118 5.170465e-45
## 6   7.123648e-05 0.7829830 0.87379850 1.982005e-35
## 7  -2.220420e-04 0.5046872 0.44773342 1.082820e-17
## 8   2.442315e-04 0.4654821 0.43037979 6.691361e-36
## 9   4.558800e-04 0.5735232 0.23198241 2.379821e-20
## 10 -1.261361e-03 0.8270838 0.01094162 2.009436e-61

可以看出 β 幾乎都是非常顯著不為0,且風險低於大盤。α 幾乎都不顯著異於0,但2011~2015年間,卻是幾乎年年下降;不過近幾年有漸漸上升跡象

繪圖呈現

year2880 = unique(Ret2880.df$year)
plot_ly(x=year2880, y=coef2880$beta,
        type="scatter", mode="lines+markers", 
        name="beta") %>%
  add_trace(y=coef2880$alpha, yaxis = "y2", 
            name="alpha") %>%
  layout(xaxis = list(title = list(text = "華南金(2880)")),
         yaxis=list(title = list(text = "beta"),
                    side = "left"),
         yaxis2=list(title = list(text = "alpha"),
                     overlaying = "y",
                     side = "right"))

4 2891 中信金

4.1 下載資料與整理

# 下載資料
# 大盤指數:^TWII
# 中信金:2891.TW
loadSymbols(Symbols=c("^TWII", "2891.TW"),
            from="2011-01-01", to="2020-12-31",
            auto.assign=TRUE) # 這一定要設定
## Warning: ^TWII contains missing values. Some functions will not work if objects
## contain missing values in the middle of the series. Consider using na.omit(),
## na.approx(), na.fill(), etc to remove or replace them.
## Warning: 2891.TW contains missing values. Some functions will not work if
## objects contain missing values in the middle of the series. Consider using
## na.omit(), na.approx(), na.fill(), etc to remove or replace them.
## [1] "^TWII"   "2891.TW"
# 注意:^TWII 下載後存入 TWII 中
# 轉換成正常的變數名稱
#TWII = get("TWII")
TW2891 = get("2891.TW")
# 處理大盤資料
str(TWII)
## An 'xts' object on 2011-01-03/2020-12-30 containing:
##   Data: num [1:2455, 1:6] 9040 9045 9014 8866 8905 ...
##  - attr(*, "dimnames")=List of 2
##   ..$ : NULL
##   ..$ : chr [1:6] "TWII.Open" "TWII.High" "TWII.Low" "TWII.Close" ...
##   Indexed by objects of class: [Date] TZ: UTC
##   xts Attributes:  
## List of 2
##  $ src    : chr "yahoo"
##  $ updated: POSIXct[1:1], format: "2021-11-14 18:11:46"
# 去掉遺失值
TWII = na.omit(TWII)
colnames(TWII) = c("Open", "High", "Low", "Close", "Volume", "Adjusted")
str(TWII)
## An 'xts' object on 2011-01-03/2020-12-30 containing:
##   Data: num [1:2444, 1:6] 9040 9045 9014 8866 8905 ...
##  - attr(*, "dimnames")=List of 2
##   ..$ : NULL
##   ..$ : chr [1:6] "Open" "High" "Low" "Close" ...
##   Indexed by objects of class: [Date] TZ: UTC
##   xts Attributes:  
## List of 3
##  $ src      : chr "yahoo"
##  $ updated  : POSIXct[1:1], format: "2021-11-14 18:11:46"
##  $ na.action: 'omit' int [1:11] 248 390 1111 1167 1254 1334 1403 1413 1414 1509 ...
##   ..- attr(*, "index")= num [1:11] 1.33e+09 1.34e+09 1.44e+09 1.44e+09 1.45e+09 ...
head(TWII)
##               Open    High     Low   Close  Volume Adjusted
## 2011-01-03 9039.63 9041.32 8994.50 9025.30 5067400 9025.267
## 2011-01-04 9045.11 9046.18 8988.58 8997.19 5270400 8997.157
## 2011-01-05 9014.32 9027.16 8812.36 8846.31 5796600 8846.277
## 2011-01-06 8866.23 8883.21 8813.63 8883.21 4362200 8883.177
## 2011-01-07 8905.25 8907.11 8738.93 8782.72 4500800 8782.688
## 2011-01-10 8798.05 8817.88 8762.50 8817.88 2885200 8817.848
# 轉成資料框
TWII.df = data.frame(Date=index(TWII),coredata(TWII))
head(TWII.df)
##         Date    Open    High     Low   Close  Volume Adjusted
## 1 2011-01-03 9039.63 9041.32 8994.50 9025.30 5067400 9025.267
## 2 2011-01-04 9045.11 9046.18 8988.58 8997.19 5270400 8997.157
## 3 2011-01-05 9014.32 9027.16 8812.36 8846.31 5796600 8846.277
## 4 2011-01-06 8866.23 8883.21 8813.63 8883.21 4362200 8883.177
## 5 2011-01-07 8905.25 8907.11 8738.93 8782.72 4500800 8782.688
## 6 2011-01-10 8798.05 8817.88 8762.50 8817.88 2885200 8817.848
# 處理中信金資料

# 去掉遺失值
TW2891 = na.omit(TW2891)
colnames(TW2891) = c("Open", "High", "Low", "Close", "Volume", "Adjusted")
str(TW2891)
## An 'xts' object on 2011-01-03/2020-12-30 containing:
##   Data: num [1:2450, 1:6] 14 14.1 13.7 13.4 13.9 ...
##  - attr(*, "dimnames")=List of 2
##   ..$ : NULL
##   ..$ : chr [1:6] "Open" "High" "Low" "Close" ...
##   Indexed by objects of class: [Date] TZ: UTC
##   xts Attributes:  
## List of 3
##  $ src      : chr "yahoo"
##  $ updated  : POSIXct[1:1], format: "2021-11-14 18:11:47"
##  $ na.action: 'omit' int [1:5] 1254 1334 1403 1509 1578
##   ..- attr(*, "index")= num [1:5] 1.45e+09 1.46e+09 1.47e+09 1.49e+09 1.50e+09
head(TW2891)
##                Open     High      Low    Close    Volume Adjusted
## 2011-01-03 13.96524 14.15920 13.90059 14.12688  85765904 9.268356
## 2011-01-04 14.09455 14.09455 13.67430 13.67430  75769600 8.971431
## 2011-01-05 13.73895 13.90059 13.25405 13.31870 104937215 8.738131
## 2011-01-06 13.35103 13.99757 13.28637 13.93291 122391692 9.141101
## 2011-01-07 13.90059 13.90059 13.44801 13.57732 101877848 8.907803
## 2011-01-10 13.70663 13.77128 13.51266 13.67430  63541412 8.971431
# 轉成資料框
TW2891.df = data.frame(Date=index(TW2891),coredata(TW2891))
head(TW2891.df)
##         Date     Open     High      Low    Close    Volume Adjusted
## 1 2011-01-03 13.96524 14.15920 13.90059 14.12688  85765904 9.268356
## 2 2011-01-04 14.09455 14.09455 13.67430 13.67430  75769600 8.971431
## 3 2011-01-05 13.73895 13.90059 13.25405 13.31870 104937215 8.738131
## 4 2011-01-06 13.35103 13.99757 13.28637 13.93291 122391692 9.141101
## 5 2011-01-07 13.90059 13.90059 13.44801 13.57732 101877848 8.907803
## 6 2011-01-10 13.70663 13.77128 13.51266 13.67430  63541412 8.971431
# 算出收益率

# Rm
Rm2891 = quantmod::periodReturn(TWII$Close, period="daily",
                                type='arithmetic')
colnames(Rm2891) = "Rm"
head(Rm2891)
##                      Rm
## 2011-01-03  0.000000000
## 2011-01-04 -0.003114509
## 2011-01-05 -0.016769775
## 2011-01-06  0.004171275
## 2011-01-07 -0.011312379
## 2011-01-10  0.004003333
Rm2891 = Rm2891[-1]
# Rq
Rq2891 = quantmod::periodReturn(TW2891$Close, period="daily",
                                type='arithmetic')
colnames(Rq2891) = "Rq"
head(Rq2891)
##                      Rq
## 2011-01-03  0.000000000
## 2011-01-04 -0.032036595
## 2011-01-05 -0.026004770
## 2011-01-06  0.046116506
## 2011-01-07 -0.025522012
## 2011-01-10  0.007142869
Rq2891 = Rq2891[-1]
# 合併資料,只取共同日期
# all=FALSE ==> 只取共同日期
Ret2891<-merge(Rm2891, Rq2891,all=FALSE) 
head(Ret2891)
##                      Rm           Rq
## 2011-01-04 -0.003114509 -0.032036595
## 2011-01-05 -0.016769775 -0.026004770
## 2011-01-06  0.004171275  0.046116506
## 2011-01-07 -0.011312379 -0.025522012
## 2011-01-10  0.004003333  0.007142869
## 2011-01-11  0.012869360  0.014184420

4.2 無風險收益率

利用台銀一年期存款利率。

# 讀取資料
twRf = read.csv("./ch20_twbank10.csv")
str(twRf)
## 'data.frame':    120 obs. of  2 variables:
##  $ ym : int  10001 10002 10003 10004 10005 10006 10007 10008 10009 10010 ...
##  $ ret: num  1.21 1.21 1.21 1.3 1.3 1.3 1.38 1.38 1.38 1.38 ...
head(twRf)
##      ym  ret
## 1 10001 1.21
## 2 10002 1.21
## 3 10003 1.21
## 4 10004 1.30
## 5 10005 1.30
## 6 10006 1.30
# 資料整理 
# 利率
twRf$ret = twRf$ret*0.01
# 日期
year = as.character(as.numeric(substr(as.character(twRf$ym),1,3))+1911)
head(year)
## [1] "2011" "2011" "2011" "2011" "2011" "2011"
month = substr(as.character(twRf$ym),4,5)
head(month)
## [1] "01" "02" "03" "04" "05" "06"
#
twRf$ym2 = paste(year, month,  sep="-")
head(twRf)
##      ym    ret     ym2
## 1 10001 0.0121 2011-01
## 2 10002 0.0121 2011-02
## 3 10003 0.0121 2011-03
## 4 10004 0.0130 2011-04
## 5 10005 0.0130 2011-05
## 6 10006 0.0130 2011-06

4.3 合併資料

將ret(2891)與twRf合併

Ret2891$Rf.month = rep(0, dim(Ret2891)[1])
for (year in seq(2011,2020)){
  
  for (mn in c("01", "02", "03", "04", "05", "06", 
               "07", "08", "09", "10", "11", "12")){
    
    ym = paste(year, mn, sep="-")
    #print(ym)
    #print(twRf[twRf$ym2==ym, "ret"])
    Ret2891$Rf.month[ym] = twRf[twRf$ym2==ym, "ret"]
  }
}

#
head(Ret2891)
##                      Rm           Rq Rf.month
## 2011-01-04 -0.003114509 -0.032036595   0.0121
## 2011-01-05 -0.016769775 -0.026004770   0.0121
## 2011-01-06  0.004171275  0.046116506   0.0121
## 2011-01-07 -0.011312379 -0.025522012   0.0121
## 2011-01-10  0.004003333  0.007142869   0.0121
## 2011-01-11  0.012869360  0.014184420   0.0121
tail(Ret2891)
##                       Rm           Rq Rf.month
## 2020-12-23  0.0032184808 -0.005181244   0.0079
## 2020-12-24  0.0040209567  0.002604114   0.0079
## 2020-12-25  0.0035811376  0.002597351   0.0079
## 2020-12-28  0.0105816724 -0.005181244   0.0079
## 2020-12-29 -0.0007609235  0.002604114   0.0079
## 2020-12-30  0.0149011642  0.025974026   0.0079

轉換成日資料

Ret2891$Rf.day = (Ret2891$Rf.month+1)^(1/20)-1
head(Ret2891)
##                      Rm           Rq Rf.month       Rf.day
## 2011-01-04 -0.003114509 -0.032036595   0.0121 0.0006015499
## 2011-01-05 -0.016769775 -0.026004770   0.0121 0.0006015499
## 2011-01-06  0.004171275  0.046116506   0.0121 0.0006015499
## 2011-01-07 -0.011312379 -0.025522012   0.0121 0.0006015499
## 2011-01-10  0.004003333  0.007142869   0.0121 0.0006015499
## 2011-01-11  0.012869360  0.014184420   0.0121 0.0006015499

4.4 繪圖

STEP1:把資料整理成資料框較方便繪圖或建模

head(Ret2891)
##                      Rm           Rq Rf.month       Rf.day
## 2011-01-04 -0.003114509 -0.032036595   0.0121 0.0006015499
## 2011-01-05 -0.016769775 -0.026004770   0.0121 0.0006015499
## 2011-01-06  0.004171275  0.046116506   0.0121 0.0006015499
## 2011-01-07 -0.011312379 -0.025522012   0.0121 0.0006015499
## 2011-01-10  0.004003333  0.007142869   0.0121 0.0006015499
## 2011-01-11  0.012869360  0.014184420   0.0121 0.0006015499
#
Ret2891.df = data.frame(Date=index(Ret2891), coredata(Ret2891))
head(Ret2891.df)
##         Date           Rm           Rq Rf.month       Rf.day
## 1 2011-01-04 -0.003114509 -0.032036595   0.0121 0.0006015499
## 2 2011-01-05 -0.016769775 -0.026004770   0.0121 0.0006015499
## 3 2011-01-06  0.004171275  0.046116506   0.0121 0.0006015499
## 4 2011-01-07 -0.011312379 -0.025522012   0.0121 0.0006015499
## 5 2011-01-10  0.004003333  0.007142869   0.0121 0.0006015499
## 6 2011-01-11  0.012869360  0.014184420   0.0121 0.0006015499

STEP2:計算各風險溢酬

Ret2891.df$Rmf = Ret2891.df$Rm - Ret2891.df$Rf.day
Ret2891.df$Rqf = Ret2891.df$Rq - Ret2891.df$Rf.day
head(Ret2891.df)
##         Date           Rm           Rq Rf.month       Rf.day          Rmf
## 1 2011-01-04 -0.003114509 -0.032036595   0.0121 0.0006015499 -0.003716059
## 2 2011-01-05 -0.016769775 -0.026004770   0.0121 0.0006015499 -0.017371325
## 3 2011-01-06  0.004171275  0.046116506   0.0121 0.0006015499  0.003569725
## 4 2011-01-07 -0.011312379 -0.025522012   0.0121 0.0006015499 -0.011913928
## 5 2011-01-10  0.004003333  0.007142869   0.0121 0.0006015499  0.003401784
## 6 2011-01-11  0.012869360  0.014184420   0.0121 0.0006015499  0.012267810
##            Rqf
## 1 -0.032638145
## 2 -0.026606320
## 3  0.045514956
## 4 -0.026123562
## 5  0.006541319
## 6  0.013582870

STEP3:畫出系統性風險溢酬與投資組合的風險溢酬的散佈圖

plot(Ret2891.df$Rmf, Ret2891.df$Rqf,
     xlab="系統性風險溢酬", ylab="投資風險溢酬",
     main="中信金(2891)十年資料")

plotList2891 = list()

par(mai=c(0.1, 0.1, 0.1, 0.1), mfrow=c(5,2))

for (year in as.character(seq(2011,2020))){
  plotData2891 = Ret2891.df[format(Ret2891.df$Date, "%Y")==year, ]
  
  fig = plot(plotData2891$Rmf, plotData2891$Rqf,
             xlab="系統性風險溢酬", ylab="投資風險溢酬",
             xlim=c(-0.065, 0.065), ylim=c(-0.11, 0.071),
             main=year)
  
  #plotList = list(plotList, fig)
}

par(mfrow=c(1,1))
plotList2891 = list()

for (year in as.character(seq(2011,2020))){
  plotData2891 = Ret2891.df[format(Ret2891.df$Date, "%Y")==year, ]
  
  fig2891 = plotly_build(plot_ly(x=~Rmf, y=~Rqf, data=plotData2891,
                                 type="scatter",
                                 mode="markers",
                                 name=year)) 
  
  plotList2891 = c(plotList2891, list(fig2891))
}

#
plotly::subplot(plotList2891,
                nrows=5,
                shareX=TRUE, shareY=TRUE,
                titleX=FALSE, titleY=FALSE)

4.5 建模

4.5.1 單一年度

算出某一年度的β

year="2020"

anaData2891 = dplyr::filter(Ret2891.df, 
                            format(Date, "%Y")==year)

out2891 = lm(Rqf ~ Rmf, data=anaData2891)
summary(out2891)
## 
## Call:
## lm(formula = Rqf ~ Rmf, data = anaData2891)
## 
## Residuals:
##       Min        1Q    Median        3Q       Max 
## -0.046779 -0.005687  0.000023  0.005381  0.039129 
## 
## Coefficients:
##               Estimate Std. Error t value Pr(>|t|)    
## (Intercept) -0.0012451  0.0006288   -1.98   0.0488 *  
## Rmf          0.8482329  0.0468810   18.09   <2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.009816 on 242 degrees of freedom
## Multiple R-squared:  0.575,  Adjusted R-squared:  0.5732 
## F-statistic: 327.4 on 1 and 242 DF,  p-value: < 2.2e-16

抓出 α,β,及其統計顯著性

# 只能抓到係數
out2891$coef
##  (Intercept)          Rmf 
## -0.001245135  0.848232878
# 可以抓到細數及其顯著性
summary(out2891)$coef
##                 Estimate   Std. Error   t value     Pr(>|t|)
## (Intercept) -0.001245135 0.0006288432 -1.980041 4.883178e-02
## Rmf          0.848232878 0.0468809550 18.093336 7.370221e-47
# 係數
summary(out2891)$coef[,1]
##  (Intercept)          Rmf 
## -0.001245135  0.848232878
# 顯著性
summary(out2891)$coef[,4]
##  (Intercept)          Rmf 
## 4.883178e-02 7.370221e-47

4.5.2 多個年度

# 抓出年代
Ret2891.df$year = format(Ret2891.df$Date, "%Y")

# 自訂函數
lm.self2891 = function(data){
  out2891 = lm(Rqf ~ Rmf, data=data)
  out2891
}

# 利用 by 分割資料。再將每組資料利用lm.self分析
outT2891 = by(Ret2891.df, Ret2891.df$year, FUN=lm.self2891)

抓出 β與α,與統計顯著性

coef2891 = data.frame()
for (i in seq(1, length(outT2891))){
  coef2891 = rbind(coef2891, 
                   c(summary(outT2891[[i]])$coef[,1], 
                     summary(outT2891[[i]])$coef[,4]))
}

colnames(coef2891) = c("alpha", "beta", "p(alpha)", "p(beta)")
coef2891
##            alpha      beta   p(alpha)      p(beta)
## 1   1.371122e-03 1.3133537 0.19315083 3.794233e-44
## 2  -1.389862e-04 1.1361638 0.85197808 5.326331e-36
## 3   5.779263e-04 0.8588918 0.29877051 2.766348e-24
## 4  -1.884023e-05 1.1889129 0.97111027 3.410333e-39
## 5   2.411052e-06 0.9675196 0.99752081 5.248152e-28
## 6   1.134113e-04 1.0285992 0.84810800 3.496546e-35
## 7   7.025935e-05 0.7476083 0.86831269 2.659560e-18
## 8   1.984156e-04 0.8367173 0.74459819 1.466219e-31
## 9  -2.797941e-04 0.5810339 0.54529609 2.586320e-15
## 10 -1.245135e-03 0.8482329 0.04883178 7.370221e-47

可以看出 β 幾乎都是非常顯著不為0,且風險低於大盤。α 幾乎都不顯著異於0,但2011~2015年間,卻是幾乎年年下降;不過近幾年有漸漸上升跡象

繪圖呈現

year2891 = unique(Ret2891.df$year)
plot_ly(x=year2891, y=coef2891$beta,
        type="scatter", mode="lines+markers", 
        name="beta") %>%
  add_trace(y=coef2891$alpha, yaxis = "y2", 
            name="alpha") %>%
  layout(xaxis = list(title = list(text = "中信金(2891)")),
         yaxis=list(title = list(text = "beta"),
                    side = "left"),
         yaxis2=list(title = list(text = "alpha"),
                     overlaying = "y",
                     side = "right"))

5 合併檢視

5.1 繪圖

兩台股系統性風險溢酬與投資風險溢酬之散佈圖

十年資料

par(mfrow=c(1,2))

fig1 <- plot(Ret2880.df$Rmf, Ret2880.df$Rqf,
             xlab="系統性風險溢酬", ylab="投資風險溢酬",
             main="華南金(2880)十年資料")

fig2 <- plot(Ret2891.df$Rmf, Ret2891.df$Rqf,
             xlab="系統性風險溢酬", ylab="投資風險溢酬",
             main="中信金(2891)十年資料")

散佈圖之說明:

  • 第一象限(右上方)代表相對高風險高報酬的金融股
  • 第二象限(左上方)代表相對低風險高報酬的金融股
  • 第三象限(左下方)代表低風險低報酬的金融股
  • 第四象限(右下方)代表高風險低報酬的金融股

由此兩圖可知華南金(2880)較集中在第三象限,屬於低風險低報酬;中信金(2891)集中在第一、二、三象限,且有零星散佈點位於第一象限,屬於相對高風險高報酬的金融股

兩台股各年度之散佈圖

註:上兩行為華南金(2880)各年度散佈圖,下兩行為中信金(2891)各年度散佈圖

plotList2880 = list()

for (year in as.character(seq(2011,2020))){
  plotData2880 = Ret2880.df[format(Ret2880.df$Date, "%Y")==year, ]
  
  fig2880 = plotly_build(plot_ly(x=~Rmf, y=~Rqf, data=plotData2880,
                                 type="scatter",
                                 mode="markers",
                                 name=year)) 
  
  plotList2880 = c(plotList2880, list(fig2880))
}

plotList2891 = list()

for (year in as.character(seq(2011,2020))){
  plotData2891 = Ret2891.df[format(Ret2891.df$Date, "%Y")==year, ]
  
  fig2891 = plotly_build(plot_ly(x=~Rmf, y=~Rqf, data=plotData2891,
                                 type="scatter",
                                 mode="markers",
                                 name=year, showlegend = FALSE)) 
  
  plotList2891 = c(plotList2891, list(fig2891))
}

list = c(plotList2880, plotList2891)

#
plotly::subplot(list,
                nrows=4,
                shareX=TRUE, shareY=TRUE,
                titleX=FALSE, titleY=FALSE)

因各年度皆分布於第一、三象限,較看不出差異,所以不再多探討兩者之間差異

5.2 建模

year2880 = unique(Ret2880.df$year)

fig3 <- plot_ly(x=year2880, y=coef2880$beta,
                yaxis = "y",type="scatter", 
                mode="lines+markers", name="beta") %>%
  add_trace(y=coef2880$alpha, yaxis = "y2",
            name="alpha") %>%
  layout(xaxis = list(title = list(text = "華南金(2880)")),
         yaxis=list(title = list(text = "beta"), side="left", range = c(0.4,1.5)),
         yaxis2=list(overlaying = "y",
                     side = "right", range = c(-0.002,0.002),
                     showticklabels = FALSE))

year2891 = unique(Ret2891.df$year)

fig4 <- plot_ly(x=year2891, y=coef2891$beta,
                yaxis = "y", type="scatter", 
                mode="lines+markers", name="beta") %>%
  add_trace(y=coef2891$alpha, yaxis = "y2",
            name="alpha") %>%
  layout(xaxis = list(title = list(text = "中信金(2891)")),
         yaxis=list(side="left", range = c(0.4,1.5), showticklabels = FALSE),
         yaxis2=list(title = list(text = "alpha"), overlaying = "y3",
                     side = "right", range = c(-0.002,0.002)))

plotly::subplot(fig3, fig4, titleX=TRUE, titleY=TRUE)

第二章節有提到:

α是總風險扣除系統性風險,額外創造的 超額報酬

β是衡量系統性風險及大盤連動性,也就是指數的波動幅度

由兩圖之折線圖可知:

  • 華南金(2880)
    • alpha(α):在2018、2019年的alpha(α)>0,但2020年跌至最低點,可想而知是因為新型冠狀病毒(COVID-19)的影響
    • beta(β):自2012年至今,華南金的beta(β)都比較低,風險相對較低  
  • 中信金(2891)
    • alpha(α):在2018年以前的alpha(α)皆>0,表示中信金在2018年以前有強大的抗跌性,至於為甚麼2019年至今alpha(α)下跌,我想也是因為新型冠狀病毒(COVID-19)所致
    • beta(β):自2016年至今,中信金的beta(β)較低,但相對於華南金(2880)還是中信金的beta(β)比較高

6 結論

論及「官股金控」以及「民營股金控」,看名字就知道,「官股金控」就是官方持有股份的比例比較高,「民營股金控」就是民間經營,所以以風險來說,當然是「官股金控」(也就是舉例中的華南金控)風險比較少,因為國家持有大部分的股份,比較不可能倒!

華南金(2880):

  • 2020年因型冠狀病毒(COVID-19)的影響造成波動,權證避險不及,鉅額虧損47億

但其餘年(2012~2019)都是呈現高alpha(α)低beta(β),相對穩定

中信金(2891):  

以折線圖來研究,可以發現重疊年份比較多,分別是2013、2014、2017及2020年,波動幅度很大

官股金控有中央銀行當靠山,又受到立法院的監督,因此投資人比較放心,所以願意付出更高的股價。 民營的比較「物美價廉」,官股則是「安全穩定」。

以現在大盤在萬點的高點,建議投資人還是選擇「官股金控」為主,萬一股市有意外時也會比較抗跌

以2008~2009年金融海嘯期間為例,上面2家民營金控的股價都跌到個位數,只剩下官股金控的一半,如下表所示:

當股災降臨之際,「安全穩定」是官股金控的最大優勢,「信心不足」則是民營金控的最大致命傷。

追求穩定的人首選公股銀行、想要獲利高的人選民營金控