Navigation: Examples and Tutorials >

Tutorial 4 - ETF Rotation





In this next tutorial, a more elaborate backtest script will be introduced.

Please close all currently open windows, and then open the file sector_etfs.rts from the Examples directory.

The above is, of course, a partial screenshot. This script is longer than the prior examples, and there's a lot going on, so take some time to study it carefully.

This example contains elements introduced in prior tutorials, including Import, Settings, Parameters, Data and Strategy sections.

Two new sections are introduced here, which are both derivations of Strategy: Template and Benchmark.

The Strategy section is where a trading strategy is defined for the purpose of backtesting it, as seen in the first two tutorials.

The Template section is an optional element that can be used to avoid repeating the same elements in multiple strategies. In other words, it is where you might define any elements that are common to more than one strategy. In this example, the Template called "base" is only used by one strategy, so it doesn't serve any purpose besides illustrating what a Template is.

In fact, this part of the script:

could just as easily have been written as follows, with the template omitted:

The two snippets above are functionally identical. The Using: base statement in the first snippet instructs the script parser to copy all the elements from the base template and insert them in the sector_etfs strategy. The idea behind this is to use "Template: base" for strategy elements such as Commission and Slippage that are often the same for every strategy.

In contrast to Template, a Benchmark section defines a strategy that will be included as a separate entity in the backtest. It is "traded" for each date in the test just as a regular strategy is and will generate its own statistics and be given its own equity curve. The only difference between a benchmark and a strategy is that the benchmark's stats are not counted as part of the combined results of the backtest.

In this script example, the benchmark is used to simply generate an equity curve for the SPY ETF in a buy-and-hold simulation, to make it easy to visually compare the strategy's equity curve to this common benchmark:

(Because Yahoo data is not dividend-adjusted but does include specific dividend amounts and dates, in order for the SPY dividends to be re-invested, the benchmark simulates exiting and re-entering the SPY position on each morning after an ex-dividend date.)

Now on to the specific strategy and its implementation in this script.

The concept is to trade the 9 standard sector ETFs derived from components of the S&P 500 index (XLB, XLE, XLF, XLI, XLK, XLP, XLU, XLV, XLY) using a monthly rotational rule based on momentum. The Data section defines all the variables needed to implement this strategy. Parameters are used in data formulas to enable some optimization.

Strength is simply the ratio of the current close to the lowest close in some number of days (63 by default, i.e., one calendar quarter)

MomoRank uses the cross-sectional rank function to calculate the strength's rank for each ETF for each date relative to the other ETFs on that date

ValueRank is the inverse of MomoRank

MyRank selects which of the above two ranks to use depending on the Momo parameter (allows comparison of momentum vs. mean-reversion as the ranking criterion)

Note also that these two rank calculations deliberately exclude the SPY benchmark from the top ranks by checking the InList name in the rank formula

Rotate evaluates to TRUE (1) for the last trading day of each month

The strategy is defined to use the above data items as follows:

EntrySetup must evaluate to TRUE (1) for there to be an entry at the next open. It will evaluate to TRUE for each ETF that is not SPY and whose rank is low enough (1 is top-ranked) to be within the MaxPositions threshold. All this will only occur if the next open will be the first open of a new month. The three clauses of the EntrySetup formula and the data elements that they refer to suffice to specify all of these factors.

ExitRule is one of several exit elements a strategy can have (in this case it's the only one). This rule simply says to exit if it's a new month and the ETF is no longer among the top ranked ETFs.

Quantity specifies the position size, in percent of current equity. S.Equity is the current account balance (including mark-to-market, i.e., net liquidation value) on any given date during the test, so this formula is simply a percentage of equity based on the Positions parameter.

To see all of this in action, first run this script first as  and then as  as we did in the first tutorial.

A results window will appear with a new line for the test results (yours will be slightly different):

Not very promising. Let's open the equity graph to see how it looks in more detail (double-click on the above row):

(Note that you can use the L key to toggle between Log scale and Arithmetic scale, or press the right mouse button on the graph to see this and other options on its menu.)

This graph shows the purpose of the SPY benchmark. Buy and hold SPY is not included in the reported 5.04% ROR or 50.98% MaxDD. Those are the stats for the ETF strategy alone. But the SPY benchmark is included in the above graph as the red line, showing that, overall, this ETF rotational strategy did not beat buy-and-hold of the index, though prior to 2014 it was slightly ahead.

Since we have some parameters, we can optimize them to see how that will affect the results. Click on  and then just select the Lookback parameter for now:

Run the 5 tests and look at the results:

Double-click on the top row (252 bars, a one-year lookback) to show how this parameter has slightly out-performed one we tested initially (63 bars, a one-quarter lookback):

Now if you want to go nuts with data mining, go back into Optimize and check all 3 parameter boxes.

Run all 50 tests and sort by net profit to see what would have worked best:

Now the rotation is substantially beating the benchmark. But which parameters were the winners?

Apparently relative weakness (mean reversion) did better than relative strength (momentum) in this case.

In fact, the top 17 results are all using this anti-momentum factor:

This is a good example of how we can sometimes learn something from an optimization, even if the goal is not (and should never be) to over-fit the parameters to the data for actual trading.

This is the end of the fourth and final written tutorial in this User Guide.

A series of video tutorials can be found on the mhptrading youtube channel.





Copyright © 2020-2024 Systematic Solutions, LLC