Post List

2016년 7월 12일 화요일

Adaptive Asset Allocation: Simple Case

최근 유행하는 Asset Allocation 시리즈
(Adaptive, Dynamic, Protective,....) 를 살펴 보면

결국 모멘텀이 꺾이는 자산을 비우고
모멘텀이 살아 있는 종목으로 바톤 터치 할 것,
여의치 않을 땐 채권이나 유동자금으로 비중을 늘려
Drawdown을 최대한 막을 것. 정도로 요약됩니다.

먼저, 국내 주식과 채권 만으로
모멘텀 기반의 Asset Allocation 이 Working 하는지
심플한 테스트를 합니다.
위 그림은 KOSPI의 12개월 롤링 수익률 입니다.

12개월 수익률이  "< 0" 이 될 경우,
주식 비중을 0% 로 만들고, 채권에 전액 투자 합니다.
그렇지 않을 경우 주식 비중을 100% 로 유지합니다.

채권 수익률은 국고채10년 지수를 이용하였으며,
2008년 2월 까진 해당 값이 없어
월 채권 수익률을 simple하게 0.18%로 두었습니다.
역사적으로 국내 주식 시장이 크게 하락한 시점은
IMF, IT 버블, 카드 대란, 서브프라임, 유로존 위기 정도 입니다.

2011년 유로존 위기를 제외하고는
주식 포지션을 줄임으로써
수익률 방어가 상당히 잘 되었습니다.

(특히 2008년의 수익률 방어가 상당히 눈에 띕니다)
 Drawdown 그래프를 보면,
그 효과를 더욱 확연히 볼 수 있습니다.


##################

이번에는 유니버스를 확장하여, MKF 섹터기준의 적용입니다.
먼저, 아래 5개 전략을 기준으로 백테스트를 시행합니다.

1) 전 섹터 동일가중
2) 전 섹터 분산가중
3) 상위 5개 섹터 동일가중
4) 상위 5개 섹터 분산가중
5) 상위 5개 섹터 최소분산 


1)
2)
3)
4)
5)
Cum Ret
2.2858
2.2929
3.8505
3.6069
3.9082
Ann Ret
0.0855
0.0857
0.1151
0.1111
0.1160
Ann Std
0.1968
0.1847
0.2475
0.2551
0.2419
Ann Sharpe
0.4344
0.4638
0.4648
0.4355
0.4794







1)번과 2)번 처럼 전 섹터에 투자하는 것은
KOSPI 대비 유의미한 알파가 나오지 않지만

3), 4), 5) 처럼 모멘텀을 이용한 전략은 
초과수익이 나오는 것이 확인됩니다.

##################

이번에는 기존에 연구한 다양한 모멘텀 전략에 따른
수익률을 비교해 봅니다.

1) 단순 12개월 동일가중
2) 최근 1개월 제외한 단순 12개월 동일가중
3) 12개월 수익률 / 변동성 (1개월 제외, 위험조정) 동일가중
4) 위험 조정 분산가중
5) 위험조정 최소분산


1)
2)
3)
4)
5)
Cum Ret
3.8505
4.0667
6.2406
6.0437
6.4367
Ann Ret
0.1151
0.1184
0.1463
0.1441
0.1484
Ann Std
0.2475
0.2492
0.2186
0.2272
0.2107
Ann Sharpe
0.4648
0.4752
0.6694
0.6342
0.7044








기존 연구와 마찬가지로 단순히 모멘텀을 사용하기 보다는
최근 1개월을 제외하거나, 변동성을 조절해 주는 것이
뛰어난 성과로 연결됩니다.

특히 변동성 조절 & 최소분산까지 가미하면
수익률, 변동성, Drawdown 모든 측면에서
향상된 성과를 보입니다.

##################

위의 방법론은 국내 자산만을 대상으로 하였고,
유의미한 수익률이 나옴을 보였습니다.

다음엔 글로벌 자산에 까지
영역을 확장한 결과를 보이겠습니다.

##################





###### (1) STOCK & BOND CASE ######

library(PerformanceAnalytics)
library(quantmod)
library(FRAPO)
price = read.csv("raw.csv", row.names = 1, header = TRUE)
ro = nrow(price)
co = ncol(price)

ret = matrix(0,ro, co)
for(i in 1:2) {
ret[, i] = Delt(price[, i]) }

ret_kospi = as.matrix(ret[,1])
ret_bond = as.matrix(ret[,2])

ret_kospi[is.na(ret_kospi)] = 0
ret_bond[is.na(ret_bond)] = 0.0018

ret_kospi_12 = rbind(matrix(0,11,1),rollapply((ret_kospi+1), 12, prod) - 1)
ret = matrix(0,ro,1)

rownames(ret_kospi_12) = rownames(price)
rownames(ret) = rownames(price)
rownames(ret_kospi) = rownames(price)
rownames(ret_bond) = rownames(price)

for (i in which(rownames(ret_kospi_12) == "1995-11-30") : (ro-1) ) {
  if ( ret_kospi_12[i] < 0 ) {
    w = 0 }
  else {
    w = 1
  }
  
w_b = 1 - w
  ret[i+1] = w * ret_kospi[i+1,] + w_b * ret_bond[i+1,]
}
    
par(mfrow = c(3,1))

chart.CumReturns(cbind(ret_kospi,ret))
legend('topleft', c("KOSPI", "AAA"), col = 1:2, lty=1, bty='n')

chart.RollingPerformance(ret_kospi, 12)

barplot(t(cbind(apply.yearly(ret, Return.cumulative),  apply.yearly(ret_kospi, Return.cumulative) )), col=1:2, beside = TRUE)
legend('topleft', c("KOSPI", "AAA"), col = 1:2, lty=1, bty='n')


###### (2) SECTOR CASE ######

price_d = read.csv("sector.csv", row.names=1)

ret_d = matrix(0,dim(price_d)[1], dim(price_d)[2])

for (i in 1 : dim(price_d)[2] ) {
  ret_d[,i] = Delt(price_d[, i])
}
rownames(ret_d) = rownames(price_d)

date_m = as.matrix(read.csv("date_m.csv", header = FALSE))
price_m = matrix(0,dim(date_m)[1],dim(price_d)[2])
rownames(price_m) = date_m

for (i in 1 : dim(price_m)[1]) {
  for (j in 1 : dim(price_m)[2]) {
    price_m[i,j] = price_d[which(rownames(ret_d) == rownames(price_m)[i]) , j ]
  }
}

ret_m = matrix(0,dim(price_m)[1], dim(price_m)[2])
for (i in 1 : dim(price_m)[2] ) {
  ret_m[,i] = Delt(price_m[, i])
}
rownames(ret_m) = rownames(price_m)

ret_kospi = as.matrix(ret_m[,dim(ret_m)[2]])
ret_kospi_12 = rbind(matrix(0,11,1),rollapply((ret_kospi+1), 12, prod) - 1)

ret_m = ret_m[, 1 : (dim(ret_m)[2]-1)]
ret_d = ret_d[, 1 : (dim(ret_d)[2]-1)]

ro = dim(ret_m)[1]
co = dim(ret_m)[2]
num = 5

ret_mom = matrix(0,ro,co)
for (i in which(rownames(ret_m) == "2002-01-31") : ro ) {
  for (j in 1: co) {
    ret_mom[i,j] = price_m[i,j] / price_m[i-12,j] - 1
  }
}

ret_mom_1m = matrix(0,ro,co)
for (i in which(rownames(ret_m) == "2002-01-31") : ro ) {
  for (j in 1: co) {
    ret_mom_1m[i,j] = price_m[i-1,j] / price_m[i-12,j] - 1
  }
}

rownames(ret_mom) = rownames(price_m)
rownames(ret_mom_1m) = rownames(price_m)

std_roll = rbind( matrix(0,12,co),  rollapply(ret_m,11,sd)[-1,][-nrow(rollapply(ret_m,11,sd)[-1,]),] )  

#----------- AAA Compare -----------#
ret_port = matrix(0,dim(ret_m),5)
rownames(ret_port) = rownames(price_m)
colnames(ret_port) = c("EW","VW","MOM & EW","MOM& VW","MOM & MV" )

ret_mom_stra = matrix(0,dim(ret_m),5)
rownames(ret_mom_stra) = rownames(price_m)
colnames(ret_mom_stra) = c("12M","12M SKIP 1M","Risk Adjusted","Risk Adjusted & VW ", "Risk Adjusted & MV")

ret_mom_mix = matrix(0,dim(ret_m),5)
rownames(ret_mom_mix) = rownames(price_m)

for ( i in which(rownames(ret_m) == "2002-01-31") : ( dim(price_m)[1] - 1 ) )  {
  #----------- 1. EW -----------#
  
  ret_port[i+1,1] = mean(ret_m[i+1,])
   
  #----------- 2. Volatility Weighted -----------#
  
  sd = matrix(0, 1, dim(ret_m)[2] )
  for (w in 1 : dim(ret_m)[2]) {
    sd[1, w] = sd( ret_d[ ( which(rownames(ret_d) == rownames(ret_m)[i]) - 60 ) : which(rownames(ret_d) == rownames(ret_m)[i]), w])
  }
  
  sd = as.matrix( (1/sd) / sum((1/sd)) )
  ret_port[i+1 , 2] = ret_m[i+1,]  %*% t(sd)
  
  #----------- 3. TOP 5 MOMENTUM, EW -----------#
  
  ret_port[i+1, 3] = mean(ret_m[ i+1, which(rank(-ret_mom[i,]) <= num)])
  

  #----------- 4. TOP 5 MOMENTUM, VW -----------#
  k = which(rank(-ret_mom[i,]) <= num)
  
  sd_vw = sd[, k]
  sd_vw = (1 / sd_vw) / sum( 1/ sd_vw)
  
  ret_port[i+1 , 4] = ret_m[i+1,k]  %*% sd_vw
  
  #----------- 5. TOP 10 MOMENTUM, MV -----------#
  
 MV는 생략합니다

  #----------- Momentum Compare -----------#
  
  ret_mom_stra[i+1, 1] = mean(ret_m[ i+1, which(rank(-ret_mom[i,]) <= num)])
  ret_mom_stra[i+1, 2] = mean(ret_m[ i+1, which(rank(-ret_mom_1m[i,]) <= num)])
  ret_mom_stra[i+1, 3] = mean(ret_m[ i+1, which(rank(- ret_mom_1m[i,] / std_roll[i, ]) <= num)])
  
  k2 =  which(rank(- ret_mom_1m[i,] / std_roll[i, ]) <= num)
  sd_mom = sd[,k2 ]
  sd_mom = (1/sd_mom) / sum(1/sd_mom)
  
  ret_mom_stra[i+1, 4] = ret_m[i+1,k2] %*% sd_mom
  MV는 생략합니다

}
ret_port = ret_port[ which(rownames(ret_port) == "2002-01-31") : nrow(ret_port) , ]
ret_mom_stra = ret_mom_stra[ which(rownames(ret_mom_stra) == "2003-01-31") : nrow(ret_mom_stra) , ]
ret_kospi = as.matrix(ret_kospi[ which(rownames(ret_kospi) == "2003-01-31") : nrow(ret_kospi) , ])
table.AnnualizedReturns(ret_port)
table.AnnualizedReturns(ret_mom_stra)

Return.cumulative(ret_port)
Return.cumulative(ret_mom_stra)

#----------- CUMULATIVE RETURN -----------#

plot(0,type='n',axes=FALSE,ann=FALSE)
par(mfrow = c(2,1))

chart.CumReturns(cbind(ret_port, ret_kospi), main = "Adaptive Asset Allocation")
legend('topleft',c("EW","VW","MOM & EW","MOM& VW","MOM & MV","KOSPI" ),col=1:6, lty=1, cex = 0.5, bty='n')

chart.CumReturns(cbind(ret_mom_stra, ret_kospi), main = "Comparing Momentum")
legend('topleft',c("12M","12M SKIP 1M","Risk Adjusted","Risk Adjusted & VW ", "Risk Adjusted & MV", "KOSPI"),col=1:6, lty=1, cex = 0.5, bty='n')

#----------- YEARLY BARPLOT -----------#

plot(0,type='n',axes=FALSE,ann=FALSE)
par(mfrow = c(2,1))

barplot(t(cbind( apply.yearly(ret_port, Return.cumulative),  apply.yearly(ret_kospi, Return.cumulative) )), col=1:6, beside = TRUE)
legend('topright',c("EW","VW","MOM & EW","MOM & VW","MOM & MV","KOSPI" ), horiz = TRUE, col=1:6, lty=1, cex = 0.4, bty='n')

barplot(t(cbind( apply.yearly(ret_mom_stra, Return.cumulative),  apply.yearly(ret_kospi, Return.cumulative) )), col=1:6, beside = TRUE)
legend('topright',c("12M","12M SKIP 1M","Risk Adjusted","Risk Adjusted & VW ", "Risk Adjusted & MV", "KOSPI"), horiz = TRUE, col=1:6, lty=1, cex = 0.4, bty='n')

#----------- DRAWDOWN -----------#

plot(0,type='n',axes=FALSE,ann=FALSE)
par(mfrow = c(2,1))

chart.Drawdown(ret_port, main = "")
legend('bottomleft',c("EW","VW","MOM & EW","MOM& VW","MOM & MV"), horiz= TRUE, col=1:5, lty=1, cex = 0.6, bty='n')

chart.Drawdown(ret_mom_stra, main = "")
legend('bottomleft',c("12M","12M SKIP 1M","Risk Adjusted","Risk Adjusted & VW ", "Risk Adjusted & MV"), horiz = TRUE, col=1:5, lty=1, cex = 0.6, bty='n')


댓글 1개:

  1. 12개월 수익률 / 변동성 (1개월 제외, 위험조정)을 사용했다는 것은 결국 샤프지수가 높은 자산에 투자한다는 것이군요! 감사합니다

    답글삭제