Robot Example 4 – Range Breakout

0

Prompted by the Forex Espionage "Advanced" System here is a robot based around a range breakout system.  It is a much simplified version of the original Turtle Trading system provided to his students by Richard Dennis way back in 1984.  It enters a trade on a breakout from the range of a number of consecutive bars.  It then exits the trade on a breakout in the opposite direction from the range of a smaller number of bars.

To get an initial feel for the system used by the legendary Turtle Traders try out this expert advisor using daily bars and the default input settings with the Long Period set to 55 and the Short Period set to 20.   You may also wish to try other timeframes and other input settings.  Does this type of system show any promise for day trading, for example?

Since this example is for a long term trend following system our initial backtests cover a long period of time! Here are the results from the MetaTrader 4 strategy tester starting on January 1st 2000, using the EUR/USD pair and the default input settings with daily bars:

Strategy Tester Report
GuruEx04
Symbol EURUSD (Euro vs US Dollar)
Period Daily (D1) 2000.01.03 00:00 – 2009.06.12 00:00 (2000.01.01 – 2009.06.13)
Model Every tick (the most precise method based on all available least timeframes)
Parameters Magic=12348; Slippage=30; Lots=0.1; LongPeriod=55; ShortPeriod=20;
Bars in test 3469 Ticks modelled 21721141 Modelling quality n/a
Mismatched charts errors 20103
Initial deposit 500.00
Total net profit 3021.91 Gross profit 8016.85 Gross loss -4994.94
Profit factor 1.60 Expected payoff 73.71
Absolute drawdown 288.05 Maximal drawdown 2083.86 (39.06%) Relative drawdown 74.01% (603.69)
Total trades 41 Short positions (won %) 18 (38.89%) Long positions (won %) 23 (52.17%)
Profit trades (% of total) 19 (46.34%) Loss trades (% of total) 22 (53.66%)
Largest profit trade 858.80 loss trade -861.00
Average profit trade 421.94 loss trade -227.04
Maximum consecutive wins (profit in money) 2 (1268.41) consecutive losses (loss in money) 3 (-800.00)
Maximal consecutive profit (count of wins) 1268.41 (2) consecutive loss (count of losses) -1312.78 (2)
Average consecutive wins 1 consecutive losses 2

Backtest Results for a Range Breakout Trading System for the Last Decade

# Time Type Order Size Price S / L T / P Profit Balance
1 2000.01.27 13:36 sell 1 0.10 0.99847 0.00000 0.00000
2 2000.02.22 16:53 close 1 0.10 1.00623 0.00000 0.00000 -80.72 419.28
3 2000.02.28 04:26 sell 2 0.10 0.96646 0.00000 0.00000
4 2000.05.26 16:43 close 2 0.10 0.92014 0.00000 0.00000 451.50 870.78
5 2000.09.06 02:13 sell 3 0.10 0.87170 0.00000 0.00000
6 2000.12.01 00:52 close 3 0.10 0.88018 0.00000 0.00000 -96.24 774.54
7 2000.12.20 00:52 buy 4 0.10 0.90878 0.00000 0.00000
8 2001.02.15 02:11 close 4 0.10 0.90590 0.00000 0.00000 -22.90 751.64
9 2001.03.15 00:37 sell 5 0.10 0.89820 0.00000 0.00000
10 2001.07.18 16:31 close 5 0.10 0.86687 0.00000 0.00000 297.31 1048.95
11 2001.08.02 03:19 buy 6 0.10 0.88398 0.00000 0.00000
12 2001.09.06 09:20 close 6 0.10 0.88370 0.00000 0.00000 0.70 1049.65
13 2001.09.14 14:34 buy 7 0.10 0.92468 0.00000 0.00000
14 2001.10.11 12:56 close 7 0.10 0.90566 0.00000 0.00000 -187.50 862.15
15 2001.11.13 14:40 sell 8 0.10 0.88190 0.00000 0.00000
16 2001.12.12 19:57 close 8 0.10 0.89898 0.00000 0.00000 -174.57 687.58
17 2002.01.25 10:55 sell 9 0.10 0.87300 0.00000 0.00000
18 2002.03.07 09:00 close 9 0.10 0.88089 0.00000 0.00000 -84.23 603.35
19 2002.04.17 10:03 buy 10 0.10 0.88753 0.00000 0.00000
20 2002.08.06 09:58 close 10 0.10 0.97230 0.00000 0.00000 858.80 1462.15
21 2002.09.17 10:50 sell 11 0.10 0.96196 0.00000 0.00000
22 2002.10.10 10:53 close 11 0.10 0.99208 0.00000 0.00000 -304.45 1157.70
23 2002.11.05 09:13 buy 12 0.10 1.00114 0.00000 0.00000
24 2002.11.23 11:22 close 12 0.10 0.98835 0.00000 0.00000 -126.00 1031.70
25 2002.12.12 15:51 buy 13 0.10 1.01848 0.00000 0.00000
26 2003.03.17 16:50 close 13 0.10 1.06868 0.00000 0.00000 511.30 1543.00
27 2003.04.30 01:42 buy 14 0.10 1.10939 0.00000 0.00000
28 2003.06.19 04:11 close 14 0.10 1.16250 0.00000 0.00000 536.30 2079.30
29 2003.07.16 01:54 sell 15 0.10 1.11508 0.00000 0.00000
30 2003.09.12 15:48 close 15 0.10 1.12778 0.00000 0.00000 -134.80 1944.50
31 2003.09.29 17:01 buy 16 0.10 1.15592 0.00000 0.00000
32 2003.11.03 16:12 close 16 0.10 1.15410 0.00000 0.00000 -14.70 1929.80
33 2003.11.18 16:09 buy 17 0.10 1.18670 0.00000 0.00000
34 2004.02.27 11:06 close 17 0.10 1.23790 0.00000 0.00000 522.30 2452.10
35 2004.03.02 17:00 sell 18 0.10 1.22932 0.00000 0.00000
36 2004.05.27 14:25 close 18 0.10 1.21875 0.00000 0.00000 94.26 2546.36
37 2004.07.07 07:54 buy 19 0.10 1.23577 0.00000 0.00000
38 2004.07.27 16:19 close 19 0.10 1.20610 0.00000 0.00000 -294.70 2251.66
39 2004.10.15 14:41 buy 20 0.10 1.24496 0.00000 0.00000
40 2005.01.07 16:08 close 20 0.10 1.31518 0.00000 0.00000 710.60 2962.26
41 2005.02.04 14:52 sell 21 0.10 1.29170 0.00000 0.00000
42 2005.02.22 04:18 close 21 0.10 1.31278 0.00000 0.00000 -212.88 2749.38
43 2005.05.12 08:56 sell 22 0.10 1.27637 0.00000 0.00000
44 2005.08.03 11:02 close 22 0.10 1.22618 0.00000 0.00000 491.37 3240.75
45 2005.09.01 14:27 buy 23 0.10 1.24938 0.00000 0.00000
46 2005.09.19 00:08 close 23 0.10 1.21570 0.00000 0.00000 -335.20 2905.55
47 2005.10.03 03:07 sell 24 0.10 1.19497 0.00000 0.00000
48 2005.12.12 13:52 close 24 0.10 1.19031 0.00000 0.00000 37.50 2943.05
49 2006.01.06 14:52 buy 25 0.10 1.21738 0.00000 0.00000
50 2006.02.03 14:59 close 25 0.10 1.20048 0.00000 0.00000 -166.20 2776.85
51 2006.04.06 10:59 buy 26 0.10 1.23237 0.00000 0.00000
52 2006.06.08 14:33 close 26 0.10 1.26895 0.00000 0.00000 372.10 3148.95
53 2006.07.18 16:47 sell 27 0.10 1.24769 0.00000 0.00000
54 2006.08.04 14:31 close 27 0.10 1.28365 0.00000 0.00000 -362.07 2786.88
55 2006.08.21 16:01 buy 28 0.10 1.29351 0.00000 0.00000
56 2006.09.08 14:37 close 28 0.10 1.26947 0.00000 0.00000 -238.40 2548.48
57 2006.10.10 11:05 sell 29 0.10 1.25560 0.00000 0.00000
58 2006.10.31 16:08 close 29 0.10 1.27528 0.00000 0.00000 -199.53 2348.95
59 2006.11.10 09:54 buy 30 0.10 1.28804 0.00000 0.00000
60 2007.01.05 14:30 close 30 0.10 1.30508 0.00000 0.00000 176.00 2524.95
61 2007.03.16 02:12 buy 31 0.10 1.32980 0.00000 0.00000
62 2007.05.10 18:58 close 31 0.10 1.34800 0.00000 0.00000 187.50 2712.45
63 2007.06.13 02:37 sell 32 0.10 1.32860 0.00000 0.00000
64 2007.07.02 09:36 close 32 0.10 1.35558 0.00000 0.00000 -272.27 2440.18
65 2007.07.10 15:15 buy 33 0.10 1.36863 0.00000 0.00000
66 2007.08.13 16:56 close 33 0.10 1.36070 0.00000 0.00000 -75.90 2364.28
67 2007.09.12 07:21 buy 34 0.10 1.38576 0.00000 0.00000
68 2007.12.14 12:22 close 34 0.10 1.45240 0.00000 0.00000 675.90 3040.18
69 2008.02.26 20:34 buy 35 0.10 1.49541 0.00000 0.00000
70 2008.05.01 10:44 close 35 0.10 1.55136 0.00000 0.00000 566.20 3606.38
71 2008.07.11 15:29 buy 36 0.10 1.59108 0.00000 0.00000
72 2008.07.29 16:12 close 36 0.10 1.56103 0.00000 0.00000 -298.90 3307.48
73 2008.08.08 02:02 sell 37 0.10 1.53010 0.00000 0.00000
74 2008.09.22 20:46 close 37 0.10 1.48129 0.00000 0.00000 482.51 3789.99
75 2008.10.02 09:26 sell 38 0.10 1.38798 0.00000 0.00000
76 2008.12.11 06:27 close 38 0.10 1.30848 0.00000 0.00000 785.90 4575.89
77 2008.12.17 05:50 buy 39 0.10 1.41518 0.00000 0.00000
78 2009.01.13 06:42 close 39 0.10 1.32881 0.00000 0.00000 -861.00 3714.89
79 2009.02.18 15:49 sell 40 0.10 1.25479 0.00000 0.00000
80 2009.03.16 11:02 close 40 0.10 1.29963 0.00000 0.00000 -451.78 3263.11
81 2009.05.20 15:43 buy 41 0.10 1.37395 0.00000 0.00000
82 2009.06.12 13:54 close at stop 41 0.10 1.39958 0.00000 0.00000 258.80 3521.91

Here's the source code for this "robot":

//+------------------------------------------------------------------+
//|                                                     GuruEx04.mq4 |
//|     Copyright © 2009, Marketing Dreams Ltd. All Rights Reserved. |
//|                                         http://trading-gurus.com |
//|                                                                  |
//| GuruTrader™ example 4                                            |
//| Version 1.0                                                      |
//|                                                                  |
//| A basic range breakout system                                    |
//| Based on the original Turtle Trading system                      |
//|                                                                  |
//| Wealth Warning! This expert is for educational purposes only.    |
//| It should NEVER be used on a live account. Past performance is   |
//| in no way indicative of future results!                          |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2009, Marketing Dreams Ltd."
#property link      "http://trading-gurus.com"
#define SLEEP_OK     250
#define SLEEP_ERR    250
//---- input parameters
extern int     Magic = 12348;
extern int     Slippage=30;
extern double  Lots=0.1;
extern int     LongPeriod=55;
extern int     ShortPeriod=20;
//---- static variables
static int     Dig;
static double  Points;
static bool    Initialized = FALSE;
static bool    Running = FALSE;
static bool    Long = FALSE;
static double  LongMax;
static double  LongMin;
static double  ShortMax;
static double  ShortMin;
static int     LastBar;
static int     OrderNumber;
static double  PositionSize;
static color   clBuy = DodgerBlue;
static color   clSell = Crimson;
//+------------------------------------------------------------------+
//| Utility functions                                                |
//+------------------------------------------------------------------+
#include <stdlib.mqh>
#include <stderror.mqh>
#include <WinUser32.mqh>
//+------------------------------------------------------------------+
//| Expert helper functions                                          |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Closes an order at market                                        |
//+------------------------------------------------------------------+
int CloseMarket(int Ticket)
{
   int    Type, ErrorCode;
   double Price, Quantity;
   OrderSelect(Ticket, SELECT_BY_TICKET);
   Type = OrderType();
   Quantity = OrderLots();
   while (TRUE) {             // Keep trying until the order really is closed
      if (Type == OP_BUY)
         Price=Bid;
      else if (Type == OP_SELL)
         Price=Ask;
      else
         return (-1);
      Print("CLOSE ", Ticket, ", ", Quantity, ", ", Price);
      if (OrderClose(Ticket, Quantity, Price, Slippage, CLR_NONE) == TRUE) {
         Sleep(SLEEP_OK);
         return (0);
      }
      else {
         ErrorCode = GetLastError();
         Print("Error closing order ", Ticket, ": ", ErrorDescription(ErrorCode),
               " (", ErrorCode, ")", " size: ", Quantity, ", prices: ",
               Price, ", ", Bid, ", ", Ask);
         Sleep(SLEEP_ERR);
         RefreshRates();
      }
   }
   return (-1);
}
//+------------------------------------------------------------------+
//| Places an order                                                  |
//+------------------------------------------------------------------+
int Order(string symbol, int Type, double Entry, double Quantity,
          double TargetPrice, double StopPrice, string comment="")
{
   string TypeStr;
   color  TypeCol;
   int    ErrorCode, Ticket;
   double Price, FillPrice;
   Price = NormalizeDouble(Entry, Dig);
   switch (Type) {
      case OP_BUY:
         TypeStr = "BUY";
         TypeCol = clBuy;
         break;
      case OP_SELL:
         TypeStr = "SELL";
         TypeCol = clSell;
         break;
      default:
         Print("Unknown order type ", Type);
         break;
   }
   Ticket = OrderSend(symbol, Type, Quantity, Price, Slippage,
              StopPrice, TargetPrice, comment, Magic, 0, TypeCol);
   if (Ticket >= 0) {
      Sleep(SLEEP_OK);
      if (OrderSelect(Ticket, SELECT_BY_TICKET) == TRUE) {
         FillPrice = OrderOpenPrice();
         if (Entry != FillPrice) {
            RefreshRates();
            Print("Slippage on order ", Ticket, " - Requested = ",
                  Entry, ", Fill = ", FillPrice, ", Current Bid = ",
                  Bid, ", Current Ask = ", Ask);
         }
      }
      else {
         ErrorCode = GetLastError();
         Print("Error selecting new order ", Ticket, ": ",
               ErrorDescription(ErrorCode), " (", ErrorCode, ")");
      }
      return (Ticket);
   }
   ErrorCode = GetLastError();
   RefreshRates();
   Print("Error opening ", TypeStr, " order: ", ErrorDescription(ErrorCode),
         " (", ErrorCode, ")", ", Entry = ", Price, ", Target = ",
         TargetPrice, ", Stop = ", StopPrice, ", Current Bid = ", Bid,
         ", Current Ask = ", Ask);
   Sleep(SLEEP_ERR);
   return (-1);
}
//+------------------------------------------------------------------+
//| Calculates Long & Short period ranges                            |
//+------------------------------------------------------------------+
void CalcRanges()
{
   int Index;
   Index = ArrayMaximum(High, LongPeriod);
   LongMax = High[Index];
   Index = ArrayMinimum(Low, LongPeriod);
   LongMin = Low[Index];
   Index = ArrayMaximum(High, ShortPeriod);
   ShortMax = High[Index];
   Index = ArrayMinimum(Low, ShortPeriod);
   ShortMin = Low[Index];
   LastBar = Bars;
}
//+------------------------------------------------------------------+
//| Performs system initialisation                                   |
//+------------------------------------------------------------------+
void InitSystem()
{
   Running = FALSE;
   PositionSize = Lots;
   RefreshRates();
   CalcRanges();
   Print("Entry Levels - Upper = ", LongMax, ", Lower = ", LongMin,
         ". Exit Levels - Upper = ", ShortMax, ", Lower = ", ShortMin);
   Initialized = TRUE;
}
//+------------------------------------------------------------------+
//| Checks for entry to a trade                                      |
//+------------------------------------------------------------------+
int CheckEntry(double Size)
{
   if (Bid > LongMax) {
      // Broken out higher so GO LONG!
      if (OrderNumber > 0)
         CloseMarket(OrderNumber);  // Close previous short order
      OrderNumber = Order(Symbol(), OP_BUY, Ask, Size, 0, 0);
      if (OrderNumber > 0) {
         Long = TRUE;
         return(1);
      }
   }
   else if (Bid < LongMin) {
      // Broken out lower so GO SHORT!
      if (OrderNumber > 0)
         CloseMarket(OrderNumber);  // Close previous long order
      OrderNumber = Order(Symbol(), OP_SELL, Bid, Size, 0, 0);
      if (OrderNumber > 0) {
         Long = FALSE;
         return(1);
      }
   }
   return(0);
}
//+------------------------------------------------------------------+
//| Checks for exit from a trade                                     |
//+------------------------------------------------------------------+
int CheckExit()
{
   int ErrorCode;
   if (Long && (Bid < ShortMin)) {
      CloseMarket(OrderNumber);  // Close long order
      if (OrderSelect(OrderNumber, SELECT_BY_TICKET) != TRUE) {
         ErrorCode = GetLastError();
         Print("Error selecting order ", OrderNumber, ": ", ErrorDescription(ErrorCode), " (", ErrorCode, ")");
         return(-1);
      }
      Print("Order ", OrderNumber, " closed: ", OrderClosePrice(), ", at ", TimeToStr(OrderCloseTime()), ". Profit = ", OrderProfit());
      return(1);
   }
   if (!Long && (Bid > ShortMax)) {
      CloseMarket(OrderNumber);  // Close short order
      if (OrderSelect(OrderNumber, SELECT_BY_TICKET) != TRUE) {
         ErrorCode = GetLastError();
         Print("Error selecting order ", OrderNumber, ": ", ErrorDescription(ErrorCode), " (", ErrorCode, ")");
         return(-1);
      }
      Print("Order ", OrderNumber, " closed: ", OrderClosePrice(), ", at ", TimeToStr(OrderCloseTime()), ". Profit = ", OrderProfit());
      return(1);
   }
   else {
      return(0);
   }
}
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int init()
{
   Dig = MarketInfo(Symbol(), MODE_DIGITS);
   Points = MarketInfo(Symbol(), MODE_POINT);
   Print("Digits = ", Dig, ", Points = ", DoubleToStr(Points, 5));
   if (!IsDemo() && !IsTesting()) {
      MessageBox("Wealth Warning! This expert is for educational purposes only." +
            " It should NEVER be used on a live account." +
            " Past performance is in no way indicative of future results!");
      Print("Initialization Failure");
      return(-1);
   }
   if (ShortPeriod >= LongPeriod) {
      Print("Error - ShortPeriod must be less than LongPeriod.");
      return(-1);
   }
   InitSystem();
   Print("Initialized OK");
   return(0);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
int deinit()
{
    Print("DeInitialized OK");
    return(0);
}
//+------------------------------------------------------------------+
//| Expert start function                                            |
//| Executed on every tick                                           |
//+------------------------------------------------------------------+
int start()
{
   if (!Initialized) {
      return(-1);
   }
   if (Bars > LastBar)
     CalcRanges();
   if (Running) {                         // Are we in a trade at the moment?
      if (CheckExit() > 0) {              // Yes - Last trade complete?
         Initialized = FALSE;             // Yes - Indicate we need to reinitialise,
         OrderNumber = 0;                 //  indicate no open order any more
         InitSystem();                    //  and start all over again!
      }
   }
   else if (CheckEntry(PositionSize) > 0) { // Entered a trade?
      Running = TRUE;                       // Yes - Indicate that we're in a trade
   }
   return(0);
}

You can also download the source code here.

Leave a Comment

Fields marked by an asterisk (*) are required.