Price Action. Automatización de la estrategia del patrón envolvente (Engulfing)

Dmitry Iglakov | 10 mayo, 2016

Introducción

Todos los traders en Forex habrán utilizado la técnica Price Action (Comportamiento del precio) en algún momento. Esto no es una simple técnica de análisis de gráficos, sino todo un sistema para determinar la posible dirección del movimiento del precio en el futuro. En este artículo, vamos a analizar el patrón envolvente (Engulfing) y crear un Asesor Experto que hará el seguimiento de este patrón y tomar las decisiones pertinentes en base a él.

Ya hemos descrito el trading automatizado con los patrones Price Action en el artículo Price Action. Automatización de la estrategia de la barra interna.


Reglas del patrón envolvente

Tenemos un patrón envolvente si el cuerpo y las sombras de una vela envuelve por completo el cuerpo y las sombras de la vela anterior. Hay dos tipos de patrones envolventes:

  • BUOVB — Bullish Outside Vertical Bar (barra vertical externa alcista);
  • BEOVB — Bearish Outside Vertical Bar (barra vertical externa bajista).

Fig. 1 Tipos de patrones en el gráfico

Fig. 1 Tipos de patrones en el gráfico

Veamos estos patrones de cerca.

BUOVB. Se puede observar en el gráfico que el máximo de la barra externa es superior al máximo de la barra anterior y el mínimo de la barra externa es inferior al mínimo de la barra anterior.

BEOVB. Este patrón también es fácil de identificar en el gráfico. El máximo de la barra externa es superior al máximo de la barra anterior y el mínimo de la barra externa es inferior al mínimo de la barra anterior.

Cada patrón da una idea clara sobre las posibles tendencias del mercado.

Fig. 2 Estructura del patrón

Fig. 2 Estructura del patrón

Reglas del patrón envolvente:
  • Para trabajar con este patrón hay que utilizar períodos de tiempo mayores: H4, D1.
  • Para encontrar el punto de entrada más óptimo, hay que utilizar otros elementos de análisis gráfico, como líneas de tendencia, niveles de soporte y resistencia, niveles de Fibonacci, otros patrones Price Action, etc.
  • Para evitar las entradas prematuras o erróneas al mercado, hay que utilizar las órdenes pendientes.
  • Los patrones que se repiten en una zona plana no se deben utilizar como señales para entrar al mercado.


Establecer los puntos de entrada para "BUOVB" y colocar las órdenes Stop

Fig. 3 Establecimiento de las órdenes Buy Stop y Stop Loss

Fig. 3 Establecimiento de las órdenes Buy Stop y Stop Loss

Vamos a analizar las reglas de entrada y colocación de las órdenes Stop para BUOVB (barra vertical externa alcista) mediante el siguiente ejemplo:

  1. Colocamos una orden Buy Stop pendiente en un precio ligeramente por encima del máximo (pocos puntos, para asegurarnos) de la barra externa.
  2. Establecemos el nivel Stop Loss por debajo del mínimo de la barra externa.
  3. Establecemos el nivel Take Profit justo antes del siguiente nivel de resistencia.


Establecer los puntos de entrada para "BEOVB" y colocar las órdenes Stop

Fig. 4 Establecimiento de las órdenes Sell Stop y Stop Loss

Fig. 4 Establecimiento de las órdenes Sell Stop y Stop Loss

Vamos a analizar las reglas de entrada y colocación de las órdenes Stop para BEOVB (barra vertical externa bajista) mediante el ejemplo anterior:

  1. Colocamos una orden Sell Stop pendiente en un precio ligeramente por debajo del mínimo (pocos puntos, para asegurarnos) de la barra externa.
  2. Establecemos el nivel Stop Loss por encima del máximo de la barra externa.
  3. Establecemos el nivel Take Profit justo antes del siguiente nivel de soporte.


Crear un Asesor Experto para el trading con el patrón envolvente

Hemos repasado el patrón envolvente y aprendido cómo entrar al mercado de forma segura, así como determinar los niveles de las órdenes Stop para limitar las pérdidas o garantizar las ganancias.

A continuación vamos a tratar de implementar los algoritmos del Asesor Experto y automatizar el trading con el patrón envolvente.

Abrimos MetaEditor desde el terminal de MetaTrader 4 y creamos un nuevo Asesor Experto (no voy a entrar en los detalles de cómo crear Asesores Expertos, ya que hay bastante información sobre este tema en el sitio web). De momento, dejamos todos los parámetros en blanco. Puede poner el nombre que quiera. Al final, obtenemos el siguiente resultado:

//+------------------------------------------------------------------+
//|                                              BEOVB_BUOVB_Bar.mq4 |
//|                                  Copyright 2015, Iglakov Dmitry. |
//|                                               cjdmitri@gmail.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2015, Iglakov Dmitry."
#property link      "cjdmitri@gmail.com"
#property version   "1.00"
#property strict
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---

//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---

  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---

  }
//+------------------------------------------------------------------+


Convertir el patrón en un algoritmo MQL4

Una vez creado el Asesor Experto hay que definir el patrón envolvente después del cierre de una vela. Para ello, introducimos nuevas variables y les asignamos unos valores. Véase el siguiente código:

//+------------------------------------------------------------------+
//|                                              BEOVB_BUOVB_Bar.mq4 |
//|                                  Copyright 2015, Iglakov Dmitry. |
//|                                               cjdmitri@gmail.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2015, Iglakov Dmitry."
#property link      "cjdmitri@gmail.com"
#property version   "1.00"
#property strict

double open1,//first candle Open price
open2,      //second candle Open price
close1,     //first candle Close price
close2,     //second candle Close price
low1,       //first candle Low price
low2,       //second candle Low price
high1,      //first candle High price
high2;      //second candle High price
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//--- define prices of necessary bars
   open1        = NormalizeDouble(iOpen(Symbol(), Period(), 1), Digits);
   open2        = NormalizeDouble(iOpen(Symbol(), Period(), 2), Digits);
   close1       = NormalizeDouble(iClose(Symbol(), Period(), 1), Digits);
   close2       = NormalizeDouble(iClose(Symbol(), Period(), 2), Digits);
   low1         = NormalizeDouble(iLow(Symbol(), Period(), 1), Digits);
   low2         = NormalizeDouble(iLow(Symbol(), Period(), 2), Digits);
   high1        = NormalizeDouble(iHigh(Symbol(), Period(), 1), Digits);
   high2        = NormalizeDouble(iHigh(Symbol(), Period(), 2), Digits);
  }
//+------------------------------------------------------------------+

Encontramos dos tipo de patrones envolventes:

void OnTick()
  {
//--- define prices of necessary bars
   open1        = NormalizeDouble(iOpen(Symbol(), Period(), 1), Digits);
   open2        = NormalizeDouble(iOpen(Symbol(), Period(), 2), Digits);
   close1       = NormalizeDouble(iClose(Symbol(), Period(), 1), Digits);
   close2       = NormalizeDouble(iClose(Symbol(), Period(), 2), Digits);
   low1         = NormalizeDouble(iLow(Symbol(), Period(), 1), Digits);
   low2         = NormalizeDouble(iLow(Symbol(), Period(), 2), Digits);
   high1        = NormalizeDouble(iHigh(Symbol(), Period(), 1), Digits);
   high2        = NormalizeDouble(iHigh(Symbol(), Period(), 2), Digits);
//--- Finding bearish pattern BEOVB
   if(low1 < low2 &&// First bar's Low is below second bar's Low
      high1 > high2 &&// First bar's High is above second bar's High
      close1 < open2 &&	//First bar's Close price is below second bar's Open
      open1 > close1 && //First bar is a bearish bar
      open2 < close2)	//Second bar is a bullish bar
     {
      //--- we have described all conditions indicating that the first bar completely engulfs the second bar and is a bearish bar
     }

Encontramos el patrón alcista de la misma manera:

//--- Finding bullish pattern BUOVB
   if(low1 < low2 &&// First bar's Low is below second bar's Low 
      high1 > high2 &&// First bar's High is above second bar's High
      close1 > open2 && //First bar's Close price is higher than second bar's Open
      open1 < close1 && //First bar is a bullish bar
      open2 > close2)   //Second bar is a bearish bar
     {
      //--- we have described all conditions indicating that the first bar completely engulfs the second bar and is a bullish bar 
     }
  • Creamos unas variables personalizables: órdenes Stop, deslizamiento (slippage), tiempo de expiración de órdenes, número mágico del Asesor Experto, lote del trading. Se puede omitir Stop Loss, puesto que se establece de acuerdo con las reglas del patrón.
  • Introducimos variables locales para normalizar el formato de las variables.
  • Además, hay que recordar que las órdenes Stop se colocan a cierta distancia de los precios de la barra. Para ello, añadimos la variable Interval que se encarga del intervalo entre los precios máximo/mínimo de las barras y de los niveles de las órdenes Stop, además de los niveles de las órdenes pendientes.
  • Añadimos la variable timeBUOVB_BEOVB para evitar la reapertura de la orden en este patrón.
  • Añadimos la variable bar1size para comprobar que la barra externa es los suficientemente grande. Por lo tanto, podemos suponer que el mercado actual no es plano.

Como resultado, obtenemos el siguiente código:

//+------------------------------------------------------------------+
//|                                              BEOVB_BUOVB_bar.mq4 |
//|                                  Copyright 2015, Iglakov Dmitry. |
//|                                               cjdmitri@gmail.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2015, Iglakov Dmitry."
#property link      "cjdmitri@gmail.com"
#property version   "1.00"
#property strict

extern int     interval          = 25;                               //Interval
extern double  lot               = 0.1;                              //Lot Size
extern int     TP                = 400;                              //Take Profit
extern int     magic             = 962231;                           //Magic number
extern int     slippage          = 2;                                //Slippage
extern int     ExpDate           = 48;                               //Expiration Hour Order
extern int     bar1size          = 900;                              //Bar 1 Size

double buyPrice,//define BuyStop setting price
buyTP,      //Take Profit BuyStop
buySL,      //Stop Loss BuyStop
sellPrice,  //define SellStop setting price
sellTP,     //Take Profit SellStop
sellSL;     //Stop Loss SellStop

double open1,//first candle Open price
open2,    //second candle Open price
close1,   //first candle Close price
close2,   //second candle Close price
low1,     //first candle Low price
low2,     //second candle Low price
high1,    //first candle High price
high2;    //second candle High price

datetime _ExpDate =0; // local variable for defining pending orders expiration time
double _bar1size;// local variable required to avoid a flat market
datetime timeBUOVB_BEOVB;// time of a bar when pattern orders were opened, to avoid re-opening
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
   double   _bid = NormalizeDouble(MarketInfo (Symbol(), MODE_BID), Digits); // define Low price 
   double   _ask     = NormalizeDouble(MarketInfo(Symbol(), MODE_ASK), Digits); //define High price
   double   _point   = MarketInfo(Symbol(), MODE_POINT);
//--- define prices of necessary bars
   open1        = NormalizeDouble(iOpen(Symbol(), Period(), 1), Digits);
   open2        = NormalizeDouble(iOpen(Symbol(), Period(), 2), Digits);
   close1       = NormalizeDouble(iClose(Symbol(), Period(), 1), Digits);
   close2       = NormalizeDouble(iClose(Symbol(), Period(), 2), Digits);
   low1         = NormalizeDouble(iLow(Symbol(), Period(), 1), Digits);
   low2         = NormalizeDouble(iLow(Symbol(), Period(), 2), Digits);
   high1        = NormalizeDouble(iHigh(Symbol(), Period(), 1), Digits);
   high2        = NormalizeDouble(iHigh(Symbol(), Period(), 2), Digits);
//---
   _bar1size=NormalizeDouble(((high1-low1)/_point),0);
//--- Finding bearish pattern BEOVB
   if(timeBUOVB_BEOVB!=iTime(Symbol(),Period(),1) && //orders are not yet opened for this pattern 
      _bar1size > bar1size && //first bar is big enough, so the market is not flat
      low1 < low2 &&//First bar's Low is below second bar's Low
      high1 > high2 &&//First bar's High is above second bar's High
      close1 < open2 && //First bar's Сlose price is lower than second bar's Open price
      open1 > close1 && //First bar is a bearish bar
      open2 < close2)   //Second bar is a bullish bar
     {
      //--- we have described all conditions indicating that the first bar completely engulfs the second bar and is a bearish bar
      timeBUOVB_BEOVB=iTime(Symbol(),Period(),1); // indicate that orders are already placed on this pattern
     }
//--- Finding bullish pattern BUOVB
   if(timeBUOVB_BEOVB!=iTime(Symbol(),Period(),1) && //orders are not yet opened for this pattern 
      _bar1size > bar1size && //first bar is big enough not to consider a flat market
      low1 < low2 &&//First bar's Low is below second bar's Low
      high1 > high2 &&//First bar's High is above second bar's High
      close1 > open2 && //First bar's Close price is higher than second bar's Open price
      open1 < close1 && //First bar is a bullish bar
      open2 > close2)   //Second bar is a bearish bar
     {
      //--- we have described all conditions indicating that the first bar completely engulfs the second bar and is a bullish bar 
      timeBUOVB_BEOVB=iTime(Symbol(),Period(),1); // indicate that orders are already placed on this pattern
     }
  }
//+------------------------------------------------------------------+


Determinar los niveles de las órdenes Stop

Hemos cumplido todas las condiciones y hemos encontrado unos patrones de gran calidad. Ahora necesitamos establecer los niveles de las órdenes Stop, los precios de las órdenes pendientes, así como el tiempo de expiración de las órdenes para cada patrón.

Vamos a añadir el siguiente código a la función OnTick():

//--- Define prices for placing orders and stop orders
   buyPrice =NormalizeDouble(high1 + interval * _point,Digits); //define a price of order placing with intervals
   buySL =NormalizeDouble(low1-interval * _point,Digits); //define stop-loss with an interval
   buyTP =NormalizeDouble(buyPrice + TP * _point,Digits); //define take profit
   _ExpDate =TimeCurrent() + ExpDate*60*60; //pending order expiration time calculation
//--- We also calculate sell orders 
   sellPrice=NormalizeDouble(low1-interval*_point,Digits);
   sellSL=NormalizeDouble(high1+interval*_point,Digits);
   sellTP=NormalizeDouble(sellPrice-TP*_point,Digits);


Corrección de los errores de ejecución

Si ya ha desarrollado algunos Asesores Expertos, seguro que sabe que los errores ocurren a menudo al cerrar y establecer las órdenes, incluyendo el tiempo de espera, los valores erróneos, etc. Para eliminar estos errores tenemos que escribir una función por separado que incluye un pequeño procesador de errores básicos.

//+----------------------------------------------------------------------------------------------------------------------+
//| The function opens or sets an order                                                                                  |
//| symbol      - symbol, at which a deal is performed.                                                                  |
//| cmd         - a deal (may be equal to any of the deal values).                                                       |
//| volume      - amount of lots.                                                                                        |
//| price       - Open price.                                                                                            |
//| slippage    - maximum price deviation for market buy or sell orders.                                                 |
//| stoploss    - position close price when an unprofitability level is reached (0 if there is no unprofitability level).|
//| takeprofit  - position close price when a profitability level is reached (0 if there is no profitability level).     |
//| comment     - order comment. The last part of comment can be changed by the trade server.                            |
//| magic       - order magic number. It can be used as a user-defined ID.                                               |
//| expiration  - pending order expiration time.                                                                         |
//| arrow_color - open arrow color on a chart. If the parameter is absent or equal to CLR_NONE,                          |
//|               the open arrow is not displayed on a chart.                                                            |
//+----------------------------------------------------------------------------------------------------------------------+
int OrderOpenF(string     OO_symbol,
               int        OO_cmd,
               double     OO_volume,
               double     OO_price,
               int        OO_slippage,
               double     OO_stoploss,
               double     OO_takeprofit,
               string     OO_comment,
               int        OO_magic,
               datetime   OO_expiration,
               color      OO_arrow_color)
  {
   int result = -1;// result of opening an order
   int Error = 0; // error when opening an order
   int attempt = 0; // amount of performed attempts 
   int attemptMax = 3; // maximum amount of attempts
   bool exit_loop = false; // exit the loop
   string lang =TerminalInfoString(TERMINAL_LANGUAGE);// trading terminal language for defining the language of the messages
   double stopllvl =NormalizeDouble(MarketInfo (OO_symbol, MODE_STOPLEVEL) * MarketInfo (OO_symbol, MODE_POINT),Digits);// minimum stop loss/take profit level, in points
                                                                                                                     //the module provides safe order opening
//--- checking stop orders for buying
   if(OO_cmd==OP_BUY || OO_cmd==OP_BUYLIMIT || OO_cmd==OP_BUYSTOP)
     {
      double tp = (OO_takeprofit - OO_price)/MarketInfo(OO_symbol, MODE_POINT);
      double sl = (OO_price - OO_stoploss)/MarketInfo(OO_symbol, MODE_POINT);
      if(tp>0 && tp<=stopllvl)
        {
         OO_takeprofit=OO_price+stopllvl+2*MarketInfo(OO_symbol,MODE_POINT);
        }
      if(sl>0 && sl<=stopllvl)
        {
         OO_stoploss=OO_price -(stopllvl+2*MarketInfo(OO_symbol,MODE_POINT));
        }
     }
//--- checking stop orders for selling
   if(OO_cmd==OP_SELL || OO_cmd==OP_SELLLIMIT || OO_cmd==OP_SELLSTOP)
     {
      double tp = (OO_price - OO_takeprofit)/MarketInfo(OO_symbol, MODE_POINT);
      double sl = (OO_stoploss - OO_price)/MarketInfo(OO_symbol, MODE_POINT);
      if(tp>0 && tp<=stopllvl)
        {
         OO_takeprofit=OO_price -(stopllvl+2*MarketInfo(OO_symbol,MODE_POINT));
        }
      if(sl>0 && sl<=stopllvl)
        {
         OO_stoploss=OO_price+stopllvl+2*MarketInfo(OO_symbol,MODE_POINT);
        }
     }
//--- while loop
   while(!exit_loop)
     {
      result=OrderSend(OO_symbol,OO_cmd,OO_volume,OO_price,OO_slippage,OO_stoploss,OO_takeprofit,OO_comment,OO_magic,OO_expiration,OO_arrow_color); //attempt to open an order using the specified parameters
      //--- if there is an error when opening an order
      if(result<0)
        {
         Error = GetLastError();                                     //assign a code to an error
         switch(Error)                                               //error enumeration
           {                                                         //order closing error enumeration and an attempt to fix them
            case  2:
               if(attempt<attemptMax)
                 {
                  attempt=attempt+1;                                 //define one more attempt
                  Sleep(3000);                                       //3 seconds of delay
                  RefreshRates();
                  break;                                             //exit switch
                 }
               if(attempt==attemptMax)
                 {
                  attempt=0;                                         //reset the amount of attempts to zero 
                  exit_loop = true;                                  //exit while
                  break;                                             //exit switch
                 }
            case  3:
               RefreshRates();
               exit_loop = true;                                     //exit while
               break;                                                //exit switch   
            case  4:
               if(attempt<attemptMax)
                 {
                  attempt=attempt+1;                                 //define one more attempt
                  Sleep(3000);                                       //3 seconds of delay
                  RefreshRates();
                  break;                                             //exit switch
                 }
               if(attempt==attemptMax)
                 {
                  attempt = 0;                                       //reset the amount of attempts to zero 
                  exit_loop = true;                                  //exit while
                  break;                                             //exit switch
                 }
            case  5:
               exit_loop = true;                                     //exit while
               break;                                                //exit switch   
            case  6:
               if(attempt<attemptMax)
                 {
                  attempt=attempt+1;                                 //define one more attempt
                  Sleep(5000);                                       //3 seconds of delay
                  break;                                             //exit switch
                 }
               if(attempt==attemptMax)
                 {
                  attempt = 0;                                       //reset the amount of attempts to zero 
                  exit_loop = true;                                  //exit while
                  break;                                             //exit switch
                 }
            case  8:
               if(attempt<attemptMax)
                 {
                  attempt=attempt+1;                                 //define one more attempt
                  Sleep(7000);                                       //3 seconds of delay
                  break;                                             //exit switch
                 }
               if(attempt==attemptMax)
                 {
                  attempt = 0;                                       //reset the amount of attempts to zero 
                  exit_loop = true;                                  //exit while
                  break;                                             //exit switch
                 }
            case 64:
               exit_loop = true;                                     //exit while
               break;                                                //exit switch
            case 65:
               exit_loop = true;                                     //exit while
               break;                                                //exit switch
            case 128:
               Sleep(3000);
               RefreshRates();
               continue;                                             //exit switch
            case 129:
               if(attempt<attemptMax)
                 {
                  attempt=attempt+1;                                 //define one more attempt
                  Sleep(3000);                                       //3 seconds of delay
                  RefreshRates();
                  break;                                             //exit switch
                 }
               if(attempt==attemptMax)
                 {
                  attempt = 0;                                       //reset the amount of attempts to zero 
                  exit_loop = true;                                  //exit while
                  break;                                             //exit switch
                 }
            case 130:
               exit_loop=true;                                       //exit while
               break;
            case 131:
               exit_loop = true;                                     //exit while
               break;                                                //exit switch
            case 132:
               Sleep(10000);                                         //sleep for 10 seconds
               RefreshRates();                                       //update data
               //exit_loop = true;                                   //exit while
               break;                                                //exit switch
            case 133:
               exit_loop=true;                                       //exit while
               break;                                                //exit switch
            case 134:
               exit_loop=true;                                       //exit while
               break;                                                //exit switch
            case 135:
               if(attempt<attemptMax)
                 {
                  attempt=attempt+1;                                 //define one more attempt
                  RefreshRates();
                  break;                                             //exit switch
                 }
               if(attempt==attemptMax)
                 {
                  attempt = 0;                                       //set the number of attempts to zero 
                  exit_loop = true;                                  //exit while
                  break;                                             //exit switch
                 }
            case 136:
               if(attempt<attemptMax)
                 {
                  attempt=attempt+1;                                 //define one more attempt
                  RefreshRates();
                  break;                                             //exit switch
                 }
               if(attempt==attemptMax)
                 {
                  attempt = 0;                                       //set the amount of attempts to zero 
                  exit_loop = true;                                  //exit while
                  break;                                             //exit switch
                 }
            case 137:
               if(attempt<attemptMax)
                 {
                  attempt=attempt+1;
                  Sleep(2000);
                  RefreshRates();
                  break;
                 }
               if(attempt==attemptMax)
                 {
                  attempt=0;
                  exit_loop=true;
                  break;
                 }
            case 138:
               if(attempt<attemptMax)
                 {
                  attempt=attempt+1;
                  Sleep(1000);
                  RefreshRates();
                  break;
                 }
               if(attempt==attemptMax)
                 {
                  attempt=0;
                  exit_loop=true;
                  break;
                 }
            case 139:
               exit_loop=true;
               break;
            case 141:
               Sleep(5000);
               exit_loop=true;
               break;
            case 145:
               exit_loop=true;
               break;
            case 146:
               if(attempt<attemptMax)
                 {
                  attempt=attempt+1;
                  Sleep(2000);
                  RefreshRates();
                  break;
                 }
               if(attempt==attemptMax)
                 {
                  attempt=0;
                  exit_loop=true;
                  break;
                 }
            case 147:
               if(attempt<attemptMax)
                 {
                  attempt=attempt+1;
                  OO_expiration=0;
                  break;
                 }
               if(attempt==attemptMax)
                 {
                  attempt=0;
                  exit_loop=true;
                  break;
                 }
            case 148:
               exit_loop=true;
               break;
            default:
               Print("Error: ",Error);
               exit_loop=true; //exit while 
               break;          //other options 
           }
        }
      //--- if no errors detected
      else
        {
         if(lang == "Russian") {Print("Ордер успешно открыт. ", result);}
         if(lang == "English") {Print("The order is successfully opened.", result);}
         Error = 0;                                //reset the error code to zero
         break;                                    //exit while
         //errorCount =0;                          //reset the amount of attempts to zero
        }
     }
   return(result);
  }
//+------------------------------------------------------------------+

Como resultado, obtenemos el siguiente código:

//+------------------------------------------------------------------+
//|                                              BEOVB_BUOVB_bar.mq4 |
//|                                  Copyright 2015, Iglakov Dmitry. |
//|                                               cjdmitri@gmail.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2015, Iglakov Dmitry."
#property link      "cjdmitri@gmail.com"
#property version   "1.00"
#property strict

extern int     interval          = 25;                               //Interval
extern double  lot               = 0.1;                              //Lot Size
extern int     TP                = 400;                              //Take Profit
extern int     magic             = 962231;                           //Magic number
extern int     slippage          = 2;                                //Slippage
extern int     ExpDate           = 48;                               //Expiration Hour Order
extern int     bar1size          = 900;                              //Bar 1 Size

double buyPrice,//define BuyStop price
buyTP,      //Take Profit BuyStop
buySL,      //Stop Loss BuyStop
sellPrice,  //define SellStop price
sellTP,     //Take Profit SellStop
sellSL;     //Stop Loss SellStop

double open1,//first candle Open price
open2,    //second candle Open price
close1,   //first candle Close price
close2,   //second candle Close price
low1,     //first candle Low price
low2,     //second candle Low price
high1,    //first candle High price
high2;    //second candle High price

datetime _ExpDate =0; // local variable for defining pending orders expiration time
double _bar1size;// local variable required to avoid a flat market
datetime timeBUOVB_BEOVB;// time of a bar when pattern orders were opened, to avoid re-opening
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
   double   _bid = NormalizeDouble(MarketInfo (Symbol(), MODE_BID), Digits); // define Low price 
   double   _ask     = NormalizeDouble(MarketInfo(Symbol(), MODE_ASK), Digits); //define High price
   double   _point   = MarketInfo(Symbol(), MODE_POINT);
//--- define prices of necessary bars
   open1        = NormalizeDouble(iOpen(Symbol(), Period(), 1), Digits);
   open2        = NormalizeDouble(iOpen(Symbol(), Period(), 2), Digits);
   close1       = NormalizeDouble(iClose(Symbol(), Period(), 1), Digits);
   close2       = NormalizeDouble(iClose(Symbol(), Period(), 2), Digits);
   low1         = NormalizeDouble(iLow(Symbol(), Period(), 1), Digits);
   low2         = NormalizeDouble(iLow(Symbol(), Period(), 2), Digits);
   high1        = NormalizeDouble(iHigh(Symbol(), Period(), 1), Digits);
   high2        = NormalizeDouble(iHigh(Symbol(), Period(), 2), Digits);
   
//--- Define prices for placing orders and stop orders
   buyPrice =NormalizeDouble(high1 + interval * _point,Digits); //define a price of order placing with intervals
   buySL =NormalizeDouble(low1-interval * _point,Digits); //define stop loss with an interval
   buyTP =NormalizeDouble(buyPrice + TP * _point,Digits); //define take profit
   _ExpDate =TimeCurrent() + ExpDate*60*60; //pending order expiration time calculation
//--- We also calculate sell orders 
   sellPrice=NormalizeDouble(low1-interval*_point,Digits);
   sellSL=NormalizeDouble(high1+interval*_point,Digits);
   sellTP=NormalizeDouble(sellPrice-TP*_point,Digits);
//---
   _bar1size=NormalizeDouble(((high1-low1)/_point),0);
//--- Finding bearish pattern BEOVB
   if(timeBUOVB_BEOVB!=iTime(Symbol(),Period(),1) && //orders are not yet opened for this pattern 
      _bar1size > bar1size && //first bar is big enough, so the market is not flat
      low1 < low2 &&//First bar's Low is below second bar's Low
      high1 > high2 &&//First bar's High is above second bar's High
      close1 < open2 && //First bar's Close price is lower than second bar's Open price
      open1 > close1 && //First bar is a bearish bar
      open2 < close2)   //Second bar is a bullish bar
     {
      //--- we have described all conditions indicating that the first bar completely engulfs the second bar and is a bearish bar
      OrderOpenF(Symbol(),OP_SELLSTOP,lot,sellPrice,slippage,sellSL,sellTP,NULL,magic,_ExpDate,Blue);
      timeBUOVB_BEOVB=iTime(Symbol(),Period(),1); //indicate that orders are already placed on this pattern
     }
//--- Finding bullish pattern BUOVB
   if(timeBUOVB_BEOVB!=iTime(Symbol(),Period(),1) && //orders are not yet opened for this pattern 
      _bar1size > bar1size && //first bar is big enough, so the market is not flat
      low1 < low2 &&//First bar's Low is below second bar's Low
      high1 > high2 &&//First bar's High is above second bar's High
      close1 > open2 && //First bar's Close price is higher than second bar's Open price
      open1 < close1 && //First bar is a bullish bar
      open2 > close2)   //Second bar is a bearish bar
     {
      //--- we have described all conditions indicating that the first bar completely engulfs the second bar and is a bullish bar 
      OrderOpenF(Symbol(),OP_BUYSTOP,lot,buyPrice,slippage,buySL,buyTP,NULL,magic,_ExpDate,Blue);
      timeBUOVB_BEOVB = iTime(Symbol(),Period(),1); //indicate that orders are already placed on this pattern
     }
  }
//+------------------------------------------------------------------+

Vamos compilar el código y comprobar si hay mensajes de error en el registro.


Prueba del asesor experto

Es el momento de probar nuestro Asesor Experto. Vamos a ejecutar la prueba de estrategias y establecer los parámetros de entrada.

Fig. 5 Parámetros de entrada para la prueba

Fig. 5 Parámetros de entrada para la prueba

  1. Hay que seleccionar un par de divisas para la prueba. He optado por el EURAUD.
  2. Hay que asegurarse de elegir el modo "Cada tick" y seleccionar la casilla "Utilizar datos" para llevar a cabo la prueba. He seleccionado todo el año 2014.
  3. Establecemos el período de tiempo D1.
  4. Iniciamos la prueba.
  5. Una vez finalizada la prueba, comprobamos el diario. Como se puede observar, no se ha producido ningún error durante el proceso.

Fig. 6 Configuración de las condiciones de la prueba

Fig. 6 Configuración de las condiciones de la prueba

La siguiente figura muestra el diario de la prueba del Asesor Experto:

Fig. 7 Diario de la prueba del Asesor Experto

Fig. 7 Diario de la prueba del Asesor Experto

Nos aseguramos de que no hay ningún error y optimizamos el Asesor Experto


Optimización

He seleccionado los siguientes parámetros para la optimización:

Fig. 8 Parámetros de la optimización

Fig. 8 Parámetros de la optimización


Fig. 9 Ajustes de la optimización

Fig. 9 Ajustes de la optimización

Como resultado de la optimización y la prueba, obtenemos el Asesor Experto listo para su uso.


Resultados de la optimización y la prueba

Después de realizar la optimización de los pares de divisas más conocidos, hemos obtenido el siguiente resultado:

Par de divisas Beneficio neto Factor de beneficio Disminución (%) Beneficio bruto  Pérdida bruta 
EURAUD 523,90 $ 3,70 2,13  727,98 $ 196,86 $
USDCHF 454,19 $ - 2,25  454,19 $ 0,00 $
GBPUSD 638,71 $ - 1,50  638,71 $ 0,00 $
EURUSD 638,86 $ - 1,85  638,86 $ 0,00 $
USDJPY 423,85 $ 5,15 2,36  525,51 $ 102,08 $
USDCAD 198,82 $ 2,41 2,74  379,08 $ 180,26 $
AUDUSD 136,14 $ 1,67 2,39  339,26 $ 203,12 $

 Tabla 1 Resultados de la optimización

Se han llevado a cabo unas pruebas más detalladas con el par de divisas EURAUD:

Fig. 10 Resultados de la prueba

Fig. 10 Resultados de la prueba


Fig. 11 Gráfico de los resultados de la prueba

Fig. 11 Gráfico de los resultados de la prueba


Conclusión

  1. En este artículo, hemos creado un Asesor Experto para el trading con el patrón envolvente.
  2. Hemos visto que los patrones Price Action pueden funcionar incluso sin filtros adicionales para entrar al mercado.
  3. No hemos recurrido a ningún truco (tipo martingala o promediado).
  4. Al establecer correctamente las órdenes Stop, se ha reducido la disminución al mínimo.
  5. No se ha utilizado ningún indicador técnico. Se basa el Asesor Experto únicamente en la lectura del gráfico "básico".

¡Gracias por leer el artículo! y espero que le haya resultado útil.