You are on page 1of 7

A Basic Logical Invest Global Market Rotation Strategy | QuantStrat TradeR https://quantstrattrader.wordpress.com/2015/05/18/a-basic-logical-invest...

Posted on May 18, 2015 by Ilya Kipnis • Posted in Asset Allocation, ETFs, R, SeekingAlpha • Tagged R •


18 Comments
This may be one of the simplest strategies I’ve ever presented on this blog, but nevertheless, it works, for
some definition of “works”.

Here’s the strategy: take five global market ETFs (MDY, ILF, FEZ, EEM, and EPP), along with a treasury
ETF (TLT), and every month, fully invest in the security that had the best momentum. While I’ve tried
various other tweaks, none have given the intended high return performance that the original variant
has.

Here’s the link (http://seekingalpha.com/article/1622832‐a‐global‐market‐rotation‐strategy‐with‐an‐
annual‐performance‐of‐41_4‐percent‐since‐2003) to the original strategy.

While I’m not quite certain of how to best go about programming the variable lookback period, this is
the code for the three month lookback.

1 of 7 12/9/2017 4:22 PM
A Basic Logical Invest Global Market Rotation Strategy | QuantStrat TradeR https://quantstrattrader.wordpress.com/2015/05/18/a-basic-logical-invest...

1 require(quantmod)
2 require(PerformanceAnalytics)
3
4 symbols <‐ c("MDY", "TLT", "EEM", "ILF", "EPP", "FEZ")
5 getSymbols(symbols, from="1990‐01‐01")
6 prices <‐ list()
7 for(i in 1:length(symbols)) {
8 prices[[i]] <‐ Ad(get(symbols[i]))
9 }
10 prices <‐ do.call(cbind, prices)
11 colnames(prices) <‐ gsub("\\.[A‐z]*", "", colnames(prices))
12 returns <‐ Return.calculate(prices)
13 returns <‐ na.omit(returns)
14
15 logicInvestGMR <‐ function(returns, lookback = 3) {
16 ep <‐ endpoints(returns, on = "months") 
17 weights <‐ list()
18 for(i in 2:(length(ep) ‐ lookback)) {
19 retSubset <‐ returns[ep[i]:ep[i+lookback],]
20 cumRets <‐ Return.cumulative(retSubset)
21 rankCum <‐ rank(cumRets)
22 weight <‐ rep(0, ncol(retSubset))
23 weight[which.max(cumRets)] <‐ 1
24 weight <‐ xts(t(weight), order.by=index(last(retSubset)))
25 weights[[i]] <‐ weight
26 }
27 weights <‐ do.call(rbind, weights)
28 stratRets <‐ Return.portfolio(R = returns, weights = weights)
29 return(stratRets)
30 }
31
32 gmr <‐ logicInvestGMR(returns)
33 charts.PerformanceSummary(gmr)

And here’s the performance:

1 > rbind(table.AnnualizedReturns(gmr), maxDrawdown(gmr), CalmarRatio(gmr))
2 portfolio.returns
3 Annualized Return                  0.287700
4 Annualized Std Dev                 0.220700
5 Annualized Sharpe (Rf=0%)          1.303500
6 Worst Drawdown                     0.222537
7 Calmar Ratio                       1.292991

With the resultant equity curve:

2 of 7 12/9/2017 4:22 PM
A Basic Logical Invest Global Market Rotation Strategy | QuantStrat TradeR https://quantstrattrader.wordpress.com/2015/05/18/a-basic-logical-invest...

While I don’t get the 34% advertised, nevertheless, the risk to reward ratio over the duration of the
backtest is fairly solid for something so simple, and I just wanted to put this out there.

Thanks for reading.

3 of 7 12/9/2017 4:22 PM
A Basic Logical Invest Global Market Rotation Strategy | QuantStrat TradeR https://quantstrattrader.wordpress.com/2015/05/18/a-basic-logical-invest...

1. Jaime says:
May 18, 2015 at 10:50 pm
Is it possible to test the following: pick one etf based on 3 mo return (“MDY”, “EEM”, “ILF”, “EPP”,
“FEZ”)
and use the Logical Invest walk forward sharpe strategy to find the optimal allocation between that
etf and TLT? Or maybe even test 2 separate screens?

Screen A (Stocks): “MDY”, “EEM”, “ILF”, “EPP”, “FEZ”
Screen B (Hedge): “TLT”, “JNK”, “PCY”, “CWB” maybe even add EFF, TIP

take one stock from each and then use the walk forward strategy to find the optimal allocation

Seems like it might be a good idea to screen between a couple of bond etfs to find the best hedge
rather than just using TLT all the time.

4 of 7 12/9/2017 4:22 PM
A Basic Logical Invest Global Market Rotation Strategy | QuantStrat TradeR https://quantstrattrader.wordpress.com/2015/05/18/a-basic-logical-invest...

2. Jean‐Marc says:
May 18, 2015 at 11:40 pm
My first reaction to this is that there is probably some level of overfitting. As the saying goes in data
science: if you torture your data long enough, it will confess… ϥ ϧ
Ϧ

It may be interesting to test this strategy by offsetting the month end by a day or two, and see if you
get similar results. If you get drastically different results, I’d say that’s a clear hint that overfitting is
at play.

Ilya Kipnis says:
May 19, 2015 at 12:29 am
To be fair, the first day of the month is pretty sacred. I’ve found that in many of my backtests that
I’ve done with monthly rotation strategies. So I’m sure there’ll be some loss of performance.

Jean‐Marc says:
May 19, 2015 at 1:36 am
Point taken.
Just for kicks, I ran your code and used a 0 to 10 days offset to see what we’d get. It’s still
pretty good, with a CAGR between 22% to 28% and all Sharpe ratios above 1.0.

Florent says:
May 29, 2015 at 10:18 pm
Hello Ilya,
I was thinking of two strategies that may run in parallel with the same universe and rotate
monthly with an offset of 2 weeks. Don’t you think it could smooth drawdown and increase
returns ?
Oh, and please, are you going to introduce the CAA ? ϥ ϧ
Ϧ

Jaime says:
May 19, 2015 at 3:35 am
I’m always suspicious of results based on first of the month trading. Shouldn’t there be a way to
test an all days start resulting in resulting in min, max & avg? That way there can be more
confidence that the strategy is robust and not reliant on a beginning of the month start date.

Anthony FJ Garner says:
May 21, 2015 at 9:18 pm
My belief is that a rolling date is the best way to avoid curve fitting. Over very long periods
the end results are much the same regardless of which day of the month your first roll date
occurs. As to Jamie’ first comment above any talk of “optimising” makes my hair stand on
end. However in my view he is quite right not to rely on tests of small numbers of
instruments, be they the stocks or the hedges.

Pingback: Quantocracyʹs Daily Wrap for 05/18/2015 | Quantocracy

4. Franc says:
May 22, 2015 at 2:49 am
I think you should lag weights for 1 period (i.e. weights <‐ lag(weights, 1)) so that previous 3‐month

5 of 7 12/9/2017 4:22 PM
A Basic Logical Invest Global Market Rotation Strategy | QuantStrat TradeR https://quantstrattrader.wordpress.com/2015/05/18/a-basic-logical-invest...

cumulative returns determine the next month weight. Let me know if I am wrong.

Ilya Kipnis says:
May 22, 2015 at 2:50 am
Already taken care of with Return.Portfolio

Franc says:
May 22, 2015 at 2:51 am
thanks ϥ
ϧ
Ϧ

Pingback: Проверка стратегии GMR с применением языка R | QuantAlgos

6. Ted Vizsla says:
May 25, 2015 at 4:48 pm
Isn’t there still a lag issue?

Assume the decision to invest in an asset based on momentum over a lookback period happens on,
e.g., a Friday (the end of the lookback period).
The weights will start on that Friday.
Return.portfolio() will give a return for the portfolio, using those weights, and it does so starting the
following Monday.
So Return.portfolio() does have a lag.
But the close‐to‐close return on Monday requires the closing price on the preceding Friday.
So you have to decide what asset to invest in using the close on Friday and also invest in that asset
before the close.

One can almost avoid this crystal ball effect by both deciding and investing say one minute before
the close on Friday.
But perhaps a more faithful backtest would start the portfolio returns on the following Tuesday.
Or do I misunderstand?

Ilya Kipnis says:
May 25, 2015 at 4:49 pm
That’s essentially the one slightly optimistic assumption — that you can get the data, say, five
minutes before close, and get in at that time. Since you’re holding for a month, it doesn’t have an
enormous effect.

7. kbglenn2 says:
August 9, 2015 at 5:08 am
How are returns calculated. I do not get close to these results.

Tks

8. GeraldM says:
April 22, 2016 at 5:29 pm
In retrospect, this looks like a curve‐fit. Frank published this towards the end of 2013. I just ran the

6 of 7 12/9/2017 4:22 PM
A Basic Logical Invest Global Market Rotation Strategy | QuantStrat TradeR https://quantstrattrader.wordpress.com/2015/05/18/a-basic-logical-invest...

code since we have a few years of out‐of‐sample data. The returns are as follows: 2014 had +1.8%,
2015 had ‐18%, 2016 (so far) has ‐1.2%. The new maximum draw‐down, which has occurred since
publication, is a whopping 35%. Anyone actually using this is getting killed.

Ilya Kipnis says:
April 22, 2016 at 5:43 pm
Oh wow, thanks for the update, Gerald! What made you decide to revisit this particular post?

Pingback: Create Amazing Looking Backtests With This One Wrong–I Mean Weird–Trick! (And
Some Troubling Logical Invest Results) | QuantStrat TradeR

Create a free website or blog at WordPress.com.

7 of 7 12/9/2017 4:22 PM

You might also like