English Русский 中文 Español Deutsch 日本語
Linguagem MQL4 para Iniciantes. Indicadores personalizados (Parte 2)

Linguagem MQL4 para Iniciantes. Indicadores personalizados (Parte 2)

MetaTrader 4Exemplos | 22 fevereiro 2016, 15:04
6 061 0
Antoniuk Oleg
Antoniuk Oleg

Introdução

Este é o quinto artigo da série "Linguagem MQL4 para Iniciantes". Hoje vamos aprender a usar objetos gráficos - uma ferramenta de desenvolvimento muito poderosa que permite aumentar substancialmente as possibilidades de utilização de indicadores. Além disso, eles podem ser usados em scripts e Expert Advisors. Vamos aprender a criar objetos, alterar seus parâmetros e verificar erros. Claro que eu não posso descrever em detalhes todos os objetos, há um monte deles. Mas você terá todo o conhecimento necessário para estudá-los. Este artigo também contém um guia de exemplo passo-a-passo de criação de um indicador de sinal complexo. Em sua base, você pode criar quaisquer indicadores de sinal que irá mostrar sinais de trade em todos os períodos para vários indicadores. Lá, muitos parâmetros serão ajustáveis, o que tornará possível alterar com facilidade a aparência do indicador.


Sobre os Objetos Gráficos

Muitas vezes você lida com eles ao trabalhar no terminal MetaTrader 4. Você pode usar objetos gráficos para diversos fins. Operadores colocam suporte e níveis de resistência, pontos de pivô, níveis Fibonacci etc. Vamos ver um exemplo simples de uso dos objetos:

Quatro objetos gráficos estão anexados a este gráfico:

  • 2 linhas horizontais
  • um objeto de texto
  • um símbolo-objeto (uma seta)

Hoje vamos aprender a anexar esses objetos usando MQL4. Imagine quantas ações manuais podem ser automatizadas usando objetos! Por exemplo, você já calculou os pontos de pivô, os níveis de suporte e resistência e depois os desenhou manualmente? Bem, não é muito trabalho, mas se este processo for automatizado em MQL4, o terminal calculará e desenhará os níveis correspondentes por si mesmo. Tudo que você precisa é de um clique duplo no nome do script e tudo será feito. Além disso, ao usar objetos gráficos podemos escrever indicadores de sinal muito úteis...


Conceito de trabalhar com objetos

O algoritmo de trabalhar com todos os objetos gráficos em MQL4 é o seguinte:

  • criação do objeto
  • modificando seus parâmetros (móveis, mudança de cor, estilo, etc.)
  • deletar um objeto

Há um certa "ciclo de vida". Agora vamos tratar de cada etapa.


Criação do Objeto Gráfico

Para desenha qualquer objeto gráfico a função universal ObjectCreate() é utilizada. Aqui está seu protótipo:

bool ObjectCreate(string name, int type, int window, datetime time1, 
                  double price1, datetime time2=0,double price2=0, 
                  datetime time3=0, double price3=0)

Se tudo estiver correto, a função retorna verdadeiro. Se ocorrer um erro ou se um objeto não puder ser criado, a função retorna falso. Para descobrir o erro de código, utilize a função GetLastError().

if(ObjectCreate(/* arguments */)==false)
{
   // an error occurred, its code should be recorded into a journal
   Print("Error of calling ObjectCreate():",GetLastError());
}

Para que precisamos do erro de código? Ele vai ajudar você a encontrar a descrição do erro e, possivelmente, eliminá-lo. Todas as descrições de código estão em: Referência MQL4 -> Padrões Constantes -> Erros de Código.

Vamos tratar de todos os argumentos da função ObjectCreate():

  • nome – um nome exclusivo de um objeto. Você não pode criar 2 objetos com o mesmo nome. Além disso, este nome será usado em outras funções para a alteração dos parâmetros da representação objeto ou para mover o objeto.
  • tipo – um tipo de objeto. Todos os tipos de objeto podem ser criados em: Referência MQL4 -> Padrões Constantes -> Tipos de Objeto. Observe que isso depende do tipo de objeto e se os argumentos da última função devem ser usados. Veja o protótipo novamente. Os valores para os últimos 4 argumentos são atribuídos por padrão: objetos diferentes requerem diferentes quantidades de dados para sua criação. É fácil. Suponha que você precisa desenhar um ponto. Quais informações você precisa? Obviamente, a posição do ponto. Isto será o suficiente, certo? E para desenhar um retângulo precisamos 2 - posições do ponto superior esquerdo e do ponto inferior direito. O mesmo acontece com a função ObjectCreate(). É universal. É preciso da posição de um ponto para desenhar uma linha horizontal e de dois pontos para desenhar um segmento de linha. Para desenhar um triângulo são necessários três pontos. É por isso que ao criar um objeto, recomenda-se estudar corretamente o número de pontos necessários para desenhá-lo.
  • janela – o número da janela na qual o objeto deve ser desenhado. Se você precisar desenhar um objeto em um gráfico, isto é, na janela principal, use 0 como o número da janela.
  • time1 – a coordenada X do primeiro ponto. O eixo-X no terminal exibe o tempo, então, indique aqui o valor do tempo. Por exemplo, para descobrir a hora da última barra disponível, você pode usar a matriz predefinida Time[], assim: Time[0].
  • preço1 – a coordenada Y do primeiro ponto. O eixo-Y no terminal exibe o preço, então, os valores de preço devem ser usados. Por exemplo, use as matrizes predefinidas Open[], Close[] etc.
  • outros argumentos são 2 pares de coordenadas análogas que definem pontos para desenhar objetos mais complexos. Se um objeto é simples, estes parâmetros não são utilizados.


Exemplo de criação de objetos. Linhas de desenho

Agora, para melhor entendimento, vamos desenhar um par de linhas. Vamos marcar o preço mínimo e o preço máximo do último dia. Primeiro precisamos criar um novo script e alterar a função start():

int  start()
{
   double price=iHigh(Symbol(),PERIOD_D1,0);
   // this useful function returns the maximal price for:
   // * specified security, in our case it is Symbol() - 
   //   active security
   // * specified period, in our case it is PERIOD_D1 (daily)
   // * specified bar, in our case it is 0, the last bar
 
   ObjectCreate("highLine",OBJ_HLINE,0,0,price);
   // let us view all parameters: 
   // "highLine" - the unique object name
   // OBJ_HLINE - object type of the horizontal line
   // 0 - the object is drawn in the main window (chart window)
   // 0 - X coordinate (time), it shouldn't be indicated, because
   //     we are drawing a horizontal line
   // price - Y coordinate (price). It is the maximal price
   
   price=iLow(Symbol(),PERIOD_D1,0);
   // the function is identical with iHigh in arguments, but it returns
   // the minimal price
   
   ObjectCreate("lowLine",OBJ_HLINE,0,0,price);
 
   return(0);
}

Claro que perdemos a verificação de erros. Se você escrever o mesmo nome para os dois objetos será sua culpa. Quando você iniciar o script, ele deve ficar assim:

As linhas estão desenhadas, mas há algo que eu não gosto. É a cor vermelha, que é muito intensa, por isso é recomendado o uso de tonalidades. Geralmente, a aparência da linha pode ser configurada.


Modificação das Propriedades do Objeto Configuração da aparência das linhas

Há uma função especial que permite a criação de parâmetros de um objeto gráfico criado. É a função ObjectSet(). Seu protótipo é:

bool ObjectSet( string name, int index, double value);

Como na função anterior, se tudo estiver correto ela retorna verdadeiro. Se houver algum erro, ela retorna falso. Por exemplo, você especificou um nome de objeto inexistente. Vamos ver os argumentos desta função:

  • name – nome do objeto criado. Antes de iniciar a modificação, certifique-se de que um objeto com esse nome existe.
  • índice – Índice da propriedade de um objeto que deve ser modificado. Todos os índices podem ser encontrados em: Referência MQL4 -> Padrões Constantes -> Propriedades de Objeto. Está função também é universal. Ela funciona de acordo com o seguinte princípio: você especifica qual propriedade deve ser alterada e qual o valor que deve ser atribuído a essa propriedade.
  • valor – este é o valor para o qual uma propriedade selecionada deve ser alterada. Por exemplo, se você alterar a cor, especifique aqui uma nova cor.

Agora vamos alterar as nossas linhas, a saber: suas cores, largura e estilo. Altere a função start() do mesmo script:

int  start()
{
   double price=iHigh(Symbol(),PERIOD_D1,0);
 
   ObjectCreate("highLine",OBJ_HLINE,0,0,price);
   price=iLow(Symbol(),PERIOD_D1,0);
   ObjectCreate("lowLine",OBJ_HLINE,0,0,price);
   
   ObjectSet("highLine",OBJPROP_COLOR,LimeGreen);
   // changing the color of the upper line
   ObjectSet("highLine",OBJPROP_WIDTH,3);
   // now the line will be 3 pixel wide
   
   ObjectSet("lowLine",OBJPROP_COLOR,Crimson);
   // changing the color of the lower line
   ObjectSet("lowLine",OBJPROP_STYLE,STYLE_DOT);
   // now the lower line will be dashed   
 
   return(0);
}

No gráfico, você verá o seguinte:



Deletar objetos

Muitas vezes você precisará excluir objetos antigos ou desnecessários. Existem várias funções para fazer isso:

bool ObjectDelete(string name);

Esta função exclui um objeto de nome especificado. Se você indicar um nome não-existente, será retornado "falso".

int ObjectsDeleteAll(int window=EMPTY,int type=EMPTY);

Esta é uma função avançada, ela retorna o número dos objetos excluídos. Ela também possui valores padrão. Se você não especificar nenhum parâmetro, o terminal irá apagar todos os objetos de um gráfico ativo:

ObjectsDeleteAll();
// deleting all objects

Se você criou um objeto em uma subjanela (por exemplo, em uma janela de algum indicador), especificando o número desta janela no primeiro argumento, você pode excluir todos os seus objetos. Vamos discutir subjanelas mais tarde, então agora indique 0 no primeiro argumento.

Se você precisar excluir todos os objetos de um determinado tipo, especifique esse tipo no segundo argumento:

ObjectsDeleteAll(0, OBJ_ARROW);
// deleting all arrows

Como usar tudo isso corretamente?

Você pode pensar que você precisa de muito conhecimento para usar tudo isso corretamente. Por exemplo, que se deve conhecer todas estas propriedades e tipos de objetos. Mas não é assim. Tudo pode ser encontrado no Guia do Usuário.

Primeiro abra a Caixa de Ferramentas (CTRL+T). Há várias guias na parte inferior, selecione Ajuda. Suponha que você precise desenhar um objeto gráfico, mas não sabe como fazer isso. A função ObjectCreate() deve ser utilizada. Escreva-a e deixe os argumentos vazios. Agora, coloque o cursor dentro do nome da função e pressione F1. E a janela Ajuda mostrará as informações sobre esta função. Isso significa que você não precisa procurar nada. Agora veja a descrição da função. Ela é seguida pela descrição de todos os seus argumentos. Preste atenção na descrição do argumento tipo:

Ela contém um link. Clicando nele você verá a lista de objetos existentes. Suponha que você goste de uma elipse:

Leia a descrição e você vai achar que 2 coordenadas são necessárias. Vamos começar:

int  start()
{
   ObjectCreate("ellipse",OBJ_ELLIPSE,0,Time[100],Low[100],Time[0],High[0]);
   // indicate 2 points for creating an ellipse:
   // * 1st - lower left point
   // * 2nd - upper right point 
 
   return(0);
}

Também está escrito que a propriedade OBJPROP_SCALE determina a correlação dos lados. Então, se a colocarmos como 1, obteremos um ciclo:

int  start()
{
   ObjectsDeleteAll();
   // clear the chart before drawing
   
   ObjectCreate("ellipse",OBJ_ELLIPSE,0,Time[100],Low[100],Time[0],High[0]);
   
   ObjectSet("ellipse",OBJPROP_SCALE,1.0);
   // change the correlation of sides
   ObjectSet("ellipse",OBJPROP_COLOR,Gold);
   // change the color
 
   return(0);
}


Tenho certeza que você também não conseguiu um ciclo, porque a escala um para um deve ser definida nas propriedades do gráfico (clique no botão direito em qualquer lugar vazio do gráfico e selecione Propriedades):


Isto tudo é fácil. Na verdade, você pode colocar o cursor em qualquer palavra-chave e pressionar F1, depois disso, você verá a informação correspondente da Ajuda. Para escrever um código rápido e eficiente usando a Ajuda integrada você não precisa lembrar de todos os nomes dos tipos e propriedades. O MetaEditor tem uma propriedade mais importante que irá ajudá-lo a escrever um código: ao escrever argumentos em uma função integrada, pressione CTRL + SHIFT + espaço. Você verá uma deixa com o protótipo da função:


Criação de objetos gráficos em subjanelas

Se você precisar desenhar objetos gráficos em uma subjanela, por exemplo, em uma janela de um indicador personalizado, você deve saber seu número. Como exemplo, vamos escrever um indicador simples que irá desenhar uma linha horizontal em uma janela separada. Crie um indicador personalizado e adicione o seguinte no código:

//+------------------------------------------------------------------+
//|                                   creatingObjectsInSubWindow.mq4 |
//|                                                     Antonuk Oleg |
//|                                            antonukoleg@gmail.com |
//+------------------------------------------------------------------+
#property copyright "Antonuk Oleg"
#property link      "antonukoleg@gmail.com"
 
#property indicator_separate_window
// indicator will be written in a separate window
#property indicator_minimum 1
// minimal indicator value is 1
#property indicator_maximum 10
// maximal is 10
 
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int init()
{
   IndicatorShortName("NiceLine");
   // this simple function sets a short indicator name,
   // you see it in the upper left corner of any indicator.
   // What for do we need it? The function WindowFind searches a subwindow
   // with a specified short name and returns its number.
 
   int windowIndex=WindowFind("NiceLine");
   // finding the window number of our indicator
   
   if(windowIndex<0)
   {
      // if the number is -1, there is an error
      Print("Can\'t find window");
      return(0);
   }  
 
   ObjectCreate("line",OBJ_HLINE,windowIndex,0,5.0);
   // drawing a line in the indicator subwindow
               
   ObjectSet("line",OBJPROP_COLOR,GreenYellow);
   ObjectSet("line",OBJPROP_WIDTH,3);
 
   WindowRedraw();      
   // redraw the window to see the line
 
   return(0);
}
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
int deinit()
{
   ObjectsDeleteAll();
   // delete all objects
   
   return(0);
}
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int start()
{
   return(0);
}

Inicie o indicador. Não há nenhuma linha!



Precisamos mudar o período do gráfico.



Agora está aqui. O que aconteceu? Na verdade, o número da subjanela não pode ser encontrado na função init()quando ela é iniciada pela primeira vez. Talvez, a razão é que a subjanela ainda não foi criada pelo terminal durante a inicialização. Existe uma maneira de evitar isto - tudo deve ser feito na função start()quando a janela já tiver sido criada, assim:

//+------------------------------------------------------------------+
//|                                   creatingObjectsInSubWindow.mq4 |
//|                                                     Antonuk Oleg |
//|                                            antonukoleg@gmail.com |
//+------------------------------------------------------------------+
#property copyright "Antonuk Oleg"
#property link      "antonukoleg@gmail.com"
 
#property indicator_separate_window
#property indicator_minimum 1
#property indicator_maximum 10
 
bool initFinished=false;
// adding a variable that will remember the initialization state.
// false - there was no initialization
// true - there was initialization
 
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int init()
{
   return(0);
}
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
int deinit()
{
   ObjectsDeleteAll();
   // deleting all objects
   
   return(0);
}
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int start()
{
   if(initFinished==false)
   {
      IndicatorShortName("NiceLine");
 
      int windowIndex=WindowFind("NiceLine");
   
      if(windowIndex<0)
      {
         // if the subwindow number is -1, there is an error
         Print("Can\'t find window");
         return(0);
      }  
 
      ObjectCreate("line",OBJ_HLINE,windowIndex,0,5.0);
      // drawing a line in the indicator subwindow
               
      ObjectSet("line",OBJPROP_COLOR,GreenYellow);
      ObjectSet("line",OBJPROP_WIDTH,3);
 
      WindowRedraw();      
      // redraw the window to see the line   
      
      initFinished=true;
      // drawing is finished
   }
   
   return(0);
}

Agora tudo será desenhado da primeira vez. O que você deve lembrar aqui é que o número da subjanela é encontrado na função start() e não na função init().


Pratique

Usando a Ajuda, tentar estudar alguns novos tipos de objetos gráficos. Depois disso, escreva um script que irá desenhá-los e configurar parâmetros. Estude isto corretamente, pratique e só depois disso continue a leitura do artigo.


Escrevendo um Indicador de Sinal. O que é isso?

Imagine a situação. Um operador utiliza vários indicadores para tomar decisões sobre a entrada no mercado: Média Móvel, SAR parabólico e Faixa Percentual de Williams. Estes são indicadores integrados que se parecem com isso:



Um operador estima constantemente uma situação no mercado da seguinte forma: o mercado deve ser introduzido quando os sinais chegam de cada um dos três indicadores:

  • Se a média móvel rápida for superior à lenta, isto é um sinal de compra. Caso contrário, de venda.
  • Se o preço for mais baixo do que o SAR Parabólico, este é um sinal de venda. Caso contrário, de compra.
  • Se o WPR for maior que -20, este é um sinal de compra. Se o WPR for menor que -80, este é um sinal de venda.

O operador tem que verificar constantemente para todas as condições e também tentar acompanhar a situação em vários períodos. É um trabalho difícil. Assim, um indicador de sinal que realiza todas as verificações poderia ajudá-lo:

Hoje aprenderemos a resolver este problema. Escreveremos um indicador de sinal que será facilmente configurado. Além disso, você pode criar facilmente sua própria modificação com seus indicadores favoritos baseados neste indicador.


Fundamentos

Enfrentaremos alguns problemas de desenho ao criar este indicador. Todos os objetos gráficos são desenhados usando coordenadas de preço e de tempo. Por isso, o que é desenhado é constantemente alterado. Para fazer os objetos ficarem em um lugar, seria preciso mudar constantemente suas coordenadas. Mas se você quiser ver como era anteriormente e alterar o gráfico, a tabela de sinal também será alterada. Mas cada regra tem exceções. Entre os objetos gráficos existe o chamado OBJ_LABEL. OBJ_LABEL. É uma marca de texto usada para o posicionamento não de preço e tempo, mas de coordenadas sobre a janela em pixels. É fácil:



Nós vemos um sinal de texto comum "X". Em seus parâmetros você pode ver que suas coordenadas são especificadas em pixels. Um pixel é o menor ponto na tela. Note que as coordenadas do canto superior esquerdo são: x=0, y=0 (0,0). Se aumentarmos x, o objeto se moverá para a direita, se diminuirmos , ele se moverá para a esquerda. O mesmo acontece com a coordenada- y. Ela pode ser alterada para cima ou para baixo. É importante compreender e lembrar este princípio. Para praticar, você pode criar uma marca e transferi-las para ver como suas coordenadas serão alteradas nas propriedades. Também, deslocando o gráfico, você pode ver cotações antigas. Onde a marca não é deslocada. Usando tais marcas podemos criar um indicador de sinal sem as desvantagens descritas acima.


Opções de Marcação de Texto

Nosso indicador de sinal usará apenas marcações de texto. Então, vamos tratar destas opções. Primeiro, crie um novo indicador (não use buffers de dados e parâmetros) e altere a função init():

int init()
{
   // now we will crate a text mark.
   // for this use the function ObjectCreate.
   // do not indicate coordinates
   ObjectCreate("signal",OBJ_LABEL,0,0,0,0,0);
 
   // change the x-coordinate
   ObjectSet("signal",OBJPROP_XDISTANCE,50);
 
   // change the y-coordinate
   ObjectSet("signal",OBJPROP_YDISTANCE,50);
 
   // to indicate the mark text, use the following function
   ObjectSetText("signal","lambada",14,"Tahoma",Gold);
   // "signal" - object name
   // "lambada" - text
   // 14 - font size
   // Gold - color
 
   return(0);
}

Isto tudo é fácil. A função ObjectCreate() será utilizada apenas na inicialização para criar todos os objetos necessários. Usando ObjectSetText(), mudaremos a aparência dos objetos em cada mudança de preço na função start(). Também precisamos mudar a função deinit():

int deinit()
{
   // when deleting the indicator delete all objects
   ObjectsDeleteAll();
 
   return(0);
}

Agora inicie o indicador e visualize os resultados:

Usaremos as seguintes opções de marcações:

  • Para disponibilizar símbolos especiais altere a fonte para Wingdings:

  • mudaremos a cor e o texto da marcação
  • mudaremos a posição e o tamanho da marcação

Uso da fonte Wingdings

Agora vamos criar uma marcação usando a fonte Wingdings. Mude a função init():

int init()
{
 
   ObjectCreate("signal",OBJ_LABEL,0,0,0,0,0);
   ObjectSet("signal",OBJPROP_XDISTANCE,50);
   ObjectSet("signal",OBJPROP_YDISTANCE,50);
 
   // use symbols from the Wingdings font
   ObjectSetText("signal",CharToStr(164),60,"Wingdings",Gold);
   // CharToStr() - this function returns a line with a single
   // symbol, the code of which is specified in the single argument.
   // Simply select a symbol from the table above and write
   // its number into this function
   // 60 - use large font
   // "Wingdings" - use font Wingdings
 
   return(0);
}

Aqui está o resultado:



Desenhando um modelo de uma tabela de sinais

Agora vamos desenhar um modelo de uma tabela de sinais. Na verdade, este será um número de quadrados:

int init()
{
   // use 2 cycles. The first cycle, with the counter "x" draws one by one
   // each column from left to wright. The second cycle draws symbols of each
   // column from top downward. At each iteration the cycle will create a mark.
   // These 2 cycles create 9 columns (9 periods) 3 marks each (3 signal types).
   for(intx=0;x<9;x++)
      for(inty=0;y<3;y++)
      {
         ObjectCreate("signal"+x+y,OBJ_LABEL,0,0,0,0,0);
         // create the next mark, Note that the mark name
         // is created "on the fly" and depends on "x" and "y" counters
 
         ObjectSet("signal"+x+y,OBJPROP_XDISTANCE,x*20);
         // change the X coordinate.
         // x*20 - each mark is created at the interval of 20 pixels
         // horizontally and directly depends on the "x" counter
 
         ObjectSet("signal"+x+y,OBJPROP_YDISTANCE,y*20);
         // change the Y coordinate.
         // y*20 - each mark is created at the interval of 20 pixels
         // vertically and directly depends on the "y" counter
 
         ObjectSetText("signal"+x+y,CharToStr(110),20,"Wingdings",Gold);
         // use the 110th symbol code (square)
      }
   
   return(0);
}


O padrão está pronto. Vamos adicionar ajustes para a esquerda e acima dele, de modo que o texto do terminal possa ser visto:

int init()
{
   for(int x=0;x<9;x++)
      for(int y=0;y<3;y++)
      {
         ObjectCreate("signal"+x+y,OBJ_LABEL,0,0,0,0,0);
         ObjectSet("signal"+x+y,OBJPROP_XDISTANCE,x*20+12);
         // adding a horizontal indent 12 pixels
         ObjectSet("signal"+x+y,OBJPROP_YDISTANCE,y*20+20);
         // adding a vertical indent 20 pixels
         ObjectSetText("signal"+x+y,CharToStr(110),20,"Wingdings",Gold);
      }
 
   return(0);
}


Ativar o Padrão

Agora vamos fazer funcionar, pelo menos, um dos quadrados. Suponha que o quadrado superior esquerdo irá mostrar um sinal de médias móveis em um período de um minuto (M1). Se houver um sinal de compra, o quadrado mudará sua cor para verde. Se houver um sinal de venda, ele se tornará vermelho. Precisamos mudar a função start():

int start()
{
   // if quick moving average (period - 13) is larger than the slow one,
   // this is a signal to buy. Check the last bar
   if(iMA(Symbol(),1,13,0,0,0,0)>iMA(Symbol(),1,24,0,0,0,0))
      ObjectSetText("signal00",CharToStr(110),20,"Wingdings",YellowGreen);
   // change the color of the mark named "signal00" (the upper left)
   // into green
 
   else
   // else, if the quick MA is smaller than the slow one, this is a signal to sell.
      ObjectSetText("signal00",CharToStr(110),20,"Wingdings",Tomato); 
      // change the color into red
 
   return(0);
}



Ativação da linha superior

Vamos continuar a ativação. O quadrado esquerdo indica o intervalo de tempo menor - M1. Agora faremos com que cada quadrado indique um período de tempo maior do que o anterior. Assim, o segundo quadrado mostra sinais em M5, o terceiro - M15 e assim por diante, até MN1. Claro, tudo isso será feito em um ciclo. O que é alterado é o nome e o período. Temos 0 quadrados, por isso usamos um contador. Mas estamos diante de um problema com períodos, porque eles são alterados sem quaisquer regularidades. Veja:


Alguém poderia pensar que um ciclo não pode ser usado aqui. Isto não é verdade. Tudo que precisamos é declarar uma matriz especial no início do código indicador:

//////////////////////////////////////////////////////////////////////
//
//                                                  signalTable.mq4 
//                                                     Antonuk Oleg 
//                                            antonukoleg@gmail.com 
//
//////////////////////////////////////////////////////////////////////
#property copyright "Antonuk Oleg"
#property link      "antonukoleg@gmail.com"
 
#property indicator_chart_window
 
intperiod[]={1,5,15,30,60,240,1440,10080,43200};

Todos os períodos são escritos na matriz, agora, eles podem ser facilmente utilizados em um ciclo:

int start()
{
   // use a cycle to activate all squares of the first line
   for(int x=0;x<9;x++)
   {
      if(iMA(Symbol(),period[x],13,0,0,0,0)>iMA(Symbol(),period[x],24,0,0,0,0))
         ObjectSetText("signal"+x+"0",CharToStr(110),20,"Wingdings",YellowGreen);
         // "signal"+x+"0" - create a mark name dynamically depending on
         // the counter "x"
      else
         ObjectSetText("signal"+x+"0",CharToStr(110),20,"Wingdings",Tomato); 
   }
 
   return(0);
}

Usamos a matriz period[] como uma tabela de correspondência do contador "x" e o período. Imagine o quanto de código seria necessário se não fosse por esta pequena matriz! Então, a primeira linha de quadrados de sinal está pronta:




Adicionar Escritos

Está tudo bem, mas é difícil de entender o que é o período de tempo do quadrado, então, vamos criar assinaturas explicativas. Também vamos usar uma matriz de correspondências que armazenará escritos para cada coluna:

#property indicator_chart_window
 
int period[]={1,5,15,30,60,240,1440,10080,43200};  
 
stringperiodString[]={"M1","M5","M15","M30","H1","H4","D1","W1","MN1"};

Os escritos serão criados no init() com a ajuda do seguinte ciclo:

int init()
{
   for(int x=0;x<9;x++)
      for(int y=0;y<3;y++)
      {
         ObjectCreate("signal"+x+y,OBJ_LABEL,0,0,0,0,0);
         ObjectSet("signal"+x+y,OBJPROP_XDISTANCE,x*20+12);
         ObjectSet("signal"+x+y,OBJPROP_YDISTANCE,y*20+20);
         ObjectSetText("signal"+x+y,CharToStr(110),20,"Wingdings",Gold);
      }
 
   // create writings for periods from left to right
   for(x=0;x<9;x++)
   {
      // everything is as usual
      ObjectCreate("textPeriod"+x,OBJ_LABEL,0,0,0,0,0);
      ObjectSet("textPeriod"+x,OBJPROP_XDISTANCE,x*20+12);
      ObjectSet("textPeriod"+x,OBJPROP_YDISTANCE,10);
      ObjectSetText("textPeriod"+x,periodString[x],8,"Tahoma",Gold);
      // we use the array periodString[], to indicate writings
   }
   
   return(0);
}


Adicionar novos parâmetros

Vamos tornar o indicador mais flexível adicionando um par de parâmetros para que um usuário possa configurar a visão externa do indicador:

#property copyright "Antonuk Oleg"
#property link      "antonukoleg@gmail.com"
 
#property indicator_chart_window
 
extern int scaleX=20, // horizontal interval at which the squares are created
           scaleY=20, // vertical interval
           offsetX=35, // horizontal indent of all squares
           offsetY=20, // vertical indent
           fontSize=20; // font size
           
int period[]={1,5,15,30,60,240,1440,10080,43200};
string periodString[]={"M1","M5","M15","M30","H1","H4","D1","W1","MN1"};

Além disso, vamos alterar o código das funções init() e start():

int init()
{
   for(int x=0;x<9;x++)
      for(int y=0;y<3;y++)
      {
         ObjectCreate("signal"+x+y,OBJ_LABEL,0,0,0,0,0);
         ObjectSet("signal"+x+y,OBJPROP_XDISTANCE,x*scaleX+offsetX);
         ObjectSet("signal"+x+y,OBJPROP_YDISTANCE,y*scaleY+offsetY);
         ObjectSetText("signal"+x+y,CharToStr(110),fontSize,"Wingdings",Gold);
      }
 
   for(x=0;x<9;x++)
   {
      ObjectCreate("textPeriod"+x,OBJ_LABEL,0,0,0,0,0);
      ObjectSet("textPeriod"+x,OBJPROP_XDISTANCE,x*scaleX+offsetX);
      ObjectSet("textPeriod"+x,OBJPROP_YDISTANCE,offsetY-10);
      ObjectSetText("textPeriod"+x,periodString[x],8,"Tahoma",Gold);
   }
   
   return(0);
}
 
int start()
{
   for(int x=0;x<9;x++)
   {
      if(iMA(Symbol(),period[x],13,0,0,0,0)>iMA(Symbol(),period[x],24,0,0,0,0))
         ObjectSetText("signal"+x+"0",CharToStr(110),fontSize,"Wingdings",YellowGreen);
      else
         ObjectSetText("signal"+x+"0",CharToStr(110),fontSize,"Wingdings",Tomato); 
   }
 
   return(0);
}

Ativação de outras linhas

A segunda linha indicará sinais da Faixa Percentual de Williams, a terceira linha - do SAR Parabólico. Modificando a função start():

int start()
{
   for(int x=0;x<9;x++)
   {
      if(iMA(Symbol(),period[x],13,0,0,0,0)>iMA(Symbol(),period[x],24,0,0,0,0))
         ObjectSetText("signal"+x+"0",CharToStr(110),fontSize,"Wingdings",YellowGreen);
      else
         ObjectSetText("signal"+x+"0",CharToStr(110),fontSize,"Wingdings",Tomato); 
   }
 
   // activate the second row
   for(x=0;x<9;x++)
   {
      // if the absolute value of WPR is lower than 20, this is a signal to buy
      if(MathAbs(iWPR(Symbol(),period[x],13,0))<20.0)
         ObjectSetText("signal"+x+"1",CharToStr(110),fontSize,"Wingdings",YellowGreen);   
      // if the absolute value of WPR is larger than 80, this is a signal to sell
      else if(MathAbs(iWPR(Symbol(),period[x],13,0))>80.0)
         ObjectSetText("signal"+x+"1",CharToStr(110),fontSize,"Wingdings",Tomato);   
      // else, if there are no signals, a square is painted gray
      else
         ObjectSetText("signal"+x+"1",CharToStr(110),fontSize,"Wingdings",DarkGray);      
   }
 
   // activate the third row
   for(x=0;x<9;x++)
   {
      // if the current price is larger than the value of SAR, this is a signal to buy
      if(iSAR(Symbol(),period[x],0.02,0.2,0)<Close[0])
         ObjectSetText("signal"+x+"2",CharToStr(110),fontSize,"Wingdings",YellowGreen);
      // otherwise, it is a signal to sell
      else
         ObjectSetText("signal"+x+"2",CharToStr(110),fontSize,"Wingdings",Tomato);
   }
 
   return(0);
}


Adicionar os nomes dos sinais

Agora, vamos colocar um nome para cada linha. Vamos criar 3 escritos sobre na esquerda utilizando, como anteriormente, uma matriz:

int period[]={1,5,15,30,60,240,1440,10080,43200};
string periodString[]={"M1","M5","M15","M30","H1","H4","D1","W1","MN1"},
       // create one more array with indicator names
string signalNameString[]={"MA","WPR","SAR"};

Altere a função init():

int init()
{
   for(int x=0;x<9;x++)
      for(int y=0;y<3;y++)
      {
         ObjectCreate("signal"+x+y,OBJ_LABEL,0,0,0,0,0);
         ObjectSet("signal"+x+y,OBJPROP_XDISTANCE,x*scaleX+offsetX);
         ObjectSet("signal"+x+y,OBJPROP_YDISTANCE,y*scaleY+offsetY);
         ObjectSetText("signal"+x+y,CharToStr(110),fontSize,"Wingdings",Gold);
      }
 
   for(x=0;x<9;x++)
   {
      ObjectCreate("textPeriod"+x,OBJ_LABEL,0,0,0,0,0);
      ObjectSet("textPeriod"+x,OBJPROP_XDISTANCE,x*scaleX+offsetX);
      ObjectSet("textPeriod"+x,OBJPROP_YDISTANCE,offsetY-10);
      ObjectSetText("textPeriod"+x,periodString[x],8,"Tahoma",Gold);
   }
   
   // draw signal names from top downwards
   for(y=0;y<3;y++)
   {
      ObjectCreate("textSignal"+y,OBJ_LABEL,0,0,0,0,0);
      ObjectSet("textSignal"+y,OBJPROP_XDISTANCE,offsetX-25);
      ObjectSet("textSignal"+y,OBJPROP_YDISTANCE,y*scaleY+offsetY+8);
      ObjectSetText("textSignal"+y,signalNameString[y],8,"Tahoma",Gold);
   }
   
   return(0);
}


Adição da opção de mudança do canto vinculativo

Agora, adicionaremos uma opção de escolha da posição do indicador de sinal. Agora ela está vinculado ao canto superior esquerdo. Se alterar a propriedade de marcação OBJPROP_CORNER, o canto será alterado. Esta propriedade pode ter os seguintes valores:

  • 0 – o canto superior esquerdo
  • 1 – o canto superior direito
  • 2 – o canto inferior esquerdo
  • 3 – o canto inferior direito

Sendo assim, vamos adicionar um novo parâmetro – corner:

#property indicator_chart_window
 
extern int scaleX=20,
           scaleY=20, 
           offsetX=35, 
           offsetY=20, 
           fontSize=20,
           corner=0; // adding a parameter for choosing a corner

E modificar a função init():

int init()
{
   // a table of signals
   for(int x=0;x<9;x++)
      for(int y=0;y<3;y++)
      {
         ObjectCreate("signal"+x+y,OBJ_LABEL,0,0,0,0,0);
         ObjectSet("signal"+x+y,OBJPROP_CORNER,corner);
         // change the corner
         ObjectSet("signal"+x+y,OBJPROP_XDISTANCE,x*scaleX+offsetX);
         ObjectSet("signal"+x+y,OBJPROP_YDISTANCE,y*scaleY+offsetY);
         ObjectSetText("signal"+x+y,CharToStr(110),fontSize,"Wingdings",Gold);
      }
 
   // name of timeframes
   for(x=0;x<9;x++)
   {
      ObjectCreate("textPeriod"+x,OBJ_LABEL,0,0,0,0,0);
      ObjectSet("textPeriod"+x,OBJPROP_CORNER,corner);
      // changing the corner
      ObjectSet("textPeriod"+x,OBJPROP_XDISTANCE,x*scaleX+offsetX);
      ObjectSet("textPeriod"+x,OBJPROP_YDISTANCE,offsetY-10);
      ObjectSetText("textPeriod"+x,periodString[x],8,"Tahoma",Gold);
   }
 
   // names of indicators
   for(y=0;y<3;y++)
   {
      ObjectCreate("textSignal"+y,OBJ_LABEL,0,0,0,0,0);
  ObjectSet("textSignal"+y,OBJPROP_CORNER,corner);
  // change the corner
      ObjectSet("textSignal"+y,OBJPROP_XDISTANCE,offsetX-25);
      ObjectSet("textSignal"+y,OBJPROP_YDISTANCE,y*scaleY+offsetY+8);
      ObjectSetText("textSignal"+y,signalNameString[y],8,"Tahoma",Gold);
   }
   
   return(0);
}

Adicionar novos parâmetros

Podemos adicionar mais alguns parâmetros para uma configuração flexível da aparência do indicador. Todos os parâmetros:

  • todas as cores disponíveis
  • todos os códigos de símbolo disponíveis

Primeiro precisamos declarar todos estes parâmetros no início do código:

extern int scaleX=20,
           scaleY=20,
           offsetX=35,
           offsetY=20,
           fontSize=20,
           corner=0,
           symbolCodeBuy=110, // a symbol code for a buy signal
           symbolCodeSell=110, // sell signal
           symbolCodeNoSignal=110; // no signal
           
extern color signalBuyColor=YellowGreen, // color of the symbol of a buy signal
             signalSellColor=Tomato, // for a sell signal
             noSignalColor=DarkGray, // no signal
             textColor=Gold; // color of all writings

Vamos modificar a função init():

int init()
{
   // table of signals
   for(int x=0;x<9;x++)
      for(int y=0;y<3;y++)
      {
         ObjectCreate("signal"+x+y,OBJ_LABEL,0,0,0,0,0);
         ObjectSet("signal"+x+y,OBJPROP_CORNER,corner);
         ObjectSet("signal"+x+y,OBJPROP_XDISTANCE,x*scaleX+offsetX);
         ObjectSet("signal"+x+y,OBJPROP_YDISTANCE,y*scaleY+offsetY);
         ObjectSetText("signal"+x+y,CharToStr(symbolCodeNoSignal),
                       fontSize,"Wingdings",noSignalColor);
      }
 
   // names of timeframes
   for(x=0;x<9;x++)
   {
      ObjectCreate("textPeriod"+x,OBJ_LABEL,0,0,0,0,0);
      ObjectSet("textPeriod"+x,OBJPROP_CORNER,corner);
      ObjectSet("textPeriod"+x,OBJPROP_XDISTANCE,x*scaleX+offsetX);
      ObjectSet("textPeriod"+x,OBJPROP_YDISTANCE,offsetY-10);
      ObjectSetText("textPeriod"+x,periodString[x],8,"Tahoma",textColor);
   }
 
   // names of indicators
   for(y=0;y<3;y++)
   {
      ObjectCreate("textSignal"+y,OBJ_LABEL,0,0,0,0,0);
      ObjectSet("textSignal"+y,OBJPROP_CORNER,corner);
      ObjectSet("textSignal"+y,OBJPROP_XDISTANCE,offsetX-25);
      ObjectSet("textSignal"+y,OBJPROP_YDISTANCE,y*scaleY+offsetY+8);
      ObjectSetText("textSignal"+y,signalNameString[y],8,"Tahoma",textColor);
   }
   
   return(0);
}

Modificando a função start():

int start()
{
   for(int x=0;x<9;x++)
   {
      if(iMA(Symbol(),period[x],13,0,0,0,0)>iMA(Symbol(),period[x],24,0,0,0,0))
         ObjectSetText("signal"+x+"0",CharToStr(symbolCodeBuy),fontSize,
         "Wingdings",signalBuyColor);
      else
         ObjectSetText("signal"+x+"0",CharToStr(symbolCodeSell),fontSize,
         "Wingdings",signalSellColor); 
   }
 
   for(x=0;x<9;x++)
   {
      if(MathAbs(iWPR(Symbol(),period[x],13,0))<20.0)
         ObjectSetText("signal"+x+"1",CharToStr(symbolCodeBuy),fontSize,
         "Wingdings",signalBuyColor);   
      else if(MathAbs(iWPR(Symbol(),period[x],13,0))>80.0)
         ObjectSetText("signal"+x+"1",CharToStr(symbolCodeSell),fontSize,
         "Wingdings",signalSellColor);   
      else
         ObjectSetText("signal"+x+"1",CharToStr(symbolCodeNoSignal),fontSize,
         "Wingdings",noSignalColor);      
   }
 
   for(x=0;x<9;x++)
   {
      if(iSAR(Symbol(),period[x],0.02,0.2,0)<Close[0])
         ObjectSetText("signal"+x+"2",CharToStr(symbolCodeBuy),fontSize,
         "Wingdings",signalBuyColor);
      else
         ObjectSetText("signal"+x+"2",CharToStr(symbolCodeSell),fontSize,
         "Wingdings",signalSellColor);
   }
 
   return(0);
}

Modificando a visão externa

O indicador está pronto. Ao alterar os parâmetros de entrada, podemos mudar totalmente a visão externa:

extern int scaleX=20,
           scaleY=20,
           offsetX=35,
           offsetY=20,
           fontSize=20,
           corner=2,
           symbolCodeBuy=67, 
           symbolCodeSell=68, 
           symbolCodeNoSignal=73; 
           
extern color signalBuyColor=Gold,
             signalSellColor=MediumPurple,
             noSignalColor=WhiteSmoke,
             textColor=Gold;



Tarefa de casa

Tente criar suas próprias condições de sinal e adicionar mais uma linha. Crie vários parâmetros novos. Por exemplo, um parâmetro que irá detectar o tamanho da fonte dos escritos (períodos de tempo e nomes de sinal). Configure a visão externa do indicador de acordo com suas próprias preferências.


Conclusão

Hoje aprendemos a utilizar objetos gráficos em scripts e indicadores. Aprendemos a criar objetos, alterar seus parâmetros e verificar erros. Você obteve conhecimento suficiente para estudar novos tipos de objetos gráficos por si só. Você também criou passo-a-passo um indicador complexo que pode ser configurado facilmente e flexivelmente.

Artigos anteriores da série "Linguagem MQL4 para iniciantes'':
  1. Linguagem MQL4 para Iniciantes. Introdução
  2. Linguagem MQL4 para Iniciantes. Perguntas difíceis em frases simples.
  3. Linguagem MQL4 para Iniciantes. Indicadores técnicos e funções integradas
  4. Linguagem MQL4 para Iniciantes. Indicadores personalizados (Parte 1)

Traduzido do Inglês pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/en/articles/1503

Modelagem de Apostas como meio de desenvolver "Intuição de Mercado" Modelagem de Apostas como meio de desenvolver "Intuição de Mercado"
O artigo trata sobre a noção de “intuição de mercado” e as formas de desenvolvê-la. O método descrito no artigo baseia-se na modelagem de apostas financeira na forma de um simples jogo.
Exibição de um novo calendário Exibição de um novo calendário
Este artigo contém a descrição para escrever um indicador simples e conveniente exibindo em uma área de trabalho os principais eventos econômicos a partir de recursos externos da Internet.
Indicador para Gráfico de Spindles Indicador para Gráfico de Spindles
O artigo apresenta a plotagem do gráfico de spindles e seu uso em estratégias de negociação e experts. Primeiro vamos discutir a aparência do gráfico, plotagem e conexão com o gráfico de velas japonesas. Em seguida, analisaremos a implementação do indicador no código fonte na linguagem MQL5. Vamos testar o expert com base no indicador e formular uma estratégia de negociação.
Indicador Taichi - uma ideia simples de formalizar os valores do Ichimoku Kinko Hyo Indicador Taichi - uma ideia simples de formalizar os valores do Ichimoku Kinko Hyo
Dificuldades para interpretar os sinais Ichimoku? Este artigo apresenta alguns princípios de formalização de valores e sinais de Ichimoku Kinko Hyo. Para visualização de seu uso o autor escolheu o par de moedas EURUSD com base em suas próprias preferências. No entanto, o indicador pode ser usado em qualquer par de moedas.