Back to Community
ETF Rotation Strategy

Sources:

The Lazy Trader ETF Rotation Strategy
http://www.the-lazy-trader.com/2015/01/etf-rotation-systems-to-beat-market-American-Equities.html

Developing A Rotation Strategy Using Highly Diversified ETFs - Part III
https://seekingalpha.com/article/2107713-developing-a-rotation-strategy-using-highly-diversified-etfs-part-iii

I buy 3 etfs based on a ranking of how it has performed in the past and the volatility.
Let me know what you think! Still work for lots of improvement!

Clone Algorithm
259
Loading...
Backtest from to with initial capital
Total Returns
--
Alpha
--
Beta
--
Sharpe
--
Sortino
--
Max Drawdown
--
Benchmark Returns
--
Volatility
--
Returns 1 Month 3 Month 6 Month 12 Month
Alpha 1 Month 3 Month 6 Month 12 Month
Beta 1 Month 3 Month 6 Month 12 Month
Sharpe 1 Month 3 Month 6 Month 12 Month
Sortino 1 Month 3 Month 6 Month 12 Month
Volatility 1 Month 3 Month 6 Month 12 Month
Max Drawdown 1 Month 3 Month 6 Month 12 Month
# Backtest ID: 58d57d8b94b5c81ccecb168f
There was a runtime error.
15 responses

Why do you rank them before? I mean, you do the returns for each ETF (20d, 3m, 6m, 1yr), but you don't need to rank them yet. First, do the score, and then rank them.
I would delete this:
day20_rank=day20_ret.rank(ascending=False)
day3mo_rank=day3mo_ret.rank(ascending=False)
day6mo_rank=day6mo_ret.rank(ascending=False)
day1yr_rank=day1yr_ret.rank(ascending=False)
vol_rank=volatility.rank(ascending=True)

Thank you,

So just to clarify. I want to rank by the average of their returns, not the average of their ranks.
i.e. I was doing
average_ranks=(1+3+7+4+3)/5
but you say
average_returns = (0.01 +0.09 +0.15 +0.10+0.19)/5
then:
rank = average_returns rank

That makes sense, here is the backtest.

Clone Algorithm
259
Loading...
Backtest from to with initial capital
Total Returns
--
Alpha
--
Beta
--
Sharpe
--
Sortino
--
Max Drawdown
--
Benchmark Returns
--
Volatility
--
Returns 1 Month 3 Month 6 Month 12 Month
Alpha 1 Month 3 Month 6 Month 12 Month
Beta 1 Month 3 Month 6 Month 12 Month
Sharpe 1 Month 3 Month 6 Month 12 Month
Sortino 1 Month 3 Month 6 Month 12 Month
Volatility 1 Month 3 Month 6 Month 12 Month
Max Drawdown 1 Month 3 Month 6 Month 12 Month
# Backtest ID: 597111b48f44b151fdd31762
There was a runtime error.

I still don't know why the alpha is so low compared with other similar strategies like this. Any one? https://www.quantopian.com/posts/global-market-rotation-strategy-buggy-implementation

I think it has to do with the performance of emerging ETFs, I used sector ETFs. I took out everything but the 3 month returns and the volatility. It performed a lot better. There's a leverage problem though, so it's not perfectly accurate right now.

Clone Algorithm
259
Loading...
Backtest from to with initial capital
Total Returns
--
Alpha
--
Beta
--
Sharpe
--
Sortino
--
Max Drawdown
--
Benchmark Returns
--
Volatility
--
Returns 1 Month 3 Month 6 Month 12 Month
Alpha 1 Month 3 Month 6 Month 12 Month
Beta 1 Month 3 Month 6 Month 12 Month
Sharpe 1 Month 3 Month 6 Month 12 Month
Sortino 1 Month 3 Month 6 Month 12 Month
Volatility 1 Month 3 Month 6 Month 12 Month
Max Drawdown 1 Month 3 Month 6 Month 12 Month
# Backtest ID: 59779e669e448e4e06de92c5
There was a runtime error.

Here is the performance with the sector etfs instead of emerging market. Interesting!

Clone Algorithm
259
Loading...
Backtest from to with initial capital
Total Returns
--
Alpha
--
Beta
--
Sharpe
--
Sortino
--
Max Drawdown
--
Benchmark Returns
--
Volatility
--
Returns 1 Month 3 Month 6 Month 12 Month
Alpha 1 Month 3 Month 6 Month 12 Month
Beta 1 Month 3 Month 6 Month 12 Month
Sharpe 1 Month 3 Month 6 Month 12 Month
Sortino 1 Month 3 Month 6 Month 12 Month
Volatility 1 Month 3 Month 6 Month 12 Month
Max Drawdown 1 Month 3 Month 6 Month 12 Month
# Backtest ID: 59779f2739718f4e1d752ccc
There was a runtime error.

I had to replace EDV with TLT. The partial fills from the stocks ordering were messing up the leverage. I'm sure there is a better way, to fix the problem and still trade EDV.

Clone Algorithm
259
Loading...
Backtest from to with initial capital
Total Returns
--
Alpha
--
Beta
--
Sharpe
--
Sortino
--
Max Drawdown
--
Benchmark Returns
--
Volatility
--
Returns 1 Month 3 Month 6 Month 12 Month
Alpha 1 Month 3 Month 6 Month 12 Month
Beta 1 Month 3 Month 6 Month 12 Month
Sharpe 1 Month 3 Month 6 Month 12 Month
Sortino 1 Month 3 Month 6 Month 12 Month
Volatility 1 Month 3 Month 6 Month 12 Month
Max Drawdown 1 Month 3 Month 6 Month 12 Month
# Backtest ID: 5977af183cbfe14e1efd5521
There was a runtime error.

When you introduce the volatility of the ETF, I think (might be wrong) that you are rewarding those with more vol. because you are adding it.

-ETF A has a 4% return, and 2% volatility = 0.7*4%+0.3*2%=2.8+0.6=3.4 Score
-ETF B has a 4% return , and 3% volatility = 0.7*4%+0.3*3%=2.8+0.9=3.7 Score

I did this based on your approach, but still not as profitable as yours

Clone Algorithm
7
Loading...
Backtest from to with initial capital
Total Returns
--
Alpha
--
Beta
--
Sharpe
--
Sortino
--
Max Drawdown
--
Benchmark Returns
--
Volatility
--
Returns 1 Month 3 Month 6 Month 12 Month
Alpha 1 Month 3 Month 6 Month 12 Month
Beta 1 Month 3 Month 6 Month 12 Month
Sharpe 1 Month 3 Month 6 Month 12 Month
Sortino 1 Month 3 Month 6 Month 12 Month
Volatility 1 Month 3 Month 6 Month 12 Month
Max Drawdown 1 Month 3 Month 6 Month 12 Month
# Backtest ID: 5978711dbcf2d651d7a146b1
There was a runtime error.

Also picking SHY instead of TLT may be a more accurate option

Start date of the EB code showing 800% is being changed to 2009. Tried this, same:

def initialize(context):  
    set_symbol_lookup_date('2004-01-31')  

@Blue So are you saying it is not trading until 2009?
@Ro FG You are exiting every time it is below the 200 day SPY, and putting it in EDV. It doesn't work as well as a safety because after the recession you get those signals, and it still goes up also.

I normalized the returns by dividing them by their volatility . I am not sure if this is correct. I also combined all the etfs from both strategies. I am trying to lower the drawdown, because the returns seem way to high. I wouldn't want to just invest in emerging etfs. What comes up must come down!

Clone Algorithm
259
Loading...
Backtest from to with initial capital
Total Returns
--
Alpha
--
Beta
--
Sharpe
--
Sortino
--
Max Drawdown
--
Benchmark Returns
--
Volatility
--
Returns 1 Month 3 Month 6 Month 12 Month
Alpha 1 Month 3 Month 6 Month 12 Month
Beta 1 Month 3 Month 6 Month 12 Month
Sharpe 1 Month 3 Month 6 Month 12 Month
Sortino 1 Month 3 Month 6 Month 12 Month
Volatility 1 Month 3 Month 6 Month 12 Month
Max Drawdown 1 Month 3 Month 6 Month 12 Month
# Backtest ID: 597b9621e3a3894f3b55fb86
There was a runtime error.

Relatively a flat strategy the last 3 years or so. Did really well up until 2010.

Clone Algorithm
259
Loading...
Backtest from to with initial capital
Total Returns
--
Alpha
--
Beta
--
Sharpe
--
Sortino
--
Max Drawdown
--
Benchmark Returns
--
Volatility
--
Returns 1 Month 3 Month 6 Month 12 Month
Alpha 1 Month 3 Month 6 Month 12 Month
Beta 1 Month 3 Month 6 Month 12 Month
Sharpe 1 Month 3 Month 6 Month 12 Month
Sortino 1 Month 3 Month 6 Month 12 Month
Volatility 1 Month 3 Month 6 Month 12 Month
Max Drawdown 1 Month 3 Month 6 Month 12 Month
# Backtest ID: 597b9782ae317c4f36b7bad4
There was a runtime error.

@EB I was saying the start date field changed to 2009 automatically. Clicking on that calendar after the test, there was a message to the effect of first available date for securities being traded, surely you've seen that a few times eh. If there's a log message about it as well, I missed it.

Switching to the second-most recent backtest above with apparent returns of 197, its profit per dollar was just 60 due to margin. A common problem. This version has apparent returns of 233 and profit per dollar is 232, so almost no margin. So not only is 233 higher than 197 but also 232 is higher than 60. Using profit per dollar activated|invested is the only way I know for comparing two algorithms apples-to-apples and seeing more clearly what they are really doing by neutralizing, or adjusting for, their use of capital, i.e. amount of risk. Maybe people don't go that route because of the reduced speed.

There were evidently so many partial fills (the cause of all that margin along with the inherent unpredictability that goes with it hand-in-hand, unintended margin with order_target_percent when there are partial fills) that I took an unusually extreme approach in reactivating close() by running an entire day before balance and again the morning of that monthly balance, as this, the first try. @Ro FG, you might want to use similar and see what happens in your version.

Clone Algorithm
8
Loading...
Backtest from to with initial capital
Total Returns
--
Alpha
--
Beta
--
Sharpe
--
Sortino
--
Max Drawdown
--
Benchmark Returns
--
Volatility
--
Returns 1 Month 3 Month 6 Month 12 Month
Alpha 1 Month 3 Month 6 Month 12 Month
Beta 1 Month 3 Month 6 Month 12 Month
Sharpe 1 Month 3 Month 6 Month 12 Month
Sortino 1 Month 3 Month 6 Month 12 Month
Volatility 1 Month 3 Month 6 Month 12 Month
Max Drawdown 1 Month 3 Month 6 Month 12 Month
# Backtest ID: 597ba96a3f6f2b53365603de
There was a runtime error.

interesting point. Dividing by the volatility lowers the drawdown, but the ratio returns/drawdown is worse.

Clone Algorithm
110
Loading...
Backtest from to with initial capital
Total Returns
--
Alpha
--
Beta
--
Sharpe
--
Sortino
--
Max Drawdown
--
Benchmark Returns
--
Volatility
--
Returns 1 Month 3 Month 6 Month 12 Month
Alpha 1 Month 3 Month 6 Month 12 Month
Beta 1 Month 3 Month 6 Month 12 Month
Sharpe 1 Month 3 Month 6 Month 12 Month
Sortino 1 Month 3 Month 6 Month 12 Month
Volatility 1 Month 3 Month 6 Month 12 Month
Max Drawdown 1 Month 3 Month 6 Month 12 Month
# Backtest ID: 59805238ea66af532117ef8c
There was a runtime error.

This version is the one that gives best results

Clone Algorithm
110
Loading...
Backtest from to with initial capital
Total Returns
--
Alpha
--
Beta
--
Sharpe
--
Sortino
--
Max Drawdown
--
Benchmark Returns
--
Volatility
--
Returns 1 Month 3 Month 6 Month 12 Month
Alpha 1 Month 3 Month 6 Month 12 Month
Beta 1 Month 3 Month 6 Month 12 Month
Sharpe 1 Month 3 Month 6 Month 12 Month
Sortino 1 Month 3 Month 6 Month 12 Month
Volatility 1 Month 3 Month 6 Month 12 Month
Max Drawdown 1 Month 3 Month 6 Month 12 Month
# Backtest ID: 59804d00ea66af532117ef44
There was a runtime error.