#Event Study

This project deals with analyzing whether there was a suspicious abnormal return for SKhynix, which has one of the biggest market cap in Korean stock market. At 7/27/2022, SKhynix reported earnings release that beat the market expectation. However, there was no significant change in stock price so we will analyze whether there was abnormal return 10days before and after the earnings release. Also, we will analyze whether the market over-reacted under-reacted to the earning release information.

#Import libraries
library(tidyquant)
## 필요한 패키지를 로딩중입니다: lubridate
## 
## 다음의 패키지를 부착합니다: 'lubridate'
## The following objects are masked from 'package:base':
## 
##     date, intersect, setdiff, union
## 필요한 패키지를 로딩중입니다: PerformanceAnalytics
## 필요한 패키지를 로딩중입니다: xts
## 필요한 패키지를 로딩중입니다: zoo
## 
## 다음의 패키지를 부착합니다: 'zoo'
## The following objects are masked from 'package:base':
## 
##     as.Date, as.Date.numeric
## 
## 다음의 패키지를 부착합니다: 'PerformanceAnalytics'
## The following object is masked from 'package:graphics':
## 
##     legend
## 필요한 패키지를 로딩중입니다: quantmod
## 필요한 패키지를 로딩중입니다: TTR
## Registered S3 method overwritten by 'quantmod':
##   method            from
##   as.zoo.data.frame zoo
## == Need to Learn tidyquant? ====================================================
## Business Science offers a 1-hour course - Learning Lab #9: Performance Analysis & Portfolio Optimization with tidyquant!
## </> Learn more at: https://university.business-science.io/p/learning-labs-pro </>
library(DT)
library(tidyverse)
## -- Attaching packages --------------------------------------- tidyverse 1.3.2 --
## v ggplot2 3.3.5     v purrr   0.3.4
## v tibble  3.1.6     v dplyr   1.0.8
## v tidyr   1.2.0     v stringr 1.4.0
## v readr   2.1.2     v forcats 0.5.1
## -- Conflicts ------------------------------------------ tidyverse_conflicts() --
## x lubridate::as.difftime() masks base::as.difftime()
## x lubridate::date()        masks base::date()
## x dplyr::filter()          masks stats::filter()
## x dplyr::first()           masks xts::first()
## x lubridate::intersect()   masks base::intersect()
## x dplyr::lag()             masks stats::lag()
## x dplyr::last()            masks xts::last()
## x lubridate::setdiff()     masks base::setdiff()
## x lubridate::union()       masks base::union()

One-Way factor

#Import KOSPI and SKhynix data
symbols <- c('^KS11','000660.KS')
stocks.prices <- tq_get(symbols,get = 'stock.prices',
                        from = '2021-07-27',
                        to = '2022-08-07') %>%
  group_by(symbol)

#Change column values
stocks.prices$symbol[stocks.prices$symbol == '^KS11'] <- 'KOSPI'
stocks.prices$symbol[stocks.prices$symbol == '000660.KS'] <- 'SKhynix'

head(stocks.prices)
## # A tibble: 6 x 8
## # Groups:   symbol [1]
##   symbol date        open  high   low close volume adjusted
##   <chr>  <date>     <dbl> <dbl> <dbl> <dbl>  <dbl>    <dbl>
## 1 KOSPI  2021-07-27 3244. 3253. 3231. 3233. 991600    3233.
## 2 KOSPI  2021-07-28 3226. 3243. 3211. 3237. 868200    3237.
## 3 KOSPI  2021-07-29 3248. 3252. 3232. 3243. 694500    3243.
## 4 KOSPI  2021-07-30 3234. 3235. 3202. 3202. 687500    3202.
## 5 KOSPI  2021-08-02 3218. 3223. 3194  3223. 560800    3223.
## 6 KOSPI  2021-08-03 3222. 3237. 3213. 3237. 653200    3237.
# Visualize 
stocks.prices %>%
  ggplot(aes(x=date,y=adjusted)) +
  geom_line(size=2,color='steelblue') +
  theme_minimal() +
  facet_wrap(~symbol, scales = 'free_y',nrow=2)+
  labs(x='Date',y='Price')+
  ggtitle('Price Chart for KOSPI and SKhynix')

#Calculate daily return
multpl_stock_daily_ret <- stocks.prices %>%
  group_by(symbol) %>%
  tq_transmute(select = adjusted,
               mutate_fun = periodReturn,
               period = 'daily',
               col_rename = 'returns')

head(multpl_stock_daily_ret)
## # A tibble: 6 x 3
## # Groups:   symbol [1]
##   symbol date        returns
##   <chr>  <date>        <dbl>
## 1 KOSPI  2021-07-27  0      
## 2 KOSPI  2021-07-28  0.00134
## 3 KOSPI  2021-07-29  0.00179
## 4 KOSPI  2021-07-30 -0.0124 
## 5 KOSPI  2021-08-02  0.00647
## 6 KOSPI  2021-08-03  0.00437
#Visualize Daily Return
multpl_stock_daily_ret %>%
  ggplot(aes(x=date,y=returns,color=symbol)) +
  geom_bar(stat='identity',postion='dodge', width = 0.5, size=2) +
  scale_y_continuous(labels = scales::percent) +
  labs(x='Year', y='Daily Returns') +
  theme_minimal() +
  scale_color_brewer(palette = 'Set2') +
  facet_wrap(~symbol,nrow=2) +
  ggtitle('Daily Return of KOSPI & SKhynix')
## Warning: Ignoring unknown parameters: postion

#Spread the data for regression
Data <- multpl_stock_daily_ret %>%
  spread(symbol,value=returns) 

datatable(Data)
#Applying one-factor model
reg <- lm(data=Data, SKhynix~KOSPI)
summary(reg)
## 
## Call:
## lm(formula = SKhynix ~ KOSPI, data = Data)
## 
## Residuals:
##       Min        1Q    Median        3Q       Max 
## -0.054548 -0.009843 -0.000620  0.009764  0.062426 
## 
## Coefficients:
##              Estimate Std. Error t value Pr(>|t|)    
## (Intercept) 0.0008518  0.0010921    0.78    0.436    
## KOSPI       1.2250925  0.1016895   12.05   <2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.01726 on 250 degrees of freedom
## Multiple R-squared:  0.3673, Adjusted R-squared:  0.3648 
## F-statistic: 145.1 on 1 and 250 DF,  p-value: < 2.2e-16

From the regression, it seems that SKhynix is more volatile than the market. Now we will compiute expected return (ER):Beta * market return, abnormal return (AR): Actual Return - ER, and t_stat: AR/Standard error (0.01726). If the t_stat is over 1.96, it suggests that there was an abnormal return and somebody might have utilized insider information and realized excess return.

#Calculate abnormal return from T1 to T2
#Extract data from 2022-07-22 ~ 2022-08-03

Data2 <- Data[237:252,]
datatable(Data2)
Data2$Expected_ret <- 1.2250926*Data2$KOSPI
Data2$Abnormal_ret <- Data2$SKhynix - Data2$Expected_ret
Data2$t_stat <- Data2$Abnormal_ret/0.0126
Data2
## # A tibble: 16 x 6
##    date           KOSPI  SKhynix Expected_ret Abnormal_ret   t_stat
##    <date>         <dbl>    <dbl>        <dbl>        <dbl>    <dbl>
##  1 2022-07-15  0.00373   0.0500      0.00457     0.0454     3.61   
##  2 2022-07-18  0.0190    0.0233      0.0233      0.0000359  0.00285
##  3 2022-07-19 -0.00180  -0.00990    -0.00221    -0.00769   -0.611  
##  4 2022-07-20  0.00670   0.0200      0.00821     0.0118     0.936  
##  5 2022-07-21  0.00935   0.00490     0.0115     -0.00655   -0.520  
##  6 2022-07-22 -0.00665  -0.0244     -0.00815    -0.0162    -1.29   
##  7 2022-07-25  0.00441   0           0.00540    -0.00540   -0.429  
##  8 2022-07-26  0.00386   0.00500     0.00472     0.000275   0.0219 
##  9 2022-07-27  0.00107  -0.00498     0.00130    -0.00628   -0.498  
## 10 2022-07-28  0.00817  -0.00600     0.0100     -0.0160    -1.27   
## 11 2022-07-29  0.00666  -0.0151      0.00816    -0.0233    -1.85   
## 12 2022-08-01  0.000306 -0.00817     0.000375   -0.00855   -0.678  
## 13 2022-08-02 -0.00515  -0.00618    -0.00631     0.000130   0.0103 
## 14 2022-08-03  0.00895   0.0104      0.0110     -0.000599  -0.0476 
## 15 2022-08-04  0.00474   0           0.00580    -0.00580   -0.461  
## 16 2022-08-05  0.00715   0.0103      0.00876     0.00149    0.119

The t statistics that were close to 1.96 or over 1.96 was observed at 7/15 and 7/29. At 7/15, TSMC reported its earnings and showed a result that beat market expectation. Thus, it seems that the market expected that SKhynix would reveal a good financial result and showed an abnormal return. At 7/29, there wasn’t any news about SKhynix so it’s suspicious regarding what affected the stock price to go down even though the market price increased slightly.

Data2$CAR <- cumprod(1+Data2$Abnormal_ret)
Data2
## # A tibble: 16 x 7
##    date           KOSPI  SKhynix Expected_ret Abnormal_ret   t_stat   CAR
##    <date>         <dbl>    <dbl>        <dbl>        <dbl>    <dbl> <dbl>
##  1 2022-07-15  0.00373   0.0500      0.00457     0.0454     3.61    1.05 
##  2 2022-07-18  0.0190    0.0233      0.0233      0.0000359  0.00285 1.05 
##  3 2022-07-19 -0.00180  -0.00990    -0.00221    -0.00769   -0.611   1.04 
##  4 2022-07-20  0.00670   0.0200      0.00821     0.0118     0.936   1.05 
##  5 2022-07-21  0.00935   0.00490     0.0115     -0.00655   -0.520   1.04 
##  6 2022-07-22 -0.00665  -0.0244     -0.00815    -0.0162    -1.29    1.03 
##  7 2022-07-25  0.00441   0           0.00540    -0.00540   -0.429   1.02 
##  8 2022-07-26  0.00386   0.00500     0.00472     0.000275   0.0219  1.02 
##  9 2022-07-27  0.00107  -0.00498     0.00130    -0.00628   -0.498   1.01 
## 10 2022-07-28  0.00817  -0.00600     0.0100     -0.0160    -1.27    0.998
## 11 2022-07-29  0.00666  -0.0151      0.00816    -0.0233    -1.85    0.975
## 12 2022-08-01  0.000306 -0.00817     0.000375   -0.00855   -0.678   0.966
## 13 2022-08-02 -0.00515  -0.00618    -0.00631     0.000130   0.0103  0.967
## 14 2022-08-03  0.00895   0.0104      0.0110     -0.000599  -0.0476  0.966
## 15 2022-08-04  0.00474   0           0.00580    -0.00580   -0.461   0.960
## 16 2022-08-05  0.00715   0.0103      0.00876     0.00149    0.119   0.962
#Visualize cumulative abnormal return
Data2 %>%
  ggplot(aes(x=date,y=CAR)) +
  geom_point(size=5,color='steelblue') +
  geom_point(aes(y=1.0141802,x=as.Date('2022-07-27')),size=5,color='red') +
  annotate('text',x=as.Date('2022-07-30'),y=1.0141802,label='Earnings Release',size=4)+
  theme_minimal() +
  labs(x='Date',y='CAR')+
  ggtitle('Cumulative Abnormal Return')

It seems that the market overreacted prior to the earnings release and was corrected to its market value.

Two-Way factor

symbols1 <- c('^KS11','000660.KS','^SOX')
stocks.prices1 <- tq_get(symbols1,get = 'stock.prices',
                        from = '2021-07-27',
                        to = '2022-08-07') %>%
  group_by(symbol)

#Change column values
stocks.prices1$symbol[stocks.prices1$symbol == '^KS11'] <- 'KOSPI'
stocks.prices1$symbol[stocks.prices1$symbol == '000660.KS'] <- 'SKhynix'
stocks.prices1$symbol[stocks.prices1$symbol == '^SOX'] <- 'Industry'

stocks.prices1
## # A tibble: 764 x 8
## # Groups:   symbol [3]
##    symbol date        open  high   low close volume adjusted
##    <chr>  <date>     <dbl> <dbl> <dbl> <dbl>  <dbl>    <dbl>
##  1 KOSPI  2021-07-27 3244. 3253. 3231. 3233. 991600    3233.
##  2 KOSPI  2021-07-28 3226. 3243. 3211. 3237. 868200    3237.
##  3 KOSPI  2021-07-29 3248. 3252. 3232. 3243. 694500    3243.
##  4 KOSPI  2021-07-30 3234. 3235. 3202. 3202. 687500    3202.
##  5 KOSPI  2021-08-02 3218. 3223. 3194  3223. 560800    3223.
##  6 KOSPI  2021-08-03 3222. 3237. 3213. 3237. 653200    3237.
##  7 KOSPI  2021-08-04 3247. 3283. 3238. 3280. 632000    3280.
##  8 KOSPI  2021-08-05 3283. 3296. 3273. 3276. 680000    3276.
##  9 KOSPI  2021-08-06 3277. 3288. 3262. 3270. 939900    3270.
## 10 KOSPI  2021-08-09 3258. 3275. 3252. 3260. 706500    3260.
## # ... with 754 more rows
# Visualize 
stocks.prices1 %>%
  ggplot(aes(x=date,y=adjusted)) +
  geom_line(size=2,color='steelblue') +
  theme_minimal() +
  facet_wrap(~symbol, scales = 'free_y',nrow=3)+
  labs(x='Date',y='Price')+
  ggtitle('Price Chart for KOSPI, SKhynix, and Indsutry')

multpl_stock_daily_ret1 <- stocks.prices1 %>%
  group_by(symbol) %>%
  tq_transmute(select = adjusted,
               mutate_fun = periodReturn,
               period = 'daily',
               col_rename = 'returns')

head(multpl_stock_daily_ret1)
## # A tibble: 6 x 3
## # Groups:   symbol [1]
##   symbol date        returns
##   <chr>  <date>        <dbl>
## 1 KOSPI  2021-07-27  0      
## 2 KOSPI  2021-07-28  0.00134
## 3 KOSPI  2021-07-29  0.00179
## 4 KOSPI  2021-07-30 -0.0124 
## 5 KOSPI  2021-08-02  0.00647
## 6 KOSPI  2021-08-03  0.00437
#Visualize Daily Return
multpl_stock_daily_ret1 %>%
  ggplot(aes(x=date,y=returns,color=symbol)) +
  geom_bar(stat='identity',postion='dodge', width = 0.5, size=2) +
  scale_y_continuous(labels = scales::percent) +
  labs(x='Year', y='Daily Returns') +
  theme_minimal() +
  scale_color_brewer(palette = 'Set2') +
  facet_wrap(~symbol,nrow=3) +
  ggtitle('Daily Return of KOSPI, SKhynix, and Industry')
## Warning: Ignoring unknown parameters: postion

library(corrplot)
## corrplot 0.92 loaded
library(timetk)

#Verifying Correlation for collinearity issue
multpl_stock_daily_ret1 %>%
  spread(symbol, value=returns) %>%
  drop_na() %>%
  tk_xts() %>%
  cor()
## Warning: Non-numeric columns being dropped: date
## Using column `date` for date_var.
##           Industry     KOSPI   SKhynix
## Industry 1.0000000 0.2082465 0.1450433
## KOSPI    0.2082465 1.0000000 0.6045920
## SKhynix  0.1450433 0.6045920 1.0000000
#Visualize Correlation
multpl_stock_daily_ret1 %>%
  spread(symbol, value=returns) %>%
  drop_na() %>%
  tk_xts() %>%
  cor() %>%
  corrplot(method = 'shade')
## Warning: Non-numeric columns being dropped: date
## Using column `date` for date_var.

Data3 <- multpl_stock_daily_ret1 %>%
  spread(symbol,value = returns) %>%
  drop_na()

datatable(Data3)
reg2 <- lm(data = Data3, SKhynix~Industry+KOSPI)
summary(reg2)
## 
## Call:
## lm(formula = SKhynix ~ Industry + KOSPI, data = Data3)
## 
## Residuals:
##       Min        1Q    Median        3Q       Max 
## -0.054591 -0.009987 -0.000504  0.009673  0.062003 
## 
## Coefficients:
##              Estimate Std. Error t value Pr(>|t|)    
## (Intercept) 0.0009113  0.0011281   0.808    0.420    
## Industry    0.0189668  0.0498212   0.381    0.704    
## KOSPI       1.2210441  0.1068729  11.425   <2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.01752 on 240 degrees of freedom
## Multiple R-squared:  0.3659, Adjusted R-squared:  0.3606 
## F-statistic: 69.25 on 2 and 240 DF,  p-value: < 2.2e-16

Although the p-value for the F-statistic was significant, the p-value for the industry was not significant. Thus, we can conclude that the one-way factor model and the two-factor model will show a similar conclusion and there is no need for further analysis.