Post List

레이블이 Factor Investing인 게시물을 표시합니다. 모든 게시물 표시
레이블이 Factor Investing인 게시물을 표시합니다. 모든 게시물 표시

2020년 6월 13일 토요일

그많던 스마트는 누가 다 먹었을까?



한때 '스마트베타'의 인기는 엄청났습니다.


그 중에서도 우량가치 ETF는 탑이었죠.

그러나 몇년이 지난 지금 
'성과가 왜이러지??' 라는 질문이 많이 나오고
딱히 아무도 답변을 해주지 못하고 있습니다.
그래서 한번 분해해 보았습니다.


사실 분석결과는 해당 ETF뿐만 아니라
현재 대부분 스마트베타 ETF의 부진에
동일하게 적용되는 원인일 겁니다.



먼저 기초지수의 성과입니다.
붉은색 라인이 ETF의 상장일인 2015-09-22 입니다.

한참 인기가 있던 17~18년까지 상승하다가 그 이후 계속 하락세입니다.



이번에는 2017년 이후 코스피지수, 우량가치지수의 성과비교 및 
누적수익률 차이 (파란색 바) 입니다.

사실 2019년 중반까지는 크게 차이가 없고,
19년 6월부터 차이가 벌어지는 중입니다.

그나마 20년 4월부터는 다시 차이 줄이는 중이네요



연도별 수익률을 살펴보면 19년, 20년도에
코스피 대비 엄청나게 언더퍼폼 중입니다.......

이번에는 그럼 코스피 지수를 한번 뜯어보도록 하죠



17년 이후 코스피와 코스피 대형주/중형주/소형주 지수입니다.
그냥 대형주 장이었습니다....
19년 이후 중형주와 소형주는 힘을 못쓰고 있습니다.



이번에는 카하트 4팩터기준
마켓, 소형주, 가치주, 모멘텀 팩터 수익률입니다.
(롱-숏 포트폴리오 기준)

코스피와 우량가치 차이가 벌어진 19년 6월 이후를 보면
마켓 팩터만 좋고 나머지 팩터는 그냥 죽음입니다



이번에는 스타일 매트릭스로 롱온리 기준으로
가치 X 사이즈를 쪼개보겠습니다. (2019년 이후)

성장주가 가치주 대비 더 좋은 성과를 보입니다.
대형가치는 죽음입니다.... 




우량가치를 4팩터 모델에 회귀분석 해보죠

term
estimate
std.error
statistic
p.value
(Intercept)
0.0002
0.0001
1.980
0.0477
MKT
0.8541
0.0064
133.879
0.0000
SMB
0.3934
0.0091
43.162
0.0000
HML
0.4111
0.0115
35.886
0.0000
UMD
-0.0614
0.0089
-6.874
0.0000


롱온리니 당연히 마켓팩터 노출도가 가장크고
베타가 0.85 정도로 낮습니다.

그다음으로는 사이즈 노출도가 가장 크네요
세번째로는 밸류 노출도가
마지막으로 모멘텀 노출도는 음수로 잡힙니다.
(뭐 이 기간동안 모멘텀 팩터가 날라가서 성과가 터진건 아닙니다만..)



일간데이터 기준 5년 롤링 회귀계수 값입니다.
마켓 팩터 노출도만 계속 증가하고
나머지 팩터에 대한 노출도는 계속 감소하는 이상한 모습을 보입니다.

심지어 마켓팩터는 지금 거의 1에 다와 갑니다...
이정도면 사실상 인덱스 펀드....???




이번에는 18년 이후를 살펴보겠습니다.
그나마 코로나 이후 밸류와 사이즈 팩터 노출도가 조금 올라오긴 했지만
시장팩터 노출도가 지배적입니다.




마지막으로 4팩터 기준 알파값과 t-value 입니다. (5년 롤링기준)

18~19년 즈음부터 알파 디케이가 급속하게 보입니다.
뭐 룰이 안통하던가?
아니면 전략이 너무 유명해져서 미미킹이 많던가?
이유는 모르겠지만 어째튼 알파가 없습니다.

19년 말부터는 심지어 알파가 음수입니다.



요약해보자면 다음과 같습니다.

- 전략의 노출도가 큰 사이즈, 밸류가 최근 전혀 작동하지 않음
- 코스피 내에서도 중소형주 개망
- 전략의 알파가 전혀 없거나 혹은 마이너스를 보임
- 최근에는 지수에 너무 붙은 느낌???

2019년 3월 4일 월요일

'Sector Neutral' factor portfolio



퀀트 투자를 하시는 분들은 대체로
섹터에 대한 편중 고려없이 포트폴리오를 구성하고는 합니다.

예를 들어 단순 전종목 중 저PER+저PBR 상위 n 종목을 구성하는 방식을 택합니다.

그러나 이러할 경우 종종 특정 섹터에 포트폴리오가 쏠리는 경우가 있습니다.

이를 방지하기 위해 다음과 같이
섹터 중립화된 팩터 포트폴리오를 구성하도록 하겠습니다.


1. 각 섹터 별로 팩터의 랭킹을 구함 (예: 저PBR 순위)
2. 해당 랭킹을 바탕으로 섹터 별 Z-Score를 계산
3. 전체 종목 중 해당 Z-Score가 낮은 상위 n 종목에 투자


예를 들어 특정 섹터 내 종목들의 PBR이 모두다 낮을 경우
단순 저PBR 투자 방법에서는 해당 섹터의 종목들을
모두다 매수하는 일이 발생할 수도 있지만,

위와 같은 방법을 이용하여 섹터별 중립화를 해줄 경우,
각 섹터 내에서 저평가된 종목들을 골고루 투자하는 장점이 있습니다.


다음은 저PBR + 고GPA 상위 50종목 백테스트 입니다.
(2001년~2019년 2월, 시가총액 상위 80%, 코스피 상장종목,
거래당 매매수수료 0.5% 적용)


섹터의 경우 FnGuide 기준 10개 섹터를 적용하였습니다.



두개 포트폴리오의 로그 누적수익률 차트입니다.

먼저 Normal은 단순 상위 50종목,
Neutral은 섹터 별로 PBR과 GPA의 랭킹과 Z-Score를 구한 후,
이를 바탕으로 상위 50종목 포트폴리오 입니다.

성과만을 보자면 중립화 보다는 단순 포트폴리오가
우수하게 보입니다.




연율화 수익률의 비교입니다
섹터 중립화 포트폴리오가 하락장에서 매우 근소하게
하락 폭이 낮은 것으로 보입니다.


Normal
Neutral
Ann Ret (Arith)
26.15%
24.02%
Ann Ret (CAGR)
25.89%
23.43%
Ann Std Dev
24.43%
23.83%
Ann Sharpe
1.0599
0.9832
Win Ratio
62.84%
63.30%
MDD
52.30%
46.16%
Roll Win (12M)
85.99%
85.51%
Roll Win (24M)
89.23%
92.82%
Roll Win (36M)
98.36%
100.00%


섹터 중립화 포트폴리오가
변동성이나 MDD 측면에서 '다소' 유리함이 보입니다.



먼저 단순 포트폴리오의 섹터별 투자 비중입니다.
시간에 따라 투자되는 섹터가 매우 들락날락 함이 보입니다.

최근에는 경기소비재에 투자되는 비중이
절반에 가까울 정도로 매우 큽니다.





반면 섹터 중립화 포트폴리오의 경우
섹터 전반적인 팩터 강도에 비례하여 투자되므로,
전 기간 비슷한 비중으로 투자됨이 보입니다.




이번에는 섹터의 분산정도를 나타낸 그래프입니다.

지표의 계산 방법은
먼저 각 섹터에 투자되는 비중들의 합을 구한 후,
이의 제곱합을 구하도록 합니다.



섹터 별 분산정도가 아예 없이,
극단적으로 한섹터에 투자되었다면 해당 값은 1이 될 것이며,

섹터 별 분산정도가 클 수록 해당 값은 낮아질 것입니다.

섹터 중립화의 경우 매우 골고루 분산되어 있음이 보입니다.




위 그림은 일반 포트폴리오의
각 섹터별 Z-Score의 분포도 입니다.

경기소비재의 경우 Z-Score가 낮은 종목,
즉 투자하는 종목이 매우 많지만,
산업재나 의료의 경우 오히려 Z-Score가 높은 종목이
많이 분포되어 있습니다.






반면에 섹터 중립화를 한 경우
먼저 랭킹을 통해 선형 분포를 만들었고
섹터 별로 Z-Score를 구하였기 때문에
모든 섹터가 일정한 분포를 보임이 확인됩니다.

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 연구원들에게 
감사의 뜻을 전합니다.