English Русский 中文 Español Deutsch 日本語 한국어 Français Italiano Türkçe
Cálculo de características integrais das emissões de indicador

Cálculo de características integrais das emissões de indicador

MetaTrader 5Exemplos | 19 março 2014, 16:29
1 394 0
Sergey Pavlov
Sergey Pavlov

Introdução

As emissões de indicador representam uma direção nova e muito promissora no estudo de séries temporais. Ela se caracteriza pelo fato de que a análise não está focada nos indicadores em si, mas em suas emissões no futuro ou no passado, com base nas quais podemos fazer realmente uma previsão do ambiente de mercado:

  • níveis de suporte e de resistência no futuro;
  • direção de tendência (movimento de preços);
  • força do movimento acumulada no passado.

O meu artigo anterior, chamado "Representação de emissões de indicador em MQL5", tratou sobre o algoritmo de representação de emissões e especificou as suas características-chave. Deixe-me lembrar você de que:

Emissão é um conjunto de pontos localizados nas interseções de linhas peculiares aos indicadores em consideração.

Os pontos de emissão, por sua vez, apresentam algumas peculiaridades:

  • Os pontos de emissão do mesmo tipo tendem a se agrupar.
  • Grupos densos de pontos podem atrair ou, contrariamente, repelir o preço.

Galeria de emissão:

Emissão do DCMV Emissão do iMA e iEnvelopes
Emissão do DCMV Emissão do iMA e iEnvelopes

Figura 1. Exemplos de gráficos de emissão de indicador. Esquerda: emissão do indicador DCMV. Direita: emissão dos indicadores iMA e iEnvelopes.

Como ilustração do cálculo das características integrais das emissões, utilizaremos os próprios envelopes de média móvel (Envelopes) e médias móveis (Moving Average) com os parâmetros de entrada, da seguinte forma:

//--- external variable for storing averaging period of the iEnvelopes indicator
input int   ma_period=140; // averaging period of the iEnvelopes indicator
//--- array for storing deviations of the iEnvelopes indicator
double      ENV[]={0.01,0.0165,0.0273,0.0452,0.0747,01234,0.204,0.3373,0.5576,0.9217,1.5237};
//--- array for storing iMA indicator periods
int         MA[]={4,7,11,19,31,51,85};

Então, procuraremos as interseções de linhas peculiares aos indicadores selecionados. O número de linhas e suas características (períodos médios e desvios) são escolhidos aleatoriamente. A emissão pode na realidade ser representada graficamente com a utilização de qualquer conjunto de parâmetros para esses indicadores (desde que eles se cruzem no espaço).

Agora que escolhemos os indicadores, vamos proceder à criação de um Expert Advisor que servirá como programa base para a análise das emissões. Precisaremos obter os dados calculados dos indicadores técnicos iMA e iEnvelopes. Eu proponho a utilização de um método descrito no Guia para uso de indicadores técnicos em Expert Advisors.

Para representar as linhas cujas interseções precisamos encontrar, precisamos apenas estabelecer dois pontos para cada uma das linhas. Assim, é suficiente obter valores de indicador para apenas duas barras (por exemplo, a atual e a anterior). O preço da barra anterior é estático, enquanto que o preço da barra atual é dinâmico e, assim, novos pontos continuam a ser gerados a cada novo tick. Aqui está o código:

//+------------------------------------------------------------------+
//|                                      emission_of_MA_envelope.mq5 |
//|                                           Copyright 2013, DC2008 |
//|                           https://www.mql5.com/ru/users/DC2008 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2013, DC2008"
#property link      "https://www.mql5.com/ru/users/DC2008"
#property version   "1.00"
//---
#include <GetIndicatorBuffers.mqh>
#include <Emission.mqh>
//--- external variable for storing averaging period of the iEnvelopes indicator
input int   ma_period=140;      // averaging period of the iEnvelopes indicator
//--- array for storing deviations of the iEnvelopes indicator
double      ENV[]={0.01,0.0165,0.0273,0.0452,0.0747,01234,0.204,0.3373,0.5576,0.9217,1.5237};
//--- array for storing the iMA indicator periods
int         MA[]={4,7,11,19,31,51,85};
//--- array for storing pointers to the iMA and iEnvelopes indicators
int         handle_MA[];
int         handle_Envelopes[];
//--- market data
datetime    T[],prevTimeBar=0;
double      H[],L[];
#define     HL(a, b) (a+b)/2
//--- class instances
CEmission      EnvMa(0,300);
PointEmission  pEmission;
//--- drawing styles for points of emission
#define     COLOR_UPPER  C'51,255,255'
#define     COLOR_LOWER  C'0,51,255'
#define     COLOR_MA     C'255,51,255'
color       colorPoint[]={COLOR_UPPER,COLOR_LOWER,COLOR_MA};
CodeColor   styleUpper={158,COLOR_UPPER,SMALL};
CodeColor   styleLower={158,COLOR_LOWER,SMALL};
CodeColor   styleMA={158,COLOR_MA,SMALL};
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   ArraySetAsSeries(T,true);
   ArraySetAsSeries(H,true);
   ArraySetAsSeries(L,true);
//---
   int size=ArraySize(MA);
   ArrayResize(handle_MA,size);
//--- create a pointer to the object - the iMA indicator
   for(int i=0; i<size; i++)
     {
      handle_MA[i]=iMA(NULL,0,MA[i],0,MODE_SMA,PRICE_MEDIAN);
      //--- if an error occurs when creating the object, print the message
      if(handle_MA[i]<0)
        {
         Print("The iMA object[",MA[i],"] has not been created: Error = ",GetLastError());
         //--- forced program termination
         return(-1);
        }
     }
//---
   size=ArraySize(ENV);
   ArrayResize(handle_Envelopes,size);
//--- create a pointer to the object - the iEnvelopes indicator
   for(int i=0; i<size; i++)
     {
      handle_Envelopes[i]=iEnvelopes(NULL,0,ma_period,0,MODE_SMA,PRICE_MEDIAN,ENV[i]);
      //--- if an error occurs when creating the object, print the message
      if(handle_Envelopes[i]<0)
        {
         Print("The iEnvelopes object[",ENV[i],"] has not been created: Error = ",GetLastError());
         //--- forced program termination
         return(-1);
        }
     }
//---
   return(0);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---

  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//--- market data
   CopyTime(NULL,0,0,2,T);
   CopyHigh(NULL,0,0,2,H);
   CopyLow(NULL,0,0,2,L);
//--- fill the declared arrays with current values from all indicator buffers
   string name;
   uint GTC=GetTickCount();
//---- indicator buffers
   double   ibMA[],ibMA1[];      // arrays for the iMA indicator
   double   ibEnvelopesUpper[];  // array for the iEnvelopes indicator (UPPER_LINE)
   double   ibEnvelopesLower[];  // array for the iEnvelopes indicator (LOWER_LINE)
   for(int i=ArraySize(handle_MA)-1; i>=0; i--)
     {
      if(!CopyBufferAsSeries(handle_MA[i],0,0,2,true,ibMA))
         return;
      //---
      for(int j=ArraySize(handle_Envelopes)-1; j>=0; j--)
        {
         if(!GetEnvelopesBuffers(handle_Envelopes[j],0,2,ibEnvelopesUpper,ibEnvelopesLower,true))
            return;
         //--- find the intersection point of the iEnvelopes(UPPER_LINE) and iMA indicators
         pEmission=EnvMa.CalcPoint(ibEnvelopesUpper[1],ibEnvelopesUpper[0],ibMA[1],ibMA[0],T[0]);
         if(pEmission.real) // if the intersection point is found, draw it in the chart
           {
            name="iEnvelopes(UPPER_LINE)"+(string)j+"=iMA"+(string)i+(string)GTC;
            EnvMa.CreatePoint(name,pEmission,styleUpper);
           }
         //--- find the intersection point of the iEnvelopes(LOWER_LINE) and iMA indicators
         pEmission=EnvMa.CalcPoint(ibEnvelopesLower[1],ibEnvelopesLower[0],ibMA[1],ibMA[0],T[0]);
         if(pEmission.real) // if the intersection point is found, draw it in the chart
           {
            name="iEnvelopes(LOWER_LINE)"+(string)j+"=iMA"+(string)i+(string)GTC;
            EnvMa.CreatePoint(name,pEmission,styleLower);
           }
        }
      //---
      for(int j=ArraySize(handle_MA)-1; j>=0; j--)
        {
         if(i!=j)
           {
            if(!CopyBufferAsSeries(handle_MA[j],0,0,2,true,ibMA1))
               return;
            //--- find the intersection point of the iMA and iMA indicators
            pEmission=EnvMa.CalcPoint(ibMA1[1],ibMA1[0],ibMA[1],ibMA[0],T[0]);
            if(pEmission.real) // if the intersection point is found, draw it in the chart
              {
               name="iMA"+(string)j+"=iMA"+(string)i+(string)GTC;
               EnvMa.CreatePoint(name,pEmission,styleMA);
              }
           }
        }
     }
//--- deletion of the graphical objects of emission not to stuff the chart
   if(T[0]>prevTimeBar) // delete once per bar
     {
      int  total=ObjectsTotal(0,0,-1);
      prevTimeBar=T[0];
      for(int obj=total-1;obj>=0;obj--)
        {
         string obj_name=ObjectName(0,obj,0,OBJ_TEXT);
         datetime obj_time=(datetime)ObjectGetInteger(0,obj_name,OBJPROP_TIME);
         if(obj_time<T[0])
            ObjectDelete(0,obj_name);
        }
      Comment("Emission © DC2008       Objects = ",total);
     }
//---
  }

Não vou me ater a cada detalhe desse Expert Advisor. O principal a ser notado aqui é que, para representar a emissão no gráfico, utilizamos uma instância de classe CEmission responsável pelo cálculo e exibição de pontos de interseção de duas linhas quaisquer.

//+------------------------------------------------------------------+
//|                                                     Emission.mqh |
//|                                           Copyright 2013, DC2008 |
//|                           https://www.mql5.com/pt/users/DC2008 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2013, DC2008"
#property link      "https://www.mql5.com/pt/users/DC2008"
#property version   "1.00"
#define  BIG   7    // point size
#define  SMALL 3    // point size
//+------------------------------------------------------------------+
//| pMABB structure                                                  |
//+------------------------------------------------------------------+
struct PointEmission
  {
   double            x;       // X-coordinate of the time point
   double            y;       // Y-coordinate of the price point
   datetime          t;       // t-coordinate of the point's time
   bool              real;    // whether the point exists
  };
//+------------------------------------------------------------------+
//| CodeColor structure                                              |
//+------------------------------------------------------------------+
struct CodeColor
  {
   long              Code;    // point symbol code 
   color             Color;   // point color
   int               Width;   // point size
  };
//+------------------------------------------------------------------+
//| Base class for emissions                                         |
//+------------------------------------------------------------------+
class CEmission
  {
private:
   int               sec;
   int               lim_Left;   // limiting range of visibility in bars
   int               lim_Right;  // limiting range of visibility in bars

public:
   PointEmission     CalcPoint(double   y1,  // Y-coordinate of straight line 1 on bar [1]
                               double   y0,  // Y-coordinate of straight line 1 on bar [0]
                               double   yy1, // Y-coordinate of straight line 2 on bar [1] 
                               double   yy0, // Y-coordinate of straight line 2 on bar [0]
                               datetime t0   // t-coordinate of the current bar Time[0]
                               );
   bool              CreatePoint(string name,            // point name
                                 PointEmission &point,   // coordinates of the point
                                 CodeColor &style);      // point drawing style
                                 CEmission(int limitLeft,int limitRight);
                    ~CEmission();
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
CEmission::CEmission(int limitLeft,int limitRight)
  {
   sec=PeriodSeconds();
   lim_Left=limitLeft;
   lim_Right=limitRight;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
CEmission::~CEmission()
  {
  }
//+------------------------------------------------------------------+
//| The CalcPoint method of the CEmission class                      |
//+------------------------------------------------------------------+
PointEmission CEmission::CalcPoint(double   y1, // Y-coordinate of straight line 1 on bar [1]
                                   double   y0, // Y-coordinate of straight line 1 on bar [0]
                                   double   yy1,// Y-coordinate of straight line 2 on bar [1]
                                   double   yy0,// Y-coordinate of straight line 2 on bar [0]
                                   datetime t0  // t-coordinate of the current bar Time[0]
                                   )
  {
   PointEmission point={NULL,NULL,NULL,false};
   double y0y1=y0-y1;
   double y1yy1=y1-yy1;
   double yy0yy1=yy0-yy1;
   double del0=yy0yy1-y0y1;
   if(MathAbs(del0)>0)
     {
      point.x=y1yy1/del0;
      if(point.xlim_Right) return(point);
      point.y=y1+y0y1*y1yy1/del0;
      if(point.y<0) return(point);
      point.t=t0+(int)(point.x*sec);
      point.real=true;
      return(point);
     }
   return(point);
  }
//+------------------------------------------------------------------+
//| The CreatePoint method of the CEmission class                    |
//+------------------------------------------------------------------+
bool CEmission::CreatePoint(string name,            // point name
                            PointEmission &point,  // coordinates of the point
                            CodeColor &style)      // point drawing style
  {
   if(ObjectCreate(0,name,OBJ_TEXT,0,0,0))
     {
      ObjectSetString(0,name,OBJPROP_FONT,"Wingdings");
      ObjectSetInteger(0,name,OBJPROP_ANCHOR,ANCHOR_CENTER);
      ObjectSetInteger(0,name,OBJPROP_FONTSIZE,style.Width);
      ObjectSetString(0,name,OBJPROP_TEXT,CharToString((uchar)style.Code));
      ObjectSetDouble(0,name,OBJPROP_PRICE,point.y);
      ObjectSetInteger(0,name,OBJPROP_TIME,point.t);
      ObjectSetInteger(0,name,OBJPROP_COLOR,style.Color);
      return(true);
     }
   return(false);
  }

Deve-se ressaltar que os pontos de emissão são representados por meio de objetos gráficos tal como Texto. Primeiramente, isso decorre do fato de que as âncoras de objeto devem ser alinhadas ao centro do símbolo. Em segundo lugar, você pode variar o tamanho do objeto dentro de um amplo limite. Essas propriedades de ponto oferecem um grande potencial para obtenção de emissões complexas.

Figura 2. Emissão original dos indicadores iMA e iEnvelopes

Figura 2. Emissão original dos indicadores iMA e iEnvelopes

 

Características integrais das emissões

Então, após posicionar o Expert Advisor proposto no gráfico, obtivemos muitos pontos de diferentes cores (veja a Figura 2):

  • Ciano - interseções de iMA e iEnvelopes, buffer UPPER_LINE.
  • Azul - interseções de iMA e iEnvelopes, buffer LOWER_LINE.
  • Magenta - interseções de iMA e iMA.

Esse caos não pode ser utilizado na negociação automatizada. Precisamos de sinais, níveis e outras características quantitativas do mercado, enquanto que aqui apenas obtivemos imagens visuais para meditação e adivinhação e nenhum número em absoluto.

As características integrais das emissões servem para generalizar os dados obtidos como resultado das emissões do indicador. 

A necessidade de características integrais das emissões também é impulsionada pelo fato de que elas oferecem oportunidades para pesquisa de mercado com a utilização de novos tipos de indicadores: canais integrais, linhas, níveis, sinais, etc. Para determinar os valores de emissão mais típicos, iniciaremos do mais simples e calcularemos o preço médio para cada tipo de ponto para, em seguida, desenhar linhas horizontais através deles conforme exibido abaixo:

Figura 3. Linhas horizontais do preço médio para cada tipo de ponto

Figura 3. Linhas horizontais do preço médio para cada tipo de ponto

Para essa finalidade, adicionaremos alguns blocos de código extra ao código existente. À seção de dados:

//--- arrays for calculation and display of integral characteristics of emissions
#define     NUMBER_TYPES_POINT   3
double      sum[NUMBER_TYPES_POINT],sumprev[NUMBER_TYPES_POINT];
datetime    sum_time[NUMBER_TYPES_POINT];
int         n[NUMBER_TYPES_POINT],W[NUMBER_TYPES_POINT];
color       colorLine[]={clrAqua,clrBlue,clrMagenta};

Ao módulo OnTick():

//--- calculation of integral characteristics of emissions
   ArrayInitialize(n,0);
   ArrayInitialize(sum,0.0);
   ArrayInitialize(sum_time,0.0);
   for(int obj=total-1;obj>=0;obj--)
     {
      string   obj_name=ObjectName(0,obj,0,OBJ_TEXT);
      datetime obj_time=(datetime)ObjectGetInteger(0,obj_name,OBJPROP_TIME);
      if(obj_time>T[0])
        {
         color    obj_color=(color)ObjectGetInteger(0,obj_name,OBJPROP_COLOR);
         double   obj_price=ObjectGetDouble(0,obj_name,OBJPROP_PRICE);
         for(int i=ArraySize(n)-1; i>=0; i--)
            if(obj_color==colorPoint[i])
              {
               n[i]++;
               sum[i]+=obj_price;
               sum_time[i]+=obj_time;
              }
        }
     }
//--- displaying integral characteristics of emissions
   for(int i=ArraySize(n)-1; i>=0; i--)
     {
      if(n[i]>0)
        {
         name="H.line."+(string)i;
         ObjectCreate(0,name,OBJ_HLINE,0,0,0,0);
         ObjectSetInteger(0,name,OBJPROP_COLOR,colorLine[i]);
         ObjectSetInteger(0,name,OBJPROP_STYLE,STYLE_DASHDOT);
         ObjectSetInteger(0,name,OBJPROP_WIDTH,1);
         ObjectSetDouble(0,name,OBJPROP_PRICE,sum[i]/n[i]);
        }
     }

Vamos continuar. Agora calcularemos o valor da hora média para cada conjunto de pontos e marcaremos ela na linha correspondente do preço médio (veja a Figura 4). Assim, obtivemos as primeiras características quantitativas das emissões, as quais nunca são estáticas e sempre se movem no espaço.

O gráfico apenas mostra as suas posições momentâneas. Precisamos, de alguma forma, mantê-las fixas no histórico para poder estudá-las mais tarde. Até agora, ainda não é claro como isso pode ser feito e precisamos pensar nisso com cuidado... Enquanto isso, realizaremos mais melhorias e exibiremos o número de pontos envolvidos no cálculo perto dos marcadores do gráfico. Estes são espécies de pesos das características obtidas que também serão úteis na análise posterior.

Figura 4. Marcadores nos pontos de interseção entre preço médio e hora média

Figura 4. Marcadores nos pontos de interseção entre preço médio e hora média

Entretanto, por conveniência da análise, utilizaremos as razões percentuais deles. Porque os principais pontos de emissão são aqueles resultantes da interseção dos indicadores iMA e iEnvelopes, consideraremos a soma deles como 100%. Vamos ver o que temos agora:

Figura 5. Razão percentual para cada tipo de ponto de emissão

Figura 5. Razão percentual para cada tipo de ponto de emissão

Se adicionarmos os três valores, eles terão mais de 100% no total. O valor de 34,4 exibido em magenta é a propriedade dos pontos de interseção de iMA e iMA em um determinado ponto de tempo, ou seja, o indicador cruzou a si mesmo, mas com dados de entrada diferentes. Nesse caso, esse é um valor de referência e podemos pensar mais adiante sobre como ele pode ser utilizado na análise de mercado.

Entretanto, outro problema surge à medida que obtemos as razões percentuais do número de pontos: como podemos consertar também os valores percentuais das características da emissão no histórico, principalmente considerando que elas também variam?!

 

Análise gráfica

Embora agora tenhamos as características integrais das emissões, ainda não estamos suficientemente próximos da análise e desenvolvimento de uma estratégia de negociação baseada nos dados obtidos. Entretanto, um leitor cuidadoso já deve ter encontrado uma solução para esse problema (veja a Figura 1). A solução é a seguinte: Propõe-se desenhar curvas integrais utilizando diferentes espessuras que sejam proporcionais à razão percentual do principais pontos de emissão.

A parte atual da curva será representada graficamente junto com a linha do preço médio entre a barra atual e a anterior, levando-se em consideração que essas coordenadas são, na realidade, obtidas do futuro. Isso é algum tipo de canal integral principal das emissões do indicador. Eu sei que isso parece realmente muito confuso... E você deve estar pensando se deve ou não continuar a leitura. Mas espero que isso fique cada vez mais interessante à medida que continuarmos.

Figura 6. Canal integral das emissões do indicador

Figura 6. Canal integral das emissões do indicador

Parece que encontramos alguma utilidade para a emissão "iMA & iMA" (exibida em magenta no gráfico). E obtivemos um novo indicador - a média móvel integrada.

Agora vamos voltar ao código do Expert Advisor para ver quais mudanças ocorreram no módulo OnTick():

//--- displaying integral characteristics of emissions
   ArrayInitialize(W,10);
   W[ArrayMaximum(n)]=20;
   W[ArrayMinimum(n)]=3;
   for(int i=ArraySize(n)-1; i>=0; i--)
     {
      if(n[i]>0)
        {
         //--- horizontal lines of mean prices
         name="H.line."+(string)i;
         ObjectCreate(0,name,OBJ_HLINE,0,0,0,0);
         ObjectSetInteger(0,name,OBJPROP_COLOR,colorLine[i]);
         ObjectSetInteger(0,name,OBJPROP_STYLE,STYLE_DASHDOT);
         ObjectSetInteger(0,name,OBJPROP_WIDTH,1);
         ObjectSetDouble(0,name,OBJPROP_PRICE,sum[i]/n[i]);
         //--- markers
         name="P."+(string)i;
         ObjectCreate(0,name,OBJ_TEXT,0,0,0);
         ObjectSetString(0,name,OBJPROP_FONT,"Wingdings");
         ObjectSetInteger(0,name,OBJPROP_ANCHOR,ANCHOR_CENTER);
         ObjectSetInteger(0,name,OBJPROP_FONTSIZE,17);
         ObjectSetString(0,name,OBJPROP_TEXT,CharToString(163));
         ObjectSetInteger(0,name,OBJPROP_COLOR,colorLine[i]);
         ObjectSetDouble(0,name,OBJPROP_PRICE,sum[i]/n[i]);
         ObjectSetInteger(0,name,OBJPROP_TIME,sum_time[i]/n[i]);
         //--- integral curves
         name="T"+(string)i+".line"+(string)T[1];
         ObjectCreate(0,name,OBJ_TREND,0,0,0);
         ObjectSetInteger(0,name,OBJPROP_COLOR,colorLine[i]);
         ObjectSetInteger(0,name,OBJPROP_WIDTH,W[i]);
         if(sumprev[i]>0)
           {
            ObjectSetDouble(0,name,OBJPROP_PRICE,0,sumprev[i]);
            ObjectSetInteger(0,name,OBJPROP_TIME,0,T[1]);
            ObjectSetDouble(0,name,OBJPROP_PRICE,1,(sum[i]/n[i]));
            ObjectSetInteger(0,name,OBJPROP_TIME,1,T[0]);
           }
         //--- numerical values of integral characteristics
         name="Text"+(string)i+".control";
         ObjectCreate(0,name,OBJ_TEXT,0,0,0);
         ObjectSetInteger(0,name,OBJPROP_ANCHOR,ANCHOR_LEFT_LOWER);
         ObjectSetInteger(0,name,OBJPROP_FONTSIZE,30);
         ObjectSetInteger(0,name,OBJPROP_COLOR,colorLine[i]);
         string str=DoubleToString((double)n[i]/(double)(n[0]+n[1])*100,1);
         ObjectSetString(0,name,OBJPROP_TEXT,str);
         ObjectSetDouble(0,name,OBJPROP_PRICE,0,(sum[i]/n[i]));
         ObjectSetInteger(0,name,OBJPROP_TIME,0,sum_time[i]/n[i]);
        }
     }

Vamos continuar a nossa análise gráfica. Mas falta algo... Parece que perdemos outra característica de emissão importante. As curvas integrais foram representadas no gráfico com base nos preços médios. Apesar disso, precisamos considerar a coordenada da hora média. Observe a figura abaixo e preste atenção especial aos limites de canal:

  • A linha ciano é o limite superior do canal.
  • A linha azul é o limite inferior do canal.

Precisamos identificar o marcador que estava mais próximo à barra zero em relação à hora.

Limite superior principal do canal
Limite inferior principal do canal

Figura 7. Características integrais principais em relação à hora. Esquerda: limite superior principal do canal. Direita: limite inferior principal do canal

Esse problema pode ser resolvido da seguinte forma: adicionamos a linha de preço (PRICE_MEDIAN) ao gráfico de preço e fazemos a linha mudar de cor dependendo da cor do marcador (ciano ou azul) que esteja mais perto da última barra (veja a Figura 7). Além disso, inserimos o seguinte bloco de código ao código existente:

//---
   if(n[ArrayMinimum(n)]>0)
     {
      datetime d[2];
      for(int j=0;j<2;j++)
        {
         d[j]=sum_time[j]/n[j];
        }
      int i=ArrayMinimum(d);

      name="Price.line"+(string)T[1];
      ObjectCreate(0,name,OBJ_TREND,0,0,0);
      ObjectSetInteger(0,name,OBJPROP_WIDTH,8);
      ObjectSetDouble(0,name,OBJPROP_PRICE,0,HL(H[1],L[1]));
      ObjectSetInteger(0,name,OBJPROP_TIME,0,T[1]);
      ObjectSetDouble(0,name,OBJPROP_PRICE,1,HL(H[0],L[0]));
      ObjectSetInteger(0,name,OBJPROP_TIME,1,T[0]);
      ObjectSetInteger(0,name,OBJPROP_COLOR,colorLine1[i]);
     }
//---

Agora esteja pronto para o próximo passo. E se tentarmos representar as emissões com base em características integrais das emissões originais, algo como emissões de segunda ordem? Afinal, essas linhas também se cruzam e deveriam, consequentemente, ter pontos de emissão. Vamos ver o que pode resultar disso. Aprimore o bloco de código anterior adicionando as seguintes linhas de código:

      //--- emissions of integral characteristics of the original emissions
      pEmission=EnvMa.CalcPoint(sumprev[0],sum[0]/n[0],sumprev[2],sum[2]/n[2],T[0]);
      if(pEmission.real) // if the intersection point is found, draw it in the chart
        {
         name="test/up"+(string)GTC;
         EnvMa.CreatePoint(name,pEmission,styleUpper2);
        }
      pEmission=EnvMa.CalcPoint(sumprev[1],sum[1]/n[1],sumprev[2],sum[2]/n[2],T[0]);
      if(pEmission.real) // if the intersection point is found, draw it in the chart
        {
         name="test/dn"+(string)GTC;
         EnvMa.CreatePoint(name,pEmission,styleLower2);
        }

E insira as seguintes linhas na seção de dados:

#define     COLOR_2_UPPER  C'102,255,255'
#define     COLOR_2_LOWER  C'51,102,255'
CodeColor   styleUpper2={178,COLOR_2_UPPER,BIG};
CodeColor   styleLower2={178,COLOR_2_LOWER,BIG};

Você pode verificar os resultados na figura abaixo. Podemos visualizar novos pontos que ainda não indicam coisa alguma.

Figura 8. Emissões de linhas integrais

Figura 8. Emissões de linhas integrais

Obviamente, as características integrais também podem ser calculadas para novos pontos (veja a Figura 9), com suas emissões representadas no gráfico e assim por diante, até que isso se torne impraticável!

Emissão Emissão
Emissão Emissão

Figura 9. Características integrais das emissões

Então, nós representamos tudo aquilo de que precisávamos no gráfico e obtivemos as características integrais das emissões. Agora podemos passar à análise delas e ao desenvolvimento de uma estratégia de negociação. Mas isso ainda parece impossível! O que está nos impedindo agora?

 

Séries temporais de emissões

A análise gráfica permite estudarmos as características integrais das emissões, mas tem um uso muito intenso de recursos. Se tentarmos executar o código proposto no modo visual do provador de estratégia, logo a velocidade de teste cairá para zero! Isso se deve ao grande número de objetos no gráfico.

Naturalmente, sente-se vontade de eliminar todo o excesso de pontos e de manter apenas as curvas integrais. Para solucionar esse problema, utilizaremos arrays (buffers) especiais.

As séries temporais de emissões são arrays especialmente organizados em que as informações sobre as emissões são acumuladas.

Elas diferem das séries temporais padrão visto que os dados contidos nelas não são organizados sequencialmente por tempo, mesmo que o tempo seja o campo principal.

Séries temporais de emissões

Figura 10. Séries temporais de características de emissão

Esses arrays são organizados de forma que os novos elementos são armazenados em células vazias ou em células preenchidas com valores antigos. Para isso, utilizaremos a classe CTimeEmission. A seguir é como isso é implementado no código:

//+------------------------------------------------------------------+
//|                                                 TimeEmission.mqh |
//|                                           Copyright 2013, DC2008 |
//|                           https://www.mql5.com/ru/users/DC2008 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2013, DC2008"
#property link      "https://www.mql5.com/ru/users/DC2008"
#property version   "1.00"
//---
#include <Emission.mqh>
#define ARRMAX       64
#define ARRDELTA     8
//+------------------------------------------------------------------+
//| pIntegral structure                                              |
//+------------------------------------------------------------------+
struct pIntegral
  {
   double            y;       // Y-coordinate of the price point (mean price of the points with the same time)
   datetime          t;       // t-coordinate of the point's time
   int               n;       // n-number of points with the same time
  };
//+------------------------------------------------------------------+
//| Base class for time series of emissions                          |
//+------------------------------------------------------------------+
class CTimeEmission
  {
private:
   pIntegral         time_series_Emission[]; // time series of emission
   int               size_ts; // number of elements in time series 
   datetime           t[1];
public:
   //--- method of writing new elements to time series of emission
   void              Write(PointEmission &point);
   //--- method of reading integral characteristics of emissions
   pIntegral         Read();
                     CTimeEmission();
                    ~CTimeEmission();
  };

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
CTimeEmission::CTimeEmission()
  {
   ArrayResize(time_series_Emission,ARRMAX,ARRMAX);
   size_ts=ArraySize(time_series_Emission);
   for(int i=size_ts-1; i>=0; i--)
      time_series_Emission[i].t=0;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
CTimeEmission::~CTimeEmission()
  {
  }
//+------------------------------------------------------------------+
//| The Write method of the CTimeEmission class                      |
//+------------------------------------------------------------------+
void CTimeEmission::Write(PointEmission &point)
  {
   CopyTime(NULL,0,0,1,t);
   size_ts=ArraySize(time_series_Emission);
   for(int k=0;k<size_ts;k++)
     {
      if(time_series_Emission[k].t<t[0]) // find the first empty cell
        {
         if(k>size_ts-ARRDELTA)
           {   // increase the array size, if necessary
            int narr=ArrayResize(time_series_Emission,size_ts+ARRMAX,ARRMAX);
            for(int l=size_ts-1;l<narr;l++)
               time_series_Emission[l].t=0;
           }
         time_series_Emission[k].y=point.y;
         time_series_Emission[k].t=point.t;
         time_series_Emission[k].n=1;
         return;
        }
      if(time_series_Emission[k].t==point.t) // find the first similar cell
        {
         time_series_Emission[k].y=(time_series_Emission[k].y*time_series_Emission[k].n+point.y)/(time_series_Emission[k].n+1);
         time_series_Emission[k].n++;
         return;
        }
     }
  }
//+------------------------------------------------------------------+
//| The Read method of the CTimeEmission class                       |
//+------------------------------------------------------------------+
pIntegral CTimeEmission::Read()
  {
   CopyTime(NULL,0,0,1,t);
   pIntegral property_Emission={0.0,0,0};
   size_ts=ArraySize(time_series_Emission);
   for(int k=0;k<size_ts;k++)
     {
      if(time_series_Emission[k].t>=t[0])
        {
         property_Emission.y+=time_series_Emission[k].y*time_series_Emission[k].n;
         property_Emission.t+=(time_series_Emission[k].t-t[0])*time_series_Emission[k].n;
         property_Emission.n+=time_series_Emission[k].n;
        }
     }
   if(property_Emission.n>0)
     {
      property_Emission.y=property_Emission.y/property_Emission.n;
      property_Emission.t=property_Emission.t/property_Emission.n+t[0];
     }
   return(property_Emission);
  }

Aqui podemos ver a implementação de dois métodos de classe: escrita de pontos de emissão em séries temporais e leitura de valores de características integrais de emissões.

 

Cálculo parcimonioso de características integrais

Agora que temos a série temporal de emissões, podemos começar a criar um algoritmo parcimonioso para o cálculo das características integrais para, em seguida, desenvolver uma estratégia de negociação. Vamos atualizar o Expert Advisor original:

//+------------------------------------------------------------------+
//|                                   emission_of_MA_envelope_ts.mq5 |
//|                                           Copyright 2013, DC2008 |
//|                           https://www.mql5.com/ru/users/DC2008 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2013, DC2008"
#property link      "https://www.mql5.com/ru/users/DC2008"
#property version   "1.00"
//---
#include <GetIndicatorBuffers.mqh>
#include <Emission.mqh>
#include <TimeEmission.mqh>
//--- number of point types
#define     NUMBER_TYPES_POINT   3
//--- array for storing the iMA indicator periods
int      MA[]={4,7,11,19,31,51,85};
//--- external variable for storing averaging period of the iEnvelopes indicator
input int ma_period=140; // averaging period of the iEnvelopes indicator
//--- array for storing deviations of the iEnvelopes indicator
double   ENV[]={0.01,0.0165,0.0273,0.0452,0.0747,01234,0.204,0.3373,0.5576,0.9217,1.5237};
//--- array for storing pointers to the iMA indicator
int      handle_MA[];
//--- array for storing pointers to the iEnvelopes indicator
int      handle_Envelopes[];
//--- market data
datetime    T[],prevTimeBar=0;
double      H[],L[];
#define     HL(a, b) (a+b)/2
//--- class instances
CEmission      EnvMa(0,200);
PointEmission  pEmission;
CTimeEmission  tsMA[NUMBER_TYPES_POINT];
pIntegral      integral[NUMBER_TYPES_POINT];
//--- drawing styles for points of emission
#define     DEL            500
//--- arrays for calculation and display of integral characteristics of emissions
double      sumprev[NUMBER_TYPES_POINT];
int         n[NUMBER_TYPES_POINT],W[NUMBER_TYPES_POINT];
color       colorLine[]={clrAqua,clrBlue,clrMagenta};
int         fontPoint[]={30,30,30};
int         fontMarker[]={16,16,16};
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   ArraySetAsSeries(T,true);
   ArraySetAsSeries(H,true);
   ArraySetAsSeries(L,true);
   ArrayInitialize(sumprev,0.0);
//---
   int size=ArraySize(MA);
   ArrayResize(handle_MA,size);
//--- create a pointer to the object - the iMA indicator
   for(int i=0; i<size; i++)
     {
      handle_MA[i]=iMA(NULL,0,MA[i],0,MODE_SMA,PRICE_MEDIAN);
      //--- if an error occurs when creating the object, print the message
      if(handle_MA[i]<0)
        {
         Print("The iMA object[",MA[i],"] has not been created: Error = ",GetLastError());
         //--- forced program termination
         return(-1);
        }
     }
//+------------------------------------------------------------------+
   size=ArraySize(ENV);
   ArrayResize(handle_Envelopes,size);
//--- create a pointer to the object - the iEnvelopes indicator
   for(int i=0; i<size; i++)
     {
      handle_Envelopes[i]=iEnvelopes(NULL,0,ma_period,0,MODE_SMA,PRICE_MEDIAN,ENV[i]);
      //--- if an error occurs when creating the object, print the message
      if(handle_Envelopes[i]<0)
        {
         Print("The iEnvelopes object[",ENV[i],"] has not been created: Error = ",GetLastError());
         //--- forced program termination
         return(-1);
        }
     }
//---
   return(0);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---

  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//--- market data
   CopyTime(NULL,0,0,2,T);
   CopyHigh(NULL,0,0,2,H);
   CopyLow(NULL,0,0,2,L);
//--- fill the declared arrays with current values from all indicator buffers
   string name;
   uint GTC=GetTickCount();
//---- indicator buffers
   double   ibMA[],ibMA1[];      // arrays for the iMA indicator
   double   ibEnvelopesUpper[];  // array for the iEnvelopes indicator (UPPER_LINE)
   double   ibEnvelopesLower[];  // array for the iEnvelopes indicator (LOWER_LINE)
   for(int i=ArraySize(handle_MA)-1; i>=0; i--)
     {
      if(!CopyBufferAsSeries(handle_MA[i],0,0,2,true,ibMA))
         return;
      //---
      for(int j=ArraySize(handle_Envelopes)-1; j>=0; j--)
        {
         if(!GetEnvelopesBuffers(handle_Envelopes[j],0,2,ibEnvelopesUpper,ibEnvelopesLower,true))
            return;
         //--- find the intersection point of the iEnvelopes(UPPER_LINE) and iMA indicators
         pEmission=EnvMa.CalcPoint(ibEnvelopesUpper[1],ibEnvelopesUpper[0],ibMA[1],ibMA[0],T[0]);
         if(pEmission.real) // if the intersection point is found, add it to the time series of emission
            tsMA[0].Write(pEmission);
         //--- find the intersection point of the iEnvelopes(LOWER_LINE) and iMA indicators
         pEmission=EnvMa.CalcPoint(ibEnvelopesLower[1],ibEnvelopesLower[0],ibMA[1],ibMA[0],T[0]);
         if(pEmission.real) // if the intersection point is found, add it to the time series of emission
            tsMA[1].Write(pEmission);
        }
      //---
      for(int j=ArraySize(handle_MA)-1; j>=0; j--)
        {
         if(i!=j)
           {
            if(!CopyBufferAsSeries(handle_MA[j],0,0,2,true,ibMA1))
               return;
            //--- find the intersection point of the iMA and iMA indicators
            pEmission=EnvMa.CalcPoint(ibMA1[1],ibMA1[0],ibMA[1],ibMA[0],T[0]);
            if(pEmission.real) // if the intersection point is found, add it to the time series of emission
               tsMA[2].Write(pEmission);
           }
        }
     }
//--- deletion of the graphical objects of emission not to stuff the chart
   if(T[0]>prevTimeBar)
     {
      prevTimeBar=T[0];
      //---
      for(int i=ArraySize(n)-1; i>=0; i--)
         sumprev[i]=integral[i].y;
      //---
      for(int obj=ObjectsTotal(0,0,-1)-1;obj>=0;obj--)
        {
         string obj_name=ObjectName(0,obj,0,OBJ_TREND);
         datetime obj_time=(datetime)ObjectGetInteger(0,obj_name,OBJPROP_TIME);
         if(obj_time<T[0]-DEL*PeriodSeconds())
            ObjectDelete(0,obj_name);
        }
      Comment("Emission © DC2008   Graphical objects = ",ObjectsTotal(0,0,-1));
     }
//--- calculation of integral characteristics of emission
   for(int i=ArraySize(n)-1; i>=0; i--)
      integral[i]=tsMA[i].Read();
//--- displaying integral characteristics of emission
   ArrayInitialize(W,5);
   if(integral[0].n>integral[1].n)
     {
      W[0]=20;
      W[1]=10;
     }
   else
     {
      W[0]=10;
      W[1]=20;
     }
   for(int i=ArraySize(n)-1; i>=0; i--)
     {
      //--- horizontal lines of mean prices
      name="H.line."+(string)i;
      ObjectCreate(0,name,OBJ_HLINE,0,0,0,0);
      ObjectSetInteger(0,name,OBJPROP_COLOR,colorLine[i]);
      ObjectSetInteger(0,name,OBJPROP_STYLE,STYLE_DASHDOT);
      ObjectSetInteger(0,name,OBJPROP_WIDTH,1);
      ObjectSetDouble(0,name,OBJPROP_PRICE,integral[i].y);
      //--- markers
      name="P."+(string)i;
      ObjectCreate(0,name,OBJ_TEXT,0,0,0);
      ObjectSetString(0,name,OBJPROP_FONT,"Wingdings");
      ObjectSetInteger(0,name,OBJPROP_ANCHOR,ANCHOR_CENTER);
      ObjectSetInteger(0,name,OBJPROP_FONTSIZE,fontMarker[i]);
      ObjectSetString(0,name,OBJPROP_TEXT,CharToString(163));
      ObjectSetInteger(0,name,OBJPROP_COLOR,colorLine[i]);
      ObjectSetDouble(0,name,OBJPROP_PRICE,integral[i].y);
      ObjectSetInteger(0,name,OBJPROP_TIME,integral[i].t);
      //--- integral curves
      name="T"+(string)i+".line"+(string)T[1];
      ObjectCreate(0,name,OBJ_TREND,0,0,0);
      ObjectSetInteger(0,name,OBJPROP_COLOR,colorLine[i]);
      ObjectSetInteger(0,name,OBJPROP_WIDTH,W[i]);
      if(sumprev[i]>0)
        {
         ObjectSetDouble(0,name,OBJPROP_PRICE,0,sumprev[i]);
         ObjectSetInteger(0,name,OBJPROP_TIME,0,T[1]);
         ObjectSetDouble(0,name,OBJPROP_PRICE,1,integral[i].y);
         ObjectSetInteger(0,name,OBJPROP_TIME,1,T[0]);
        }
      //--- numerical values of integral characteristics
      if(integral[0].n+integral[1].n>0)
        {
         name="Text"+(string)i+".control";
         ObjectCreate(0,name,OBJ_TEXT,0,0,0);
         ObjectSetInteger(0,name,OBJPROP_ANCHOR,ANCHOR_LEFT_LOWER);
         ObjectSetInteger(0,name,OBJPROP_FONTSIZE,fontPoint[i]);
         ObjectSetInteger(0,name,OBJPROP_COLOR,colorLine[i]);
         string str=DoubleToString((double)integral[i].n/(double)(integral[0].n+integral[1].n)*100,1);
         ObjectSetString(0,name,OBJPROP_TEXT,str);
         ObjectSetDouble(0,name,OBJPROP_PRICE,0,integral[i].y);
         ObjectSetInteger(0,name,OBJPROP_TIME,0,integral[i].t);
        }
     }
  }

O código ficou mais curto, enquanto que a velocidade de cálculo aumentou. Agora você pode testar e otimizar os seus robôs de negociação sem visualização! 

 

Uso de características integrais na negociação

As características integrais podem ser utilizadas como gerador de sinais para:

  • Avanço de canal;
  • Interseção umas com as outras ou com o preço;
  • Mudança de direção.
Por exemplo, a figura abaixo mostra como as características integrais das emissões podem ser hipoteticamente utilizadas em interseções com o preço. Sinais de venda são gerados quando o preço é cruzado de forma ascendente pela curva azul e os sinais de compra são gerados no cruzamento descendente do preço com a curva ciano.

Figura 11. Sinais de negociação nas interseções das características integrais das emissões

Figura 11. Sinais de negociação nas interseções das características integrais das emissões

 

Conclusão

  1. O cálculo de características integrais das emissões do indicador fornece novas ferramentas e métodos para a análise de mercado (séries temporais).
  2. Utilizando as séries temporais, conseguimos aumentar a velocidade dos cálculos das características integrais.
  3. E isso abriu a possibilidade de desenvolvermos estratégias de negociação automatizadas que utilizam emissões.

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

Informações gerais sobre os sinais de negociação para MetaTrader 4 e MetaTrader 5 Informações gerais sobre os sinais de negociação para MetaTrader 4 e MetaTrader 5
Sinais de negociação MetaTrader 4 / MetaTrader 5 é um serviço que permite que os negociadores copiem as operações de um provedor de sinais. O nosso objetivo foi desenvolver o novo serviço amplamente utilizado protegendo os assinantes e livrando eles de custos desnecessários.
Fundamentos básicos da programação MQL5: Tempo Fundamentos básicos da programação MQL5: Tempo
Este artigo foca nas funções padrões do MQL5 para trabalhar com o tempo, bem como técnicas de programação e funções praticamente úteis para trabalhar com o tempo que são necessárias ao criar Expert Advisors e indicadores. Atenção particular é dedicada à teoria geral da medição de tempo. Este artigo deve ser de interesse principalmente para programadores MQL5 novatos.
Widgets de sinais de negociação para MetaTrader 4 e MetaTrader 5 Widgets de sinais de negociação para MetaTrader 4 e MetaTrader 5
Recentemente, o usuário do MetaTrader 4 e MetaTrader 5 recebeu uma oportunidade de tornar-se um provedor de sinais e receber lucros adicionais. Agora, você pode exibir os seus sucessos de negociação em seu website, blog ou página de rede social utilizando os novos widgets. Os benefícios do uso de widgets são óbvios: eles aumentam a popularidade do provedor de sinais, estabelecem a reputação deles como negociadores de sucesso bem como atraem novos assinantes. Todos os negociadores que colocam os widgets em outros websites podem desfrutar desses benefícios.
Como testar um robô de negociação antes da compra Como testar um robô de negociação antes da compra
A compra de um robô de negociação no Mercado MQL5 apresenta uma vantagem distinta em relação a todas as outras opções similares - um sistema automatizado oferecido pode ser inteiramente testado diretamente no terminal MetaTrader 5. Antes da compra, um Expert Advisor pode e deve ser cuidadosamente executado em todos os modos não favoráveis no Strategy Tester integrado para que você entenda completamente o sistema.