#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()
#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.
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.