English Русский 中文 Español Deutsch 日本語 한국어 Français Italiano Türkçe
preview
Indicadores múltiplos em um gráfico (Parte 04): Iniciando pelo EA

Indicadores múltiplos em um gráfico (Parte 04): Iniciando pelo EA

MetaTrader 5Negociação | 24 fevereiro 2022, 07:41
1 027 2
Daniel Jose
Daniel Jose

Introdução

Em artigos anteriores, eu expliquei como criar um indicador com múltiplas sub janela, mas apesar de ser interessante de se fazer, quando usamos um indicador personalizado, a coisa é bem simples de ser feita, mas quando tentamos fazer isto em um programa EA, a coisa toda começa a se tornar um pouco mais complexa, já que não temos os mesmos meios que temos em um indicador personalizado, neste ponto a programação se torna necessária, e saber criar o código adequado para se ter uma sub janela é primordial, apesar de não ser uma tarefa tão trivial, já que saber colocar uma sub janela em um EA não envolve muita codificação, mas apenas um certo conhecimento de como o MQL5 funciona.


Planejamento

Já temos nosso indicador personalizado funcionado, ou seja nossa classe objeto já é funcional, e sendo ele uma classe objeto podemos transportá-lo facilmente para outros modelos, mas simplesmente declarar e tentar usar a classe em nosso EA não fará as coisas funcionarem da mesma forma que fizemos em nosso indicador personalizado, e o motivo é que não contamos com a possibilidade de uma sub janela em nosso EA. Mas ai você pensa e se eu utilizar o indicador personalizado que já se encontra compilado e funcionando e chamá-lo de dentro da EA via comando iCustom ?!?! Poderia dar certo ... Bem na verdade até daria certo, desde que não fosse necessário uma sub janela, e o comando ficaria assim:

#property copyright "Daniel Jose"
//+------------------------------------------------------------------+
input string user01 = "";            //Indicadores a usar
input string user02 = "";               //Ativos a acompanhar
//+------------------------------------------------------------------+
int OnInit()
{
        int m_handleSub;

//... Código do EA ...

        if ((m_handleSub = iCustom(NULL, 0, "Chart In SubWindows\\Chart In SubWindow.ex5", user01, user02)) == INVALID_HANDLE) return INIT_FAILED;
        if (!ChartIndicatorAdd(ChartID(), 0, m_handleSub)) return INIT_FAILED;
//... Código do EA ...

        ChartRedraw();
        
        return(INIT_SUCCEEDED);
}
//...Resto do codigo do EA ...

Este fragmento singelo de código é sim capaz de carregar nosso indicador personalizado, mas no entanto ele não irá funcionar corretamente, pois não temos a presença de uma sub janela, neste caso quando o código for executado no EA, ele irá aplicar o nosso indicador diretamente na janela principal, ou seja nosso gráfico será ocultado pelos templates carregados pelo indicador, e definitivamente não é isto que estamos querendo.

Então nosso real e principal problema é criar uma sub janela que possa ser utilizada para assim podermos usar o nosso indicador já funcional. Mas por que criar uma sub janela para logo depois executar o nosso indicador ?!?! Isto não faz sentido, é melhor adicionarmos as funcionalidades diretamente no nosso EA e assim superar qualquer limitação que possa vim a acontecer.

Pensando nisto temos então algumas tarefas para serem feitas:

Tarefa Objetivo
1 => Criar um indicador de uso geral, ou seja genérico Permitir criar e usar o comando iCustom sem poluir em nada o gráfico
2 => Incluir de alguma forma este indicador ao EA  Isto irá permitir transportar o EA com todas as funcionalidades sem problemas
3 => Criar uma classe objeto generalista para sub janelas  Permitir adicionar sub janelas via nosso EA
4 => Fazer nossa classe C_TemplateChart se ligar a classe de janelas Isto irá permitir controlar o conteúdo da sub janelas sem mudar em nada o código já funcional.

Apesar de parecer trabalhoso, as questões são bem simples de serem resolvidas. Então vamos resolver cada um dos pontos.


Implementação: Criar um indicador de uso geral

Esta parte pode ser resolvida criando um código totalmente limpo, porém funcional de um indicador personalizado. No caso o código ficaria assim:

#property copyright "Daniel Jose"
#property version   "1.00"
#property description "Este arquivo serve apenas como Suporte ao Indicador em SubWin"
#property indicator_chart_window
#property indicator_plots 0
//+------------------------------------------------------------------+
int OnInit()
{
        return INIT_SUCCEEDED;
}
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[])
{
        return rates_total;
}
//+------------------------------------------------------------------+

Somente isto e mais nada. Vamos salvar este arquivo como SubSupport.mq5, só que ele não ficará junto com outros indicadores, transfira ele para o diretório RESOURCE do nosso EA, então a estrutura de arquivos ficaria conforme a imagem abaixo:


Isto tem um motivo muito grande para ser feito, mas por enquanto deixe assim. Agora passemos para a próxima tarefa.


Implementação: Incluir o indicador genérico no EA

Para se conseguir fazer isto teremos que adicionar o seguinte código no inicio do nosso EA.

//+------------------------------------------------------------------+
#define def_Resource "Resources\\SubSupport.ex5"
//+------------------------------------------------------------------+
#resource def_Resource
//+------------------------------------------------------------------+

Isto irá incorporar o código compilado do indicador genérico ao nosso EA, uma vez feito isto o indicador genérico poderá ter o arquivo .ex5 deletado, já que ele não será mais necessário. Agora atenção a um fato, caso no momento de compilar o código do EA o executável SubSupport.ex5 não seja encontrado, o compilador irá automaticamente compilar o código do nosso indicador genérico SubSupport.mq5 e adicionar este executável recém compilado ao nosso EA, ou seja se você modificar por qualquer razão o arquivo SubSupport.mq5 e desejar adicionar as mudanças ao EA, delete o arquivo SubSupport.ex5, caso contrário as mudanças não serão adicionadas.

É muito importante se ter este detalhe em mente, pois em alguns casos é necessário saber como adicionar as novas mudanças a um recurso.

Bem, o indicador genérico já esta fazendo parte do nosso EA, passemos então a próxima tarefa.


Implementação: Criar uma classe objeto de sub janelas

Esta parte é igualmente simples, mas no entanto temos que decidir algumas coisas antes de sair codificando, e estas são o seguinte: Quais funções realmente precisaremos ter nesta classe ?!?! Eu decidi usar as seguintes inicialmente:

Função Descrição
Init Criar uma sub janela no gráfico via código do EA
Close Finaliza uma sub janela no gráfico via código do EA

Esta funções não fará testes, estou desta forma imaginando que elas serão chamadas apenas uma única vez durante todo o tempo de vida do EA. Mas já que nosso EA esta crescendo é bom já pensar em torná-lo ainda mais prático para o futuro, então vamos acionar uma nova classe objeto a ele será chamada C_Terminal, esta classe irá dar suporte a diversas coisas ligadas ao terminal gráfico, mas não se preocupem com isto por enquanto, vamos então ver a ultima tarefa, já que não tem como implementar uma solução de forma parcial.


Implementação: Herdando a classe C_TemplateChart

Quanto eu decidi criar as coisas usando OOP ( Programação Orientada a Objetos ) fiz isto por já saber que existem vantagens muito grandes em se usar tal abordagem, entre elas está a segurança e a herança, apesar de termos também o polimorfismo, mas este iremos usar mais para frente quando formos criar um sistema de ordens cruzadas, mas aqui vamos usar uma das boas coisas que a OOP nos traz, a herança. Pois bem, a nossa classe C_TemplateChart já se encontra totalmente funcional, e vendo isto, não queremos ter o trabalho de reprogramar tudo de novo, ou correr o risco de adicionar códigos na classe, e estes códigos impedirem a classe de ser usada em outros locais. Solução usamos a herança e assim adicionamos novos códigos ou funcionalidades sem mudar em nada o código original.

Usar a herança nos traz diversos benefícios, entre eles temos: O código já testado permanece testado; a complexidade cresce sem um igual crescimento na quantidade de código; apenas novas funcionalidades de fato precisam se testadas; o que não muda simplesmente é herdado garantindo a estabilidade, enfim, a coisa vai melhorando com o mínimo de esforço, mas com o máximo de segurança, para entender veja o esquema abaixo.


A classe avô é a classe mais básica, onde temos um nível de manipulação dos dados em menor escala, mas quando a classe pai herda as coisas da classe avô, todas as coisas declaradas como publicas na classe avô poderão ser vistas e usadas pela classe pai, mas também poderemos fazer adições de novas coisas a classe pai, mas isto em nada irá afetar o que foi herdado e mantido durante a herança, mas se a classe pai já esta concluída e funcionado e desejamos expandir as coisas ainda mais sem mudar em nada as classes mais abaixo, então criamos uma classe filho e esta agora terá todas as funcionalidades das classes anteriores, mas podemos mudar a forma como as coisas funcionam, e isto é a parte interessante da herança, e ao fazer estas mudanças as demais classes não serão afetadas. No entanto existe uma limitação aqui, diferente do C++ que permite heranças múltipla, ou seja, o filho irá herdar características tanto do lado paterno quanto do materno, no MQL5 isto não é possível, então a estrutura fica sempre um pouco defasada, mas ainda assim você consegue tirar algum proveito da herança. Um exemplo de herança múltipla pode ser visto abaixo:

Bem então como fazemos isto em MQL5 ? Como declaramos a herança e assim possamos tirar proveito disto ?!?! A forma mais clara de entender é lendo este conteúdo Programação Orientada a Objetos ( OOP ) mas aqui iremos direto ao ponto. A herança se dará usando as seguintes linhas:

#include "C_TemplateChart.mqh"
//+------------------------------------------------------------------+
class C_SubWindow : public C_TemplateChart
{
// ... Código da classe
};

Vejam que a classe C_SubWindow irá herdar de forma publica a classe C_TemplateChart, então a partir deste momento poderemos usar a classe C_SubWindow para acessar as funcionalidades da classe C_TemplateChart, ou seja herdamos a classe C_TemplateChart e podemos modificá-la ou incrementá-la sem corrermos riscos de estragar o código já testado.

No fragmento de código acima, eu destaquei uma coisa, notem que esta entre aspas ( " ) e não como é de costume usar ( < > ) e por que eu fiz isto ?!?! Como a linguagem C++, o MQL5 tem algumas coisas bem interessantes, porém que confundem quem esta começando a aprender a arte da programação, quando colocamos um arquivo de cabeçario entre os sinais de maior e menor ( < > ) estamos nos referindo a um caminho absoluto, ou seja o compilador irá seguir exatamente o caminho que indicarmos a ele, mas quando usamos aspas como foi feito, o compilador irá usar um caminho relativo, ou para você entender melhor, ele irá primeiro começar no diretório atual onde o arquivo de trabalho se encontra. Isto talvez soe estranho, mas existem casos em que teremos o mesmo nome para arquivos cujo conteúdo é diferente, e eles estarão em diretórios diferentes, mas no entanto queremos nos referir ao diretório atual, então usamos as aspas para fazer isto.

As duas funções que planejamos usar anteriormente, INIT e CLOSE podem ser vista abaixo:

//+------------------------------------------------------------------+
bool Init(void)
{
        if (m_handleSub != INVALID_HANDLE) return true;
        if ((m_handleSub = iCustom(NULL, 0, "::" + def_Resource)) == INVALID_HANDLE) return false;
        m_IdSub = (int) ChartGetInteger(Terminal.Get_ID(), CHART_WINDOWS_TOTAL);
        if (!ChartIndicatorAdd(Terminal.Get_ID(), m_IdSub, m_handleSub)) return false;
                
        return true;
}
//+------------------------------------------------------------------+
void Close(void)
{
        ClearTemplateChart();
        if (m_handleSub == INVALID_HANDLE) return;
        IndicatorRelease(m_IdSub);
        ChartIndicatorDelete(Terminal.Get_ID(), m_IdSub, ChartIndicatorName(Terminal.Get_ID(), m_IdSub, 0));
        ChartRedraw();
        m_handleSub = INVALID_HANDLE;
}
//+------------------------------------------------------------------+

Vejam que o código é super simples e curto, mas tem algo que precisamos tomar cuidado, observem a parte destacada do mesmo. É preciso tomar cuidado para que não se cometa o erro no momento de adicionar esta parte, pois se você não deixar exatamente assim, o executável SubSupport.ex5 que pedimos para adicionar ao EA não será visto dentro do EA, e sim de fora do EA. Para entender leia sobre Resources, mas basicamente é o seguinte se você usar ( :: ) isto irá indicar que o EA deverá usar o recurso interno presente dentro dele, mas se apenas indicarmos o nome do recurso o EA irá procurar ele dentro do diretório MQL5, desta forma se o arquivo não existir no local indicado a função irá falhar, mesmo que o arquivo tenha sido adicionado como um recurso do EA.

Então uma vez carregado o recurso, verificamos o numero de sub janelas presentes, e adicionamos um indicador nesta sub janela.

O que este código de fato esta fazendo pode ser visto abaixo:

input string user01 = "";               //Indicadores a usar
input string user02 = "";               //Ativos a acompanhar
//+------------------------------------------------------------------+
int OnInit()
{
        int m_handleSub;

//...   

        if ((m_handleSub = iCustom(NULL, 0, "Chart In SubWindows\\Chart In SubWindow.ex5", user01, user02)) == INVALID_HANDLE) return INIT_FAILED;
        if (!ChartIndicatorAdd(ChartID(), (int) ChartGetInteger(ChartID(), CHART_WINDOWS_TOTAL), m_handleSub)) return INIT_FAILED;

//...

        ChartRedraw();
        
   return(INIT_SUCCEEDED);
}
//...Resto do código do EA ...

Ambos os códigos irão funcionar de forma idêntica, mas a versão da classe objeto nos permitirá agregar mais coisas no decorrer do tempo, já a versão mostrada acima, é uma versão já consolidada e não irá mudar, mas ambos executaram a mesma coisa, criar uma sub janela a partir do EA e colocar nesta sub janela todo o indicador personalizado criado anteriormente. Notem que o código sofreu apenas e tão somente uma única modificação do código visto lá no inicio do artigo e que ela esta em destaque.


Conclusão

É muito interessante e curioso a forma como decidimos percorrer um caminho para alcançar nossos objetivos, várias vezes somos confrontados e imaginamos ser difícil conseguir atingir os objetivos, mas com um pouco de paciência e dedicação conseguimos superar obstáculos que pareciam inicialmente intransponíveis. Neste artigo demostrei como você pode ampliar as funcionalidade de uma classe sem de fato mexer nela usando para isto a herança, e ao mesmo tempo mostrei como você pode adicionar indicadores ao seus gráficos, de forma que os mesmo funcionem conforme já foi testado. Adicionamos um programa ex5 dentro de nosso EA e usamos ele sem precisar transportar o ex5 original, bastando carregar o EA.

O arquivo anexado contém todas as melhorias desenvolvidas até o presente momento, mas em breve teremos ainda mais coisas interessantes neste código. 😁👍


Arquivos anexados |
Últimos Comentários | Ir para discussão (2)
Mateus Cerqueira Lopes
Mateus Cerqueira Lopes | 25 fev 2022 em 17:50
Ola Daniel, estou acompanhando seus artigos, mas e a parte 03?
Daniel Jose
Daniel Jose | 26 fev 2022 em 13:28
Mateus Lopes #:
Ola Daniel, estou acompanhando seus artigos, mas e a parte 03?

Houve um pequeno problema no momento que foi pedido a liberação para publicação, mas já autorizei a publicação da Parte 03, em breve ela estará disponível também, este problema foi mais causado por conta da quantidade de artigos que eu já envie ... atualmente tem outros 15 artigos para eles analisarem, todos envolvidos no desenvolvimento deste EA e em cada um a coisa vai ficando cada vez mais complexa .... mas obrigado por estar acompanhando a serie ... aguarde novidades imensas a partir do artigo 05, a partir dali a coisa irá realmente valer a pena, pois se tornará algo de gente grande, estes primeiro são só para apresentar o que irá vim pela frente ...😁👍

Indicadores múltiplos em um gráfico (Parte 03): Desenvolvendo definições para usuários Indicadores múltiplos em um gráfico (Parte 03): Desenvolvendo definições para usuários
Primeira atualização nas funcionalidades no sistema indicador. No artigo anterior Indicadores múltiplos em um gráfico eu expliquei o código base para poder usar mais de um indicador dentro de uma sub janela, mas aquilo que foi apresentado foi apenas a base inicial de um sistema muito maior.
Stop-loss fixo com base na ação do preço e RSI (stop-loss "inteligente") Stop-loss fixo com base na ação do preço e RSI (stop-loss "inteligente")
O Stop-loss é a principal ferramenta de gerenciamento de dinheiro na negociação. O uso eficaz do stop-loss, take-profit e tamanho do lote pode tornar a negociação mais consistente e, em geral, mais lucrativa. No entanto, fazer uso disto tem suas próprias dificuldades. A principal delas é a caça ao stop-loss. Neste artigo analisaremos como minimizar o efeito da caça ao stop-loss e compararemos isto com o uso clássico de stop loss para determinar lucratividade.
Melhorando o reconhecimento de padrões de velas por meio de velas Doji Melhorando o reconhecimento de padrões de velas por meio de velas Doji
Como encontrar padrões de velas com mais frequência do que o habitual. Por trás da simplicidade dos padrões de velas, há também uma séria desvantagem que pode ser evitada usando os abundantes recursos das modernas ferramentas de automação de negociação.
Combinatória e teoria da probabilidade para negociação (Parte V): análise de curva Combinatória e teoria da probabilidade para negociação (Parte V): análise de curva
Neste artigo, explorei as possibilidades de reduzir amostras multiestado complexas a amostras simples de estado duplo. O objetivo principal é obter uma análise e umas conclusões que possam ajudar no desenvolvimento de algoritmos de negociação escaláveis baseados na teoria da probabilidade. Naturalmente, a matemática também está envolvida, mas dada a experiência de artigos anteriores, vejo que informações mais gerais são muito mais úteis do que detalhes.