미국에 상장된 SPDR의 섹터 ETF 9종을 이용한
섹터 로테이션 전략을 테스트합니다.
먼저, 사용된 9개 ETF는 다음과 같습니다.
XLY: Consumer Discretionary SPDR
XLP: Consumer Staples Select Sect. SPDR
XLF: Financial Select Sector SPDR
XLE: Energy Select Sector SPDR
XLV: Health Care SPDR
XLI: The Industrial Select Sector SPDR
XLB: Materials Select Sector SPDR
XLK: Technology Select Sector SPDR
XLU: Utilities SPDR
Cash 대용 ETF는 다음과 같습니다.
SHY: iShares Barclays 1-3 Year Treasry Bnd
9개 섹터 ETF의 누적수익률은 다음과 같습니다.
다음은 섹터 모멘텀 전략의 백테스트 입니다.
먼저 9개 섹터 중 12개월 누적 수익률 상위 5개 섹터를 선택한 후,
이 중 누적 수익률이 (+)인 섹터만 선택합니다.
선택된 섹터에 각 20%씩 비중을 부여하며,
주식 비중이 남을 경우 단기채권 혹은 현금 ETF를 매입합니다.
매매에 따른 수수료는 매수/매도 시 30bp로 가정합니다.
아래는 해당 로직을 적용한 백테스트 포트폴리오와,
미국 S&P 500을 추종하는 SPY ETF 수익률의 비교입니다.
Portfolio
|
SPY
|
|
Ann Ret (Arith)
|
6.58%
|
6.75%
|
Ann Ret (CAGR)
|
5.77%
|
4.95%
|
Ann Std Dev
|
13.90%
|
19.56%
|
Ann Sharpe
|
0.4154
|
0.2532
|
Win Ratio
|
0.5346
|
0.5391
|
MDD
|
27.34%
|
55.19%
|
전체적으로 수익률은 비슷하지만
단순 지수의 Buy & Hold 대비
훨씬 낮은 변동성과 MDD를 보입니다.
다음은 매 월별 투자비중과 Cash의 투자비중입니다.
2002년과 2008년 Market Crash 시절,
대부분의 금액이 Cash에 투자되어 추가적인 하락을 방어합니다.
다음은 매 월별 턴오버 입니다.
위 테스트의 코드는 다음과 같습니다.
ipak = function(pkg){ new.pkg = pkg[!(pkg %in% installed.packages()[, "Package"])] if (length(new.pkg)) install.packages(new.pkg, dependencies = TRUE) sapply(pkg, require, character.only = TRUE) } stat_summary = function(x) { x = as.matrix(x) stat_table = round(rbind(Return.annualized(x, geometric = FALSE), table.AnnualizedReturns(x), UpsideFrequency(x), maxDrawdown(x)), 4) rownames(stat_table) = c("Ann Ret (Arith)", "Ann Ret (CAGR)", "Ann Std Dev", "Ann Sharpe", "Win Ratio", "MDD") return(stat_table) } packages = c("PerformanceAnalytics", "quantmod", "PortfolioAnalytics") ipak(packages) symbols = c("XLY", "XLP", "XLF", "XLE", "XLV", "XLI", "XLB", "XLK", "XLU", "SHY") symbols_bm = c("SPY") getSymbols(c(symbols,symbols_bm), src="yahoo", from = "1998-12-31") ################################################## ### XLY: Consumer Discretionary SPDR ############# ### XLP: Consumer Staples Select Sect. SPDR ###### ### XLF: Financial Select Sector SPDR ############ ### XLE: Energy Select Sector SPDR ############### ### XLV: Health Care SPDR ######################## ### XLI: The Industrial Select Sector SPDR ####### ### XLB: Materials Select Sector SPDR ############ ### XLK: Technology Select Sector SPDR ########### ### XLU: Utilities SPDR ########################## ### SHY: iShares Barclays 1-3 Year Treasry Bnd ### prices = list() for(i in 1:length(symbols)) { prices[[i]] = Ad(get(symbols[[i]])) } prices = do.call(cbind, prices) bm = Ad(get(symbols_bm)) rets = na.omit(Return.calculate(prices[, -ncol(prices)])) ret_cash =na.omit(Return.calculate(prices[, ncol(prices)])) ret_bm = na.omit(Return.calculate(bm)) num = 5 lookback = 12 fee = 0.0030 wts = list() ep = endpoints(rets, on = "months") for(i in (lookback+1) : (length(ep)) ) { sub_cum = Return.cumulative( rets[c(ep[i-12] : ep[i]) , ]) K = which(rank(- sub_cum) <= num & sub_cum >= 0) wt = rep(0, ncol(rets)) wt[K] = 1 / num names(wt) = colnames(rets) wt = xts(t(wt), order.by = index(rets[ep[i]])) wts[[i]] = wt } wts = round(do.call(rbind, wts), 3) wts$zeros = 1 - rowSums(wts) rets$zeros = ret_cash Sector = Return.portfolio(R = rets, weights = wts, verbose = TRUE) Sector_ret = Sector$return Sector_Turnover = xts(rowSums(abs(Sector$BOP.Weight - lag(Sector$EOP.Weight)), na.rm = TRUE), order.by = index(Sector$BOP.Weight)) Sector_ret_net = round(Sector_ret - Sector_Turnover * fee, 4) compare = na.omit(cbind(Sector_ret_net,ret_bm)) charts.PerformanceSummary(compare, main = "") stat_summary(compare) chart.StackedBar(wts, col = rainbow10equal) apply.yearly(compare, Return.cumulative)
안녕하십니까? 요즘은 금융관련 R을 공부하던 중인데 이런 code를 공개해 주심에 무한 감사드립니다. 지금은 코드만 봐서는 전부 이해할 수는 없지만, 열심히 공부해서 저도 이렇게 나눌 수 있는 사람이 되겠습니다.
답글삭제이정도 코드는 구글에 몇일만 검색하면 나오는거라 ㅎㅎ
삭제