Post List

2019년 2월 15일 금요일

Fama French 팩터 데이터를 이용한 수익률 팩터분석 (Handa Partners 데이터)


파마-프렌치의 3팩터 모형은 
포트폴리오 투자의 발전에 지대한 영향을 끼쳤습니다.

또한, 본인의 포트폴리오 성과가 어떠한 팩터의 영향을 받는지
분석을 통해 확인해보는 것은 너무나 중요한 과정입니다.

그러나 미국, 혹은 글로벌 팩터 인덱스의 경우
French Library를 통해 손쉽게 구할 수 있지만,

한국의 경우 그 데이터를 제공하는 곳도 없고,
직접 손으로 가공해야 하는 문제가 있었습니다.


이러하나 문제를 해결하기 위해 Handa Partners 에서
파마-프렌치의 3팩터, 5팩터, 모멘텀 팩터 수익률을
가공 및 무료 제공하게 되었습니다.



제공데이터는 french library와 동일하게
m by n 형식의 데이터 및
Long Short 기반의 팩터 수익률이며,
(일간 / 월간 / 년간)

팩터지수 생성방법 역시 기존 french library와 동일합니다.




해당 데이터를 이용해 간단한 예제로
(삼성전자)수익률의 팩터분석을 해보도록 하겠습니다.

먼저 3팩터 수익률과 모멘텀팩터 수익률의
공유 링크는 다음과 같습니다.

https://drive.google.com/file/d/10VLyoL0YO7Q_jPW_TjXf4LC2ZLt5FQtU/view?usp=sharing
https://drive.google.com/file/d/1ICsw0Ar-egopA8PvjvlXAtD8W063mklO/view?usp=sharing


물론 해당 링크로 접속하여 csv 파일을 직접 다운로드 받을수도 있지만
R내에서 구글드라이브에 직접 접속하여
파일을 다운로드 받도록 하겠습니다.


# change time zone to 'UTC'
Sys.setenv(TZ = 'utc')

# import package
library(googledrive)
library(tidyverse)
library(tibble)
library(quantmod)
library(xts)
library(PerformanceAnalytics)
library(HenryQuant)

먼저 Sys.setenv() 함수를 이용해 타임존을 UTC로 고정해줍니다.
(타임존이 달라 merge가 오류나는 문제를 사전방지하기 위해서 입니다.)

그 후, 필요한 패키지들을 불러오도록 합니다.
설치되지 않은 패키지를 먼저 설치하셔야 합니다.

먼저 googledrive에서 직접 파일을 가져오기 위해서는
파일의 id를 알아야 합니다.

https://drive.google.com/file/d/10VLyoL0YO7Q_jPW_TjXf4LC2ZLt5FQtU/view?usp=sharing

공유 링크에서 d와 view에 위치하는 부분이
해당 파일의 id 부분입니다.


temp = tempfile(fileext = ".csv")
drive_download(
  as_id('10VLyoL0YO7Q_jPW_TjXf4LC2ZLt5FQtU'),
  path = temp, overwrite = TRUE)
data = read.csv(temp)

먼저 tempfile() 함수를 이용해 임시 저장명을 설정한 후,
googledrive 패키지 내의 drive_download() 함수를 이용하여
구글드라이브 내 파일을 다운로드 합니다.
as_id() 함수 내에 위에서 구한 id값을 입력해주면 됩니다.

(처음 연결시 api 접속 권한 여부를 묻습니다)

그 후, read.csv() 함수를 통해 임시로 저장된 csv 파일을 불러오면 됩니다.


그러나 우리는 불러올 파일이 2개 (3팩터, 모멘텀)이므로,
lapply() 함수를 통해 한번에 다운로드 및 불러오기를 하도록 하겠습니다.


factor_id = c('10VLyoL0YO7Q_jPW_TjXf4LC2ZLt5FQtU', # three factor
              '1ICsw0Ar-egopA8PvjvlXAtD8W063mklO') # momentum
data = lapply(factor_id, function(x) {
  temp = tempfile(fileext = ".csv")
  drive_download(
    as_id(x), path = temp, overwrite = TRUE)
  read.csv(temp, stringsAsFactors = FALSE)})


factor_id 변수에 각 id 값을 저장한 후,
lapply()를 통해 불러온 값을 data 변수에 저장합니다.
해당 값은 리스트 형태로 저장되게 됩니다.


head(data[[1]])
           X       Mkt.Rf          SMB           HML           Rf
1 1988-04-01 -0.003663825  0.006331417 -0.0063024610 0.0003638249
2 1988-04-02  0.001550689  0.004574786  0.0064338837 0.0003493105
3 1988-04-04  0.004450689  0.008480783 -0.0030068985 0.0003493105
4 1988-04-06 -0.003971062  0.009926942  0.0023735369 0.0003710623
5 1988-04-07 -0.004338390 -0.001103435 -0.0005957512 0.0003383900
6 1988-04-08 -0.008810635  0.002028100 -0.0016204276 0.0004106347

 head(data[[2]])
           X          Mom
1 1988-04-01 -0.019880074
2 1988-04-02  0.001489464
3 1988-04-04 -0.022180690
4 1988-04-06 -0.009574020
5 1988-04-07 -0.000376635
6 1988-04-08 -0.015355354

1998년부터 현재까지의 팩터데이터가 다운로드 받아졌습니다.


# tidy data
data = inner_join(data[[1]], data[[2]], by = 'X')

head(data)
           X       Mkt.Rf          SMB           HML           Rf          Mom
1 1988-04-01 -0.003663825  0.006331417 -0.0063024610 0.0003638249 -0.019880074
2 1988-04-02  0.001550689  0.004574786  0.0064338837 0.0003493105  0.001489464
3 1988-04-04  0.004450689  0.008480783 -0.0030068985 0.0003493105 -0.022180690
4 1988-04-06 -0.003971062  0.009926942  0.0023735369 0.0003710623 -0.009574020
5 1988-04-07 -0.004338390 -0.001103435 -0.0005957512 0.0003383900 -0.000376635
6 1988-04-08 -0.008810635  0.002028100 -0.0016204276 0.0004106347 -0.015355354

dplyr 패키지의 inner_join() 함수를 이용해
두 데이터를 하나로 합치도록 하겠습니다.

일자에 해당하는 컬럼의 열이름이 'X'로 저장되어 있으므로,
by 파라미터를 'X'로 설정해 줍니다.


factor_data = data %>%
  rename(Date = X, MKT = Mkt.Rf, MOM = Mom) %>%
  select(Date, MKT, SMB, HML, MOM, Rf) %>%
  column_to_rownames(var = 'Date') %>%
  as.xts()

이번에는 데이터 필터링 작업을 해주도록 합니다.
먼저 열이름중 XMkt.Rf, Mom 값을
rename() 함수를 사용하여 바꿔주도록 합니다.

그 후 select() 함수를 이용해 해당하는 열을 선택 후,
tibble 패키지의 column_to_rownames() 함수를 이용해
Date열을 행이름으로 변경해 줍니다.

마지막으로 해당 데이터프레임을 xts 형태로 변경해 줍니다.

# plot data
charts.PerformanceSummary(factor_data)

정리된 데이터를 그래프로 나타내보도록 합니다.
y축의 스케일 문제 때문에 제대로 확인이 불가능합니다.
HenryQuant 패키지를 이용해 다시 그려보도록 합니다.

plot_cumulative(factor_data, ylog = TRUE)


y축을 로그화 시켜 제대로된 그래프가 그려집니다.
장기간 동안 모멘텀 팩터와 시장 팩터는 마이너스 수익률을,
SMB와 HML은 그나마 (+)임이 보이지만,
무위험 이자율과 별 차이가 없는 모습입니다.


plot_cumulative(factor_data['2002::'], ylog = TRUE)


2002년부터 시계열을 잘라보도록 하겠습니다.
역시나 모멘텀 팩터가 매우 부진합니다.


ss = getSymbols('005930.KS', from = '1999-12-30',
                auto.assign = FALSE) %>%
  Cl() %>%
  na.locf() %>%
  `colnames<- span="">('Samsung')
ss.ret = Return.calculate(ss) %>% na.omit()

이번에는 getSymbols() 함수를 이용하여 삼성전자의 주가를 불러온 후,
수익률을 구하도록 합니다.

Cl()을 통해 수정주가 부분만을 뽑아냈으며,
국내 종목의 경우 NA 데이터가 있는 경우가 있으므로
na.locf()를 통해 NA 데이터는 전일 주가로 보정하도록 합니다.


plot_cumulative(ss.ret)


삼성전자의 수익률 그래프입니다.
16,17년 폭발적 성장이 매우 눈에 띕니다.

data.df = merge(ss.ret, factor_data) %>% na.omit() 


삼성전자의 수익률 데이터와 팩터 수익률 데이터를 합쳐주도록 합니다.
두 데이터 모두 현재 xts 형태이므로
시계열 값(index)를 기준으로 합쳐지게 됩니다.


data.lm = lm( (Samsung-Rf) ~ MKT + SMB + HML + MOM,
              data = data.df)  
summary(data.lm)

Call:
lm(formula = (Samsung - Rf) ~ MKT + SMB + HML + MOM, data = data.df)

Residuals:
      Min        1Q    Median        3Q       Max 
-0.075526 -0.008469 -0.000653  0.007773  0.079781 

Coefficients:
              Estimate Std. Error t value Pr(>|t|)    
(Intercept)  0.0006768  0.0002148   3.151  0.00164 ** 
MKT          1.0324518  0.0173208  59.608  < 2e-16 ***
SMB         -0.2988326  0.0239916 -12.456  < 2e-16 ***
HML         -0.3232725  0.0330418  -9.784  < 2e-16 ***
MOM          0.0686728  0.0276871   2.480  0.01316 *  
---
Signif. codes:  0 *** 0.001 ** 0.01 * 0.05 . 0.1   1

Residual standard error: 0.01468 on 4704 degrees of freedom
Multiple R-squared:    0.6, Adjusted R-squared:  0.5997 
F-statistic:  1764 on 4 and 4704 DF,  p-value: < 2.2e-16


이젠 본격적으로 회귀분석을 실시해 주도록 합니다.

lm() 함수를 이용하여 OLS 회귀분석을 하며,
y변수는 Ri-Rf에 해당하는 값을,
x변수는 MKT, SMB, HML, MOM 팩터값을 입력해 줍니다.

summary() 함수를 이용할 경우 
결과값을 출력할 수 있지만 지나치게 데이터가 길고 복잡합니다.


broom::tidy(data.lm)
# A tibble: 5 x 5
  term         estimate std.error statistic  p.value
  <chr>                         
1 (Intercept)  0.000677  0.000215      3.15 1.64e- 3
2 MKT          1.03      0.0173       59.6  0.      
3 SMB         -0.299     0.0240      -12.5  4.63e-35
4 HML         -0.323     0.0330       -9.78 2.16e-22
5 MOM          0.0687    0.0277        2.48 1.32e- 2

broom 패키지의 tidy() 함수를 이용하면
회귀분석 결과값을 매우 깔끔하게 모을 수 있습니다.

statistic은 t-value를 의미합니다.

1) alpha부분인 intercept가 매우 유의미하며,
이는 4팩터로 설명되지 않는 알파가 있음을 의미합니다.

2) MKT 팩터는 1.03으로써 시장과 매우 비슷하며,
가장 설명력이 높은 팩터입니다.

3) SMB 팩터는 t-value가 -12로 매우 유의하며,
그 값이 음수인것으로 보아 대형주 효과가 있음을 알 수 있습니다.

4) HML 팩터는 t-vale가 -9로 역시나 유의하며,
음수인것으로 보아 성장주 효과가 있음을 알 수 있습니다.

5) UMD 팩터는 t-value가 2.5로 다소 유의하며,
양수인것으로 보아 모멘텀 효과가 있음을 알 수 있습니다.

즉 삼성전자 주식의 수익률은 
시장 베타와 매우 가까우며,
대형주, 성장주, 모멘텀 효과를 많이 받습니다.

그러나 4팩터로도 설명되지 않는 추가적인 알파가 있습니다.


마지막으로 다음 결과물을 논문에 많이 쓰이는
테이블로 출력하도록 하겠습니다.

# Regression Table
library(stargazer)
stargazer(data.lm,
          type = 'text',
          report = ("vc*t"),
          out = 'regression_table.html')

===============================================
                        Dependent variable:    
                    ---------------------------
                          (Samsung - Rf)       
-----------------------------------------------
MKT                          1.032***          
                            t = 59.608         
                                               
SMB                          -0.299***         
                            t = -12.456        
                                               
HML                          -0.323***         
                            t = -9.784         
                                               
MOM                           0.069**          
                             t = 2.480         
                                               
Constant                     0.001***          
                             t = 3.151         
                                               
-----------------------------------------------
Observations                   4,709           
R2                             0.600           
Adjusted R2                    0.600           
Residual Std. Error      0.015 (df = 4704)     
F Statistic         1,764.097*** (df = 4; 4704)
===============================================
Note:               *p<0.1; **p<0.05; ***p<0.01

stargazer 패키지는 회귀분석 값을 테이블로 나타내줍니다.
report 기본적으로 p-value 기준이며,
"vc*t"를 통해 t값을 출력하도록 합니다.

out은 결과물이 저장될 위치이며,
.html 형식으로 저장하도록 합니다.

워킹 디렉토리에 저장된 regression_table.html 
파일을 확인해보면,
위에서 출력된 값과 동일하게 html 파일로 저장되 있음이 확인됩니다.

바로 복사 붙여넣기를 통해 논문에 입력할 수 있습니다.




이 외에도 팩터 지수를 통해

residual momentum 혹은
idiosyncratic volatility와 같이
복잡한 전략도 구현이 가능합니다.



데이터를 생성 및 제공해 준 Handa Partners 연구원들에게 
감사의 뜻을 전합니다.

댓글 6개:

  1. Handa Partners의 Factor 분석기초 데이터를 알려주시고, 팩터투자 관련 자료를 시의적절하게 공유해주셔서 크게 도움이 됩니다. 애써서 공부하신 내용을 공유해주시는 노력이 한국 팩터투자의 수준을 높힐 것으로 기대합니다. 늘 감사합니다. ^^

    답글삭제
  2. 오늘도 새로운 패키지를 배워갑니다

    답글삭제
  3. 이거 파이썬으로도 해주세요 ^^

    답글삭제
  4. 혹시 2019년 4월 밖에 데이터가 없는데 최근 데이터까지 업로드 해주실순 없을까요??ㅠㅠ

    답글삭제
  5. 안녕하세요, 현재 같은 경로의 드라이브 파일을 받았는데 수치가 많이 다른 점을 발견했습니다..ㅎㅎ cumulated return 기준으로 rf 는 성장세인 반면 나머지는 모두 0 근처에서 횡보하네요 ㅠㅠ.

    답글삭제