Ação do Preço: Automatizando a Estratégia de Negociação "Inside Bar"

Dmitry Iglakov | 26 outubro, 2015

Introdução

Todos os traders de Forex se deparam com a Ação do Preço em algum ponto. Esta não é uma mera técnica de análise gráfica, mas todo um sistema para definir a possível orientação do movimento do preço no futuro. Neste artigo vamos olhar para o padrão "Inside Bar" em detalhes e desenvolver um EA para o rastreamento e realizaçao de operações de negociação neste padrão.


Sobre a Ação do Preço

A ação do preço é um método de detecção de movimento de preços sem indicador, usando padrões simples e complexos, bem como elementos auxiliares gráfico (linhas verticais e de tendências, níveis Fibo, níveis horizontais, suporte/resistência, etc).

À primeira vista o método pode parecer um pouco complicado, mas na verdade não é. O método está ganhando popularidade de ano para ano, pois as suas vantagens são evidentes, por exemplo: quando comparado com os métodos que envolvem indicadores técnicos.


"Inside Bar" (Barra Envolvida)

O padrão "Inside Bar" é uma barra que tem o seu corpo e as sombras envolvidos inteiramente dentro do intervalo da barra anterior (mãe). A "Inside Bar" de Alta encontra-se envolvida pela barra mãe, formando um padrão altista. A "Inside Bar" de Baixa encontra-se envolvida pela barra mãe, formando um padrão baixista. Estes padrões formados são considerados como um potencial sinal de entrada.

Este é um padrão de dois lados, pois pode indicar tanto uma reversão como uma continuação de tendência.

Fig. 1. "Inside Bar" (Barra Envolvida)

Fig. 1. "Inside Bar" (Barra Envolvida)


Fig. 2. Layout do padrão "Inside Bar"

Fig. 2. Layout do padrão "Inside Bar"

Regras da "Inside Bar" (Barra Envolvida):

Fig. 3. Definindo uma genuína "Inside Bar" no GBPUSD D1

Fig. 3. Definindo uma genuína "Inside Bar" no GBPUSD D1

Tendo isto em mente, vamos tentar definir uma verdadeira "Inside Bar". No gráfico acima podemos ver que uma barra de alta foi formada após um acentuado movimento descendente, esta barra encontra-se completamente envolvida dentro dos limites da anterior. O padrão é confirmado pelo fato de ter sido formado no nível de suporte. A terceira confirmação é a ausência de plano lateral das outras barras. Uma vez que o padrão satisfaça as regras, pode ser considerado genuíno.


Definindo Pontos de Entrada e Ordens Stop

Então, nós encontramos uma verdadeira "Inside Bar" no gráfico (Fig. 3). Como devemos entrar no mercado e onde devemos definir nossas Ordens de Stop? Vamos examinar a Figura 4.

Fig. 4. Definir Buy Stop e Ordens Stop

Fig. 4. Definir Buy Stop e Ordens Stop

Primeiro, vamos considerar o exemplo acima para definir as regras do nível stop:

  1. Definir uma ordem pendente Buy Stop ligeiramente acima Máxima do preço da Barra Mãe (apenas alguns pontos a mais, para confirmação).
  2. Definir um nível de Stop Loss abaixo do nível de suporte, mais ou menos na mínima de preço da Barra Mãe. Esta é uma proteção adicional no caso de uma ordem pendente ser acionada.
  3. Definir um nível de Take Profit ligeiramente menor do que o nível de resistência mais próximo.
Não se esqueça que uma "Inside Bar" pode ser seguida por uma inversão ou manutenção de tendência, ou seja, precisamos de uma ordem stop de venda também.

Fig. 5. Definindo Buy Stop e Ordens Stop

Fig. 5. Definindo Sell Stop e Ordens Stop

Primeiro, vamos considerar o exemplo acima para definir as regras do nível stop:

  1. Definir uma ordem pendente Sell Stop ligeiramente abaixo da Mínima de Preço da Barra Mãe (apenas alguns pontos abaixo, para confirmação).
  2. Definir um nível de Stop Loss acima da Máxima de preço da Barra Mãe.
  3. Definir um nível de Take Profit ligeiramente menor do que o nível de suporte mais próximo.


Desenvolver um Expert Advisor de Negociação Baseado na "Inside Bar"

Agora que sabemos todas as regras necessárias para definir uma verdadeira "Inside Bar", entrar no mercado e definir ordens stop, podemos finalmente implementar o Expert Advisor apropriado a fim de operar com o padrão "Inside Bar".

Vamos abrir o MetaEditor do terminal MetaTrader 4 e criar um novo Expert Advisor (eu acredito que não necessito entrar nesta área, uma vez que o site oferece muitas informações sobre como criar um Expert Advisor). Todos os parâmetros são deixados em branco nesta fase. Você pode nomeá-los como quiser. O código resultante ficará da seguinte forma:

//+------------------------------------------------------------------+
//|                                                    InsideBar.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
//+------------------------------------------------------------------+
//| Função de inicialização do expert                                |
//+------------------------------------------------------------------+
int OnInit()
  {
//---

//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Função desinicialização do expert                                |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---

  }
//+------------------------------------------------------------------+
//| Função tick do Expert                                            |
//+------------------------------------------------------------------+
void OnTick()
  {
//---

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


Convertendo o Padrão em MQL4 Algorithm

Depois de ter criado o EA, precisamos definir uma "Inside Bar" após uma outra barra ser fechada. Para fazer isso, vamos introduzir novas variáveis e atribuir valores a elas. Veja o código abaixo:

//+------------------------------------------------------------------+
//|                                                    InsideBar.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,//Abertura do preço da primeira barra
open2,    //Abertura do preço da Segunda barra
close1,   //Fechamento do preço da primeira barra
close2,   //Fechamento do preço da segunda barra 
low1,     //Mínima do preço da primeira barra
low2,     //Mínima do preço da segunda barra 
high1,    //Máxima do preço da primeira barra 
high2;    //Máxima do preço da segunda barra
//+------------------------------------------------------------------+
//| Função de inicialização do expert                                |
//+------------------------------------------------------------------+
int OnInit()
  {
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Função desinicialização do expert                                |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
  }
//+------------------------------------------------------------------+
//| Função tick do Expert                                            |
//+------------------------------------------------------------------+
void OnTick()
  {
//--- Definir os preços das barras necessárias
   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);
  }
//+------------------------------------------------------------------+

Como exemplo, vamos considerar que uma Barra Mãe é de baixa(barra 2), enquanto uma Inside Bar é de alta(barra 1). Vamos adicionar uma série de condições para o corpo da função OnTick():

void OnTick()
  {
//--- Definir os preços das barras necessárias
   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);
// --- Se a segunda barra é de baixa, enquanto a primeira é de alta
   if(open2>close2 && //Segunda barra é de baixa
      close1>open1 && //Primeira barra é de alta
      high2>high1 &&  //Máxima da segunda barra excede a Máxima da primeira
      open2>close1 && //Abertura da segunda barra excede o Fechamento da primeira barra
      low2<low1)      //Mínima da segunda barra e menor do que a Mínima da primeira barra
     {
      //--- Listamos todas as condições que definem que a primeira barra está completamente envolvida pela segunda
     }
  }

Como resultado, obtém-se o seguinte código:

//+------------------------------------------------------------------+
//|                                                    InsideBar.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          = 20;                               //Intervalos
extern double  lot               = 0.1;                              //Tamanho do Lote
extern int     TP                = 300;                              //Take Profit
extern int     magic             = 555124;                           //Número mágico
extern int     slippage          = 2;                                //Desvio
extern int     ExpDate           = 48;                               //Hora de Expiração da Ordem
extern int     bar2size          = 800;                              //Tamanho da Barra 2

double   buyPrice,//Definir o preço da ordem BuyStop
buyTP,      //Take Profit da ordem BuyStop
buySL,      //Stop Loss da ordem BuyStop
sellPrice,  //Definir o preço da ordem SellStop
sellTP,     //Take Profit da ordem SellStop
sellSL;     //Stop Loss da ordem SellStop

double   open1,//Abertura do preço da primeira barra
open2,    //Abertura do preço da Segunda barra
close1,   //Fechamento do preço da primeira barra
close2,   //Fechamento do preço da segunda barra 
low1,     //Mínima do preço da primeira barra
low2,     //Mínima do preço da segunda barra 
high1,    //Máxima do preço da primeira barra 
high2;    //Máxima do preço da segunda barra

datetime _ExpDate=0;          //variável local para definir um tempo de expiração da ordem pendente
double     _bar2size;
datetime timeBarInside;         //tempo da barra em que a ordem da "Inside Bar" foi aberta, para evitar uma reabertura
//+------------------------------------------------------------------+
//| Função de inicialização do expert                                |
//+------------------------------------------------------------------+
int OnInit()
  {
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Função desinicialização do expert                                |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
  }
//+------------------------------------------------------------------+
//| Função tick do Expert                                            |
//+------------------------------------------------------------------+
void OnTick()
  {
   double   _bid     = NormalizeDouble(MarketInfo(Symbol(), MODE_BID), Digits); //define um preço menor 
   double   _ask     = NormalizeDouble(MarketInfo(Symbol(), MODE_ASK), Digits); //define um preço maior
   double   _point   = MarketInfo(Symbol(), MODE_POINT);
//--- Definir os preços das barras necessárias
   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);
//---
   _bar2size=NormalizeDouble(((high2-low2)/_point),0);
// --- Se a segunda barra é de baixa, enquanto a primeira é de alta
   if(timeBarInside!=iTime(Symbol(),Period(),1) && //Sem ordens abertas ainda neste padrão 
      _bar2size>bar2size && //a segunda barra tem de ser grande o suficiente, de modo que o mercado não seja lateral
      open2>close2 && //Segunda barra é de baixa
      close1>open1 && //Primeira barra é de alta
      high2>high1 &&  //Máxima da segunda barra excede a Máxima da primeira
      open2>close1 && //Abertura da segunda barra excede o Fechamento da primeira barra
      low2<low1)      //Mínima da segunda barra é menor do que a Mínima da primeira barra
     {
      //--- Listamos todas as condições que definem que a primeira barra está completamente envolvida pela segunda
      timeBarInside=iTime(Symbol(),Period(),1); //indica que as ordens já estão colocados neste padrão
     }
  }
//+------------------------------------------------------------------+


Definindo níveis de Stop Order

Agora que todos os preparativos estão completos, nós só temos que definir os níveis de ordem de parada e preços de encomenda. Além disso, não se esqueça de um cálculo de tempo de validade da ordem.

Vamos adicionar o código a seguir ao corpo da função OnTick():

buyPrice=NormalizeDouble(high2+interval*_point,Digits);       //define um preço da ordem considerando o intervalo
      buySL=NormalizeDouble(low2-interval*_point,Digits);     //definir um stop loss considerando o intervalo
      buyTP=NormalizeDouble(buyPrice+TP*_point,Digits);       //define um take profit
      _ExpDate=TimeCurrent()+ExpDate*60*60;                   //o cálculo do tempo de expiração da ordem pendente
      sellPrice=NormalizeDouble(low2-interval*_point,Digits);
      sellSL=NormalizeDouble(high2+interval*_point,Digits);
      sellTP=NormalizeDouble(sellPrice-TP*_point,Digits);


Correção de Erros de Execução

Se você já se dedica ao desenvolvimento de Expert Advisors, você provavelmente sabe que os erros acontecem muitas vezes ao fechar e definir as ordens, incluindo o tempo de espera, paradas incorretas, etc. Para eliminar esses erros, devemos escrever uma função separada com um pequeno manipulador "built-in" de erros básicos.

//+----------------------------------------------------------------------------------------------------------------------+
//| A função abre ou define uma ordem                                                                                    |
//| symbol      - símbolo (ativo) onde uma operação de negociação é realizada.                                           |
//| cmd         - uma operação (pode ser igual a qualquer um dos valores da negociação).                                 |
//| volume      - quantidade de lotes.                                                                                   |
//| price       - Abertura do preço.                                                                                     |
//| slippage    - desvio máximo do preço para as ordens de compra ou venda do mercado.                                   |
//| stoploss    - fechamento da posição quando um nível de perda é alcançado (0 se não há nível definido de perda).      |
//| takeprofit  - fechamento da posição quando um nível de lucro é alcançado  (0 se não há nível definido de lucro).     |
//| comment     - ordem comentada. A última parte do comentário pode ser alterada pelo servidor de negociação.           |
//| magic       - número mágico da ordem Ele pode ser usado como uma ID definida pelo usuário.                           |
//| expiration  - tempo de expiração da ordem pendente.                                                                  |
//| arrow_color - cor da seta aberta num gráfico. Se o parâmetro estiver ausente ou igual a CLR_NONE,                    |
//|               a seta aberta não é exibida num gráfico.                                                               |
//+----------------------------------------------------------------------------------------------------------------------+
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;    //resultado da abertura de uma ordem
   int      Error       = 0;     //erro ao abrir uma ordem
   int      attempt     = 0;     //quantidade de tentativas realizadas
   int      attemptMax  = 3;     //quantidade máxima de tentativas
   bool     exit_loop   = false; //sair do loop
   string   lang=TerminalInfoString(TERMINAL_LANGUAGE);  //linguagem do terminal de negociação para definir o idioma das mensagens
   double   stopllvl=NormalizeDouble(MarketInfo(OO_symbol,MODE_STOPLEVEL)*MarketInfo(OO_symbol,MODE_POINT),Digits);  //stop loss mínimo/ nível do take profit, em pontos
                                                                                                                     //o módulo fornece uma abertura de ordem segura. 
//--- Verificar ordens stop para comprar
   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));
        }
     }
//--- checar Ordens de stop para a venda
   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);
        }
     }
//--- enquanto no 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); //tentativa de abrir uma ordem usando os parâmetros especificados
      //--- Se houver um erro ao abrir uma ordem
      if(result<0)
        {
         Error = GetLastError();                                     //atribuir código a um erro
         switch(Error)                                               //erro de enumeração
           {                                                         //erro de enumeração do fechamento ordem e uma tentativa de corrigi-la
            case  2:
               if(attempt<attemptMax)
                 {
                  attempt=attempt+1;                                 //definir mais de uma tentativa
                  Sleep(3000);                                       //3 segundos de atraso
                  RefreshRates();
                  break;                                             //interruptor de saída
                 }
               if(attempt==attemptMax)
                 {
                  attempt=0;                                         //redefinir a quantidade de tentativas para zero 
                  exit_loop = true;                                  //saída por enquanto
                  break;                                             //interruptor de saída
                 }
            case  3:
               RefreshRates();
               exit_loop = true;                                    //saída por enquanto
               break;                                                 //interruptor de saída  
            case  4:
               if(attempt<attemptMax)
                 {
                  attempt=attempt+1;                                 //definir mais de uma tentativa
                  Sleep(3000);                                       //3 segundos de atraso
                  RefreshRates();
                  break;                                             //interruptor de saída
                 }
               if(attempt==attemptMax)
                 {
                  attempt = 0;                                       //redefinir a quantidade de tentativas para zero 
                  exit_loop = true;                                  //saída por enquanto
                  break;                                             //interruptor de saída
                 }
            case  5:
               exit_loop = true;                                    //saída por enquanto
               break;                                                 //interruptor de saída  
            case  6:
               if(attempt<attemptMax)
                 {
                  attempt=attempt+1;                                 //definir mais de uma tentativa
                  Sleep(5000);                                       //3 segundos de atraso
                  break;                                             //interruptor de saída
                 }
               if(attempt==attemptMax)
                 {
                  attempt = 0;                                       //redefinir a quantidade de tentativas para zero 
                  exit_loop = true;                                  //saída por enquanto
                  break;                                             //interruptor de saída
                 }
            case  8:
               if(attempt<attemptMax)
                 {
                  attempt=attempt+1;                                 //definir mais de uma tentativa
                  Sleep(7000);                                       //3 segundos de atraso
                  break;                                             //interruptor de saída
                 }
               if(attempt==attemptMax)
                 {
                  attempt = 0;                                       //redefinir a quantidade de tentativas para zero 
                  exit_loop = true;                                  //saída por enquanto
                  break;                                             //interruptor de saída
                 }
            case 64:
               exit_loop = true;                                    //saída por enquanto
               break;                                                //interruptor de saída
            case 65:
               exit_loop = true;                                    //saída por enquanto
               break;                                                //interruptor de saída
            case 128:
               Sleep(3000);
               RefreshRates();
               continue;                                             //interruptor de saída
            case 129:
               if(attempt<attemptMax)
                 {
                  attempt=attempt+1;                                 //definir mais de uma tentativa
                  Sleep(3000);                                       //3 segundos de atraso
                  RefreshRates();
                  break;                                             //interruptor de saída
                 }
               if(attempt==attemptMax)
                 {
                  attempt = 0;                                       //redefinir a quantidade de tentativas para zero 
                  exit_loop = true;                                  //saída por enquanto
                  break;                                             //interruptor de saída
                 }
            case 130:
               exit_loop=true;                                      //saída por enquanto
               break;
            case 131:
               exit_loop = true;                                    //saída por enquanto
               break;                                                //interruptor de saída
            case 132:
               Sleep(10000);                                         //aguardar por 10 segundos
               RefreshRates();                                       //atualizar dados
               //exit_loop = true;                                   //interruptor de saída
               break;                                                //interruptor de saída
            case 133:
               exit_loop=true;                                      //saída por enquanto
               break;                                                //interruptor de saída
            case 134:
               exit_loop=true;                                      //saída por enquanto
               break;                                                //interruptor de saída
            case 135:
               if(attempt<attemptMax)
                 {
                  attempt=attempt+1;                                 //definir mais de uma tentativa
                  RefreshRates();
                  break;                                             //interruptor de saída
                 }
               if(attempt==attemptMax)
                 {
                  attempt = 0;                                       // definir o número de tentativas para zero 
                  exit_loop = true;                                  //saída por enquanto
                  break;                                             //interruptor de saída
                 }
            case 136:
               if(attempt<attemptMax)
                 {
                  attempt=attempt+1;                                 //definir mais de uma tentativa
                  RefreshRates();
                  break;                                             //interruptor de saída
                 }
               if(attempt==attemptMax)
                 {
                  attempt = 0;                                       //definir o número de tentativas para zero 
                  exit_loop = true;                                  //saída por enquanto
                  break;                                             //interruptor de saída
                 }
            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; //saída por enquanto
               break;          //outras opções 
           }
        }
      //--- Se não houver erros detectados
      else
        {
         if(lang == "Russian") {Print("Ордер успешно открыт. ", result);}
         if(lang == "English") {Print("The order is successfully opened.", result);}
         Error = 0;                                //redefinir o código de erro para zero
         break;                                    //saída por enquanto
         //errorCount =0;                          //redefinir a quantidade de tentativas para zero
        }
     }
   return(result);
  }
//+------------------------------------------------------------------+

Como resultado, obtém-se o seguinte código:

//+------------------------------------------------------------------+
//|                                                    InsideBar.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          = 20;                               //Intervalos
extern double  lot               = 0.1;                              //Tamanho do Lote
extern int     TP                = 300;                              //Take Profit
extern int     magic             = 555124;                           //Número mágico
extern int     slippage          = 2;                                //Desvio
extern int     ExpDate           = 48;                               //Hora de Expiração da Ordem
extern int     bar2size          = 800;                              //Tamanho da Barra 2

double   buyPrice,//Definir o preço da ordem BuyStop
buyTP,      //Take Profit da ordem BuyStop
buySL,      //Stop Loss da ordem BuyStop
sellPrice,  //Definir o preço da ordem SellStop
sellTP,     //Take Profit da ordem SellStop
sellSL;     //Stop Loss da ordem SellStop

double   open1,//Abertura do preço da primeira barra
open2,    //Abertura do preço da Segunda barra
close1,   //Fechamento do preço da primeira barra
close2,   //Fechamento do preço da segunda barra 
low1,     //Mínima do preço da primeira barra
low2,     //Mínima do preço da segunda barra 
high1,    //Máxima do preço da primeira barra 
high2;    //Máxima do preço da segunda barra

datetime _ExpDate=0;          //variável local para definir um tempo de expiração da ordem pendente
double     _bar2size;
datetime timeBarInside;       //tempo da barra da ordem "Inside Bar" que foi aberta, para evitar uma reabertura
//+------------------------------------------------------------------+
//| Função de inicialização do expert                                |
//+------------------------------------------------------------------+
int OnInit()
  {
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Função desinicialização do expert                                |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
  }
//+------------------------------------------------------------------+
//| Função tick do Expert                                            |
//+------------------------------------------------------------------+
void OnTick()
  {
   double   _bid     = NormalizeDouble(MarketInfo(Symbol(), MODE_BID), Digits); //define um preço menor 
   double   _ask     = NormalizeDouble(MarketInfo(Symbol(), MODE_ASK), Digits); //define um preço maior
   double   _point   = MarketInfo(Symbol(), MODE_POINT);
//--- Definir os preços das barras necessárias
   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);
//---
   _bar2size=NormalizeDouble(((high2-low2)/_point),0);
// --- Se a segunda barra é de baixa, enquanto a primeira é de alta
   if(timeBarInside!=iTime(Symbol(),Period(),1) && //Sem ordens abertas ainda neste padrão 
      _bar2size>bar2size && //a segunda barra tem de ser grande o suficiente, de modo que o mercado não seja lateral
      open2>close2 && //Segunda barra é de baixa
      close1>open1 && //Primeira barra é de alta
      high2>high1 &&  //Máxima da segunda barra excede a Máxima da primeira
      open2>close1 && //Abertura da segunda barra excede o Fechamento da primeira barra
      low2<low1)      //Mínima da segunda barra é menor do que a Mínima da primeira barra
     {
      buyPrice=NormalizeDouble(high2+interval*_point,Digits); //define um preço da ordem considerando o intervalo
      buySL=NormalizeDouble(low2-interval*_point,Digits);     //definir um stop loss considerando o intervalo
      buyTP=NormalizeDouble(buyPrice+TP*_point,Digits);       //define um take profit
      _ExpDate=TimeCurrent()+ExpDate*60*60;                   //o cálculo do tempo de expiração da ordem pendente
      sellPrice=NormalizeDouble(low2-interval*_point,Digits);
      sellSL=NormalizeDouble(high2+interval*_point,Digits);
      sellTP=NormalizeDouble(sellPrice-TP*_point,Digits);
      OrderOpenF(Symbol(),OP_BUYSTOP,lot,buyPrice,slippage,buySL,buyTP,NULL,magic,_ExpDate,Blue);
      OrderOpenF(Symbol(),OP_SELLSTOP,lot,sellPrice,slippage,sellSL,sellTP,NULL,magic,_ExpDate,Blue);
      //--- listamos todas as condições que definem que a primeira barra está completamente envolvida pela segunda
      timeBarInside=iTime(Symbol(),Period(),1); //indica que as ordens já estão colocadas neste padrão
     }
  }
//+------------------------------------------------------------------+

Agora, vamos realizar a compilação e verificar se há mensagens de erro no arquivo de registro (log).


Testando o Expert Advisor

É hora de testar o nosso Expert Advisor. Vamos lançar no Testador de Estratégia e definir os parâmetros de entrada. Eu especifiquei os parâmetros da seguinte forma:

Fig. 6. Parâmetros de entrada para teste

Fig. 6. Parâmetros de entrada para teste

  1. Selecione um símbolo (neste exemplo é o CADJPY).
  2. Certifique-se de definir o teste no modo "Cada tick" e definir que o teste deve ser realizado com dados do histórico. Eu selecionei todo o ano de 2014.
  3. Defina o prazo D1.
  4. Lançar o teste.
  5. Após a conclusão do teste, verifique o log. Como podemos ver, nenhum erro de execução ocorreu no processo.

Abaixo é a diário de teste do EA:

Fig. 7. Diário de teste do Expert Advisor

Fig. 7. Diário de teste do Expert Advisor

Certifique-se de que não existem erros e otimize o EA.


Otimização

Eu selecionei os seguintes parâmetros para a otimização:

Fig. 8. Parâmetros de otimização

Fig. 8. Parâmetros de otimização


Fig. 9. Configurações de otimização

Fig. 9. Configurações de otimização

Assim temos agora o robô pronto para uso.


Otimização e Resultados dos Testes

Fig. 10. Resultados do teste

Fig. 10. Resultados do teste


Fig. 11. Grafico com os resultados do teste

Fig. 11. Grafico com os resultados do teste


Conclusão

  1. Nós desenvolvemos um Expert Advisor padrão pronto para ser usado, operando com o padrão "Inside Bar".
  2. Temos a certeza de que os padrões Ação de Preço podem trabalhar mesmo sem filtros adicionais na entrada do mercado.
  3. Nenhum truque (como Martingale ou média) foi utilizado.
  4. O Rebaixamento foi minimizado através da definição correta das ordens de Stop Loss.
  5. Nao foram utilizados indicadores técnicos. O robô de negociação é baseado exclusivamente na leitura de um gráfico de "barras".

Obrigado por ler! Espero que este artigo tenha sido útil.