Post List

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년 말부터는 심지어 알파가 음수입니다.



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

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

2020년 3월 26일 목요일

지난해 $ 1Billion (1조) 이상을 번 5명의 헤지펀드 수장들



블룸버그 추정기준 작년 1조 이상을 번 5명의 헤지펀드 매니저를 소개합니다!!! (헤지펀드의 2%-20% 를 가정하여 산출했다고 합니다.)


크리스 혼에 대한 이미지 검색결과

1위: 크리스 혼 (TCI Fund Management)
수익: 2조 2,619억



짐 사이먼스에 대한 이미지 검색결과

2위: 짐 사이먼스 (Renaissance Technologies)
수익: 2조 1,209억

퀀트의 전설 짐 사이먼 형님은 아쉽게 2등..





켄 그리핀에 대한 이미지 검색결과

3위: 켄 그리핀 (Citadel)
수익: 1조 8,390억


스티브 코헨에 대한 이미지 검색결과

4위: 스티브 코헨 (Point72 Asset Management)
수익: 1조 5,447억


chase coleman tiger global에 대한 이미지 검색결과

5위: 체이스 콜먼 (Tiger Global Management)
수익: 1조 3,547억



2020년 3월 23일 월요일

파도가 심할때는 잠시 쉬어갑시다


투자는 무엇일까요? 어떤 면에서 저는 수익률이라는 보물을 찾아 먼 바다를 항해하는 것이 아닌가 합니다. 재무제표라는 나침반과, 바람이라는 주가 모멘텀, 배라는 기업을 가지고요.

바다의 바람이 평소와 같으면 항해도 평소와 같이 하면 됩니다. 믿을 만한 나침반(재무제표)을 가지고 바람(모멘텀)을 타고 앞으로 나아가기만 하면 되죠. 배가 튼튼할 수록 더 좋겠죠.

그러나 안개가 가득끼고 폭풍우가 몰아치면 아무리 좋은 나침반도, 배도 쓸모가 없습니다. 어설프게 자연에 맞서려다가는 침몰하는게 눈에 뻔합니다. 이럴때는 무리해서 배를 끌고나가기 보다 바람이 잦아들때까지 배를 정박하고 기다리는게 좋지 않을까요? 어짜피 그 보물은 누가 먼저 가져간다고 내 것이 사라지는 것도 아니니까요. 살아야 보물도 찾죠.

2020년 3월 14일 토요일

유동성 소용돌이: 하락은 어떻게 하락을 부추기는가?



여러분이 생각하는 것 보다 시장은 복잡한 형태의 함수로 이루어져 있습니다. 각종 파생상품, 레버리지, 대차거래, 신용매매 등이 여기에 해당합니다.

헤지펀드의 경우 100% 매수 포지션을 위해 자기돈 100%를 내는 경우는 거의 없습니다. 자기돈의 50%로 주식을 매수하면 나머지 50%는 프라임 브로커에서 이 주식들을 담보로 제공해준 자금을 통해 매수하면 됩니다. 이것이 흔히 알고있는 '레버리지' 이죠. 개인들의 신용미수 역시 이와 동일하다고 보면 됩니다.

정상적인 시장에서 이러한 메커니즘은 아무 문제가 없겠죠. 그러나 시장이 급락하고 공포에 휩싸여, 모두가 탈출하고 싶어할 때는 얘기가 다릅니다.




먼저 시장에 엄청난 쇼크가 발생한다고 생각합시다. 먼저 쇼크로 인한 손실때문에 트레이더는 포지션을 줄여야 합니다. 그러나 더 큰 문제는 프라임브로커와의 자금 조달 관계입니다. 위험을 느낀 프라임 브로커들이 더욱 많은 담보를 요구하거나, 혹은 부도위험, 손실관리 등 각종 위험관리를 위해 더이상 자금제공을 하지 않기도 합니다.

결국 트레이더는 애초에 매도해야했던 금액에 더해 더 큰 매도를 해야하며, 이는 엄청난 매도 압력을 만들어냅니다. 그 결과 동일한 포지션을 가진 모든 트레이더는 더 큰 손해를 보게 됩니다.


시장의 매도 압력이 커지면 어떻게 될까요? 이러한 주문 불균형으로 인해 시장 변동은 더 커지고 유동성은 말라붙게 됩니다. 일반적인 상황에서 이런 트레이더들이 유동성 공급자였는데, 이제 그들은 매도만을 위해 달려가고 있으니까요.

악순환은 다시 돌아옵니다. 변동성이 높아지고 유동성이 하락함에  따라 위험을 느낌 프라임브로커는 또다시 증거금을 올리고, 트레이더가 포지션을 정리하도록 만듭니다. 트레이더역시 손실로 인해 포지션을 추가로 줄여야 하며, 투자자나 경영자들이 돈을 뺴가기도 합니다. 이런 악순환은 계속 반복됩니다. 이러한 일련의 과정을 유동성 소용돌이 라고 합니다.



이 상황은 언제 멈출까요? 바로 디레버리징이 끝날때 입니다. 모든 복잡한 함수가 정리되면 가격은 바닥에 도달합니다. 그 후 일부 트레이더는 다시 레버리지를 사용하여 매수를 하기 시작하면 가격은 내재가치를 향해 반등하기 시작합니다. 이 내재가치는 기존 보다 하락한 지점에서 평형을 이루게 됩니다.

물론 그 반등이 몇일만에 끝날지, 아니면 몇달이나 걸릴지는 아무도 모르지겠지만요... (논문에서는 알수 있다고 하니 우리모두 공부합시다!)



참고문헌: Pedersen, Lasse Heje. When everyone runs for the exit. No. w15297. National Bureau of Economic Research, 2009.

2019년 11월 15일 금요일

dtplyr: dplyr의 편리함과 data.table의 속도를 그대로!



R 내에서 데이터 처리시 가장 많이 사용되는 패키지는 dplyr 입니다. 개인적으로 dplyr을 쓰지 않는 다는 것은 R의 1%도 활용하지 못한다는 생각이 들 정도입니다. 그러나 데이터 양이 늘어날수록 속도가 느려지는 것은 당연합니다.

물론 data.table 패키지라는 해결책도 있습니다. R 뿐만 아니라 다른 언어들과 비교해도 속도에서 만큼은 깡패급으로 빠릅니다. 그러나 사용하기에 문법이 너무 복잡해 접근이 쉽지 않습니다.

(아무리 외워도 외워지지 않는 그놈의 DT[i, j, by].....)


이런 문제를 해결하기 위해 Rstudio에서 새로운 해법을 내놓았습니다. dplyr 문법을 입력하면 data.table 명령어로 래핑하여 데이터를 처리하는, 즉 dplyr의 편리함과 data.table의 속도를 둘 다 잡은 dtplyr 패키지를 선보였습니다.


두말할 필요없이 속도 비교를 해보도록 합시다.

library(nycflights13)
library(data.table)
library(dtplyr)
library(dplyr, warn.conflicts = FALSE)
library(microbenchmark)
library(ggplot2)

먼저 필요한 패키지들을 불러옵니다. dplyr의 경우 warn.conflicts() 인자를 FALSE로 두어 충돌 메세지를 끄도록 합니다.
CRAN 버젼 dtplyr 설치시 에러가 날 수 있습니다. 이는 연결 패키지인 data.table이 최근에 업데이트 되어서이며, data.table을 제거 후 인스톨 한후 dtplyr을 설치하면 잘 설치 됩니다.
# load data
df = flights
dim(df)
## [1] 336776     19
head(df)
## # A tibble: 6 x 19
##    year month   day dep_time sched_dep_time dep_delay arr_time
##                            
## 1  2013     1     1      517            515         2      830
## 2  2013     1     1      533            529         4      850
## 3  2013     1     1      542            540         2      923
## 4  2013     1     1      544            545        -1     1004
## 5  2013     1     1      554            600        -6      812
## 6  2013     1     1      554            558        -4      740
## # ... with 12 more variables: sched_arr_time , arr_delay ,
## #   carrier , flight , tailnum , origin , dest ,
## #   air_time , distance , hour , minute ,
## #   time_hour 
필요한 flight 데이터를 불러오도록 합니다. 총 336776개의 행으로 구성되어 있습니다.

df_dt = data.table(df)
df_tb = as_tibble(df)
df_lz = lazy_dt(df)
데이터 테이블을 각 형식에 맞게 바꿔주도록 합니다. data.table() 함수를 이용해 데이터테이블 형태로, as_tibble() 함수를 이용해 티블 형태로, 마지막으로 dtplyr 패키지의 lazy_dt() 함수를 이용해 dtplyr_step_first 형태로 바꾸어 줍니다. 해당 형식을 통해 dplyr 명령어를 data.table 명령어로 래핑하여 데이터를 처리하게 됩니다.

summary(df_lz)
##               Length Class      Mode       
## parent        19     data.table list       
## vars          19     -none-     character  
## groups         0     -none-     character  
## implicit_copy  1     -none-     logical    
## needs_copy     1     -none-     logical    
## env            5     -none-     environment
## name           1     -none-     name
summary()를 통해 확인해보면 data.table 클래스에 굉장히 독특한 형태로 생겼습니다.
이제 본격적으로 속도를 비교해보도록 하겠습니다. 먼저 필터에 대한 속도 비교입니다.

dtply을 이용할 경우 lazy_dt()를 통해 변경된 데이터에 기존 dplyr 명령어를 그대로 사용해서 데이터처리를 하며, as_tibble() 을 통해 티블 형태로 변경해주길 권장합니다. (그렇지 않으면 용량이 매우 큰 dtplyr_step_first 형태로 남아있게 됩니다.)
results = microbenchmark(
  `data.table` = df_dt[origin == 'JFK' & carrier == 'AA'] ,
  `dplyr` = df_tb %>% filter(origin == 'JFK' & carrier == 'AA'),
  `dtplyr` = df_lz %>% filter(origin == 'JFK' & carrier == 'AA') %>% as_tibble(),
  times = 100
)

results
## Unit: milliseconds
##        expr    min      lq      mean   median       uq     max neval cld
##  data.table 5.2220 6.92075  7.842533  7.49525  8.31910 19.4979   100 a  
##       dplyr 8.1038 9.33090 11.130208 10.14395 11.50605 27.7445   100   c
##      dtplyr 6.5998 8.35225  8.902763  8.83630  9.42860 11.7533   100  b
autoplot(results) +
  aes(fill = expr) +
  theme_bw() +
  labs(title = "Filter")

data.table이 압도적으로 빠르며, 그뒤가 dtplyr, dplyr 순입니다. 물론 data.table과 dtplyr은 간혹 속도가 매우 오래 걸리는 경우가 있어 mean 값이 증가하는 경우도 있습니다.
그러나 data.table와 dtplyr 진정한 위력은 매우 복잡한 데이터를 처리하는데 있습니다. 이번에는 그룹화, 통계값 계산, 필터링 이라는 복잡한 데이터처리를 해보도록 하겠습니다.

results2 = microbenchmark(

  `data.table` = df_dt[, .(mean_delay = mean(dep_delay, na.rm = TRUE)),
        by = c('year', 'month', 'day', 'carrier', 'origin')][mean_delay >= 10],

  `dplyr` = df_tb %>%
    group_by(year, month, day, carrier, origin) %>%
    summarize(mean_delay = mean(dep_delay, na.rm = TRUE)) %>%
    ungroup() %>%
    filter(mean_delay >= 10),

  `dtplyr` = df_lz %>%
    group_by(year, month, day, carrier, origin) %>%
    summarize(mean_delay = mean(dep_delay, na.rm = TRUE)) %>%
    ungroup() %>%
    filter(mean_delay >= 10) %>%
    as_tibble(),

  times = 100
)

results2
## Unit: milliseconds
##        expr     min       lq     mean   median       uq      max neval cld
##  data.table 14.1369 16.05185 17.85918 16.82690 18.81835  25.7218   100 a  
##       dplyr 71.1181 81.33950 91.00665 90.43740 99.06195 130.1543   100   c
##      dtplyr 14.9752 19.12145 22.18545 20.24325 21.60995 148.0419   100  b
autoplot(results2) +
  aes(fill = expr) +
  theme_bw() +
  labs(title = "group_by, mean, filter")


data.table과 dtply이 dplyr에 비해 압도적인 속도 차이를 보입니다. 이러한 차이는 데이터 크기가 늘어날수록, 그리고 데이터 처리 구조가 복잡해 질수록 늘어나게 됩니다.
이처럼 dtplyr은 기존 dplyr 문법을 활용하여 data.table과 거의 비슷한 성능을 내는 보물같은 패키지입니다.