Momentum in R: Part 2
October
20, 2012
By rbresearch
Many of the sites I linked
to in the previous post have articles or papers on momentum investing that
investigate the typical ranking factors; 3, 6, 9, and 12 month returns. Most
(not all) of the articles seek to find which is the “best” look-back period to
rank the assets. Say that the outcome of the article is that the 6 month
look-back has the highest returns. A trading a strategy that just uses a 6
month look-back period to rank the assets leaves me vulnerable to over-fitting
based on the backtest results. The backtest tells us nothing more than which
strategy performed the best in the past, it tells us nothing about the future…
duh!
Whenever I review the
results from backtests, I always ask myself a lot of “what if” questions. Here
are 3 “what if” questions that I would ask for this backtest are:
- What if the strategy based on a 6 month look-back under performs and the 9 month or 3 month starts to over perform?
- What if the strategies based on 3, 6, and 9 month look-back periods have about the same return and risk profile, which strategy should I trade?
- What if the assets with high volatility are dominating the rankings and hence driving the returns?
The backtests shown are
simple backtests meant to demonstrate the variability in returns based on
look-back periods and number of assets traded.
The graphs below show the
performance of a momentum strategy using 3, 6, 9, and 12 month returns and
trading the Top 1, 4, and 8 ranked assets. You will notice that there is
significant volatility and variability in returns only trading 1 asset. The
variability between look-back periods is reduced, but there is still no one
clear “best” look-back period. There are periods of under performance and over
performance for all look back periods in the test.
Here is the R code used for the backtests and the plots. Leave a comment
if you have any questions about the code below.
# Computes the
rank of an xts object of ranking factors
# ranking
factors are the factors that are ranked (i.e. asset returns)
#
# args:
# x = xts object of ranking factors
#
# Returns:
# Returns an xts object with ranks
# (e.g. for ranking asset returns, the asset
with the greatest return
# receives a
rank of 1)
}
# Converts
daily data to monthly and returns only the monthly close
# Note: only
used with Yahoo Finance data so far
# Thanks to
Joshua Ulrich for the Monthly Ad function
#
# args:
# x = daily price data from Yahoo Finance
#
# Returns:
# xts object with the monthly adjusted close
prices
Ad(to.monthly(x, indexAt = 'lastof',
drop.time = TRUE, name = sym))
}
# Function to
compute the CAGR given simple returns
#
# args:
# x = xts of simple returns
# m = periods per year (i.e. monthly = 12,
daily = 252)
#
# Returns the
Compound Annual Growth Rate
}
# returns a
list containing a matrix of individual asset returns
# and the
comnbined returns
# args:
# xts.ret = xts of one period returns
# xts.rank = xts of ranks
# n = number of top ranked assets to trade
# ret.fill.na = number of return periods to
fill with NA
#
# Returns:
# returns an xts object of simple returns
# trade the
top n asset(s)
# if the rank
of last period is less than or equal to n,
# then I would
experience the return for this month.
# lag the rank
object by one period to avoid look ahead bias
# for trading
the top ranked asset, replace all ranks above n
# with NA to
set up for element wise multiplication to get
# the realized
returns
lag.rank[lag.rank
> n] <- NA
# set the
element to 1 for assets ranked <= to rank
lag.rank[lag.rank
<= n] <- 1
# element wise
multiplication of the
# 1 period
return matrix and lagged rank matrix
# average the
rows of the mat.ret to get the
# return for
that period
vec.ret[1:z] <- NA
# convert to
an xts object
}
currency("USD")
symbols <- c("XLY", "XLP", "XLE", "XLF", "XLV", "XLI", "XLK", "XLB", "XLU", "EFA")#, "TLT", "IEF", "SHY")
# create new environment to store symbols
symEnv <- new.env()
# getSymbols and assign the symbols to the symEnv environment
# xts object of the monthly adjusted close prices
# monthly returns
monthly.returns
<- ROC(x = symbols.close, n = 1, type = "discrete", na.pad = TRUE)
#############################################################################
# rate of change and rank based on a single period for 3, 6, 9, and 12
months
#############################################################################
roc.three
<- ROC(x = symbols.close , n = 3, type = "discrete")
rank.three
<- RankRB(roc.three)
roc.six
<- ROC(x = symbols.close , n = 6, type = "discrete")
rank.six
<- RankRB(roc.six)
roc.nine
<- ROC(x = symbols.close , n = 9, type = "discrete")
rank.nine
<- RankRB(roc.nine)
roc.twelve
<- ROC(x = symbols.close , n = 12, type = "discrete")
rank.twelve
<- RankRB(roc.twelve)
num.assets
<- 4
# simple momentum test based on 3 month ROC to rank
case1
<- SimpleMomentumTest(xts.ret =
monthly.returns, xts.rank = rank.three,
n = num.assets, ret.fill.na = 15)
# simple momentum test based on 6 month ROC to rank
case2
<- SimpleMomentumTest(xts.ret =
monthly.returns, xts.rank = rank.six,
n = num.assets, ret.fill.na = 15)
# simple momentum test based on 9 month ROC to rank
case3
<- SimpleMomentumTest(xts.ret =
monthly.returns, xts.rank = rank.nine,
n = num.assets, ret.fill.na = 15)
# simple momentum test based on 12 month ROC to rank
case4
<- SimpleMomentumTest(xts.ret =
monthly.returns, xts.rank = rank.twelve,
n = num.assets, ret.fill.na = 15)
charts.PerformanceSummary(R = returns,
Rf = 0, geometric
= TRUE,
main = "Momentum Cumulative Return: Top 4 Assets")
table.Stats(returns)
CAGR(returns, m = 12)
print("End")
No hay comentarios:
Publicar un comentario