English Русский 中文 Español Deutsch 日本語
Expert Advisor para Negociação no Canal

Expert Advisor para Negociação no Canal

MetaTrader 4Exemplos | 4 novembro 2015, 14:50
1 007 0
Genkov
Genkov

Introdução

Com este artigo quero compartilhar minha experiência com os traders inexperientes que sabem o básico de MQL4, publicando um programa que pode ser útil quando da negociação num canal. Antes de iniciar a negociação neste sistema, você deve compreender claramente os princípios subjacentes, ou seja, como o tamanho do canal e a mudança de direção são dependentes do movimento do preço. Cada linha do canal está baseada em fractais inteiramente formados dentro da variação das barras visíveis no gráfico.

O Expert Advisor Semi-automático para Negociação no Canal

O programa padrão está nos arquivos anexados.

Primeiro vamos decidir sobre o número de barras para a pesquisa fractal por pontos, neste momento nós também definiremos o valor do espaço para as setas serem exibidas no gráfico.

switch (Period())
{
case 1:     B_F=12; space=0.0002; break;
case 5:     B_F=48; space=0.0003; break;
case 15:    B_F=24; space=0.0004; break;
case 30:    B_F=24; space=0.0004; break;
case 60:    B_F=12; space=0.0007; break;
case 240:   B_F=15; space=0.0012; break;
case 1440:  B_F=10; space=0.0030; break;
case 10080: B_F=6;  space=0.0040; break;
}

Começamos criando o canal pela pesquisa de pontos de referências (barras) e através destes pontos as linhas do canal serão desenhadas. Pelos pontos identificados, superiores ou inferiores, vamos determinar as seguintes condições a nível de variáveis globais:

  • Extrem = (0) - fractal não foi encontrado,
  • Extrem = (1) - fractal superior encontrado, // qualquer número positivo
  • Extrem = (-1) - fractal inferior encontrado, // qualquer número negativo

Vamos definir os valores iniciais de indeterminação para pontos de referência e as suas posições no gráfico da seguinte forma:

NB1=-1; NB2=-1; Extrem=0;

O teste começará a partir da terceira barra (contada como "0") tendo em vista a possível "formação fractal".

TestBar=2;  // Número da barra que está sendo testada

Para identificar os casos em que a barra testado coincide com o valor máximo ou mínimo que encontra-se dentro das faixas acima definidas, vamos adicionar um loop (while). A condição de loop será uma expressão com valores negativos dos números das barras. Também o número da barra a ser testada deverá ser menor do que o número total de barras envolvidas.

while(((NB1==-1) || (NB2==-1)) && (TestBar<AllB))

Primeiro vamos assumir que os pontos da extremidade inferior enganam e testamos as barras para ver se elas combinam com os valores mínimos. Se dois pontos são encontrados, as condições do loop tornam-se falsas e a execução do operador será encerrada.

Abaixo está o trecho do loop "while" para a identificação de pontos inferiores no gráfico. A busca de pontos de referência superiores é implementada de uma forma similar.

//comece a contar a partir da terceira barra (contada como "0") para "identificação do fractal"
TestBar=2;  // Número da barra que está sendo testada
NB1=-1; NB2=-1; Extrem=0;   // Assume que os números das barras e das extremidades não são determinados 
while(((NB1==-1) || (NB2==-1)) && (TestBar<AllB))
  {//w1
// -------------------------------------------------------------------------------------+
//  Se: o valor Extrem é menor do que (1) (duas opções possíveis: "0" e "-1"), 
//  então o índice do valor de menor preço coincide com o índice da barra considerada
// -------------------------------------------------------------------------------------+   
   if((Extrem<1) && (TestBar==iLowest(Symbol(),Period(),MODE_LOW,B_F*2+1,TestBar-B_F)))
     {//w2
      // se "0" não existe extremidade naquele momento,
      if(Extrem==0)
        {//w3
         // atribuir: o valor (-1) ao ponto de extremidade identificado, indicando assim  
         // que esta é a extremidade inferior, o número da barra determinada (NB1) e o valor do preço (Pr1).   
         Extrem=-1; NB1=TestBar; Pr1=Low[NB1];
        }//-w3
      else  if(Extrem!=0) // o primeiro ponto foi encontrado no início,
                          // caso contrário, o número e o valor do preço são atribuídos ao ponto 2
        {//w4
         NB2=TestBar; Pr2=Low[NB2];
        }//-w4
      // para fins de controle, os valores podem ser impressos: Print("bar #= ",NB2," price value= ",Pr2); 
     }//-w2
// -------------------------------------------------------------------------------------+

Se apenas um ponto for encontrado, então as condições do loop permanecerão verdadeiras e o operador irá prosseguir à extremidade superior. Se 2 pontos superiores não podem ser encontrados, então no momento não há pontos para criar um canal.

if((NB1==-1) || (NB2==-1)) // não existem pontos de referência encontrados nas últimas barras AllB

Com dois pontos de referência disponíveis, calcula-se a taxa de variação de preços:

RatePr=(Pr2-Pr1)/(NB2-NB1);

Então encontramos o primeiro ponto de referência da linha do canal como uma projeção do primeiro ponto de referência na barra "0":

double Tk1=Pr1-NB1*RatePr;

O segundo ponto de referência da linha do canal é identificado dentro do alcance visual no lado esquerdo do gráfico, por exemplo, 50 barras à esquerda a partir do segundo ponto de referência.

double Tk2=Tk1+(NB2+50)*RatePr;

Vamos agora traçar a linha paralela do canal oposta à linha determinada:

Para encontrar o terceiro ponto de referência, vamos testar se as barras encontram-se entre os outros dois pontos de referência a partir de NB1 para NB2 (ou de "0" para NB2 e da segunda barra para NB2). Os testes serão feitos com base na extremidade que está na direção oposta aos pontos encontrados. Por exemplo, se os pontos determinados são pontos superiores do gráfico, então as barras serão testadas com base nas Mínimas dos preços. Depois de encontrar o terceiro ponto de referência, os outros dois pontos de referência para a linha oposta do canal são determinados na mesma seção.

O trecho a seguir é fornecido com comentários detalhados.

// Plotar a linha oposta do canal paralela à linha determinada.
// Localizar o ponto de referência para a linha oposta de canal. 
// Pegue a mínima do preço da 2ª barra como origem da pesquisa.
Tk3=Low[2]-2*RatePr; // Projeção da segunda barra na barra "0" 
for(i=3;i<=NB2;i++) // iniciar a pesquisa a partir da 3ª barra
  {//2(1)Up
   if(Low[i]<Tk3+i*RatePr) // Usar o valor da mínima do preço para projeção na barra "0"
     {//3(1)Up
      Tk3=Low[i]-i*RatePr; // Terceiro ponto de referência (projeção na barra "0")
      Pr5=Low[i];          // o terceiro ponto de referência para a linha inferior do canal
      NB5=i;               // número da barra do terceiro ponto de referência
     }//-3(1)Up
  }//-2(1)Up

Após o terceiro ponto de referência ter sido encontrado, você pode desenhar esses pontos no gráfico, suprimido os existentes anteriormente.

O trecho do programa para desenhar pontos de referência no gráfico é mostrado abaixo.

   ObjectDelete("Rep1"); ObjectDelete("Rep2"); ObjectDelete("Rep3"); ObjectDelete("Rep5");
   ObjectCreate("Rep1",OBJ_ARROW, 0, TmR1, Pr1+2*space);
      ObjectSet("Rep1", OBJPROP_COLOR, Yellow);
      ObjectSet("Rep1", OBJPROP_ARROWCODE,72); 
   ObjectCreate("Rep2",OBJ_ARROW, 0, TmR2, Pr2+2*space);
      ObjectSet("Rep2", OBJPROP_COLOR, Yellow);
      ObjectSet("Rep2", OBJPROP_ARROWCODE,72); 
   ObjectCreate("Rep5",OBJ_ARROW, 0, TmR5, Pr5-space);
      ObjectSet("Rep5", OBJPROP_COLOR, Yellow);
      ObjectSet("Rep5", OBJPROP_ARROWCODE,71);
  ObjectDelete("Cross2");

Como resultado, serão visualizados os símbolos dos pontos de referência acima/abaixo (por favor veja abaixo)

Depois de determinar três e quatro pontos de referência, as linhas podem ser plotadas no gráfico:

DelObj1();  
ObjectCreate("Tr1",OBJ_TREND,0,Tm2,Tk2,Tm1,Tk1);
  ObjectSet("Tr1",OBJPROP_COLOR,Lime); 
  ObjectSet("Tr1",OBJPROP_WIDTH,1); //2
  ObjectSet("Tr1",OBJPROP_STYLE,STYLE_SOLID); 
ObjectCreate("Tr2",OBJ_TREND,0,Tm2,Tk4,Tm1,Tk3); 
  ObjectSet("Tr2",OBJPROP_COLOR,Lime); 
  ObjectSet("Tr2",OBJPROP_WIDTH,1); //2
  ObjectSet("Tr2",OBJPROP_STYLE,STYLE_SOLID); 
ObjectCreate("Med",OBJ_TREND,0,Tm2,(Tk2+Tk4)/2,Tm1,(Tk1+Tk3)/2);
  ObjectSet("Med",OBJPROP_COLOR,Lime); 
  ObjectSet("Med",OBJPROP_WIDTH,1); 
  ObjectSet("Med",OBJPROP_STYLE,STYLE_DOT); 

Vamos calcular os valores medianos e os limites do canal nas últimas 6 barras:

for(int i=0;i<6;i++)
  {
   TLUp_[i]=Tk1+i*RatePr;
   TLDn_[i]=Tk3+i*RatePr;
   Med_[i]=(TLUp_[i]+TLDn_[i])/2;
  }

Se o preço cruzou a linha do canal, então marcá-lo com um asterisco e adicionar um som de notificação:

if(Bid>TLUp_[0])
  {
   bool TrUp=true; //bool TrDn=false; 
   ObjectDelete("Cross1");  ObjectDelete("Cross2");
   ObjectCreate("Cross1",OBJ_ARROW,0,Tm1,High[1]+2*space);
   ObjectSet("Cross1",OBJPROP_COLOR,DeepPink);
   ObjectSet("Cross1",OBJPROP_ARROWCODE,171);
   PlaySound("alert.wav"); // O arquivo deve estar localizado no caminho de diretório: terminal_directory\sounds
  }

Se houver um fractal integralmente formado nas últimas barras, marcá-lo no gráfico:

ObjectDelete("Fraktal"+(q-1));  //ObjectDelete("Frakt"+(w-1));
ObjectCreate("Fraktal"+q,OBJ_ARROW, 0, Time[2], High[2]+2*space+0.0002);
ObjectSet   ("Fraktal"+q, OBJPROP_COLOR, Orchid);
ObjectSet   ("Fraktal"+q, OBJPROP_ARROWCODE,217);


Nós acabamos de considerar certas peculiaridades e trechos de programas relacionados com a criação de uma canal baseado em fractais.

Agora vamos falar sobre a possibilidade de negociação neste canal.

Suponha que o canal é direcionado para cima e a barra atual esta está se movendo para baixo e perto de cruzar o limite inferior do canal. Nesta situação os possíveis comportamento dos preços podem ser os seguintes:

  • O preço retorna para cima antes de atingir o limite inferior;
  • O preço vai atingir o limite inferior e retornar para cima;
  • O preço vai cruzar a linha de canal e em seguida retorna para cima;
  • Vai travessar o limite inferior e o preço vai continuar se movendo para baixo (rompimento para baixo).

Quando falamos em cruzamento do limite inferior da barra, estamos nos referindo a mínima do preço.
Em face disso os três primeiros padrões de movimento do preços são adequados para abrir uma posição "BUY". Vamos dar uma olhada neles. Devemos ter em mente que o canal neste Expert Advisor é criado com base em fractais totalmente formados. Portanto há uma possibilidade de que o canal mude a sua direção após uma correção do fractal nas últimas três barras, precisamos levar esta situação em consideração.

Vamos rever o primeiro padrão. A barra atual deverá ser aberta no valor maior do que a mínima da barra anterior (barra 1), o valor mínimo da terceira barra a esquerda também deverá ser maior do que o valor mínimo da barra 1. Então 3 barras (contados a partir da direita para a esquerda, ou seja, a partir da barra 0) é o valor mínimo necessário para a formação de um fractal. E se a direção para cima do canal não mudou, podemos abrir uma posição BUY.

Agora algumas palavras sobre a mudança na direção do canal. Se o canal for plotado com base em pontos de referência mais baixo, com o ponto mínimo fractal acima da linha inferior do canal, então a direção do canal não vai mudar.

Se o canal for plotado com com base em pontos de referência mais alto, a direção do canal permanecerá a mesma. A questão decorrente do primeiro padrão é se o valor da diferença entre o limite inferior do canal e o valor mínimo do fractal formado perto desse limite pode ser considerado suficiente. Este valor depende principalmente do tamanho do canal.

O terceiro padrão de movimento do preço como regra leva à alteração da inclinação do canal e até mesmo os resultados na mudança da direção do canal, pois o fractal é formada abaixo do limite inferior do canal. Se o canal foi criado com base nos valores mínimos dos dois primeiros pontos de referência e o valor do fractal formado acabou por ser menor do que o primeiro ponto de referência e maior do que o segundo ponto de referência,então a declividade do canal será ajustada e a direção permanecerá para cima.

Se o valor mínimo da barra do fractal formado também for menor do que o segundo ponto de referência, então a direção do canal muda para baixo. A recíproca é verdadeira para as posições SELL, porém no sentido oposto. Abaixo estão exemplos de negociação utilizando o Expert Advisor proposto.


Nos blocos para abertura de ordem e posição de rastreamento, você pode encontrar um exemplo das condições de abertura e fechamento de posição testadas no modo de demonstração. Resultado de teste:


O código do programa completo é descrito abaixo:

//+------------------------------------------------------------------+
//|                                             Expert_Ch_v83_2_.mq4 |
//|                                            2009, author - Genkov |
//|                                                     Genkov@bk.ru |
//+------------------------------------------------------------------+
#property copyright "2009, author - Genkov"
#property link      "Genkov@bk.ru"
//+------------------------------------------------------------------+
extern double SL_B=200;
extern double TP_B=50;
extern double SL_S=200;
extern double TP_S=50;
extern double Lots=1.0;
double TrailingStop=40;
int Magic,i;
extern int AllB=240;        // número de barras para cálculos
int TestBar=0;              // índice da barra que está sendo testada
double RatePr=0;            // taxa de variação de preços - pips/barras
int NB1=-1,NB2=-1,NB3,NB5;  // número das barras dos pontos de referência
int Extrem=0;               // índices dos pontos de extremidade: 
/* Extrem = (0)  - fractal não foi encontrado, 
     xtrem = (1)  - fractal superior encontrado (qualquer número positivo)
     Extrem = (-1) - fractal inferior encontrado (qualquer número negativo)
  */
double Pr1=0,Pr2=0,Pr3,Pr5,// preços das barras referenciadas com fractais 
Tk1,Tk2,Tk3,Tk4,Tk5; // preços de pontos de referência para plotar as linhas do canal 
double space;               // distância do preço até a "seta"
double TLUp_[10],TLDn_[10],// valores dos limites do canal
Med_[10];
int B_F=0;                  // Número das barras para fractais num período
datetime Tm1,Tm2,Tm3,Tm5;   // Tempo das barras dos pontos de referência
string SH;                  // declividade do canal
bool FraktUp=false;         // flag do símbolo do fractal superior
bool FraktDn=false;         // flag do símbolo do fractal inferior 
int q,w;
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
void DelObj1()
  {
   ObjectDelete("Tr1");
   ObjectDelete("Tr2");
   ObjectDelete("Med");
  }
//+------------------------------------------------------------------+
void Op_Sell_Ch()
  {
   if(!OrderSend(Symbol(),OP_SELL,Lots,Bid,2,Ask+SL_S*Point,Bid-TP_S*Point," ",Magic,0,Red))
     { Print("  Error when opening a SELL order  # ",GetLastError()); }
   return(0);
  }
//+------------------------------------------------------------------+
void Op_Buy_Ch()
  {
   if(!OrderSend(Symbol(),OP_BUY,Lots,Ask,2,Bid-SL_B*Point,Ask+TP_B*Point," ",Magic,0,Blue))
     { Print("  Error when opening a SELL order  # ",GetLastError()); }
   return(0);
  }
//+------------------------------------------------------------------+
void Close_B_lot()
  {
   if(!OrderClose(OrderTicket(),OrderLots(),Bid,2,HotPink)) // fechando lote 0.1  
     {
      Print(" Closed order #= ",OrderTicket(),"Error #= ",GetLastError());
      RefreshRates();
     }
  }
//+------------------------------------------------------------------+
void Close_S_lot()
  {
   if(!OrderClose(OrderTicket(),OrderLots(),Ask,2,Aqua)) // fechando lote 0.1  
     {
      Print(" Closed order #= ",OrderTicket(),"Error #= ",GetLastError());
      RefreshRates();
     }
  }
// ===================================================================+
int start()
  {
   int StopLevel=MarketInfo(Symbol(),MODE_STOPLEVEL);
// Número de barras para a pesquisa do fractal por períodos    
   switch(Period())
     {
      case 1:     B_F=12; space=0.0002; break;
      case 5:     B_F=48; space=0.0003; break;
      case 15:    B_F=24; space=0.0004; break;
      case 30:    B_F=24; space=0.0004; break;
      case 60:    B_F=12; space=0.0007; break;
      case 240:   B_F=15; space=0.0012; break;
      case 1440:  B_F=10; space=0.0030; break;
      case 10080: B_F=6;  space=0.0040; break;
     }
// ====================================================================================+
// Criando um canal:
//comece a contar a partir da terceira barra (contada como "0") para "identificação do fractal"
   TestBar=2;  // Número da barra que está sendo testada
   NB1=-1; NB2=-1; Extrem=0;   // Assume que os números das barras e das extremidades não são determinados 
   while(((NB1==-1) || (NB2==-1)) && (TestBar<AllB))
     {//w1
      // -------------------------------------------------------------------------------+
      //  Se: o valor Extrem é menor do que (1) (duas opções possíveis: "0" e "-1"), 
      //  então o índice do valor de menor preço coincide com o índice da barra considerada
      // -------------------------------------------------------------------------------+   
      if((Extrem<1) && (TestBar==iLowest(Symbol(),Period(),MODE_LOW,B_F*2+1,TestBar-B_F)))
        {//w2
         // se "0" não existe extremidade naquele momento,
         if(Extrem==0)
           {//w3
            // atribuir: o valor (-1) ao ponto de extremidade identificado, indicando assim  
            // que esta é a extremidade inferior, o número da barra determinada (NB1) e o valor do preço (Pr1).   
            Extrem=-1; NB1=TestBar; Pr1=Low[NB1];
           }//-w3
         else  if(Extrem!=0) // o primeiro ponto foi encontrado no início,
                             // caso contrário, o número e o valor do preço são atribuídos ao ponto 2
           {//w4
            NB2=TestBar; Pr2=Low[NB2];
           }//-w4
         // para fins de controle, os valores podem ser impressos: Print("bar #= ",NB2," price value= ",Pr2); 
        }//-w2
      // -------------------------------------------------------------------------------+
      //  Se: o valor Extrem é maior do que (-1) (duas opções possíveis: "0" e "1") e o índice de preço mais elevado
      //  valor coincide com o número da barra considerada - (similar à acima)
      // -------------------------------------------------------------------------------+
      if((Extrem>-1) && (TestBar==iHighest(Symbol(),Period(),MODE_HIGH,B_F*2+1,TestBar-B_F)))
        {//w5
         // se Extrem==0 
         if(Extrem==0)
           {//w6
            // armazena o número da barra (NB1) e o valor do preço (Pr1).
            Extrem=1; NB1=TestBar; Pr1=High[NB1];
           }//-w6
         else // Caso contrário, o número e o valor do preço será atribuído ao ponto 2
           {//w7
            NB2=TestBar; Pr2=High[NB2];
           }//-w7
        }//-w5
      TestBar++;
     }//-w1
// -----------------------------------------------------------------------------------+
   if((NB1==-1) || (NB2==-1)) // Não existem pontos de referência encontrados nas últimas barras ALLB
     {
      DelObj1(); ObjectDelete("Cross1"); ObjectDelete("Cross2");  ObjectDelete("Rep1");
      ObjectDelete("Rep2"); ObjectDelete("Rep3"); ObjectDelete("Rep5");
      // Imprimir(" === > nenhuma barra no canal "); // para fins de controle único (pode ser suprimido)
      return(-1);
     }
// --------------------------------- 
// Calcular a taxa de variação dos preços.
   RatePr=(Pr2-Pr1)/(NB2-NB1);
// Se o valor for positivo, estamos lidando com um canal de baixa, caso contrário - de alta.
   if(RatePr>0) SH="downward"; else  SH="upward";
// Determinar o tempo dos pontos de referência para as linhas de canal
   Tm1=Time[0];    Tm2=Time[NB2+50];
// **************************************************************************************   
   if(Extrem==1) // Se uma extremidade superior foi encontrada primeiro 
     {//1(Extrem=1)
      // Com dois pontos de referência e a taxa de variação dos preços disponíveis,
      // determinar pontos de referência desta linha:
      // O primeiro ponto de referência é a projeção do ponto de referência sobre a barra "0" 
      double Tk1=Pr1-NB1*RatePr;
      // O segundo ponto de referência é a projeção no lado esquerdo do gráfico
      double Tk2=Tk1+(NB2+50)*RatePr;
      // Plotar a linha oposta do canal paralela à linha determinada.
      // Localizar o ponto de referência para a linha oposta de canal. 
      // Pegue a mínima do preço da 2ª barra como origem da pesquisa.
      Tk3=Low[2]-2*RatePr; // Projeção da segunda barra na barra "0" 
      for(i=3;i<=NB2;i++) // iniciar a pesquisa a partir da 3ª barra
        {//2(1)Up
         if(Low[i]<Tk3+i*RatePr) // Usar o valor da mínima do preço para projeção na barra "0"
           {//3(1)Up
            Tk3=Low[i]-i*RatePr; // Terceiro ponto de referência (projeção na barra "0")
            Pr5=Low[i];          // o terceiro ponto de referência para a linha inferior do canal
            NB5=i;               // número da barra do terceiro ponto de referência
           }//-3(1)Up
        }//-2(1)Up
      // olhando agora para as duas primeiras barras: "0" e "1"; seus valores da Mínima podem ser menores do que a segunda barra
      // Se considerarmos o ajuste do canal utilizando estas duas barras, o canal será 
      // mais amplo seguindo o movimento descendente dos preços; se este movimento for ignorado 
      // pode ser considerado como um rompimento da linha do canal de fuga (possível início de uma tendência!)
      // if(Low[0]<Tk3) {Tk3=Low[0]; Pr5=Low[0]; NB5=0;}
      // if(Low[1]<Tk3+RatePr) {Tk3=Tk3+RatePr; Pr5=Low[1]; NB5=1;}
      datetime TmR1=Time[NB1];    datetime TmR2=Time[NB2];   datetime TmR5=Time[NB5];
      // -------------------------------------------------------------------------------------
      // os seguintes operadores são destinados ao controle visual do desempenho do programa (eles podem ser excluídos)
      // e exibem o valor da declividade do canal, da taxa de velocidade,dos números e do tempo dos pontos de referência no Extrem = 1
      string TNB1=TimeToStr(TmR1,TIME_DATE|TIME_MINUTES);
      string TNB2=TimeToStr(TmR2,TIME_DATE|TIME_MINUTES);
      string TNB5=TimeToStr(TmR5,TIME_DATE|TIME_MINUTES);
      //   Imprimir(" channel- ",SH," ; speed = ",DoubleToStr(NormalizeDouble(RatePr,8),8),
      //         " pip / bar"," ; Extrem= ",Extrem);
      //   Imprimir(" NB2= ",NB2," ; time= ",TNB2," ; NB5= ",NB5,
      //         " ; time= ",TNB5," ; NB1= ",NB1," ; time= ",TNB1);
      // --------------------------------------------------------------------------------------
      // Para a clareza do desempenho do programa, marque os pontos das referências nas linhas do canal no gráfico
      ObjectDelete("Rep1"); ObjectDelete("Rep2"); ObjectDelete("Rep3"); ObjectDelete("Rep5");
      ObjectCreate("Rep1",OBJ_ARROW,0,TmR1,Pr1+2*space);
      ObjectSet("Rep1",OBJPROP_COLOR,Yellow);
      ObjectSet("Rep1",OBJPROP_ARROWCODE,72);
      ObjectCreate("Rep2",OBJ_ARROW,0,TmR2,Pr2+2*space);
      ObjectSet("Rep2",OBJPROP_COLOR,Yellow);
      ObjectSet("Rep2",OBJPROP_ARROWCODE,72);
      ObjectCreate("Rep5",OBJ_ARROW,0,TmR5,Pr5-space);
      ObjectSet("Rep5",OBJPROP_COLOR,Yellow);
      ObjectSet("Rep5",OBJPROP_ARROWCODE,71);
      ObjectDelete("Cross2");
      // -------------------------------------------------------------------------------------
      // calcula os preços de coordenadas dos pontos de referência no limite inferior do canal:
      double Tk3=Pr5-RatePr*NB5; // preço do limite inferior do canal no ponto "0"
      double Tk4=Tk3+RatePr*(NB2+50);// preço do limite inferior do canal no lado esquerdo do gráfico
     }//- 1(Extrem=1)
// ******************************************************************************************
   else  if(Extrem==-1)// se uma extremidade superior foi encontrada primeiro 
     {//1(Extrem= -1)
                                     / /preços de pontos de referência no limite inferior do canal:
      Tk3=Pr1-NB1*RatePr;      // no ponto "0"
      Tk4=Tk3+(NB2+50)*RatePr; // no ponto do lado esquerdo 
                               // Plotar a linha oposta do canal paralela à linha determinada.
      // Localizar o ponto de referência para a linha oposta do canal. 
      // Pegue o preço da segunda barra como a origem da pesquisa.
      Tk1=High[2]-2*RatePr; // projeção da segunda barra na barra "0" 
      for(i=3;i<=NB2;i++) // iniciar a pesquisa a partir da 3ª barra
        {//2(-1)
         if(High[i]>Tk1+i*RatePr)
           {//3(-1)
            Tk1=High[i]-i*RatePr; // o terceiro ponto de referência (projeção na barra "0")
            Pr3=High[i];          // o terceiro ponto de referência para a linha superior do canal
            NB3=i;                // número da barras do terceiro ponto de referência
           }//-3(-1)
         // Agora olha para as duas primeiras barras: "0" e "1"
         // if(High[0]>Tk1) {Tk1=High[0]; Pr3=High[0]; NB3=0;}
         // if(High[1]>Tk1+RatePr) {Tk1=Tk1+RatePr; Pr3=High[1]; NB3=1;}
         TmR1=Time[NB1];    TmR2=Time[NB2];   datetime TmR3=Time[NB3];
        }//- 2(-1)
      // ---------------------------------------------------------------------------------
      // Adicionar os seguintes operadores para monitorar os resultados de desempenho 
      //(eles não afetam o desempenho do programa e podem ser excluídos),
      // Eles exibem o valor de declive, a taxa de velocidade bem como números do canal (velocidade)  
      // e o tempo dos pontos de referência no Extrem = -1

      // TNB1=TimeToStr(TmR1,TIME_DATE|TIME_MINUTES);  
      // TNB2=TimeToStr(TmR2,TIME_DATE|TIME_MINUTES);
      // string TNB3=TimeToStr(TmR3,TIME_DATE|TIME_MINUTES);
      // Imprimir(" channel- ",SH," ; price speed rate= ",DoubleToStr(NormalizeDouble(RatePr,8),8),
      //       " pip / bar"," ; Extrem= ",Extrem);
      // Imprimir(" ; NB2= ",NB2," ; time= ",TNB2," ; NB3= ",NB3,
      //       " ; time= ",TNB3," ; NB1= ",NB1," ; time= ",TNB1);
      // ----------------------------------------------------------------------------------
      // para maior clareza, marque os pontos de referência na linha do canal no gráfico
      ObjectDelete("Rep1"); ObjectDelete("Rep2");
      ObjectDelete("Rep3"); ObjectDelete("Rep5");
      ObjectCreate("Rep1",OBJ_ARROW,0,TmR1,Pr1-space);
      ObjectSet("Rep1",OBJPROP_COLOR,Yellow);
      ObjectSet("Rep1",OBJPROP_ARROWCODE,71);
      ObjectCreate("Rep2",OBJ_ARROW,0,TmR2,Pr2-space);
      ObjectSet("Rep2",OBJPROP_COLOR,Yellow);
      ObjectSet("Rep2",OBJPROP_ARROWCODE,71);
      ObjectCreate("Rep3",OBJ_ARROW,0,TmR3,Pr3+2*space);
      ObjectSet("Rep3",OBJPROP_COLOR,Yellow);
      ObjectSet("Rep3",OBJPROP_ARROWCODE,72);
      ObjectDelete("Cross1");
      // ---------------------------------------------------------------------------------    
      // calcular os preços dos pontos de referência no limite superior do canal:
      Tk1=Pr3-RatePr*NB3; // preço do limite superior do canal no ponto "0"
      Tk2=Tk1+RatePr*(NB2+50);// preço do limite superior do canal no ponto do lado esquerdo
     }//-1(Extrem= -1)
// ---------------------------------======================================================
// calcular os valores médios dos limites do canal e dos limites do canal nas últimas 6 barras
   for(int i=0;i<6;i++)
     {
      TLUp_[i]=Tk1+i*RatePr;
      TLDn_[i]=Tk3+i*RatePr;
      Med_[i]=(TLUp_[i]+TLDn_[i])/2;
     }
// --------------------------------------------------------------------
// Se o preço cruzar a linha superior do canal, marcar com um asterisco e adicionar uma notificação sonora
   if(Bid>TLUp_[0])
     {
      bool TrUp=true; //bool TrDn=false; 
      ObjectDelete("Cross1");  ObjectDelete("Cross2");
      ObjectCreate("Cross1",OBJ_ARROW,0,Tm1,High[1]+2*space);
      ObjectSet("Cross1",OBJPROP_COLOR,DeepPink);
      ObjectSet("Cross1",OBJPROP_ARROWCODE,171);
      PlaySound("alert.wav"); // O arquivo deve estar localizado no caminho de diretório: terminal_directory\sounds
     }
// Se o preço cruzar a linha inferior do canal, marcar com um asterisco e adicionar uma notificação sonora
   if(Bid<TLDn_[0])
     {
      ObjectDelete("Cross2");  ObjectDelete("Cross1");
      /// Imprimir(" "houve um cruzamento da linha inferior do canal" ");
      ObjectCreate("Cross2",OBJ_ARROW,0,Tm1,Low[1]-space);
      ObjectSet("Cross2",OBJPROP_COLOR,DodgerBlue);
      ObjectSet("Cross2",OBJPROP_ARROWCODE,171);
      PlaySound("alert.wav"); // O arquivo deve estar localizado no caminho de diretório: terminal_directory\sounds
     }
// ------------------------------------------------------------------------------------- 
// Traçar os limites do canal no gráfico, deletando os anteriores 
   DelObj1();
   ObjectCreate("Tr1",OBJ_TREND,0,Tm2,Tk2,Tm1,Tk1);
   ObjectSet("Tr1",OBJPROP_COLOR,Lime);
   ObjectSet("Tr1",OBJPROP_WIDTH,1); //2
   ObjectSet("Tr1",OBJPROP_STYLE,STYLE_SOLID);
   ObjectCreate("Tr2",OBJ_TREND,0,Tm2,Tk4,Tm1,Tk3);
   ObjectSet("Tr2",OBJPROP_COLOR,Lime);
   ObjectSet("Tr2",OBJPROP_WIDTH,1); //2
   ObjectSet("Tr2",OBJPROP_STYLE,STYLE_SOLID);
   ObjectCreate("Med",OBJ_TREND,0,Tm2,(Tk2+Tk4)/2,Tm1,(Tk1+Tk3)/2);
   ObjectSet("Med",OBJPROP_COLOR,Lime);
   ObjectSet("Med",OBJPROP_WIDTH,1);
   ObjectSet("Med",OBJPROP_STYLE,STYLE_DOT);
// ---- Bloco de marcação dos fractais no gráfico ---------------------------------
   if((High[2]>High[1] && Bid<High[2] && High[2]>High[3] && High[2]>High[4]) || 
      (High[2]==High[1] && Bid<High[1] && High[2]>High[3] && High[2]>High[4]))
     {
      double FraktalUp=High[2]; // fractal superior
      double FraktalDn=0;
      // Se um fractal foi formado, colocar um símbolo marcando
      // um novo ponto de referência - apagar o símbolo marcando o cruzamento da linha superior do canal pelo preço.
      if(High[2]>=TLUp_[i]) ObjectDelete("Cross1");
      ObjectDelete("Fraktal"+(q-1));  //ObjectDelete("Frakt"+(w-1));
      ObjectCreate("Fraktal"+q,OBJ_ARROW,0,Time[2],High[2]+2*space+0.0002);
      ObjectSet("Fraktal"+q,OBJPROP_COLOR,Orchid);
      ObjectSet("Fraktal"+q,OBJPROP_ARROWCODE,217);
      bool FraktUp=true; //bool FraktDn=false;// será útil na negociação
      q++;
     }
   if((Low[2]<Low[1] && Bid>Low[2] && Low[2]<Low[3] && Low[2]<Low[4]) || 
      (Low[2]==Low[1] && Bid>Low[1] && Low[2]<Low[3] && Low[2]<Low[4]))
     {
      FraktalDn=Low[2]; // fractal inferior 
      FraktalUp=0;
      if(Low[2]>=TLUp_[i]) ObjectDelete("Cross2");
      ObjectDelete("Frakt"+(w-1)); //ObjectDelete("Fraktal"+(q-1));
      ObjectCreate("Frakt"+w,OBJ_ARROW,0,Time[2],Low[2]-2*space);
      ObjectSet("Frakt"+w,OBJPROP_COLOR,Orchid);
      ObjectSet("Frakt"+w,OBJPROP_ARROWCODE,218);
      FraktDn=true; FraktUp=false;
      w++;
     }
// -------------------------------------------------------------------------+
// Bloco das condições de abertura da posição. Este é apenas um exemplo     +
// e não deve ser considerado como uma recomendação para o uso!             +          
// -------------------------------------------------------------------------+
   if(OrdersTotal()<1) // negociar uma posição  
     {
      // - 16- SELL ---
      if(Extrem==1 && // dois pontos de referência superiores
         RatePr>0 && // canal direcionado para baixo
         (Tk1-Tk3)>20*Point && // tamanho do canal > 20pip 
         Bid<High[1] && // o preço é menor do que a barra anterior
         (TLUp_[1]-High[1])<3*Point) // a primeira barra está dentro da linha superior do canal no valor de 3pip
        {
         Print(" Open - 16-SELL === ");
         //   SL_S=50;
         //   if(SL_S<StopLevel) SL_S=StopLevel;
         //   TP_S=80; 
         Op_Sell_Ch();
         return(0);
        }
      // - 18- BUY ---
      if(Extrem==-1 && // dois pontos de referência inferiores
         RatePr<0 && // canal dirigido para cima
         (Tk1-Tk3)>20*Point && // tamanho do canal > 20pip 
         Bid>Low[1] && // o preço é maior do que a barra anterior
         (Low[1]-TLDn_[1])<3*Point) // a primeira barra está dentro da linha inferior do canal no valor de 3pip
        {
         Print(" Open - 18-BUY === ");
         //    SL_B=50;
         //    if(SL_B<StopLevel) SL_B=StopLevel;
         //    TP_B=80; 
         Op_Buy_Ch();
         return(0);
        }
     }
//------------------------------------------------------------------------+
// Rastreando as aberturas das posições SELL                              |
//+=======================================================================+
   for(i=OrdersTotal()-1;i>=0;i--) // seleção do loop da ordem SELL
     {//1-posição do loop selecionado
      if(!OrderSelect(i,SELECT_BY_POS,MODE_TRADES))
        {Print("Order selection error = ",GetLastError()); }
      if(OrderType()==OP_SELL) // Se houver uma ordem SELL aberta
        { //2-type_Sell
         if((FraktalDn<=TLDn_[2] || 
            Low[2]<=TLDn_[2]) && 
            (Bid>Low[1] && Low[1]<=TLDn_[1]) && 
            (OrderOpenPrice()-Bid)*Point>0) // nenhuma perda! 
           {//5
            Print(" close by the lower channel line ");
            Close_S_lot();
            //  se o canal está para cima 
            if(RatePr<0)
              {
               Print(" Open a Buy position ");
               Op_Buy_Ch();
              }
           }//-5
        }//-2 type_Sell
      //------------------------------------------------------------------------+
      //  Rastreando as aberturas das posições BUY                              |
      //+=======================================================================+
      else
      if(OrderType()==OP_BUY) // Se houver uma ordem aberta BUY
        { //4-type_Buy
         if((FraktalUp>=TLUp_[2] || 
            High[2]>=TLUp_[2]) && 
            // se o canal for criado com base nos pontos de referência inferiores e está direcionado para cima, 
            // o preço cruzou o limite superior e está a ponto de se mover para baixo, 
            // a barra de "1" foi maior do que a barra "0" e maior do que a barra "2" que se situava na linha superior do canal, 
            // esta parece ser uma formação fractal com o aumento do tamanho do canal. 
            // Ao mesmo tempo, o indicador Stochastic está acima de 80.0
            // e ele começa a decrescer para cruzar a linha de sinal. 
            // Então não devemos ficar na expectativa da barra "0" estar totalmente formada, ou seja, é altamente provável 
            // que o preço vai cair, portanto fechar a posição BUY.
            (Bid<High[1] && High[1]>=TLUp_[1]) && 
            (Ask-OrderOpenPrice())*Point>0) // não numa perda!
           {//5
            Print(" close by the upper channel line ");
            Close_B_lot();
            // E se o canal está para baixo 
            if(RatePr>0)
              {
               Print(" Open a Sell position ");
               Op_Sell_Ch();
              }
           }//-5
        }//-4-type_Buy
     }//-loop de seleção da posição
//----------------
   return(0);
  }
//+------------------------------------------------------------------+


Conclusão

Eu acredito que a questão sobre a possibilidade de negociação no canal deve ser respondida de forma positiva. Estou ansioso para qualquer feedback crítico para melhorar ainda mais o Expert Advisor. Eu espero que esta minha experiência não seja útil somente aos traders inexperientes, mas a todos.

Traduzido do russo pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/ru/articles/1375

Notificações SMS do Status do EA Notificações SMS do Status do EA
Desenvolvimento de um sistema de notificações SMS que informa sobre o status do seu EA para que você esteja sempre ciente de qualquer situação crítica, onde quer que esteja.
Ação do Preço: Automatizando a Estratégia de Negociação "Inside Bar" Ação do Preço: Automatizando a Estratégia de Negociação "Inside Bar"
O artigo descreve o desenvolvimento de um Expert Advisor MetaTrader 4 baseado na estratégia "Inside Bar" (Barra Envolvida), incluindo princípios para detecção deste padrão, bem como configurações de regras para uma ordem stop e pendente. Os resultados dos testes e otimização são publicados também.
Lite_EXPERT2.mqh: Kit Funcional para Desenvolvedores de Expert Advisors Lite_EXPERT2.mqh: Kit Funcional para Desenvolvedores de Expert Advisors
Este artigo continua a série "Expert Advisors Baseados nos Sistemas de Negociação Populares e na Alquimia da Otimização de Robô de Negociação". Tem o objetivo de familiarizar os leitores com uma biblioteca de funções mais universal do arquivo Lite_EXPERT2.mqh.
Melhorar a Qualidade do Código com Ajuda do Teste de Unidade Melhorar a Qualidade do Código com Ajuda do Teste de Unidade
Mesmo programas simples muitas vezes têm erros que parecem inacreditáveis. "Como eu fiz isto?" é o nosso primeiro pensamento quando tal erro é revelado. "Como posso evitar isto?" é a segunda questão que vem à nossa mente com menos freqüência. É impossível criar um código absolutamente impecável, especialmente em grandes projetos, mas é possível usar tecnologias para auxiliar na detecção oportuna. O artigo descreve como a qualidade do código MQL4 pode ser melhorada com a ajuda do popular método de Teste de Unidade.