Exibição dos níveis de apoio/resistência

18 fevereiro 2016, 15:21
Slobodov Gleb
0
555

Introdução

O artigo trata da detecção e indicação dos níveis de apoio/resistência no programa MetaTrader 4. Com base em um algoritmo simples, o conveniente e universal indicador FindLevels cria linhas de apoio horizontais no gráfico de símbolos. Você pode vê-lo abaixo:


O artigo também lida com um tópico bastante útil: a criação de um indicador simples, capaz de exibir os resultados de diferentes períodos de tempo em um espaço de trabalho. Você pode ver um exemplo abaixo.


O primeiro indicador exibe os níveis de apoio (linhas grossas de cor bege), com base em cotas de 30 minutos. O segundo indicador, executado na mesma janela, exibe os níveis com base no período de tempo de 15 minutos (linhas finas tracejadas de cor roxa) os sobre níveis de 30 minutos. Veja a seção "Interação dos indicadores" para obter mais detalhes.

O presente artigo é uma continuação do artigo a respeito da criação de um script para a detecção dos níveis de apoio, mas a diferença entre eles é que este artigo foi escrito para aqueles que já se encontram no nível avançado de programação e uso da plataforma MetaTrader 4. É por isso que eu recomendo a todos os iniciantes, e a todos aqueles que considerarem este artigo muito complicado, começar com a leitura do meu artigo anterior, chamado Um método para o desenho dos níveis de apoio/resistência.


Revisão teórica

Vamos descrever o algoritmo de detecção dos níveis de apoio/resistência, que será subsequentemente realizado no indicador FindLevels. Um nível de apoio/resistência é um valor de preço que não pode ser cruzado devido a algumas forças. Estas podem ser as forças induzidas pela marca psicológica, a influência de agentes importantes, ou uma grande quantidade de pedidos de StopLoss nesta área. É obvio que as cotas irão cruzar essa linha com uma frequência muito menor do que as outras linhas, que não são de apoio. Você pode encontrar evidências deste fato em muitos livros sobre negociação.

Para tirar vantagem deste fato, nós temos que calcular a quantidade de barras que cruzam cada preço. Este é o resultado dos cálculos descritos no artigo anterior:



O eixo horizontal nesta figura é um preço/ o eixo vertical marca a quantidade de barras cruzando o preço. O gráfico possui muitos mínimos locais, como você pode ver na figura. Um mínimo local é um ponto que pertence a um intervalo diferente de zero, e que é, ele mesmo, o mínimo deste intervalo. Agora nós temos que selecionar os mínimos locais de acordo com certas características.



Em primeiro lugar, nós vamos definir uma constante, MaxR, que é o raio da área. Se um mínimo local não for o mínimo que pertence à área do raio MaxR, ele não é adequado à nossa tarefa. Em segundo lugar, nós vamos definir o parâmetro MaxCrossesLevel. Se o máximo da função diferir do mínimo por menos do que o MaxCrossesLevel na área do MaxR, nós não iremos exibir este mínimo local, pois ele não é significativo o bastante. Este é o mecanismo de detecção dos níveis de apoio/resistência. Seguindo este algoritmo simples, nós vamos escrever o indicador.


Funções auxiliares

Como descrito acima, o indicador FindLevels é projetado para trabalhar com cotas de qualquer período de tempo. O período de tempo é definido pelo usuário (variável TimePeriod). De modo a manter a simplicidade do código, vamos definir duas funções fáceis que não exigem explicações adicionais:


double prLow(int i)
  {
    return (iLow(NULL,TimePeriod,i));
  }
 
double prHigh(int i)
  {
    return (iHigh(NULL,TimePeriod,i));
  }

A terceira e a quarta funções são necessárias para a exibição conveniente dos níveis de apoio, da sua largura, cor e modo de indicação, que dependerão do período de tempo:


int Period2Int(int TmPeriod)
  {
    switch(TmPeriod)
      {
        case PERIOD_M1  : return(0);
        case PERIOD_M5  : return(1);
        case PERIOD_M15 : return(2);
        case PERIOD_M30 : return(3);
        case PERIOD_H1  : return(4);
        case PERIOD_H4  : return(5);
        case PERIOD_D1  : return(6);
        case PERIOD_W1  : return(7);
        case PERIOD_MN1 : return(8);
      }      
    return (0);
  }
 
string Period2AlpthabetString(int TmPeriod)
  {
    return(Alphabet[Period2Int(TmPeriod)]); 
  }
        


A sentido de se definir a função Period2AlphabetString() é descrito na seção "Interação dos indicadores", e o uso da função Period2Int() será esclarecido na próxima seção.



Escrita do indicador

Vamos começar com as variáveis externas, que são definidas pelo usuário:

extern int MaxLimit = 1000;
extern int MaxCrossesLevel = 10;
extern double MaxR = 0.001;
extern int TimePeriod = 0;
extern color LineColor = White;
extern int LineWidth = 0;
extern int LineStyle = 0;   

  • MaxLimit - a quantidade de barras históricas em uso;
  • MaxCrossesLevel – a diferença mínima entre o máximo local e mínimo local (veja a descrição detalhada na seção "Revisão teórica");
  • MaxR – o raio da área na qual o mínimo é detectado;
  • TimePeriod – o período de tempo da detecção dos níveis de apoio. Por padrão, trata-se do período de tempo da janela de mapeamento;
  • LineColor – a cor das linhas exibidas;
  • LineWidth – a largura da linha, 0 por padrão;
  • LineStyle – o estilo da linha, 0 por padrão.

Se os valores de LineColor, LineWidth ou LineStyle forem definidos pelo usuário como padrão, nós os alteraremos, durante a realização do procedimento Init, àqueles que dependerão do período de tempo. Então a exibição das linhas de diferentes períodos de tempo não serão idênticas, e nós seremos capazes de diferenciá-las com facilidade.

int init()
  {
    if(TimePeriod == 0)
        TimePeriod = Period();
 
    if(TimePeriod != 0 && LineWidth == 0)
        if(Period2Int(TimePeriod) - Period2Int(Period()) >= 0)
            LineWidth = Widths[Period2Int(TimePeriod) - Period2Int(Period())];
        else
          {
            LineWidth = 0;
            if(LineStyle == 0)
                LineStyle = STYLE_DASH;
          }
 
    if(TimePeriod != 0 && LineColor == White)
        LineColor = Colors[Period2Int(TimePeriod)];
 
    return(0);
  }


Na primeira linha nós definimos o valor do TimePeriod, caso ele tenha sido configurado como padrão. E então nós determinamos a largura da linha. Quanto maior for o valor do TimePeriod em relação ao período de tempo do gráfico (a janela de mapeamento), mais largas serão as linhas. Caso o TimePeriod for menor do que o período do gráfico, a largura da linha será igual a 0, e a linha será tracejada. Cada período de tempo possui a sua própria cor.


As matrizes Colors[] e Width[] são definidas do seguinte modo:

color  Colors[] = {Red,Maroon, Sienna, OrangeRed, Purple,I ndigo,
                   DarkViolet, MediumBlue, DarkSlateGray};
int    Widths[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};

Vamos definir as variáveis restantes:

int CrossBarsNum[];
bool CrossBarsMin[];
double d1Num = 0.0, d2Num = 0.0;
datetime TMaxI = 0;


  • A matriz CrossBarsNum[] – a matriz que indica a quantidade de barras por cada preço;
  • CrossBarsMin[] – a matriz que corresponde ao fato de a linha com o preço definido ser um mínimo local ou não;
  • d1Num e d2Num - os preços mínimo e máximo que pertencem ao intervalo de barras entre 0 e MaxLimit;
  • TMaxI – indica o tempo da última barra processada.
#define MaxLines 1000
string LineName[MaxLines];
int LineIndex = 0;

  • MaxLines - a quantidade máxima de linhas que você criará;

  • LineName[] – a matriz dos seus nomes;

  • LineIndex – o índice da célula vazia na matriz LineName[].


Vamos passar a função start():


int counted_bars = IndicatorCounted();
int limit = MathMin(Bars - counted_bars, MaxLimit);
 
double d1 = prLow(iLowest(NULL, TimePeriod, MODE_LOW, limit, 0));
double d2 = prHigh(iHighest(NULL, TimePeriod, MODE_HIGH, limit, 0));

Nós calculamos a variável limite usando a quantidade de barras que não foram alteradas desde a última busca do indicador. d1 e d2 representam o mínimo e o máximo do preço no intervalo entre 0 e o limite.

if(d1Num != d1 || d2Num != d2)
  {
    ArrayResize(CrossBarsNum, (d2 - d1)*10000);
    ArrayResize(CrossBarsMin, (d2 - d1)*10000);
 
    if(d1Num != d1 && d1Num != 0.0)
      {
        ArrayCopy(CrossBarsNum, CrossBarsNum, 0, (d1Num - d1)*10000);
        ArrayCopy(CrossBarsMin, CrossBarsMin, 0, (d1Num - d1)*10000);
      }
 
    d1Num = d1;
    d2Num = d2;
  }

Durante a operação do indicador, as diferenças de preços abrangidas pelas matrizes CrossBarsNum[] e CrossBarsMin[] podem mudar. Sempre que isso acontece, nós temos que aumentar a quantidade de células na matriz e movê-la para a direita, se necessário. Geralmente isso acontece se as novas variáveis d1 e d2 não correspondem às variáveis d1Num e d2Num que foram obtidas na última execução da função start().

for(double d = d1; d <= d2; d += 0.0001)
  {
    int di = (d - d1)*10000;
    for(int i = 1; i < limit; i++)
        if(d > prLow(i) && d < prHigh(i))
            CrossBarsNum[di]++;
    if(Time[limit] != TMaxI&&TMaxI != 0)
        if(d > prLow(iBarShift(NULL, 0, TMaxI)) && 
           d < prHigh(iBarShift(NULL, 0, TMaxI)))
            CrossBarsNum[di]--;
  }
TMaxI = Time[limit] - 1;

Após termos nos assegurado de que as nossas matrizes possuem as dimensões necessárias, nós começamos a calcular as novas barras para cada preço, e a aumentar o valor de CrossBarsNum[] quando a barra cruza o nível do preço. Como as barras surgem constantemente, as barras antigas serão excluídas do intervalo [0 : limite]. Por este motivo, nós temos que verificar essas barras e reduzir o valor de CrossBarsNum[] em caso de intersecção. Em seguida, vamos atribuir o tempo da última barra calculada à variável TmaxI.

double l = MaxR*10000;
for(d = d1 + MaxR; d <= d2 - MaxR; d += 0.0001)
  {
    di = (d - d1)*10000;
    if(!CrossBarsMin[di] && CrossBarsNum[ArrayMaximum(CrossBarsNum, 2*l, di - l)] - 
       CrossBarsNum[ArrayMinimum(CrossBarsNum, 2*l, di - l)] > MaxCrossesLevel &&
       CrossBarsNum[di] == CrossBarsNum[ArrayMinimum(CrossBarsNum, 2*l, di - l)] &&
       CrossBarsNum[di-1] != CrossBarsNum[ArrayMinimum(CrossBarsNum, 2*l, di - l)])
      {
        CrossBarsMin[di] = true;
        LineName[LineIndex] = Period2AlpthabetString(TimePeriod) + TimePeriod + "_" + d;
        ObjectCreate(LineName[LineIndex], OBJ_HLINE, 0, 0, d);
        ObjectSet(LineName[LineIndex], OBJPROP_COLOR, LineColor);
        ObjectSet(LineName[LineIndex], OBJPROP_WIDTH, LineWidth);
        ObjectSet(LineName[LineIndex], OBJPROP_STYLE, LineStyle);
        LineIndex++;
      }
    if(CrossBarsMin[di] && CrossBarsNum[di] != 
       CrossBarsNum[ArrayMinimum(CrossBarsNum, 2*l, di - l)])
      {
        CrossBarsMin[di] = false;
        ObjectDelete(Period2AlpthabetString(TimePeriod) + TimePeriod + "_" + d);
      }          
  }

Ao fim do procedimento start(), nós novamente monitoramos a matriz CrossBarsMin[] de modo a determinar os novos mínimos locais e a deletar os antigos, que já não são os mínimos locais. Apesar de haver mais de um mínimo local possível (há vários valores adequados na matriz CrossBarsMin[], e todos eles são os mínimos locais), nós temos que derivar apenas um deles. Nós usaremos o mínimo local com o preço mais baixo.

CrossBarsNum[di] == CrossBarsNum[ArrayMinimum(CrossBarsNum, 2*l, di - l)] &&
CrossBarsNum[di-1]!= CrossBarsNum[ArrayMinimum(CrossBarsNum, 2*l, di - l)]

Não há nada de complicado na criação de um novo objeto gráfico - uma linha horizontal. Nós definimos as características desta linha: a largura, o estilo, a cor, que foram projetadas anteriormente no procedimento Init. Não há nada de complicado na deleção dos níveis que já não são níveis de apoio. Há uma coisa que não está clara: por que e para qual fim nós usamos a função Period2AlpthabetString(TimePeriod) no nome do objeto? O próximo parágrafo descreve essa questão, que já foi mencionada várias vezes anteriormente.

Interação dos indicadores

Como mencionamos no início do artigo, o indicador FindLevels foi projetado para indicar os níveis de apoio de vários períodos de tempo em um gráfico. Para fazer isso, nós precisamos do seguinte:

  1. Deve ser possível inicializar o indicador várias vezes, e o indicador deve ter os dados de entrada com o período de tempo;

  2. As linhas devem ser diferentes, e nós devemos ser capazes de definir com facilidade o período de tempo ao qual cada nível de apoio pertence;

  3. Todas as linhas devem ser traçadas a partir dos períodos de tempo longo e curto.

O primeiro ponto não deve causar qualquer problema. Nós não temos variáveis globais. Há diferentes nomes de objetos gráficos para cada período de tempo, pois o período está no nome do objeto (por exemplo, “f30_1.25600000”, 30 é o período de tempo), e portanto não ocorrerão conflitos quando nós inicializarmos os vários indicadores.

O segundo ponto é realizado com sucesso, pois a cor de cada linha depende do período (LineColor=Colors[Period2Int(TimePeriod)]).

Ainda temos o terceiro ponto. É evidente que, se uma linha é a linha de apoio do gráfico de 5 minutos, ela também será a linha de apoio do gráfico de 30 minutos. Se essas linhas entrarem em conflito em relação ao preço e possuírem a mesma largura, nós simplesmente não veremos uma delas! É por isso que linhas de diferentes períodos de tempo devem ter larguras diferentes. Nós faremos com que as linhas de apoio dos períodos de tempo mais longos sejam mais largas do que aqueles dos períodos mais curtos. Isso faz sentido, pois as linhas que pertencem aos intervalos longos são mais significativas.

Nós precisamos definir a prioridade correta de exibição das linhas. As linhas mais finas devem ser exibidas no final, e devem se sobrepor às linhas grossas, para que possam ser vistas com clareza. No programa MetaTrader 4, os objetos são exibidos em ordem alfabética. Portanto é necessário que os nomes das linhas dos períodos mais longos sejam alfabeticamente anteriores às linhas dos períodos mais curtos. É por isso que nós criamos a função que define a letra do alfabeto latino de acordo com o período.


string Period2AlpthabetString(int TmPeriod)
  {
    return (Alphabet[Period2Int(TmPeriod)]);
  }


O alfabeto é a matriz de letras latinas em ordem inversa. O nome completo de cada nível de apoio é o seguinte: Period2AlpthabetString(TimePeriod)+TimePeriod+"_"+d.

Para fins de clareza, vamos consultar a captura de tela do início do artigo:


Resumo

O teste do indicador mostrou que ele funciona corretamente. É fácil usá-lo, pois ele pode exibir os dados dos diferentes períodos de tempo. O período de teste mostrou que é mais conveniente o indicador exibir 3-10 níveis de apoio para cada período de tempo. Para fazer isso, nós temos que selecionar os itens de entrada correspondentes MaxR e MaxCrossesLevel. Durante o teste, o MaxR variou entre 0,0003 para períodos de tempo mais curtos e 0,002 para períodos mais longos. O MaxCrossesLevel variou entre 3 e 20. Talvez fosse útil configurar o indicador de modo que ele pudesse exibir uma certa quantidade dos níveis de apoio mais significativos, mas isso tonaria o código mais complicado. Eu acredito que as pessoas que gostarem do meu indicador serão capazes de fazer isso sozinhas com facilidade.


Traduzido do russo pela MetaQuotes Software Corp.
Artigo original: https://www.mql5.com/ru/articles/1440

Arquivos anexados |
FindLevels.mq4 (5.21 KB)
Um método para o desenho dos níveis de apoio/resistência Um método para o desenho dos níveis de apoio/resistência

Este artigo descreve o processo de criação de um script simples para a detecção dos níveis de apoio/resistência. Ele foi escrito para iniciantes, então você encontrará uma explicação detalhada de cada estágio do processo. Contudo, apesar do script ser bastante simples, o artigo também será útil para traders avançados e usuários da plataforma MetaTrader 4. Ele contém exemplos da exportação de dados para o formato tabular, da importação da tabela para o Microsoft Excel, e do delineamento de gráficos para a realização de uma análise mais detalhada.

Negociações com o uso do Linux Negociações com o uso do Linux

O artigo descreve como usar indicadores para monitorar a situação dos mercados financeiros online.

Filtragem de acordo com o histórico Filtragem de acordo com o histórico

O artigo descreve o uso de negociações virtuais como uma parte integral do filtro de abertura de negociações.

Modelagem de mudanças de cotação no provador e análise da estabilidade do expert advisor Modelagem de mudanças de cotação no provador e análise da estabilidade do expert advisor

A mudança de cotação é um grande problema para muitos expert advisors, especialmente para aqueles que possuem condições bastante sensíveis para a entrada/saída de uma negociação. Neste artigo, é oferecida uma forma de verificar a estabilidade de mudança de cotações de um EA.