The Trend Experiment

This is the second part of the trend experiment article series, involving 900 systems and 10 different “smoothing” or “low-lag” indicators for finding out if trend really exists and can be exploited by a simple algorithmic system. When you do such an experiment, you have normally some expectations about the outcome, such as:

  • Trend exists, but is difficult to detect and to exploit. The experiment will find only a few profitable and a lot more unprofitable systems (with realistic trade costs).
  • More sophisticated indicators, such as the Decycler or the Lowpass filter, will produce better results than the old SMA, EMA, or HMA. Modern indicators have less lag and thus react faster on the begin and end of a trend.
  • White’s Reality Check will reveal a data mining bias rather close to the returns of the best systems from the experiment. If algorithmic trend trading were easy, anyone would be doing it.
  • EUR/USD will return better results because according to trader’s wisdom, currencies are “more trending”.

However the results were quite a surprise.

The Trend Test System

This is the script Trend.c used for the trend experiment:

var objective() 
{ 
  return WinTotal/max(1,LossTotal); // Profit factor
}

var filter(var* Data,int Period);

void run()
{
  set(PARAMETERS|LOGFILE);
  PlotHeight1 = 200;
  PlotScale = 8;
  ColorBars[1] = BLACK; // winning trades
  ColorBars[2] = GREY; // losing trades

  StartDate = 2010;
  BarPeriod = 15;
  LookBack = 80*4*24; // 80 trading days ~ 4 months
	
  while(asset(loop("EUR/USD","SPX500","XAG/USD")))
  while(algo(loop("M15","H1","H4")))
  {
    if(Algo == "M15")
      TimeFrame = 1; // 15 minutes
    else if(Algo == "H1")
      TimeFrame = 4; // 1 hour
    else if(Algo == "H4")
      TimeFrame = 16;	// 4 hours

    int Periods[10] = { 10,20,50,100,200,500,1000,2000,5000,10000 };
    int Period = Periods[optimize(0,0,9,1)];
		
    vars Prices = series(price());
    vars Smoothed = series(filter(Prices,Period));

    if(valley(Smoothed))
      enterLong();
    else if(peak(Smoothed))
      enterShort();
  } 
}

This script is supposed to run in Zorro’s “Train” mode. We’re not really training the systems, but Train mode produces parameter histograms, and that’s what we want. The script is basically the same as described in the previous article, but two asset and algo loops are now used for cycling through three different assets (EUR/USD, S&P 500, and Silver) and three time frames (15 minutes, 1 hour, 4 hours). The optimize function selects the time period of the smoothing indicator, in 10 steps from 10 to 10,000 time frames. The meaning of the Zorro-specific functions like asset, algo, loop, optimize can be found in the Zorro manual.

6 years of price history from 2010 to 2015 are used for the simulation. The default trade costs – commission, bid/ask spread, and rollover – are taken from the average 2015 parameters of a FXCM microlot account. FXCM is not the cheapest broker, so the expectation value of a random-trading simulation is not zero, but a loss, dependent on the number of trades. For comparing results we’re using the profit factor, calculated in the objective function. The script calls a filter function that is defined as a prototype, and contained in a main script that includes Trend.c. So any of the indicators is represented by a very short main script like this (TrendLowpass.c):

#include "Strategy\Trend.c"

var filter(var* Data,int Period)
{
  return LowPass(Data,Period);
}

All the scripts can be downloaded from the scripts2015 archive at the sidebar. There’s also a batch file included that starts them all and lets them run in parallel.

The Results

When you select one of the scripts and click Zorro’s  [Train] button, it will grind its wheels about 10 minutes and then spit out a sheet of histograms like this (for the ZMA):

ZMA

We got 9 histograms from the combinations of EUR/USD, S&P 500, and Silver (horizontally) with bar sizes of 15 minutes, 1 hour, and 4 hours. The red bars are the objective return – in this case, the profit factor,  total win divided by total loss. If they are above 1.0 (left scale), the system was profitable. The black and grey bars are the number of winning and losing trades (right scale). The steps on the X axis are the indicator time period; they normally don’t go all the way to 10 because systems are discarded when the time period exceeded 4 months or the system entered less than 30 trades. That’s why the experiment didn’t produce 900 systems, but only 705.

We can see that the profit generally increases, and the number of trades decreases with the time frame. As typical for trend trading systems we got far more losing trades (grey) than winning trades (black). 13 of the 82 systems in the histograms above have been profitable, 69 were losers. Most of the profitable systems traded EUR/USD. Only one S&P 500 system, and only three silver trading systems produced any profit. Here’s a statistic of all winners and losers from the 705 tested systems:

Asset, Period, Indicator Rate Total Won Lost
EUR/USD 38% 237 89 148
S&P 500 3% 237 6 231
Silver 21% 231 48 183
15 Minutes 14% 297 41 256
1 Hour 20% 239 48 191
4 Hours 32% 169 54 115
ALMA 16% 64 10 54
Decycle 15% 74 11 63
EMA 20% 69 14 55
HMA 25% 63 16 47
Laguerre 31% 32 10 22
LinearReg 26% 74 19 53
Lowpass 20% 71 14 57
SMA 23%  70  16  54
Smooth 19% 108 20 88
ZMA 16% 82 13 69

Since the results are for 2010-2015, you might get different figures when testing different time periods. The Rate column shows the percentage of successful systems. We got a mix of expected and unexpected results. Almost 40% of the EUR/USD systems are winners,  which seems to confirm that currencies tend to trend. The S&P 500 index however is not trending at all –  and this despite the fact that it shows the most significant trend in the long run, as visible in the title image. But here we’re looking for shorter term trends that can be exploited by day trading. Silver, with 20% winners, has at least some trend. Longer time frames produce dramatically better results, mostly due to less trade costs, but also partly because trend seems to prefer long cycles and low frequencies. (You can see that the difference comes not from trade costs alone when you test the systems with spread, commission, slippage, and rollover set to zero). 1-day bar periods would be even more profitable. But I haven’t included them in the test because they produce not enough trades for statistical significance.

The indicators show a surprising behavior. The old traditional indicators put up a good fight. Ehler’s smoothing, decycling, and zero-lag indicators, produce less profitable systems than their classic counterparts. However we’ll see later that the modern indicators are in fact more profitable, although within a smaller parameter range. But they all occupy the top of the profit list. The best systems, with modern indicators and long time frames, have profit factors up to 2.

Does this mean that we can put them together in a compound system and will get rich? I don’t know, because I haven’t determined yet the Data Mining Bias produced by this experiment. For this we need to store and randomize the balance curves, and apply White’s Reality Check. This will be the topic of the next article of the Trend Experiment series.

Conclusion

  • Different markets show very different behavior. EUR/USD and silver are significantly more profitable with short-term trend following than S&P500.
  • Low-lag smoothing indicators have a smaller profitable parameter range than traditional indicators, but produce higher profits.

9 thoughts on “The Trend Experiment”

  1. Hi,

    great work, but please help me to understand one thing.
    Your are saying, that you are testing 900 systems; my understanding is that the optimization chooses of the 10 parameters parameters. So are you testing 90 systems (optimized though) or 900 and my understanding of the optimization is wrong?

  2. It is 900 systems and no optimization. The optimize function is used here not for optimization, but for generating variants of systems.

  3. Is it possible to access the results of EVERY trade during the generation of the variants, I see you can use “balance” and other general trading variables. But I’d like to have a file like the testtrades file, when doing a test.

  4. Yes, with a different script that writes the trade results in a log file. By default, individual trade results are not logged in train mode, only in test and trade mode.

  5. What is your experiment and data accuracy?
    What is this situation? Spread, commission, slippage, rollover

  6. Hi Johann,

    is it me or the Trend.c has a bug in the code:

    else if(Algo == “H4”)
    TimeFrame = 6; // 4 hours

    Shouldn’t it be: TimeFrame = 16?

  7. “The S&P 500 index however is not trending at all – and this despite the fact that it shows the most significant trend in the long run, as visible in the title image. But here we’re looking for shorter term trends that can be exploited by day trading. ”

    How should I modify the test if I’m interesting in looking for trends that I can exploit with trades that last a week to a month?

    Thanks for such an insightful article.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.