Discussão do artigo "Desenvolvendo Sistemas de Trading ICT Avançados: Implementando Order Blocks em um Indicador"

 

Novo artigo Desenvolvendo Sistemas de Trading ICT Avançados: Implementando Order Blocks em um Indicador foi publicado:

Neste artigo, vamos aprender a criar um indicador que detecta, desenha e emite alertas sobre a mitigação de order blocks. Também veremos em detalhes como identificar esses blocos no gráfico, configurar alertas precisos e visualizar sua posição utilizando retângulos, para compreender melhor a ação do preço. Este indicador servirá como uma ferramenta-chave para traders que seguem os Smart Money Concepts e a metodologia do Inner Circle Trader.

Blocos de Ordem são zonas no gráfico onde ordens pendentes provavelmente estão aguardando para serem executadas.

Isso normalmente ocorre quando um grande participante do mercado, como uma instituição financeira, deseja entrar em uma posição significativa, mas não possui liquidez suficiente para executar toda a ordem de uma vez sem impactar o mercado. De acordo com as leis básicas de oferta e demanda, a execução de uma parte da ordem faz o preço subir (no caso de uma compra) em uma busca agressiva por vendedores que possam fornecer a liquidez necessária para completar a negociação.

Como o participante institucional não pode executar a ordem completa de uma só vez sem causar uma alteração substancial no preço, ele divide a ordem em partes menores. Isso permite que concluam a operação sem que o preço se mova significativamente antes de entrarem totalmente em sua posição.

A partir desse conceito, podemos identificar essas zonas em um gráfico de preços como áreas de forte desequilíbrio entre oferta e demanda (seja para compra ou para venda). A seguir, exploraremos três maneiras de identificar essas zonas e como implementá-las em código.


Autor: Niquel Mendoza

 

Bom dia Mendoza

Obrigado por seu esforço.

Minha pergunta é: já que estamos usando a função OnCalculate:

int OnCalculate(const int rates_total,

const int prev_calculated,

const datetime &time[],// Série temporal de tempos abertos

const double &open[], // Série temporal de preços de abertura

const double &high[],// Série temporal de preços altos

const double &low[],// Série temporal de preços baixos

const double &close[],// Série temporal de preços de fechamento

const long &tick_volume[],// Série temporal do volume do tick

const long &volume[],// Série temporal de preços de barra

const int &spread[])//


Por que devemos criar novas matrizes e reorganizá-las?

 
Ahmed Fouad Abdellatief a função OnCalculate:

int OnCalculate(const int rates_total,

const int prev_calculated,

const datetime &time[],// Série temporal de tempos abertos

const double &open[], // Série temporal de preços de abertura

const double &high[],// Série temporal de preços altos

const double &low[],// Série temporal de preços baixos

const double &close[],// Série temporal de preços de fechamento

const long &tick_volume[],// Série temporal do volume do tick

const long &volume[],// Série temporal de preços de barra

const int &spread[])//


Por que devemos criar novas matrizes e reorganizá-las?

Olá Ahmed, muito obrigado por seu comentário. Você está certo. Não há necessidade de criar novas matrizes, pois a função OnCalculate já nos fornece todos os dados prontos para uso. Eu fiz isso por hábito na época, mas é melhor trabalhar diretamente com os dados que já estão lá. A propósito, se você quiser o código mais atualizado, vou deixá-lo aqui para você. Nesse novo código, os arrays que já vêm por padrão são usados, a lógica para detectar os blocos de ordem é a mesma.
Arquivos anexados:
 
Niquel Mendoza #:
datetime  mitigados_alcsitas(double price, const double &lowArray[], const  datetime &Time[], datetime start, datetime end)
 {
  int startIndex = iBarShift(_Symbol, PERIOD_CURRENT, start);
  int endIndex = iBarShift(_Symbol, PERIOD_CURRENT, end);

  NormalizeDouble(price, _Digits);
  for(int i = startIndex - 2 ; i >= endIndex + 1 ; i--)
   {
    if(price > lowArray[i])
     {
      return Time[i]; //si encuentra que si hubo retorna el tiempo de la vela donde hubo la mitigacion
      Print("el orderblock tuvo mitigaciones", TimeToString(end));
     }
   }

  return 0; /Em caso de não ter sido encontrada nenhuma mitigação, retorna 0
 }

E assim por diante, em quatro funções vizinhas.

 
trader6_1 #:

E assim por diante, em quatro funções vizinhas.

Olá, você está absolutamente certo. Eu estava errado ao pensar que NormalizeDouble funcionava por referência. Na verdade, ele retorna um valor arredondado e, para que uma variável receba esse valor, é necessário atribuí-lo explicitamente a ela. Desculpe-me por isso; acho que aprendi dessa forma quando escrevi o código e foi assim que ele ficou preso. Sinto muito mesmo. Estou usando o NormalizeDouble aqui mais por precaução, embora não ache que ele tenha um impacto significativo na verificação da mitigação de um bloco de ordens de alta (com base em meus testes). Obrigado por apontar isso. Poderíamos optar por atribuir "price = NormalizeDouble(price, _Digits)" diretamente ou excluir essa linha, já que a normalização não parece afetar significativamente a análise.

 
Muito obrigado, obrigado por compartilhar. Prossiga para a próxima parte.
 
Niquel Mendoza #:
Olá Ahmed, muito obrigado por seu comentário. Você está certo. Não há necessidade de criar novas matrizes, pois a função OnCalculate já nos fornece todos os dados prontos para uso. Eu fiz isso por hábito na época, mas é melhor trabalhar diretamente com os dados que já estão lá. A propósito, se você quiser o código mais atualizado, vou deixá-lo aqui para você. Nesse novo código, os arrays que já vêm por padrão são usados, a lógica para detectar os blocos de ordem é a mesma.
Niquel Mendoza #:
Olá Ahmed, muito obrigado pelo seu comentário. Você está certo. Não há necessidade de criar novas matrizes, pois a função OnCalculate já nos fornece todos os dados prontos para uso. Eu fiz isso por hábito na época, mas é melhor trabalhar diretamente com os dados que já estão lá. A propósito, se você quiser o código mais atualizado, vou deixá-lo aqui para você. Nesse novo código, os arrays que já vêm por padrão são usados, a lógica para detectar os blocos de ordem é a mesma.

Há outro motivo para a criação de matrizes separadas: se você decidir incorporar a lógica em um EA, não haverá a função OnCalculate. Além disso, se desejar criar versões com várias moedas ou vários períodos de tempo, precisará de várias matrizes ou matrizes com vários demônios, e 90% do trabalho já estará feito.

Minha pergunta é: por que a maioria dos desenvolvedores transforma os dados em séries temporais? Converti um EA MQ4 em MQ5 e não percebi que as séries temporais estavam disponíveis, então mantive todas as matrizes como bases zero, não como séries temporais.Descobri que isso facilita muito a vida, pois há uma correspondência de 1 para 1 entre os dados e as matrizes de suporte, não é mais necessário redefinir, redimensionar e redefinir novamente para séries temporais, apenas redimensionar e, finalmente, o mais importante, apenas um sistema de numeração de barras. Para as funções do Metaquotes que insistem em uma série temporal, faço a indexação inversa na chamada.


Olá, acabei de baixar seu código-fonte, versão 1, compilei e apliquei a um gráfico EURUSD H4 e não apareceu nada. Fui ao painel de propriedades, não mudei nada, fechei e o png apareceu. Apenas barras verdes, sem vermelhas, e quando começam, não terminam. Alguma sugestão?Baixei a Parte 2 da discussão acima e, de modo geral, ela apresentava os mesmos problemas, mas também três mais recentes. Os problemas de iniciar, parar, verde e vermelho eram evidentes. Além disso, parece que havia critérios diferentes, pois o número de bandas não correspondia exatamente. Além disso, tentei alterar a cor verde para clrLime e ela mudou, mas definitivamente não era Lime.

Pergunto isso porque não consigo fazer com que o Strategy Tester seja exibido corretamente na tela ao testar um EA no modo visual ou ao testar um indicador
Arquivos anexados:
EURUSDH4_1.png  72 kb
EURUSDH4.png  63 kb
 

Oi Niquel,

Estou anexando uma versão ligeiramente revisada da sua parte 2.

Acrescentei ErrorDescription(errornumber), que está em STDLIB.EX5, para expandir suas várias mensagens de erro. Por algum motivo, não consegui colocar a importação diretamente no indicador, portanto, minha solução alternativa foi incluí-la em um arquivo de inclusão BlockOrder Common.mqh, onde ela funciona para mim. Você pode executar o indicador no Google Translate para converter o texto em inglês?

Também adicionei um número de versão, 2.01, ao programa. Usando a definição, adicionei o número da versão como um prefixo do RectangleCreate para permitir a execução conjunta das versões 1 e 2, embora não tenha alterado a versão 1.

Como sugestão, você poderia calcular uma média móvel sobre os volumes e exibi-la na parte inferior da tela. Presumo que seja necessário algum ajuste decimal.


Aguardo ansiosamente sua próxima atualização


CapeCoddah

Arquivos anexados:
 
CapeCoddah #:

Há outro motivo para criar matrizes separadas: se você decidir incorporar a lógica em um EA, não haverá a função OnCalculate. Além disso, se você quiser criar versões com várias moedas ou vários períodos, precisará de várias matrizes ou matrizes com vários demônios, e 90% do trabalho já estará feito.

Minha pergunta é: por que a maioria dos desenvolvedores transforma os dados em séries temporais? Converti um EA MQ4 em MQ5 e não percebi que as séries temporais estavam disponíveis, então mantive todas as matrizes como bases zero, não como séries temporais.Descobri que isso facilita muito a vida, pois há uma correspondência de 1 para 1 entre os dados e as matrizes de suporte, não é mais necessário redefinir, redimensionar e redefinir novamente para séries temporais, apenas redimensionar e, finalmente, o mais importante, apenas um sistema de numeração de barras. Para as funções do Metaquotes que insistem em uma série temporal, faço a indexação inversa na chamada.

Oi CapeCoddah, No meu caso, geralmente uso matrizes na forma de séries temporais para trabalhar com dados de preços ou indicadores, principalmente por conveniência e por hábito. Entretanto, reconheço que esse nem sempre é o melhor motivo para usá-los. Para indicadores, muitas vezes pode ser mais prático trabalhar com matrizes baseadas em zero, pois elas simplificam o gerenciamento de índices e reduzem a necessidade de reinicialização ou redimensionamento constante. No meu caso, ao programar o indicador de blocos de ordens, optei por usar séries temporais porque foi assim que estruturei a recuperação de blocos de ordens desde o início.

 
CapeCoddah #:

Acabei de fazer o download do código-fonte, versão 1, compilei e apliquei a um gráfico EURUSD H4 e nada apareceu. Fui ao painel de propriedades, não alterei nada, fechei e o png apareceu. Apenas barras verdes, sem vermelhas e, quando começam, não terminam. Alguma sugestão?Baixei a Parte 2 da discussão acima e, de modo geral, ela apresentava os mesmos problemas, mas também três mais recentes. Os problemas de iniciar, parar, verde e vermelho eram evidentes. Além disso, parece que havia critérios diferentes, pois o número de bandas não correspondia exatamente. Além disso, tentei alterar a cor verde para clrLime e ela mudou, mas definitivamente não era Lime.

Pergunto isso porque não consigo fazer com que o Strategy Tester seja exibido corretamente na tela ao testar um EA no modo visual ou ao testar um indicador

Com relação ao primeiro problema, acho que pode ser devido ao fato de o indicador não carregar os dados corretamente. Isso geralmente acontece ao mudar de gráfico ou abrir um novo. No entanto, se for um gráfico que já estava em uso, valeria a pena investigar melhor por que os blocos de ordens não estão sendo obtidos. Nesse caso, seria útil incluir mensagens de depuração (Print) no código para identificar o problema.

Com relação ao segundo problema, em que apenas os blocos de ordens de alta são desenhados, pode ser porque o EURUSD no período H4 está atualmente em 600-700 candlestick highs. Nesse contexto, é possível que todos os blocos de ordens de baixa tenham sido atenuados e, por isso, não são desenhados no gráfico.

Com relação à mudança de critérios, reduzi algumas variáveis booleanas no código. Entretanto, não seria um problema reintroduzir essas condições, se necessário.

Com relação às cores, a versão mais recente que publiquei nos comentários aplica transparência às cores dos retângulos do bloco de ordens. Talvez seja por isso que as cores não correspondam visualmente às das versões anteriores. Por fim, com relação à animação, não entendi muito bem a que você estava se referindo. Você poderia explicar com mais detalhes o que quer dizer com animação nesse contexto?

 
Niquel Mendoza #:

Oi CapeCoddah, No meu caso, geralmente uso matrizes na forma de séries temporais para trabalhar com dados de preços ou indicadores, principalmente por conveniência e por hábito. Entretanto, reconheço que esse nem sempre é o melhor motivo para usá-los. Para indicadores, muitas vezes pode ser mais prático trabalhar com matrizes baseadas em zero, pois elas simplificam o gerenciamento de índices e reduzem a necessidade de reinicialização ou redimensionamento constante. No meu caso, ao programar o indicador de blocos de ordens, optei por usar séries temporais porque foi assim que estruturei a recuperação de blocos de ordens desde o início.

Quando eu estava redimensionando matrizes no MQ4, descobri que precisava definir a série temporal da matriz como falsa, redimensionar e redefinir a série temporal como verdadeira. Como não uso isso no MQ5, não sei se ainda é apropriado.