Previous: Trend Trading

Workshop 5: Counter-Trend Trading, Optimization, Walk Forward Analysis.

Bob: Last month I ran into Warren Buffett and asked him for a trading advice. That's what he said: 'Be greedy when others are fearful'.
Alice: Interesting. And what does it mean?
Bob: He didn't tell, but went away. But I think he wants me to go against the trend.
Alice: Isn't that just the opposite of your last strategy?
Bob: You got it. Please automatize this. Prices often move up and down in cycles. You must check if the price is close to the bottom or top of a cycle. This is the right moment to buy or sell.
Alice: I can use a bandpass filter for cutting off the trend and the noise, and getting a clean price cycle.
Bob: Sounds good.
Alice: For finding how close the cycle is to its peaks, I can normalize it to a fixed range, and transform it to a Gaussian distribution. This makes the peaks of the cycle relatively sharp and well defined, so we won't get too many false signals.
Bob: I have no idea what you're talking about. But when it's sharp and well defined, I like it.

The counter trend algorithm

This is Alice's counter trend trading script (Workshop5):

function run()
{
  BarPeriod = 240;  // 4 hour bars
  LookBack = 500;   // maximum indicator time period
  set(PARAMETERS);  // generate and use optimized parameters
  StartDate = 2005;
  NumWFOCycles = 10;
  if(ReTrain) {
    UpdateDays = -1; 
    SelectWFO = -1; 
  }
 
// calculate the buy/sell signal with optimized parameters
  vars Price = series(price(0));
  vars Filtered = series(BandPass(Price,optimize(30,20,40),0.5));
  vars Signal = series(FisherN(Filtered,500));
  var Threshold = optimize(1,0.5,1.5,0.1);
 
// buy and sell
  Stop = optimize(4,2,10) * ATR(100);
  Trail = 4*ATR(100);
 
  if(crossUnder(Signal,-Threshold))
    enterLong(); 
  else if(crossOver(Signal,Threshold))
    enterShort();
 
// plot signals and thresholds
  plot("Filtered",Filtered,NEW,BLUE);
  plot("Signal",Signal,NEW,RED);
  plot("Threshold1",Threshold,0,BLACK);
  plot("Threshold2",-Threshold,0,BLACK);
  PlotWidth = 600;
  PlotHeight1 = 300;
}

Since counter trend trading is affected by market cycles and more sensitive to the bar period than trend trading, Alice has set the bar period to a fixed value of 4 hours, or 240 minutes. PARAMETERS is a flag - similar to the LOGFILE flag that we know from the last workshop - that tells Zorro to generate and use optimized parameters. LookBack must be set to the 'worst case' lookback time of the strategy. Since the lookback time depends on an optimized parameter, Zorro can here not determine it in advance, so we should make it a habit to set the LookBack variable directly when we optimize a strategy. In this case we set it to the 500 bars required for the later used FisherN function.

In this strategy, a bandpass filter is fed with the price curve. The BandPass function is similar to the LowPass function except that it also dampens high frequencies, i.e. short cycles. Its frequency curve can be examined in the Filters chapter. This way the trend (a cycle with a very long period) and the noise (short period cycles) are removed from the price curve. The result is a clean curve that consists mostly of the medium-period peaks and valleys. It's stored in a new series named Filtered.

The center period of the BandPass filter is set from the return value of an optimize function. Its first parameter is the default value, which is 30. The next two numbers, 20 and 40, are the parameter range, i.e. the lower and upper limit of the time period. So the BandPass time period will be optimized between 20 to 40. During the optimization process, Zorro will try to find not the best, but the most robust time period within this range.

Just like the original prices, the values of the Filtered price curve are still all over the place. For generating a trade signal they must be normalized, i.e. 'compressed' to a defined range. The Fisher Transformation transforms a curve into a Gaussian distribution - that's the famous 'bell curve' distribution where most values are in the center and only few values are outside the +1...-1 range. Normalization and Fisher transformation are done with the FisherN function. It uses the last 500 bars for the normalization.

The resulting Signal series can now finally be compared with an upper and lower Threshold for generating trade signals. The Threshold is optimized between 0.5 and 1.5 in steps of 0.1. Alice's intention is to let any Signal value that exceeds the threshold range trigger a trade. Before that, Alice places a stop loss at an adaptive distance from the price, just as in the previous trend trading script. The ATR function is again used to determine the stop loss distance with an optimized factor. Additionally to the stop loss, Alice has also placed a trail limit 4 average candles away from the current price.

If the trade now goes in favorable direction by more than 4 average candles, the stop loss will follow the price at a distance of 8 candles. This ensures that all trades that reach an 8 candle profit are guaranteed to end with a win, regardless how the price further behaves. 

When the Signal curve crosses the negative threshold from above - meaning when Signal falls below -1 - the price is supposedly close to the bottom of the main cycle, so Alice expects the price to rise, and buys long. When the threshold is crossed from below - meaning Signal rises above 1 - the price is close to a peak and she buys short. This is just the opposite of what she did in trend trading. For identifying the threshold crossing she uses the crossOver() and crossUnder() functions.

Training with Walk Forward Optimization

Training serves two purposes. At first, it improves the 'robustness' of a strategy. During the training run, strategy parameters are optimized and adapted to the market until the strategy returns stable profits with minimum deviation. The second purpose is finding out how sensitive the system is to small parameter changes. The more sensitive, the less likely is it that backtest results are reproduced in live trading.

Alice used Walk-Forward Optimization (WFO), which is not merely an optimization, but an analysis method that tests the strategy together with its parameter ranges and optimization method. If a strategy fails in a walk forward analysis, it will also fail in real trading, even if it collected huge profits in backtests. For this reason, walk forward optimization is the most important process when developing a strategy.

WFO is activated by setting NumWFOCycles. It uses a data frame that is shifted in 10 cycles over the simulation period. The frame consists of a training period and a subsequent test as in the figure here. The lookback periods at the begin are needed to collect initial data for the functions. The training periods generate the parameters that are then tested in the subsequent test periods. This ensures that every test uses "unseen" price data that were not used for optimizing its parameters - just as in real trading. The data frame is then shifted over the simulation period for verifiying how the strategy would fare when started at different times. Because the test period is now much smaller than the whole simulation period, Alice has set a far backStartDate = 2005. This way enough data can be collected for getting a test period from 2010 to 2015.

For training the strategy, click [Train] and observe what the optimize calls do. It now takes a few minutes because the simulation period is about 10 years, and a full optimization is performed for any of the 10 cycles. The optimized parameters are stored in a separate parameter file for every WFO cycle. After the training phase, which can take about one minute depending on the PC speed, you'll see charts pop up in your Internet browser, like this:

Parameter 1 (bandpass time period)
 
Parameter 2 (Threshold)
 
Parameter 3 (Stop factor)

The parameter charts show how the parameter values affect the performance of the strategy. The red bars are the return ratio of the training period - that's basically the total win divided by the total loss, multiplied by a penalty factor for less trades. The dark blue bars are the number of losing trades and the light blue bars are the number of winning trades. We can see that the time period produces slightly increasing returns up to about 35, then the returns go down. Threshold has the best performance at about 1.0. The stop factor - the third parameter - slightly goes up and has a maximum at about 7. We can also see here that a distant stop, although it increases the risk and eventually reduces the profit, achieves a higher number of profitable trades and thus a better 'accuracy' of the strategy.

All red bars ending above 1.0 indicate a profitable parameter combination. In this case they stay above 1.0 over the whole range, which means that the strategy performance is quite robust and not very sensitive to parameter changes. The optimized parameters are stored in the file Data/Workshop5_EURUSD.par (the file name would be different for other assets).

After training, click [Test]. The data from the training is now used for a walk forward analysis. This is the equity curve:

We can see that the strategy still stays profitable with walk forward analysis, but the equity curve does not look smooth and the return in 2013 and 2015 was negative. In the next workshop we'll learn how to make strategy returns more steady and reliable so that Bob can really derive a regular income from them.

Real time optimizing a WFO strategy

When trading a walk forward optimized strategy, it should be regularly re-trained and adapted to the current market situation, just as in the WFO process. For this, Alice has added the ReTrain clause to the script. ReTrain is nonzero when the [Train] button is clicked during live trading. UpdateDays is the time period for automatically downloading new price data for the current asset from the broker's server, which is then used for the subsequent training cycle. If set to -1, the price data is updated to the current date. SelectWFO tells Zorro not to optimize the whole simulation period, but only a certain WFO cycle; in this case, the last cycle (-1) that is used for live trading.

Clicking [Train] every couple of months (as indicated by "WFO test cycles" in the performance report) will continue the WFO process during trading, and make the strategy independent of external parameter settings. This way we have essentially a 'parameter-free' strategy.

Plotting signals

Since the trade rules are somewhat more complicated than the simple lowpass function of the previous lesson, Alice needs to see how the various series look like, for checking if everything works as supposed. This happens in the last lines at the end of the script.

plot("Filtered",Filtered,NEW,BLUE);

This line generates a plot of the Filtered series. It's plotted in a NEW chart window with color BLUE. We can use the plot function to plot anything into the chart, either in the main chart with the price and equity curve, or below the main chart in a new window. The Signal curve and the upper and lower Threshold are plotted in another new chart window below the chart:

The blue curve in the middle window is the plot of the Filtered series. It shows the price fluctuation in the range of about +/-0.005, equivalent to about 50 pips. The bottom window displays the Signal series. The black lines are the thresholds that trigger buy and sell signals when Signal crosses over or under them. Plotting variables and series in the chart greatly helps to understand and improve the trade rules. For examining a part of the chart in details, the PlotDate and PlotBars variables can be used to 'zoom into' a part of the chart.

What have we learned in this workshop?

Next: Portfolio Trading


Further reading: ► Training, plot, signal processing, optimize, NumWFOCycles