English Русский 中文 Español Deutsch 日本語 한국어 Français Italiano Türkçe
Criando indicadores de ponto no MQL5

Criando indicadores de ponto no MQL5

MetaTrader 5Indicadores | 24 dezembro 2013, 08:12
5 089 0
Denis Zyatkevich
Denis Zyatkevich

Introdução

Nas negociações, seria conveniente ter o maior número de informações para acompanhar o cenário detalhado das mudanças de preço. Você pode utilizar o gráfico de ponto. Vamos tentar criar um gráfico de ponto no MQL5.

Esse artigo descreve a crianção de dois indicadores: um gráfico de escala de preço e um gráfico "Tick Candles" que desenha as velas que contêm um número específico de escalas. Cada um dos indicadores adotados apresenta os valores de preço recebidos ao arquivo para a formação dos dados do indicador após o reinício do terminal do cliente (esses dados também podem ser utilizados por outros programas).

Criando Indicador de Escala

Vamos gravar um indicador no MQL5 que desenhe dados em escala no gráfico. Um exemplo desse indicador é apresentado na Fig. 1:

Figura 1. Exemplo de um gráfico de ponto

O indicador traça duas linhas: preços de compra e venda. O traçado de cada um pode ser desativado nas opções do indicador.

O indicador registra os preços do símbolo atual recebidos pelo corretor em um arquivo de texto com o seguinte formato: horário do servidor, preço de compra e preço de venda:

2010.03.26 19:43:02 1.33955 1.33968

O nome do arquivo corresponde ao nome do instrumento financeiro (por exemplo, EURUSD.txt). Os arquivos ficam localizados no seguinte caminho: MT5_Folder\MQL5\Files. O diretório adicional para um arquivo e o prefixo de nome do arquivo podem ser especificados nas opções do indicador (pode ser útil se existem vários indicadores anexos aos gráficos de mesmo símbolo).

Para criar um indicador, inicialize o terminal de cliente do MetaTrader 5 e inicialize o MetaQuotes Language Editor pressionando a tecla F4. Vamos começar a gravar o código de um programa.

Vamos especificar que o indicador deve ser plotado em uma janela separada abaixo do gráfico de preço:

// indicator in a separate window
#property indicator_separate_window

As duas linhas de indicador (preços de compra e venda, respectivamente) devem ser traçados de modo que tenhamos que usar dois traçados gráficos:

// two graphic plots are used: for Bid and Ask lines
#property indicator_plots 2

Temos que especificar duas memórias de armazenamento (buffers) do indicador contendo os dados a serem traçados no gráfico:

// two indicator's buffers
#property indicator_buffers 2

Para cada linha do indicador, vamos definir o tipo de desenho DESENHAR LINHA (linha), estilo de desenho ESTILO SÓLIDO (linha sólida) e etiquetas de texto "Compra" e "Venda":

// drawing type of a Bid line
#property indicator_type1 DRAW_LINE
// drawing color of a Bid line
#property indicator_color1 Red
// drawing style of a Bid line
#property indicator_style1 STYLE_SOLID
// text label of a Bid line
#property indicator_label1 "Bid"
// drawing type of an Ask line
#property indicator_type2 DRAW_LINE
// drawing color of an Ask line
#property indicator_color2 Blue
// drawing style of an Ask line
#property indicator_style2 STYLE_SOLID
// text label of an Ask line
#property indicator_label2 "Ask"

Vamos especificar as variáveis de entrada, cujos valores podem ser alterados pelo usuário no menu de opções do indicador.

// the BidLineEnable indicates showing of a Bid line
input bool BidLineEnable=true; // Show Bid Line
// the AskLineEnable indicates showing of an Ask line
input bool AskLineEnable=true; // Show Ask Line
// the path_prefix defines a path and file name prefix
input string path_prefix=""; // FileName Prefix

As variáveis BidLineEnable e AskLineEnable permitem a você habilitar e desabilitar a exibição das linhas Compra e Venda no indicador. A variável path_prefix permite a você especificar o prefixo de nome do arquivo posicionado antes do nome do arquivo. Usando essa variável, você também pode especificar o caminho para um subdiretório, por exemplo, se path_prefix = "MyBroker/test_", o caminho para os arquivos será conforme abaixo: "MetaTrader5_Folder\MQL5\Files\MyBroker", para o símbolo "EURUSD" o nome do arquivo será "test_EURUSD.txt".

No nível global, vamos mostrar as variáveis que serão usadas em várias funções do indicador, os valores dessas variáveis é salvo entre os comandos do indicador:

// the tick_stored variable is a number of served quotes
int ticks_stored;
// the BidBuffer[] and AskBuffer[] arrays - are indicator's buffers
double BidBuffer[],AskBuffer[];

A variável tick_stored será utilizada para armazenar o número de cotações disponível. O BidBuffer[] and AskBuffer[] são arranjos dinâmicos, utilizados como um buffer de indicador, os dados de preço, traçados no gráfico como linhas de Compra e venda são armazenados nesses buffers.

A função OnInit sugere que os arranjos BidBuffer[] e AskBuffer[] contêm os dados para o tracejamento. Vamos especificar que os dados com valores do buffer do indicador, igual a zero, não deve ser traçado no gráfico.

void OnInit()
  {
   // the BidBuffer[] is an indicator buffer
   SetIndexBuffer(0,BidBuffer,INDICATOR_DATA);
   // the AskBuffer[] is an indicator buffer
   SetIndexBuffer(1,AskBuffer,INDICATOR_DATA);
   // setting EMPTY_VALUE for a Bid line
   PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0);
   // setting EMPTY_VALUE for an Ask line
   PlotIndexSetDouble(1,PLOT_EMPTY_VALUE,0);
  }

Nesse momento criamos a função OnCalculate e listamos todos os parâmetros passados à função, quando necessário:

int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])

Vamos mostrar as variáveis:

// the file_handle variable is a file handle
// the BidPosition and AskPosition - are positions of Bid and Ask prices in the string;
// the line_string_len is a length of a string, read from the file, i is a loop counter;
int file_handle,BidPosition,AskPosition,line_string_len,i;
// the last_price_bid is the last Bid quote
double last_price_bid=SymbolInfoDouble(Symbol(),SYMBOL_BID);
// the last_price_ask is the last Ask quote
double last_price_ask=SymbolInfoDouble(Symbol(),SYMBOL_ASK);
// the filename is a name of a file, the file_buffer is a string, 
// used as a buffer for reading and writing of string data
string filename,file_buffer;

A variável file_handle de um tipo inteiro será utilizada para armazenar o identificador de um arquivo nas operações de arquivo, as BidPosition e AskPosition - serão utilizadas para um armazenamento de posições iniciais de preços de compra e venda na cadeia, o ine_string_len - será utilizado para o comprimento da cadeia, leitura do arquivo, a variável i será utilizada como um contador cíclico. Os valores dos últimos preços de compra e venda recebidos são armazenados nas variáveis last_price_bid and last_price_ask. A variável de cadeia de nome de arquivo é utilizado para armazenar o nome do arquivo, o file_buffer é uma cadeia utilizada para leitura e escrita no arquivo.

O nome do arquivo é construído da variável path_prefix, nome do instrumento financeiro e a extensão de arquivo ".txt". O uso da função StringConcatenate é mais preferível que a concatenação das cadeias usando o operador de adição, porque funciona mais rápido e econômico quanto a memória.

// File name formation from the path_prefix variable, name
// of financial instrument and ".Txt" symbols
StringConcatenate(filename,path_prefix,Symbol(),".txt");

Abrimos o arquivo utilizando a função FileOpen para utilização posterior:

// Opening a file for reading and writing, codepage ANSI, shared reading mode
file_handle=FileOpen(filename,FILE_READ|FILE_WRITE|FILE_ANSI|FILE_SHARE_READ);

Utilizamos os sinalizadores FILE_READ e FILE_WRITE, porque iremos ler e escrever dados no arquivo, o sinalizador FILE_ANSI indica que a página de código ANSI será utilizada (o padrão é Unicode), o sinalizador FILE_SHARE_READ representa que o acesso compartilhado é permitido para leitura por outros aplicativos que estiverem que o estiverem utilizando.

Na primeira inicialização do indicador não há qualquer dado (ou o período do gráfico foi alterado):

 // At first execution of OnCalculate function, we are reading the quotes from a file
 if(prev_calculated==0)
  {
   // Reading the first line from the file and determine the length of a string
   line_string_len=StringLen(FileReadString(file_handle))+2;
   // if file is large (contains more quotes than rates_total/2)
   if(FileSize(file_handle)>(ulong)line_string_len*rates_total/2)
     {
      // Setting file pointer to read the latest rates_total/2 quotes
      FileSeek(file_handle,-line_string_len*rates_total/2,SEEK_END);
      // Moving file pointer to the beginning of the next line
      FileReadString(file_handle);
     }
   // if file size is small
   else
     {
      // Moving file pointer at the beginning of a file
      FileSeek(file_handle,0,SEEK_SET);
     }
   // Reset the counter of stored quotes
   ticks_stored=0;
   // Reading until the end of the file
   while(FileIsEnding(file_handle)==false)
    {
      // Reading a string from the file
      file_buffer=FileReadString(file_handle);
      // Processing of string if its length is larger than 6 characters
      if(StringLen(file_buffer)>6)
        {
         // Finding the start position of Bid price in the line
         BidPosition=StringFind(file_buffer," ",StringFind(file_buffer," ")+1)+1;
         // Finding the start position of Ask price in the line
         AskPosition=StringFind(file_buffer," ",BidPosition)+1;
         // If the Bid line should be plotted, adding this value to BidBuffer[] array
         if(BidLineEnable) 
         BidBuffer[ticks_stored]=StringToDouble(StringSubstr(file_buffer,BidPosition,AskPosition-BidPosition-1));
         // If the Ask line should be plotted, adding this value to AskBuffer[] array
         if(AskLineEnable) 
         AskBuffer[ticks_stored]=StringToDouble(StringSubstr(file_buffer,AskPosition));
         // Increasing the counter of stored quotes
         ticks_stored++;
        }
     }
  }

Limitaremos o número de cotações que devem ser lidas do arquivo pela metade do número de barras no gráfico. Inicialmente, lemos a cadeia do arquivo e determinamos seu comprimento. Ao fim de uma linha existem dois caracteres adicionais com códigos 10 e 13 ("newline" e "carriage return"), de modo que devemos aumentar o comprimento de linha em 2.

Supomos que o comprimento médio das linhas restantes do arquivo seja o mesmo. Se o comprimento do arquivo é maior que o produto de uma linha pelo número de rates_total/2 (por exemplo, se o arquivo conter mais cotações que rates_total/2), leremos somente as últimas cotações do rates_total/2. Feito isso, configuramos o ponteiro do arquivo na distância, igualamos ao produto do comprimento de uma cadeia por rates_total/2 (do fim do arquivo) e lemos uma linha do arquivo para alinhar o ponteiro do arquivo ao início de uma linha.

Perceba que comparamos dois valores utilizando o operador if eles têm tipos diferentes: o comprimento do arquivo é do tipo ulong, a expressão do lado direito tem o tipo int. Portanto realizamos a distribuição explícita da expressão do lado direito para o tipo ulong.

Se o arquivo conter menos cotações do que rates_total/2, então deslocamos o ponteiro do arquivo para o início do arquivo.

Configuramos o contador de cotações para zero e lemos as linhas de um arquivo até atingir o fim de um arquivo. O processamento das cadeias é realizado pelas cadeias de comprimento superior a 6 caracteres - é o comprimento mínimo de cadeia que contém um caractere para a data, horário, compra e venda e separadores entre si. Extraímos os valores de compra e venda de uma cadeia, lemos pelo arquivo se a linha correspondente deve ser plotada e aumentamos o contador de cotações.

Se os dados foram lidos anteriormente, deslocamos o ponteiro do arquivo no fim no arquivo utilizando a função FileSeek (os novos dados são escritos no arquivo). Utilizando a função StringConcatenate geramos a cadeia, que será escrita dentro do arquivo utilizando a função FileWrite. Adicionamos os novos valores de preços de compra e venda para BidBuffer[] e AskBuffer[], arranjos, se a linha correspondente deve ser tracejada e aumentar o contador de cotações.

  // If the data have been read before
else
  {
   // Moving file pointer at the end of the file
   FileSeek(file_handle,0,SEEK_END);
   // Forming a string, that should be written to the file
   StringConcatenate(file_buffer,TimeCurrent()," ",DoubleToString(last_price_bid,_Digits)," ",DoubleToString(last_price_ask,_Digits));
   // Writing a string to the file
   FileWrite(file_handle,file_buffer);
   // If the Bid line should be plotted, adding the last Bid price to the BidBuffer[] array
   if(BidLineEnable) BidBuffer[ticks_stored]=last_price_bid;
   // If the Ask line should be plotted, adding the last Ask price to the AskBuffer[] array
   if(AskLineEnable) AskBuffer[ticks_stored]=last_price_ask;
   // Increasing the quotes counter
   ticks_stored++;
  }

Pode-se perguntar porque você não lê os dados de um arquivo por dentro da função OnInit? O motivo é o seguinte: o comprimento dos arranjos dinâmicos BidBuffer[] e AskBuffer[] não foi definido sendo especificado quando a função OnCalculate é acionada.

Fechamos o arquivo aberto anteriormente:

// Closing the file
FileClose(file_handle);

Para o caso do contador de cotações seja igual ou maior que o número de barras no gráfico após a leitura do arquivo ou após a soma aos arranjos BidBuffer[] e AskBuffer[], a metade das cotações antigas será removida e as restantes serão deslocadas para seus locais.

// If number of quotes is more or equal than number of bars in the chart
if(ticks_stored>=rates_total)
  {
   // Removing the first tick_stored/2 quotes and shifting remaining quotes
   for(i=ticks_stored/2;i<ticks_stored;i++)
     {
      // If the Bid line should be plotted, shifting the values of BidBuffer[] array on tick_stored/2
      if(BidLineEnable) BidBuffer[i-ticks_stored/2]=BidBuffer[i];
      // If the Ask line should be plotted, shifting the values of AskBuffer[] array on tick_stored/2
      if(AskLineEnable) AskBuffer[i-ticks_stored/2]=AskBuffer[i];
     }
   // Changing the value of a counter
   ticks_stored-=ticks_stored/2;
  }

Os arranjos BidBuffer[] a AskBuffer[] das memórias de armazenamento (buffers) do indicador não são uma série temporal, dessa forma o elemento recente tem índice igual a ticks_stored-1 o gráfico recente tem índice igual a rates_total-1. Para reuní-los ao mesmo nível, vamos mudar a linha do indicador utilizando a função PlotIndexSetInteger.

// Shifting the Bid line to align with the price chart
PlotIndexSetInteger(0,PLOT_SHIFT,rates_total-ticks_stored);
// Shifting the Ask line to align with the price chart
PlotIndexSetInteger(1,PLOT_SHIFT,rates_total-ticks_stored);

Os valores dos preços recentes recebidos são armazenados no BidBuffer[] e no AskBuffer[] com o índice igual ao rates_total-1 (se as linhas correspondentes devem ser plotadas) para exibi-los no canto superior esquerdo da janela do indicador.

// If the Bid line should be plotted, placing the value to the last element 
// of BidBuffer [] array to show the last Bid price in the indicator's window  
if(BidLineEnable) BidBuffer[rates_total-1]=last_price_bid;
// If the Ask line should be plotted, placing the value to the last element 
// of AskBuffer [] array to show the last Ask price in the indicator's window
if(AskLineEnable) AskBuffer[rates_total-1]=last_price_ask;

A execução da função OnCalculate é completada pelo retorno do rates_total (você pode retornar qualquer número diferente de zero), o código da função termina com uma chaveta.

// Return from OnCalculate(), return a value, different from zero   
return(rates_total);
}

O indicador de escala foi escrito. O código-fonte do indicador pode ser baixado no link, localizado no fim do artigo.

Criando o indicador do gráfico "de velas"

Agora vamos escrever um indicador, que plota as chamados "velas". Diferente dos gráficos de vela, onde cada vela corresponde ao período específico de tempo, o gráfico "de velas" tem a estrutura diferente: cada vela tem alguns números pré-definidos de pontos, recebidos do corretor (velas de mesmo volume). Esse indicador se parece conforme mostrado na Figura 2:


Figura 2. O indicador do gráfico "de velas"

O indicador do gráfico "de velas", assim como o indicador de ponto, considerado acima, escreve todas as cotações recebidas no arquivo. O formato dos dados e os detalhes da localização do arquivo são os mesmos. O caminho do arquivo, o prefixo do nome, o número de pontos para uma vela e o tipo de um preço (compra ou venda) pode ser especificado nas opções do indicador.

Para criar um indicador, inicialize o terminal de cliente do MetaTrader 5 e inicialize o MetaQuotes Language Editor pressionando a tecla F4.

Vamos especificar que ele seja plotado em uma janela separada.

// Indicator is plotted in a separate window
#property indicator_separate_window

O indicador tem somente uma plotagem gráfica: velas coloridas.

// One graphic plot is used, color candles
#property indicator_plots 1

Precisamos de quatro memórias de armazenamento (buffers) para mostrar as velas coloridas e para armazenar os valores de dados de preço (aberto, alto, baixo e próximo) valores do preço para cada vela. Também precisamos de uma memória de armazenamento (buffer) adicional para armazenar índices de cor das velas.

// We need 4 buffers for OHLC prices and one - for the index of color
#property indicator_buffers 5

Vamos especificar o tipo de desenho: DESENHAR VELAS COLORIDAS - velas coloridas.

// Specifying the drawing type - color candles
#property indicator_type1 DRAW_COLOR_CANDLES

Vamos especificar as cores que serão usadas para as velas:

// Specifying the colors for the candles
#property indicator_color1 Gray,Red,Green

Vamos criar os price_types do tipo de enumeração, contendo um dos seguintes valores: Compra ou venda:

/ / Declaration of the enumeration
enum price_types
  (
   Bid,
   Ask
  )

Especificamos as variáveis de entrada, que podem ser alterados pelo usuário no menu de opções do indicador.

// The ticks_in_candle input variable specifies the number of ticks,
// corresponding to one candle
input int ticks_in_candle=16; //Tick Count in Candles
// The applied_price input variable of price_types type indicates 
// the type of the data, that is used in the indicator: Preços de compra ou venda.
input price_types applied_price=0; // Price
// The path_prefix input variable specifies the path and prefix to the file name
input string path_prefix=""; // FileName Prefix

A variável ticks_in_candle especifica o número de pontos correspondente a uma vela. A variável applied_price indica o tipo de um preço usado para a construção das velas. Compra ou venda. O prefixo do diretório e do nome do arquivo para dados de pontos históricos podem ser especificados na variável path_prefix.

As variáveis com valores que devem ser salvos entre os acionamentos do indicador são declaradas no nível global.

// The ticks_stored variable contains the number of stored quotes
int ticks_stored;
// The TicksBuffer [] array is used to store the incoming prices
// The OpenBuffer [], HighBuffer [], LowBuffer [] and CloseBuffer [] arrays
// are used to store the OHLC prices of the candles
// The ColorIndexBuffer [] array is used to store the index of color candles
double TicksBuffer[],OpenBuffer[],HighBuffer[],LowBuffer[],CloseBuffer[],ColorIndexBuffer[];

A variável tick_stored é utilizada para armazenar o número de cotações disponível. O arranjo TicksBuffer[] é usado para um armazenamento das cotações recebidas, os arranjos OpenBuffer[], HighBuffer[], LowBuffer[] e CloseBuffer[] são usados para um armazenamento de preços de vela (abertura, mais alto, mais baixo e encerramento) que será plotado no gráfico. O arranjo ColorIndexBuffer[] é usado para um armazenamento do índice de cores das velas.

A função OnInit mostra que os arranjos OpenBuffer[], HighBuffer[], LowBuffer[] e CloseBuffer[] são usadas como umas memórias de armazenamento (buffers) de indicador, o arranjo ColorIndexBuffer[] contém um índice de cores de velas, o arranjo TicksBuffer[] é usado para os cálculos intermediários:

void OnInit()
  {
   // The OpenBuffer[] array is an indicator buffer
   SetIndexBuffer(0,OpenBuffer,INDICATOR_DATA);
   // The HighBuffer[] array is an indicator buffer
   SetIndexBuffer(1,HighBuffer,INDICATOR_DATA);
   // The LowBuffer[] array is an indicator buffer
   SetIndexBuffer(2,LowBuffer,INDICATOR_DATA);
   // The CloseBuffer[] array is an indicator buffer
   SetIndexBuffer(3,CloseBuffer,INDICATOR_DATA);
   // The ColorIndexBuffer[] array is the buffer of the color index
   SetIndexBuffer(4,ColorIndexBuffer,INDICATOR_COLOR_INDEX);
   // The TicksBuffer[] array is used for intermediate calculations
   SetIndexBuffer(5,TicksBuffer,INDICATOR_CALCULATIONS);

A seguir especificamos os arranjos OpenBuffer[], HighBuffer[], LowBuffer[], CloseBuffer[] e ColorIndexBuffer[] como séries temporais (por exemplo, os dados mais recentes têm índice 0):

   // The indexation of OpenBuffer[] array as timeseries
   ArraySetAsSeries(OpenBuffer,true);
   // The indexation of HighBuffer[] array as timeseries
   ArraySetAsSeries(HighBuffer,true);
   // The indexation of LowBuffer[] array as timeseries
   ArraySetAsSeries(LowBuffer,true);
   // The indexation of CloseBuffer[] array as timeseries
   ArraySetAsSeries(CloseBuffer,true);
   // The indexation of the ColorIndexBuffer [] array as timeseries
   ArraySetAsSeries(ColorIndexBuffer,true);

Os valores das memórias de armazenamento (buffers) do indicador iguais a zero não devem ser plotados no gráfico:

   // The null values of Open prices (0th graphic plot) should not be plotted
   PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0);
   // The null values of High prices (1st graphic plot) should not be plotted
   PlotIndexSetDouble(1,PLOT_EMPTY_VALUE,0);
   // The null values of Low prices (2nd graphic plot) should not be plotted
   PlotIndexSetDouble(2,PLOT_EMPTY_VALUE,0);
   // The null values of Close prices (3rd graphic plot) should not be plotted
   PlotIndexSetDouble(3,PLOT_EMPTY_VALUE,0);

A gravação da função OnInit está completa, fechamos a função utilizando uma chaveta.

Chegou o momento de escrever a função OnCalculate. Vamos especificar todos os parâmetros passados para a função:

int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
  {

Mostramos as variáveis, que serão utilizadas na função OnInit.

// the file_handle variable is a file handle
// the BidPosition and AskPosition - are positions of Bid and Ask prices in the string;
// the line_string_len is a length of a string, read from the file, 
// CandleNumber - number of candle, for which the prices OHLC are determined,
// i - loop counter;
int file_handle,BidPosition,AskPosition,line_string_len,CandleNumber,i;
// The last_price_bid variable is the recent received Bid price
double last_price_bid=SymbolInfoDouble(Symbol(),SYMBOL_BID);
// The last_price_ask variable is the recent received Ask price
double last_price_ask=SymbolInfoDouble(Symbol(),SYMBOL_ASK);
// the filename is a name of a file, the file_buffer is a string, 
// used as a buffer for reading and writing of string data
string filename,file_buffer;

A variável file_handle de um tipo inteiro é utilizada para armazenar o identificador de um arquivo nas operações de arquivo, as BidPosition e AskPosition são utilizadas para um armazenamento de posições iniciais de preços de compra e venda na cadeia, o line_string_len é um comprimento da cadeia, lido de um arquivo, o CandleNumber - é o índice da vela calculada, a variável i é utilizada como um contador cíclico.

Os valores dos últimos preços de compra e venda recebidos são armazenados nas variáveis do tipo duplo last_price_bid elast_price_ask. A variável filename de um tipo de cadeia é utilizada para um armazenamento do nome do arquivo, o file_buffer é uma cadeia utilizada em operações de arquivo.

O tamanho do arranjo TicksBuffer[] não é configurado automaticamente, ao contrário dos arranjos OpenBuffer[], HighBuffer[], LowBuffer[], CloseBuffer[] e ColorIndexBuffer[], que são memórias de armazenamento (buffers) do indicador, então vamos estabelecer o tamanho de um arranjo TicksBuffer[] do mesmo tamanho dos arranjos OpenBuffer[], HighBuffer[], LowBuffer[], CloseBuffer[] e ColorIndexBuffer[]:

// Setting the size of TicksBuffer[] array
ArrayResize(TicksBuffer,ArraySize(CloseBuffer));

Prepare o nome do arquivo da variável path_prefix, o nome do instrumento financeiro e a extensão ".txt":

// File name formation from the path_prefix variable, name
// of financial instrument and ".Txt" symbols
StringConcatenate(filename,path_prefix,Symbol(),".txt");

Vamos abrir o arquivo com parâmetros descrito acima para o indicador anterior.

// Opening a file for reading and writing, codepage ANSI, shared reading mode
file_handle=FileOpen(filename,FILE_READ|FILE_WRITE|FILE_ANSI|FILE_SHARE_READ);

Se a função OnCalculate é chamada pela primeira vez e não houverem quaisquer dados no arranjo TicksBuffer[], lemos os mesmos do arquivo.

if(prev_calculated==0)
  {
   // Reading the first line from the file and determine the length of a string
   line_string_len=StringLen(FileReadString(file_handle))+2;
   // if file is large (contains more quotes than rates_total/2)
   if(FileSize(file_handle)>(ulong)line_string_len*rates_total/2)
     {
      // Setting file pointer to read the latest rates_total/2 quotes
      FileSeek(file_handle,-line_string_len*rates_total/2,SEEK_END);
      // Moving file pointer to the beginning of the next line
      FileReadString(file_handle);
     }
   // if file size is small
   else
     {
      // Moving file pointer at the beginning of a file
      FileSeek(file_handle,0,SEEK_SET);
     }
   // Reset the counter of stored quotes
   ticks_stored=0;
   // Reading until the end of the file
   while(FileIsEnding(file_handle)==false)
     {
      // Reading a string from thefile
      file_buffer=FileReadString(file_handle);
      // Processing of string if its length is larger than 6 characters
      if(StringLen(file_buffer)>6)
        {
         // Finding the start position of Bid price in the line
         BidPosition=StringFind(file_buffer," ",StringFind(file_buffer," ")+1)+1;
          //Finding the start position of Ask price in the line
         AskPosition=StringFind(file_buffer," ",BidPosition)+1;
         // If the Bid prices are used, adding the Bid price to TicksBuffer[] array
         if(applied_price==0)
         TicksBuffer[ticks_stored]=StringToDouble(StringSubstr(file_buffer,BidPosition,AskPosition-BidPosition-1));
         // If the Ask prices are used, adding the Ask price to TicksBuffer[] array
         if(applied_price==1)
         TicksBuffer[ticks_stored]=StringToDouble(StringSubstr(file_buffer,AskPosition));
         // Increasing the counter of stored quotes
         ticks_stored++;
        }
     }
  }

A leitura de cotações do arquivo foi descrita acima com maiores detalhes, é a mesma do indicador anterior.

Se as cotações foram lidas antes de dentro o arranjo TicksBuffer[], escrevemos alguns novos valores de preço no arquivo, colocamos um novo preço no arranjo TicksBuffer[] e aumentamos o contador de cotações:

// If the data have been read before
else
  {
   // Moving file pointer at the end of the file
   FileSeek(file_handle,0,SEEK_END);
   // Forming a string, that should be written to the file
   StringConcatenate(file_buffer,TimeCurrent()," ",DoubleToString(last_price_bid,_Digits)," ",DoubleToString(last_price_ask,_Digits));
   // Writing a string to the file
   FileWrite(file_handle,file_buffer);
   // If the Bid prices are used, adding the last Bid price to TicksBuffer[] array
   if(applied_price==0) TicksBuffer[ticks_stored]=last_price_bid;
   // If the Ask prices are used, adding the last Ask price to TicksBuffer[] array
   if(applied_price==1) TicksBuffer[ticks_stored]=last_price_ask;
   // Increasing the quotes counter
   ticks_stored++;
  }

Fechamento do arquivo:

// Closing the file
FileClose(file_handle);

Se o número de cotações armazenadas alcançar o número de barras do gráfico de preço ou tornar-se maior, retiramos a metade dos dados mais antigos e deslocamos os dados restantes:

// If number of quotes is more or equal than number of bars in the chart
if(ticks_stored>=rates_total)
  {
   // Removing the first tick_stored/2 quotes and shifting remaining quotes
   for(i=ticks_stored/2;i<ticks_stored;i++)
     {
      // Shifting the data to the beginning in the TicksBuffer[] array on tick_stored/2
      TicksBuffer[i-ticks_stored/2]=TicksBuffer[i];
     }
   // Changing the quotes counter
   ticks_stored-=ticks_stored/2;
  }

Vamos calcular os valores OHLC para cada vela e colocar esses valores nas memórias de armazenamento (buffers) do indicador correspondentes:

   // We assign the CandleNumber with a number of invalid candle
   CandleNumber=-1;
   // Search for all the price data available for candle formation
   for(i=0;i<ticks_stored;i++)
     {
      // If this candle is forming already
      if(CandleNumber==(int)(MathFloor((ticks_stored-1)/ticks_in_candle)-MathFloor(i/ticks_in_candle)))
        {
         // The current quote is still closing price of the current candle
         CloseBuffer[CandleNumber]=TicksBuffer[i];
         // If the current price is greater than the highest price of the current candle,
          // it will be a new highest price of the candle
         if(TicksBuffer[i]>HighBuffer[CandleNumber]) HighBuffer[CandleNumber]=TicksBuffer[i];
         // If the current price is lower than the lowest price of the current candle, 
          // it will be a new lowest price of the candle
         if(TicksBuffer[i]<LowBuffer[CandleNumber]) LowBuffer[CandleNumber]=TicksBuffer[i];
         // If the candle is bullish, it will have a color with index 2 (green)
         if(CloseBuffer[CandleNumber]>OpenBuffer[CandleNumber]) ColorIndexBuffer[CandleNumber]=2;
         // If the candle is bearish, it will have a color with index 1 (red)
         if(CloseBuffer[CandleNumber]<OpenBuffer[CandleNumber]) ColorIndexBuffer[CandleNumber]=1;
         // If the opening and closing prices are equal, then the candle will have a color with index 0 (grey)
         if(CloseBuffer[CandleNumber]==OpenBuffer[CandleNumber]) ColorIndexBuffer[CandleNumber]=0;
        }
      // If this candle hasn't benn calculated yet
      else
        {
         // Let's determine the index of a candle
         CandleNumber=(int)(MathFloor((ticks_stored-1)/ticks_in_candle)-MathFloor(i/ticks_in_candle));
         // The current quote will be the opening price of a candle
         OpenBuffer[CandleNumber]=TicksBuffer[i];
         // The current quote will be the highest price of a candle
         HighBuffer[CandleNumber]=TicksBuffer[i];
         // The current quote will be the lowest price of a candle
         LowBuffer[CandleNumber]=TicksBuffer[i];
         // The current quote will be the closing price of a candle
         CloseBuffer[CandleNumber]=TicksBuffer[i];
         // The candle will have a color with index 0 (gray)
         ColorIndexBuffer[CandleNumber]=0;
        }
     }

A execução da função OnCalculate é concluída ao retornar de um valor não nulo, o que quer dizer que aquele arranjo TicksBuffer[] já tem os dados e é desnecessário lê-los na próximo acionamento da função. Posicionamos chaveta de fechamento no fim da função.

 // Return from OnCalculate(), return a value, different from zero   
 return(rates_total);
}

No fim deste artigo existe um link que pode ser usado para baixar o código-fonte completo do indicador.

Conclusão

Neste artigo, examinamos a criação de dois indicadores de ponto: o indicador de gráfico de ponto e o indicador do gráfico "de velas".

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

Arquivos anexados |
tickindicator.mq5 (8.28 KB)
Guia passo a passo para iniciantes para escrever um Expert Advisor no MQL5 Guia passo a passo para iniciantes para escrever um Expert Advisor no MQL5
A programação de Expert Advisors no MQL5 é simples, e você pode aprender facilmente. Neste guia passo a passo, você verá os passos básicos necessários para escrever um simples Expert Advisor com base em uma estratégia de negócio de desenvolvimento. São apresentados, a estrutura de um Expert Advisor, o uso de indicadores técnicos embutidos e funções de negociação, os detalhes do modo de Depuração e uso do Strategy Tester.
Estilos de desenhos no MQL5 Estilos de desenhos no MQL5
Existem 6 estilos de desenho no MQL4 e 18 estilos de desenho no MQL5. Então pode valer a pena escrever um artigo para introduzir os estilos de desenhos do MQL5. Neste artigo consideraremos os detalhes de estilos de desenho no MQL5. Além disso, criaremos um indicador para demonstrar como usar esses estilos de desenhos e refinar a diagramação.
Criar um quadro de informação utilizando classes de biblioteca padrão e o Google Chart API Criar um quadro de informação utilizando classes de biblioteca padrão e o Google Chart API
A linguagem de programação MQL5 foca principalmente na criação dos sistemas de negociação automatizada e instrumentos complexos da análise técnica. Mas, fora isso, ela permite criar sistemas de informação interessantes para rastrear situações de mercado e fornece uma conexão de retorno com o negociante. O artigo descreve os componentes da Biblioteca Padrão MQL5, e mostra exemplos de seu uso na prática para alcançar estes objetivos. Ela também demonstra um exemplo para utilizar o Google Chart API para criação de gráficos.
Como chamar indicadores no MQL5 Como chamar indicadores no MQL5
Com a nova versão da linguagem de programação MQL disponível, não apenas a abordagem para lidar com indicadores mudou, mas também, existem novas formas de como criar indicadores. Além disso, você tem a flexibilidade adicional trabalhando com os buffers do indicador - agora você pode especificar a direção desejada de indexação e obter exatamente quantos valores de indicadores você quiser. Este artigo explica os métodos básicos de chamada de indicadores e recuperar dados dos buffers do indicador.