2019年4月16日,纏訟2年的高通(Qualcomm)及蘋果(Apple)終於達成了大和解。高通原本為蘋果iPhone晶片的主要供應商,由於權利金的訴訟而導致雙方都大受影響。有趣的是,許多媒體都宣稱這個和解對兩造都有非常正面的影響,那兩家公司的投資人是否買單呢?本文將會介紹財務上如何衡量事件在股價方面的影響,用R來計算高通及蘋果的累積異常報酬(Cumulative Abnormal Return, CAR)。

何謂異常報酬?

異常報酬,顧名思義就是實際報酬與預期報酬的差額。傳統財務理論認為,股價反應的是標的資產(underlying asset)的基本價值(fundamental value),假如A公司的股價理論上要從今天的100元漲至明天的110元,此時我們預期有10%的報酬率,但是明天股價卻收在115元,實際報酬率則是15%。總的來說,我們實際上的報酬率比預期還要多5%(15% - 10%),這個預期外的報酬就是異常報酬。

實際要怎麼做?

概念大致懂了,那麼可以開始想辦法估算理論的報酬了,最簡單、也是學術界最常用的方式就是運用市場模型(Market Model)。市場模型是一個簡單迴歸模型,將個股報酬作為應變數(Y),市場報酬作為自變數(X),估算出來的迴歸係數習慣上稱之為貝塔值(Beta, \(\beta\)),模型的設定如下, \[R_i = \alpha + \beta R_m + e\] \(R_i\)為第\(i\)個股票的報酬率。\(R_m\)為市場報酬率。\(alpha\)\(e\)依序為截距項及殘差。只要先運用歷史的資料,透過市場模型,就能夠估算出Beta(\(\hat{\beta}\)),接著再以估計的Beta計算預期報酬,這樣就能將實際發生的報酬率減去預期報酬,並取得異常報酬。在估計前,我們先取得股價資料,

library(tidyquant)
# Qualcomm
qcom <- tq_get("QCOM")
head(qcom)
## # A tibble: 6 x 7
##   date        open  high   low close   volume adjusted
##   <date>     <dbl> <dbl> <dbl> <dbl>    <dbl>    <dbl>
## 1 2009-01-02  35.7  37.1  35.3  37.0 14756600     28.5
## 2 2009-01-05  36.6  36.9  36.0  36.5 16601600     28.1
## 3 2009-01-06  36.9  37.7  36.3  37.2 16507800     28.6
## 4 2009-01-07  36.5  36.7  35.1  35.5 16718900     27.4
## 5 2009-01-08  35.4  35.6  34.5  35.3 16352300     27.2
## 6 2009-01-09  35.5  35.9  33.5  35   15970000     26.9
# Apple
aapl <- tq_get("AAPL")
head(aapl)
## # A tibble: 6 x 7
##   date        open  high   low close    volume adjusted
##   <date>     <dbl> <dbl> <dbl> <dbl>     <dbl>    <dbl>
## 1 2009-01-02  12.3  13.0  12.2  13.0 186503800     8.61
## 2 2009-01-05  13.3  13.7  13.2  13.5 295402100     8.97
## 3 2009-01-06  13.7  13.9  13.2  13.3 322327600     8.83
## 4 2009-01-07  13.1  13.2  12.9  13.0 188262200     8.64
## 5 2009-01-08  12.9  13.3  12.9  13.2 168375200     8.80
## 6 2009-01-09  13.3  13.3  12.9  12.9 136711400     8.60

tidyquant套件的股價來源為Yahoo Finance,所以股價的代碼必須先到Yahoo Finance的網站查詢,以我們的例子來看,高通的代碼為QCOM;蘋果的代碼為AAPL。若是沒有設定資料期間,預設應該是直接下載10年的歷史資料,變數方面包括日期(date)、開盤價(open)、最高價(high)、最低價(low)、收盤價(close)、成交量(volume)、及調整價(adjusted)。通常會以調整價作為基準而非收盤價,因為收盤價可能會受到除權息的影響而不適合拿來研究。

時間的取捨

在這次的事件研究中,我只想看事件前後約1個月左右的異常報酬變化。這個事件前後的時間間隔稱為事件窗口(window),窗口的設定可以自行設定,例如,前後10天我們可以表示成:[-10,10]。另外,事件的發生日在高通與蘋果的事件中就是2019-04-16。在R中處理資料時要注意,窗口必須以交易日為基準,不能直接用R的lubridate套件來直接進行日期變數的加減。

事件窗口的設定端看研究者自己決定,但基本上不會將時間拉到一年以上(雖然還是有研究特別去看一年、甚至是三年的影響,但相對少見)。而估計期間卻是比較固定的,上面也有提到,我們必須以歷史資料來跑市場模型,才會先取得估計後的Beta值,接著計算預期報酬,那歷史資料的區間要怎麼抓呢?這個估計期間一般採用[-180,-30],也就是過去180天至過去30天的交易資料。

為什麼不用[-180,0]呢?我想這可能是由於,太靠近事件日的股價有可能已經反應了部分事件資訊,已經失去“平常”的走勢,畢竟預期報酬的意義就是要估計“如果事件沒發生的話”的報酬,因此不能使用太靠近事件日的歷史資料來進行估計。

R示範

接下來就直接以程式來示範怎麼進行上述的過程吧。

事件日的設定

在設定事件日前,建議先將個股股價跟大盤的資料先合併好數,確保資料沒有遺漏值,再開始計算新變數。接下來計算模型需要兩個的變數(\(R_i\), \(R_m\)),並做一些資料處理,我以ROC計算報酬率,ROCTTR套件中用來計算報酬率的函數,分為連續(continuous)及間斷(discrete)兩種方式,預設為連續,這個函數在財務中很常見也很好用。

下一步透過mutate函數增加新變數eventday,我的計算方法是將每個日期的列(row)值減去事件當日的列(row)值,前提是資料比須先以日期由前到後作排列。以qcom這個資料集為例,事件當日2019-04-16對應到第253列,這時候which(date == eventdate)就會等於253,前一天2019-04-15的資料在第252列,減去事件日的列值253,就會得到-1,以此類推,這樣就可以簡單得到事件日的編號(eventday)。

# eventdate
eventdate <- ymd("2019-04-16")
# Qualcomm
qcom <- tq_get("QCOM", from = "2018-04-16", to = Sys.Date())
# 以S&P 500為大盤指數
market <- tq_get("^GSPC", from = "2018-04-16", to = Sys.Date())
# 稍微整理一下資料,將adjusted作為指數的基準,並且改名成index
market <- market %>% 
        select(date, index = adjusted)
# merge data
df <- qcom %>% 
        select(date, price = adjusted) %>% 
        merge(market, by = "date", all.x = T) %>% 
        mutate(Ri = ROC(price), Rm = ROC(index)) %>% 
        na.omit()
# window
df <- df %>% 
        mutate(eventday = 1:length(date) - which(date == eventdate))
head(df, 10L)
##          date    price   index           Ri            Rm eventday
## 1  2018-04-17 53.08315 2706.39  0.010533942  1.060507e-02     -251
## 2  2018-04-18 52.96807 2708.64 -0.002170311  8.310204e-04     -250
## 3  2018-04-19 50.41701 2693.13 -0.049360739 -5.742582e-03     -249
## 4  2018-04-20 49.33329 2670.14 -0.021729452 -8.573177e-03     -248
## 5  2018-04-23 48.46056 2670.29 -0.017848918  5.622993e-05     -247
## 6  2018-04-24 47.89472 2634.56 -0.011744878 -1.347089e-02     -246
## 7  2018-04-25 47.71250 2639.40 -0.003811934  1.835374e-03     -245
## 8  2018-04-26 48.40302 2666.94  0.014368729  1.038014e-02     -244
## 9  2018-04-27 49.01680 2669.91  0.012600991  1.113005e-03     -243
## 10 2018-04-30 48.92090 2648.05 -0.001958348 -8.221192e-03     -242

模型估計

從上面print out的資料內容,我們目前有日期(date)、個股股價(adjusted)、大盤指數(index)、個股報酬率(Ri)、大盤報酬率(Rm)、與事件日的差距(eventday),處理完資料後,以[-180,-30]的副資料集來估計市場模型,

# 以事件日[-180, -30]之區間來估計beta
estimate <- df %>% 
        subset(eventday >= -180 & eventday <= -30)
# Regression
fit <- lm(Ri ~ Rm, data = estimate)
fit$coefficients
##   (Intercept)            Rm 
## -0.0008540568  0.9185173030
# 回傳Beta
beta <- fit$coefficients[2]

在迴歸模型跑完之後,將結果存入fit物件中,其中coefficients就是估計出來的迴歸係數,要注意,第一個是截距項的係數,第二個值才是第一個自變數的係數,也就是我們的Beta,接下來要把Beta拿去乘以事件窗口下的市場報酬(\(R_m\))才會得到我們在事件窗口下的預期報酬,時間上跟估計區間是不同的,要避免混淆。接下來以事件窗口[-10,+10]為例,並且計算異常報酬,

# 要以資料集df來做,不要用到estimate
car_qcom <- df %>% 
    subset(eventday >= -10 & eventday <= 10) %>% 
    mutate(expected = Rm * beta,
           abnormal = Ri - expected)
select(car, date, eventday, expected, abnormal)
## Error in select(car, date, eventday, expected, abnormal): object 'car' not found
# 接著計算累積的異常報酬(Cumulative abnormal return)
car_qcom <- car_qcom %>% 
        mutate(CAR = cumsum(abnormal)*100)
select(car_qcom, date, eventday, CAR)
##          date eventday        CAR
## 1  2019-04-02      -10  0.4815710
## 2  2019-04-03       -9 -0.4238533
## 3  2019-04-04       -8 -0.3035490
## 4  2019-04-05       -7 -0.5039992
## 5  2019-04-08       -6 -0.9975755
## 6  2019-04-09       -5 -0.9941233
## 7  2019-04-10       -4 -3.2643795
## 8  2019-04-11       -3 -4.0341683
## 9  2019-04-12       -2 -2.7783197
## 10 2019-04-15       -1 -2.3174449
## 11 2019-04-16        0 18.5056825
## 12 2019-04-17        1 30.2704566
## 13 2019-04-18        2 31.1445939
## 14 2019-04-22        3 33.6219516
## 15 2019-04-23        4 38.4465615
## 16 2019-04-24        5 38.7748655
## 17 2019-04-25        6 36.7609866
## 18 2019-04-26        7 38.1603538
## 19 2019-04-29        8 38.7635824
## 20 2019-04-30        9 37.3842533
## 21 2019-05-01       10 38.3542058

視覺化

接下來我們直接以highcharter套件來做視覺化的呈現,

library(highcharter)
hchart(car_qcom, type = "area", hcaes(x = eventday, y = CAR)) %>% 
    hc_title(text = "Qualcomm") %>% 
    hc_subtitle(text = "source: finance.yahoo.com") %>% 
    hc_xAxis(title = list(text = "Event Day"),
             plotLines = list(
      list(label = NULL,
           color = "#8F223A",
           width = 2,
           value = 0))) %>% 
    hc_yAxis(title = list(text = "CAR"),
             labels = list(format = '{value:.0f}%'),
             plotLines = list(
               list(label = NULL,
                    color = "#8F223A",
                    width = 2,
                    value = 0))) %>% 
    hc_tooltip(pointFormat="CAR: {point.y:.1f}%") %>% 
    hc_add_theme(hc_theme_ft())

其實從圖就可以看出大和解對高通有非常明顯的正面影響,事件日當天就有19.6%的累積異常報酬,之後甚至最高到38.8%,經濟意涵上這個幅度是非常大的。如果仔細去看那幾天高通的股價的話,事件發生前10天(4/10)高通的股價在58.09,發生當天就到了70.45,10天後(5/1)到了86.37,由於美國沒有漲跌幅限制,價格反應地非常劇烈,這個現象非常有趣,我們也透過統計的方法證實這個事件對於高通在股票市場上是有顯著影響的。

在做這類實證研究時,我習慣將上述這些過程編寫成自定義的函數,只要改變一下參數,我們就能將同樣的過程套用在其他股票、事件上,以下做個範例。

進階使用

以下先寫一個累積異常報酬的函數,有幾個地方需要注意的是:

  • eventdate轉換成Date格式
  • 取得股價、大盤的變數,直接改變並篩選變數
CAR <- function(symbol, market, eventdate, window_start, window_end) {
  eventdate <- ymd(eventdate)
  stock <- tq_get(symbol) %>% 
    select(date, price = adjusted)
  mkt <- tq_get(market) %>% 
    select(date, index = adjusted)
  df <- stock %>% 
    merge(mkt, by = "date", all.x = T) %>% 
    mutate(eventday = 1:length(date) - which(ymd(date) == eventdate),
           Ri = ROC(price),
           Rm = ROC(index, type = "continuous")) %>% 
    na.omit()
  # 以事件日[-180, -30]之區間來估計beta
  estimate <- df %>% 
    subset(eventday >= -180 & eventday <= -30)
  fit <- lm(Ri ~ Rm, data = estimate)
  beta <- fit$coefficients[2]
  # 開始計算Cumulative Abnormal Return
  car <- df %>% 
    subset(eventday >= window_start & eventday <= window_end) %>% 
    mutate(expected = Rm * beta,
           excess = Ri - expected,
           CAR = cumsum(excess)*100)
  return(car)
}
# Apple
car_aapl <- CAR("AAPL", market = "^GSPC", window_start = -10, window_end = +10, eventdate = "2019-04-16")

畫圖也可以寫成函數:

hc_CAR <- function(data, title) {
  hchart(data, type = "area", hcaes(x = eventday, y = CAR), marginTop = 100) %>% 
    hc_title(text = title) %>% 
    hc_subtitle(text = "source: finance.yahoo.com") %>% 
    hc_xAxis(title = list(text = "Event Day"),
             plotLines = list(
      list(label = NULL,
           color = "#8F223A",
           width = 2,
           value = 0))) %>% 
    hc_yAxis(title = list(text = "CAR"),
             labels = list(format = '{value:.0f}%'),
             plotLines = list(
               list(label = NULL,
                    color = "#8F223A",
                    width = 2,
                    value = 0))) %>% 
    hc_tooltip(pointFormat="CAR: {point.y:.1f}%") %>% 
    hc_add_theme(hc_theme_ft())
}
hc_CAR(car_aapl, "Apple")

顯著性測試

如果要更嚴謹地檢測CAR到底存不存在,就要檢測有沒有顯著異於0,這邊示範最基礎的均數檢定。從結果來看,p-value只要小於0.01就代表,在信心水準1%下,高通之平均CAR顯著大於0,蘋果則沒有顯著的CAR,由於事件窗口比較短,樣本數比較少,所以一般來說簡單t檢定的結果在小樣本下其實是比較存疑的,但高通的變動這麼明顯,就算用更加嚴謹的檢定,應該是不影響結論的。

t.test(car_qcom$CAR)
## 
##  One Sample t-test
## 
## data:  car_qcom$CAR
## t = 4.1937, df = 20, p-value = 0.0004473
## alternative hypothesis: true mean is not equal to 0
## 95 percent confidence interval:
##   8.73678 26.03004
## sample estimates:
## mean of x 
##  17.38341
t.test(car_aapl$CAR)
## 
##  One Sample t-test
## 
## data:  car_aapl$CAR
## t = 9.5834, df = 20, p-value = 6.439e-09
## alternative hypothesis: true mean is not equal to 0
## 95 percent confidence interval:
##  2.399938 3.735371
## sample estimates:
## mean of x 
##  3.067654

結語

DellaVigna and Pollet (2009) 就用CAR來檢視盈餘宣告在星期五與否有什麼影響。當盈餘宣告超乎分析師預期時,而這些正或是負的非預期部分稱為earnings surprise,當公司有正的surprise時,通常在surprise發生後會有正的異常報酬,有趣的是,他們發現當這些公司選在星期五宣告盈餘的話,股市對於surprise的反應會比較慢,也就是CAR比較小而且延緩到比較長的時間,他們解釋因為人們在星期五的關注程度會降低,這種有限關注度(limited attention)的解釋觀點很直覺也很有趣。我想在實務上,如果作為公司的CEO,知道自己即將宣告出乎意料的負面消息,可以選在星期五在宣告,這樣股價可能不會崩跌地太嚴重。

事件後的股價反應在學術上常用盈餘慣性(Post-earnings-announcement drift, PEAD)來檢定,其實就是運用CAR來計算,雖然這方法最早在1968年就被Ball and Brown (1968)提出,但一直到現在不論是寫碩士論文還是學術期刊都廣泛被運用。未來希望還有機會介紹更多不同的事件研究法,或是介紹他們的應用。


參考資料

Ball, R., & Brown, P. (1968). An Empirical Evaluation of Accounting Income Numbers. Journal of Accounting Research, 6(2), 159-178. doi:10.2307/2490232

DellaVigna, S., & Pollet, J. (2009). Investor Inattention and Friday Earnings Announcements. The Journal of Finance, 64(2), 709-749. Retrieved from http://www.jstor.org/stable/20487983