Contratos futuros contínuos em MetaTrader 5

Vladimir Karputov | 10 julho, 2014

Introdução

O trader não pode criar seus próprios gráficos em MetaTrader 5, pois somente podem ser construídos com os ativos da corretora. O trader necessita de um produto sintético - os contratos futuros contínuos. O problema é que somente a corretora pode fazer emendas de contratos e somente a corretora decide se vai ligar os contratos futuros sobre o símbolo dado.

Felizmente, o histórico dos futuros fechados está sempre disponível no terminal. Use este histórico para emendar os contratos futuros no terminal.


Convenções:

  1. Todos os dados, desenhos e imagens no artigo baseiam-se no contrato futuro real do índice de Ações Ucraniana.
  2. Seções de código substituídos ou adicionados no artigo serão marcado com cores.Por exemplo:
    //+------------------------------------------------------------------+
    //|                                               This is an example |
    //|                                               of the edited code |
    //+------------------------------------------------------------------+

O primeiro problema: sobrepor dados

Os contratos futuros próximos são negociados com datas sobrepostas,

isso significa que o futuro é colocado em negociação enquanto outros futuros ainda tem dois meses para serem fechados.

Fig. 1. Datas se sobrepõem em contratos de futuros

Fig. 1. Datas se sobrepõem em contratos de futuros

A figura mostra que 09.16.2013 é a data de início da negociação do contrato futuro UX-3.14, embora o contrato futuro UX-12.13 ainda está em aberto.


O segundo problema: escolher a forma de emendar

Existem dois métodos de emendar:

Fig. 2. Emendando. Adição simples.

Fig. 2. Emendando. Adição simples

Fig. 3. Emendando. Adição com deslocamento

Fig. 3. Emendando. Adição com deslocamento


Configurações no terminal

O contrato futuro deve ser colocado em ordem descendente:

Fig. 4. Observação do mercado

Fig. 4. Observação do mercado


Escrevendo um indicador

O indicador padrão deve ser colocado na pasta "indicators" no seguinte caminho de diretório: terminal_data_folder\MQL5\Indicators. Criar a pasta Synthetics em MyIndicators (que você vai abrir na pasta \Indicators). Permitirá que você salve o espaço na pasta \Indicators na Biblioteca Padrão (Standard Library) e facilitará o lançamento sincronizado dos indicadores na seção Armazenamento MQL5. O caminho final da pastas fica assim: terminal_data_folder\MQL5\Indicators\MyIndicators\Synthetics.

Na pasta Synthetics criamos um novo arquivo:

Fig. 5. Criamos um novo arquivo do indicador

Fig. 5. O novo arquivo criado do indicador

Defina o novo tipo de arquivo - "Indicador Personalizado":

Fig. 6. Defina o novo tipo de arquivo - "indicador personalizado"

Fig. 6. Defina o novo tipo de arquivo - "indicador personalizado"

Pressione o botão "Avançar" e abra a janela "propriedades gerais do indicador personalizado". Digite o nome do indicador - "SYNT", adicione dois parâmetros O primeiro parâmetro "Number_futures_gluing" (Número de futuros para colagem) determina o número de instrumentos a serem conectados. Note que 2 é o menor valor possível de "Number_futures_for_gluing". A segunda opção "Gluing type" (Tipo de colagem) determina o tipo de emenda no indicador padrão - "simple addition"(adição simples):

Fig. 7. Parâmetros do indicador personalizado

Fig. 7. Os parâmetros do indicador personalizado

Preste atenção para a opção "Gluing type": a emenda pode ser "simples adição" ou "adição com deslocamento". Nesta fase você não pode adicionar na lista os dois tipos de emenda. É por isso que deixamos a "simples adição" como padrão. Durante o processo de escrever o código do indicador "SYNT", mais tarde será ativada a opção para ver a lista dropdown (suspensa) com os tipos de emendas.

Na janela seguinte, selecione os handlers (manipuladores) dos eventos do indicador:

Fig. 8. Handlers de eventos do indicador

Fig. 8. Os handlers de eventos do indicador

Note que a função OnTimer() será usada pelo indicador "SYNT". A principal funcionalidade do indicador situa-se no OnTimer() . O indicador pode ser anexado ao gráfico do ativo com o trade finalizado (este ativo não incluirá o evento OnCalculate) ou com o gráfico do ativo com um trade em andamento.

Pressione o botão "Avançar" e nas "Propriedades gerais do programa indicador personalizado" assinale "Indicador em janela separada":

Fig. 9. Escolha a opção "indicador em janela separada"

Fig. 9. opção "indicador em janela separada"

Pressione o botão "Concluído" e você vai ver o modelo do indicador "SYNT".


Organizar a lista dropdown (suspensa)

Para ver os tipos de emendas como uma lista suspensa você precisa declarar a enumeração ENUM_GLUING_TYPE nas opções dos indicadores.

Declarar enumeração na área global no início do bloco dos parâmetros de entrada:

#property indicator_separate_window
//+------------------------------------------------------------------+
//|  Splicing types enumeration                                      |
//+------------------------------------------------------------------+
enum ENUM_GLUING_TYPE
  {
   simple_addition,        // simple addition||simple addition
   addition_with_shift     // addition with shift||addition with shift
  };  
//--- input parameters || input parameters
input ENUM_GLUING_TYPE  gluing_type=simple_addition;
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+

Agora você pode verificar como a lista suspensa é exibida.

Você deve compilar o arquivo do indicador (F7). Agora, depois de ter anexado o indicador, você pode ver as opções da lista suspensa:

Fig. 10. Temos, agora, uma lista dropdown nos parâmetros

Fig. 10. Agora você tem a
lista dropdown nos parâmetros
 

Adicionar a descrição do indicador que será exibido na guia "Geral" quando for anexado ao gráfico pela primeira vez ou quando as suas propriedades forem alteradas:

#property version   "1.00"
//+------------------------------------------------------------------+
//| version   "1.00": The timer history swapping                     |
//+------------------------------------------------------------------+
#property description "Indicator for several futures splicing."
#property description "Is drawn in the latest futures window"
#property description "Uses N first symbols for drawing"
#property description "which were taken from the \"Market review\"."

#property indicator_separate_window 

O método de construção do indicador - DRAW_COLOR_CANDLES - candles coloridos.

Você precisa de 4 buffers para o indicador e um buffer para o índice de armazenamento de cor. O estilo de linha do indicador - STYLE_SOLID - linha contínua. Mostrar tudo no código do indicador:

#property description "taken from the \"Market review\"."

//--- indicator settings || indicator settings
#property indicator_separate_window
#property indicator_buffers 5 
#property indicator_plots   1
//--- plot Bars || bars plotting
#property indicator_label1    "SYNT"
#property indicator_type1     DRAW_COLOR_CANDLES
#property indicator_style1    STYLE_SOLID
#property indicator_width1    1
//+------------------------------------------------------------------+
//|  enumeration of splicing methods                                 |
//+------------------------------------------------------------------+

Digite o parâmetro de entrada "number_futures_gluing" - o número de instrumentos necessários para a construção. O valor padrão do "number_futures_gluing" é igual a 2:

//--- input parameters || input parameters
input int               numder_futures_gluing=2;
input ENUM_GLUING_TYPE  gluing_type=simple_addition;

Declarar os 4 buffers para o indicador, um buffer para o índice de armazenamento de cor e um array auxiliar LoadHistory[].

#property indicator_style1    STYLE_SOLID
#property indicator_width1    1
//--- indicator buffers || indicator buffers
double            OpenBuffer[];
double            HighBuffer[];
double            LowBuffer[];
double            CloseBuffer[];
double            ColorCandlesColors[];
double            LoadHistory[];
//+------------------------------------------------------------------+
//|  enumeration of splicing methods                                 |
//+------------------------------------------------------------------+

Anexar os buffers do indicador aos arrays dinâmicos de uma dimensão, definir a indexação dos buffers como nas timeseries:

//--- indicator buffers mapping
//--- indicator buffers mapping
   SetIndexBuffer(0,OpenBuffer,INDICATOR_DATA);
   SetIndexBuffer(1,HighBuffer,INDICATOR_DATA);
   SetIndexBuffer(2,LowBuffer,INDICATOR_DATA);
   SetIndexBuffer(3,CloseBuffer,INDICATOR_DATA);
   SetIndexBuffer(4,ColorCandlesColors,INDICATOR_COLOR_INDEX);
   SetIndexBuffer(5,LoadHistory,INDICATOR_CALCULATIONS);
//--- set buffer indexing as timeseries
//--- set buffer indexing as in timeseries
   ArraySetAsSeries(OpenBuffer,true);
   ArraySetAsSeries(HighBuffer,true);
   ArraySetAsSeries(LowBuffer,true);
   ArraySetAsSeries(CloseBuffer,true);
   ArraySetAsSeries(ColorCandlesColors,true);
//---
   return(INIT_SUCCEEDED);

Para exibir o nome das séries do indicador ("Open", "High", "Low" e "Close") na "janela de dados" é necessário a variável s_symbol:

input int               numder_futures_gluing=2;
input ENUM_GLUING_TYPE  gluing_type=simple_addition;
//--- symbol name
string s_symbol;
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+

Para ativar o indicador você precisa da variável shft_array e duas flags, good_history e indicator_rendered:

input ENUM_GLUING_TYPE  gluing_type=simple_addition;
//--- symbol name
string   s_symbol;
int      shift_array=0;
bool     good_history=false;        //history is not prepared||history not prepared
bool     indicator_rendered=false;  // indicator is not drawn
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+

Em seguida, configure o indicador e conecte o buffer do índice de cor para a cor escolhida:

   ArraySetAsSeries(CloseBuffer,true);
   ArraySetAsSeries(ColorCandlesColors,true);
//--- set accuracy || accuracy of the indicator values 
   IndicatorSetInteger(INDICATOR_DIGITS,0);
//--- set drawing line empty value || empty value of the drawing line 
   PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0.0);
//--- set labels for the line || displayed name in the DataWindow
   PlotIndexSetString(0,PLOT_LABEL,s_symbol+" Open;"+s_symbol+" High;"+s_symbol+" Low;"+s_symbol+" Close");
   IndicatorSetString(INDICATOR_SHORTNAME,"SYNT");
//--- set number of colors in color buffer || number of colors in the buffer
   PlotIndexSetInteger(0,PLOT_COLOR_INDEXES,9);
//--- set line color || set the line color
   PlotIndexSetInteger(0,PLOT_LINE_COLOR,0,clrBlue);
   PlotIndexSetInteger(0,PLOT_LINE_COLOR,1,clrOrange);
   PlotIndexSetInteger(0,PLOT_LINE_COLOR,2,clrRed);
   PlotIndexSetInteger(0,PLOT_LINE_COLOR,3,clrGreen);
   PlotIndexSetInteger(0,PLOT_LINE_COLOR,4,clrPink);
   PlotIndexSetInteger(0,PLOT_LINE_COLOR,5,clrIndigo);
   PlotIndexSetInteger(0,PLOT_LINE_COLOR,6,clrPaleVioletRed);
   PlotIndexSetInteger(0,PLOT_LINE_COLOR,7,clrDarkViolet);
   PlotIndexSetInteger(0,PLOT_LINE_COLOR,8,clrDimGray);
//---
   return(INIT_SUCCEEDED);

Adicionar a inicialização do temporizador com intervalos de 3 segundos e o gerador de números aleatórios na função OnInit() :

   PlotIndexSetInteger(0,PLOT_LINE_COLOR,7,clrDarkViolet);
   PlotIndexSetInteger(0,PLOT_LINE_COLOR,8,clrDimGray);
//---
   EventSetTimer(3);
//--- random number generator initializor
   MathSrand(GetTickCount());
//---
   return(INIT_SUCCEEDED);

É necessário pelo menos dois símbolos (ativos) para processar a emenda.

Verifique o número de instrumentos (ativos) para emendar na função OnCalculate():

                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
  {
//--- checking the number of instruments || checking the number of instruments
   if(numder_futures_gluing<=1)
     {
      //--- create the message line
      string comm=StringFormat("For the indicator choose not less than %d symbols",numder_futures_gluing);
      //--- display the message in comment in the chart main window
      Comment(comm);
      return(0);
     }
//--- return value of prev_calculated for next call
   return(rates_total);

Depois de ter verificado o número de ativos para a emenda, verificar se o indicador já foi desenhado. Se o indicador foi desenhado, então você pode sair do OnCalculate() :

      Comment(comm);
      return(0);
     }
   if(indicator_rendered==true) return(rates_total);
//--- return value of prev_calculated for next call
   return(rates_total);

Como o indicador "SYNT" é usado principalmente para analisar a tendência de desenvolvimento de barras diárias, considero que não há necessidade de proceder novos cálculos em cada tick. Não haverá cálculos do indicador "SYNT" a cada tick.

Você precisa calcular o indicador apenas nos seguintes casos:

   if(indicator_rendered==true) return(rates_total);
//--- if calculations were started the first time
//--- or if we need to calculate the indicator for two or more bars (changes in history)
//--- remember, that the "0" bar - is the left-most
   if(prev_calculated==0 || rates_total>prev_calculated+1)
     {
     }
//--- return value of prev_calculated for next call
   return(rates_total);


Inicialização forçada dos buffers do indicador

Os buffers do indicador "SYNT" são conectados nos arrays dinâmicos

Quando o indicador é lançado pela primeira vez, os buffers são inicializados forçadamente. Prosseguir com a inicialização no OnCalculate(). Por que você precisa conduzir-lo no OnCalculate() e não no OnInit? A explicação está na figura abaixo:

Fig. 11. A inicialização do array no OnCalculate()

Fig. 11. A inicialização do array no OnCalculate()

Como você pode ver na Fig.11, o evento OnCalculate() irá ocorrer em qualquer caso, enquanto que o OnInit() é ativado quando você faz a atualização do gráfico por meio do comando "Update". Portanto, a inicialização dos arrays serão conduzidas no OnCalculate():

//--- remember, that the "0" bar - is the left-most
   if(prev_calculated==0 || rates_total>prev_calculated+1)
     {
      //--- arrays initialization
      ArrayInitialize(OpenBuffer,0);
      ArrayInitialize(HighBuffer,0);
      ArrayInitialize(LowBuffer,0);
      ArrayInitialize(CloseBuffer,0);
     }
//--- return value of prev_calculated for next call
   return(rates_total);

A função ArrayInitialize() inicializa o buffer do indicador Neste caso a inicialização mostra zeros.

Se você tentar inicializar o indicador de buffer pelo EMPTY_VALUE , você não poderá emendar os indicadores sobre o "SYNT".


Algoritmo da Adição simples

Fig. 12. Algoritmo de adição simples

Fig. 12. Algoritmo da Adição simples

 

As datas na imagem são o início e fim da circulação dos contratos futuros UX-9.13, UX-12.13 e UX-3.14. Estes dados são apresentados na tabela:

Símbolo (Ativo)Início da circulaçãoFinal da circulação
UX-9.1303.15.201309.16.2013
UX-12.1306.17.201312.16.2013
UX-3.1409.16.201303.17.2014

 

Na Fig. 10, data 12.25.2013 - é uma data do calendário real. O ativo UX-3.14 ainda é válido.

O método de emenda "Adição Simples" será implementado na função SimpleAddition:

//+------------------------------------------------------------------+
//| Timer function                                                   |
//+------------------------------------------------------------------+
void OnTimer()
  {
//---
  }
//+------------------------------------------------------------------+
//| Simple addition                                                  |
//| Simple addition. Add in the indicator array                      |
//| sibmUP symbol                                                    |
//+------------------------------------------------------------------+
bool SimpleAddition(string simbUP,string simbDOWN,ENUM_TIMEFRAMES period,int Color)
  {
  }
//+------------------------------------------------------------------+

simbUP é o contrato futuro de alta, simbDOWN é contrato futuro de baixa, ambos estão localizados na janela de "Análise do mercado". Color - cor usada para desenhar os contratos futuros. 

O código completo da função SimpleAddition() é descrita abaixo:

//+------------------------------------------------------------------+
//| Simple addition                                                  |
//| Simple addition. Add in the indicator array                      |
//| sibmUP symbol                                                    |
//+------------------------------------------------------------------+
bool SimpleAddition(string simbUP,string simbDOWN,ENUM_TIMEFRAMES period,int Color)//////
  {
   datetime expiration_time_UP;     // simbUP symbol expiration date
   datetime expiration_time_DOWN;   // simbDOWN expiration date

   expiration_time_UP=int(SymbolInfoInteger(simbUP,SYMBOL_EXPIRATION_TIME));
   if(expiration_time_UP>TimeLocal())
     {
      expiration_time_UP=TimeLocal();
     }
   if(simbDOWN!="")
     {
      expiration_time_DOWN=int(SymbolInfoInteger(simbDOWN,SYMBOL_EXPIRATION_TIME));
     }
   else
     {
      expiration_time_DOWN=int(SymbolInfoInteger(simbUP,SYMBOL_START_TIME));
     }
//--- Open, High, Low and Close prices will be copied in the rates[] array 
   MqlRates rates[];
   ArraySetAsSeries(rates,true);
   int copied=0;           //--- copied number
   copied=CopyRates(simbUP,period,expiration_time_DOWN,expiration_time_UP,rates);
   if(copied>0)
     {
      for(int j=shift_array;j<shift_array+copied;j++)
        {
         //--- write prices in buffers
         OpenBuffer[j]=rates[j-shift_array].open;
         HighBuffer[j]=rates[j-shift_array].high;
         LowBuffer[j]=rates[j-shift_array].low;
         CloseBuffer[j]=rates[j-shift_array].close;
         ColorCandlesColors[j]=Color;
        }
      shift_array=shift_array+copied;
      indicator_rendered=true;
      ChartRedraw();
     }
   else
     {
      Print("Unable to get the symbol history data",simbUP);
      indicator_rendered=false;
      return(false);
     }
//---  Simple addition end
   return(true);
  }
//+------------------------------------------------------------------+


Algoritmo da Adição com deslocamento


Fig. 13. Algoritmo da emenda Adição com deslocamento

Fig. 13. Algoritmo da emenda Adição com deslocamento  

Este algoritmo de emenda em comparação com a adição simples, começa 10 dias antes fechar o ativo. O método de emenda "Adição com deslocamento" é processado na função AdditionWithShift():

//--- Simple addition end
   return(true);
  }
//+------------------------------------------------------------------+
//| Addition With Shift                                              |
//| Addition with Shift. Add in the indicator array only             |
//| sibmUP symbol                                                    |
//+------------------------------------------------------------------+
bool AdditionWithShift(string simbUP,string simbDOWN,ENUM_TIMEFRAMES period,int Color)
  {
//--- 
   return(true);
  }
//+------------------------------------------------------------------+

A diferença entre as funções AdditionWithShift() e SimpleAddition() está em duas linhas - vai subtrair 10 dias a contar das datas:

   .
   .
   .
   expiration_time_UP=int(SymbolInfoInteger(simbUP,SYMBOL_EXPIRATION_TIME))-86400*10;
   .
   .
   .
   expiration_time_DOWN=int(SymbolInfoInteger(simbDOWN,SYMBOL_EXPIRATION_TIME))-86400*10;
   .
   .
   .

Devido à pequena diferença de códigos, não vou mostrar o código completo da função AdditionWithShift(), você pode encontrar o código no arquivo do indicador no artigo.

Apesar das diferenças entre as funções AdditionWithShift() e SimpleAddition(), é melhor você não uni-las para fazer uma função universal (no caso de novas mudanças no algoritmo ou, por exemplo, executando testes).


Histórico do pré-carregamento dos ativos

A função CheckLoadHistory() copia todo o histórico dos símbolos no buffer auxiliar tmp_rates.

Se o processo de cópia for bem sucedido, o valor true é atribuído a flag good_history, significando que se pode começar a desenhar o indicador:

//--- Addition With Shift end
   return(true);
  }
//+------------------------------------------------------------------+
//| Request to receive all history from a trade server               |
//| Request to recieve all history from a trade server               |
//+------------------------------------------------------------------+
bool CheckLoadHistory(string symbol,ENUM_TIMEFRAMES period)
  {
   MqlRates tmp_rates[];      // the Open, High, Low and Close prices will be copied in the rates[]array 
   datetime start_time;       // start time of the instrument trades
   datetime expiration_time;  // expiration time of the instrument trade
   start_time=int(SymbolInfoInteger(symbol,SYMBOL_START_TIME));
   expiration_time=int(SymbolInfoInteger(symbol,SYMBOL_EXPIRATION_TIME));
   if(CopyRates(symbol,period,start_time,expiration_time,tmp_rates)>0)
     {
      good_history=true;
     }
   else
     {
      good_history=false;
     }
//--- 
   return(true);
  }
//+------------------------------------------------------------------+

Você pode copiar todo o histórico dos contratos futuros, onde o histórico copiado não ocupará muito espaço.


OnTimer - a função principal do indicador

Agora você tem o código para dois métodos de emendas e o código para carregar o histórico de modo que você pode mudar a função OnTimer():

//+------------------------------------------------------------------+
//| Timer function                                                   |
//+------------------------------------------------------------------+
void OnTimer()
  {
   if(indicator_rendered==true) return;
   if(good_history==true)
     {
      int t=0;       // color || color
      int number;
      switch(gluing_type)
        {
         case simple_addition:
            for(int n=0;n<numder_futures_gluing;n++)
              {
               //--- get the random number
               number=MathRand();
               //--- get the color index as the modulo
               t=number%(PlotIndexGetInteger(0,PLOT_COLOR_INDEXES)-1);
               SimpleAddition(SymbolName(n,true),SymbolName(n+1,true),PERIOD_D1,t);
              }
            break;
         case addition_with_shift:
            for(int n=0;n<numder_futures_gluing;n++)
              {
               //--- get random number
               number=MathRand();
               //--- get the color index as the modulo
               t=number%(PlotIndexGetInteger(0,PLOT_COLOR_INDEXES)-1);
               AdditionWithShift(SymbolName(n,true),SymbolName(n+1,true),PERIOD_D1,t);
              }
            break;
        }
     }
   else
     {
      for(int n=0;n<numder_futures_gluing;n++)
        {
         CheckLoadHistory(SymbolName(n,true),PERIOD_D1);
        }
     }
  }
//+------------------------------------------------------------------+

O indicador esta concluído. Você pode compilar e anexar ao gráfico. É melhor escolher o ativo com o negócio fechado e definir o período em H1.


Saída inicial do indicador "SYNT"

Depois de ter anexado os dois modelos de indicadores "SYNT" de diferentes métodos de emenda ao gráfico, você pode comparar esses métodos:

Fig. 14. Comparando os dois métodos de emendas de contratos futuros

  Fig. 14. Comparando os dois métodos de emendas de contratos futuros


A possibilidade de juntar indicadores (padrão e personalizado)

Indicadores personalizados podem ser emendados com a primeira chamada OnCalculate e o indicador "SYNT":

int OnCalculate (const int rates_total,      // size of the array price[]
                 const int prev_calculated,  // calculated bars during the previous call
                 const int begin,            // tangible data starting point
                 const double& price[]       // calculation array
   );

Na janela "Navegador" abra a lista "Indicadores personalizados". Em seguida, abra a lista de "Exemplos", escolha e coloque o indicador "SYNT" no ativo. Na aba "Parâmetros", escolha "Dados do indicador anterior" na lista suspensa. 

Aqui está a lista com os indicadores que você pode emendar no indicador "SYNT" que será executado sem erros.

O indicador "SYNT" emendando três contratos futuros com o indicador Custom Moving Average anexado:

Fig. 15. Um exemplo de três ativos emendados

Fig. 15. Um exemplo de três ativos emendados


Conclusão

É mais fácil analisar o comportamento dos ativos mais antigos no gráfico aberto dentro do timeframe diário. Embora o número de indicadores técnicos é restrito, este método ajuda a traçar o comportamento dos preços nos contratos futuros contínuos.