English Русский Español Deutsch 日本語
preview
Desenvolvendo um sistema de Replay (Parte 74): Um novo Chart Trade (I)

Desenvolvendo um sistema de Replay (Parte 74): Um novo Chart Trade (I)

MetaTrader 5Exemplos |
203 0
Daniel Jose
Daniel Jose

Introdução

No artigo anterior Desenvolvendo um sistema de Replay (Parte 73): Uma comunicação inusitada (II), fechamos a segunda etapa de desenvolvimento, da nossa aplicação, que será responsável por gerar o replay/simulador. Ou seja, até o momento, conseguimos fazer com que todo o sistema, venha a se comportar de modo bem adequado. Ou melhor dizendo, venha a ter uma funcionalidade, de uma maneira a termos uma apresentação de algo que seria, muito próximo a real a movimentação de mercado.

No entanto, tudo que foi feito até o momento, é apenas uma parcela do que realmente precisamos fazer. Então agora entramos na terceira fase de desenvolvimento. Nesta fase, inicialmente iremos de fato focar não mais na aplicação de replay/simulador. O foco neste ponto, será trabalhar em conjunto com o servidor de negociação real. Ou seja, iremos de fato, desenvolver as ferramentas necessárias para poder, abrir, controlar e finalizar uma posição.

Algumas destas ferramentas já foram vistas no passado, e isto, dentro desta mesma sequência. Mas como toda a aplicação de replay/simulação, passou por diversas mudanças ao longo do tempo, precisaremos refazer, ou no mínimo, adequar, antigas ferramentas a um novo modelo. E a primeira das ferramentas que começaremos a trabalhar é o: Chart Trade. Esta ferramenta, visa poder nós auxiliar a abrir ou fechar uma posição. Isto fazendo as operações a mercado. No entanto, o MetaTrader 5, já conta com tais recursos, no modo padrão de instalação. Este recurso são os botões de One Click Trading, que podem ser vistos na imagem logo a seguir:

Apesar de tais botões serem bem uteis, e funcionarem perfeitamente bem. Os mesmos não nos são nada uteis. Isto por conta, que eles são voltados, para se comunicarem com o servidor de negociação real. E nosso sistema de replay/simulação, não é de fato um servidor. Ele é um serviço, ou melhor um conjunto de aplicações, que tenta simular o que seria um servidor real.

Por este motivo, precisamos criar nossas próprias ferramentas. Isto para tentar conseguir suprir, o que vem por padrão no MetaTrader 5, mas que não conseguiremos fazer uso, já que estamos simulando o que seria o servidor real.

Aqui vale uma nota importante: Todo este trabalho, que estou tendo para mostrar como fazer as coisas. Se deve ao fato de que, a programação que está sendo feita e visa usar apenas e somente o MQL5. O fato de isto está sendo feito, torna todo o trabalho ainda mais interessante. Isto olhando pelo ponto de vista da implementação da aplicação. Já que criar algo consiga trabalhar como se fosse o servidor real de negociação, usando o MQL5 puro, tem sido uma tarefa bastante interessante. Mas seria consideravelmente mais simples, isto pelo ponto de vista da programação, criar uma aplicação em C/C++, que faria uso de sockets. Esta implementação em C/C++, deveria de fato, criar todo os protocolos que seriam usados para que o MetaTrader 5, viesse a assumir que estaria em contato com um servidor.

Apesar deste tipo de abordagem, simplificar bastante diversas coisas. Isto por que nos permitiria de fato, usar o MetaTrader 5, em sua instalação padrão, não seria algo que nos ajudaria a entender ainda mais sobre o MQL5. Se tal implementação em C/C++, fosse de fato implementada, não seria necessário fazer nenhum uso do MQL5. Veja quanta coisa séria perdida, em termos de conhecimento sobre como programar em MQL5. Mas como aceitei o desafio de criar algo, tão complexo, quando um simulador em MQL5 puro. Tenho até o momento conseguido cumprir o meu objetivo. Mas agora vamos entrar na fase, onde iremos de fato dar um tempo no replay/simulador. Então durante um tempo, você verá as coisas funcionando em um conta demo. Mas a implementação será sempre pensada, em vir a ser utilizada no replay/simulador.


O nascimento de um novo Chart Trade

A última vez que falamos sobre Chart Trade, foi no artigo Desenvolvendo um sistema de Replay (Parte 47): Projeto do Chart Trade (VI). Pois bem, apesar de não temos mexido nele desde então, chegou a hora de voltar a mexer nele. Mas como de lá até aqui, muitas coisas mudaram. Muito daquele código, simplesmente não nos serve mais. Estando totalmente obsoleto, devendo assim ser descartado. Porém como grande parte dos conceitos, visto naquela época, ainda se mantém e podem ser aplicados ainda. Vamos retomar a construção. Mas com um pequeno detalhe: O código agora será integralmente reformulado a ponto de poder usar os novos conceitos, que foram desenvolvidos até o presente momento.

Uma coisa, que é importante você entender neste momento. Indicadores NÃO PODEM ABRIR, MODIFICAR E FECHAR seja posições, seja ordens. Quem é responsável por tal coisa é o Expert Advisor. Mas, porém, toda via e entretanto, não iremos de fato trabalhar o Chart Trade como um código de Expert Advisor. Iremos sim, fazer com que o Chart Trade, seja um indicador, que irá se comunicar com um Expert Advisor, a fim de conseguir executar seu trabalho.

Se você compreendeu, de fato, os últimos artigos desta sequência. Deve ter notado que a forma de enviar comunicações entre os indicadores e o serviço, se dava via eventos customizados. Fazer uso de tais eventos, é com toda a certeza, a maneira mais prática de repassar dados entre os programas da aplicação de replay/simulador. Novamente, mesmo que estejamos fazendo uma pausa no desenvolvimento do replay/simulador. Tudo será pensado em relação a ele. Então sendo assim, a primeira coisa a ser feita, será criar alguns novos valores de eventos customizados. Assim sendo, o novo arquivo Defines.mqh, pode ser visto logo abaixo:

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. #define def_VERSION_DEBUG
05. //+------------------------------------------------------------------+
06. #ifdef def_VERSION_DEBUG
07.    #define macro_DEBUG_MODE(A) \
08.                Print(__FILE__, " ", __LINE__, " ", __FUNCTION__ + " " + #A + " = " + (string)(A));
09. #else
10.    #define macro_DEBUG_MODE(A)
11. #endif
12. //+------------------------------------------------------------------+
13. #define def_SymbolReplay         "RePlay"
14. #define def_MaxPosSlider          400
15. #define def_MaskTimeService       0xFED00000
16. #define def_IndicatorTimeFrame    (_Period < 60 ? _Period : (_Period < PERIOD_D1 ? _Period - 16325 : (_Period == PERIOD_D1 ? 84 : (_Period == PERIOD_W1 ? 91 : 96))))
17. #define def_IndexTimeFrame        4
18. //+------------------------------------------------------------------+
19. union uCast_Double
20. {
21.    double   dValue;
22.    long     _long;                                  // 1 Information
23.    datetime _datetime;                              // 1 Information
24.    uint     _32b[sizeof(double) / sizeof(uint)];    // 2 Informations
25.    ushort   _16b[sizeof(double) / sizeof(ushort)];  // 4 Informations
26.    uchar    _8b [sizeof(double) / sizeof(uchar)];   // 8 Informations
27. };
28. //+------------------------------------------------------------------+
29. enum EnumEvents    {
30.          evHideMouse,               //Hide mouse price line
31.          evShowMouse,               //Show mouse price line
32.          evHideBarTime,             //Hide bar time
33.          evShowBarTime,             //Show bar time
34.          evHideDailyVar,            //Hide daily variation
35.          evShowDailyVar,            //Show daily variation
36.          evHidePriceVar,            //Hide instantaneous variation
37.          evShowPriceVar,            //Show instantaneous variation
38.          evCtrlReplayInit,          //Initialize replay control
39.          evChartTradeBuy,           //Market buy event
40.          evChartTradeSell,          //Market sales event 
41.          evChartTradeCloseAll       //Event to close positions
42.                   };
43. //+------------------------------------------------------------------+

Código fonte do arquivo Defines.mqh

Note que as únicas mudanças que ocorreram, foram o surgimento das seguintes linhas: 39, 40 e 41. Estas linhas definem os eventos que serão disparados a fim de que o indicador Chart Trade, possa dizer ao Expert Advisor, que algo deverá ser feito. Então quem de fato, faz as coisas acontecerem, em temos de abertura e fechamento de posições é o Expert Advisor. Note que aqui, não estou falando em termos de ordens. A real necessidade do Chart Trade, se deve em substituir o sistema padrão do MetaTrader 5. Este sistema é o que nos permite a abertura ou fechamento de uma posição. Seja aumentando a mão, seja fazendo parciais. O indicador Chart Trade irá justamente fazer a mesma coisa. Só que nos permitindo depois, usar os mesmos conceitos no replay/simulador. As operações neste caso serão sempre a mercado. Depois iremos de fato trabalhar em um outro sistema, que nos permitirá fazer uso de ordens pendentes. Mas vamos dar um passo de cada vez. E o conceito, mais simples de implementar é execução a mercado.

Feito isto, vamos precisar fazer com que o antigo indicador, que foi visto no artigo informado no início deste tópico, venha a funcionar. Você não estava pensando que iriamos de fato, refazer toda a programação do indicador do zero. Estava? Pois em nenhum momento cogitei tal coisa. Isto seria uma completa e total sandice.

Então vamos ao código do indicador, que foi modificado e por alguns motivos que você compreenderá no decorrer das explicações. Vamos então começar vendo o arquivo de cabeçalho C_AdjustTemplate.mqh. Este pode ser visualizado na íntegra logo abaixo.

001. //+------------------------------------------------------------------+
002. #property copyright "Daniel Jose"
003. //+------------------------------------------------------------------+
004. #include "../Auxiliar/C_Terminal.mqh"
005. //+------------------------------------------------------------------+
006. #define def_PATH_BTN "Images\\Market Replay\\Chart Trade"
007. #define def_BTN_BUY   def_PATH_BTN + "\\BUY.bmp"
008. #define def_BTN_SELL  def_PATH_BTN + "\\SELL.bmp"
009. #define def_BTN_DT    def_PATH_BTN + "\\DT.bmp"
010. #define def_BTN_SW    def_PATH_BTN + "\\SW.bmp"
011. #define def_BTN_MAX   def_PATH_BTN + "\\MAX.bmp"
012. #define def_BTN_MIN   def_PATH_BTN + "\\MIN.bmp"
013. #define def_IDE_RAD   def_PATH_BTN + "\\IDE_RAD.tpl"
014. #define def_IDE_RAD   "Files\\Chart Trade\\IDE_RAD.tpl"
015. //+------------------------------------------------------------------+
016. #resource "\\" + def_BTN_BUY
017. #resource "\\" + def_BTN_SELL
018. #resource "\\" + def_BTN_DT
019. #resource "\\" + def_BTN_SW
020. #resource "\\" + def_BTN_MAX
021. #resource "\\" + def_BTN_MIN
022. #resource "\\" + def_IDE_RAD as string IdeRad;
023. //+------------------------------------------------------------------+
024. class C_AdjustTemplate
025. {
026.    private   :
027.       string m_szName[],
028.              m_szFind[],
029.              m_szReplace[],
030.              m_szFileName;
031.       int    m_maxIndex,
032.              m_FileIn,
033.              m_FileOut;
034.       bool   m_bFirst;
035. //+------------------------------------------------------------------+
036.    public   :
037. //+------------------------------------------------------------------+
038.       C_AdjustTemplate(const string szFile, const bool bFirst = false)
039.          :m_maxIndex(0),
040.           m_szFileName(szFile),
041.           m_bFirst(bFirst),
042.           m_FileIn(INVALID_HANDLE),
043.           m_FileOut(INVALID_HANDLE)
044.          {
045.             ResetLastError();
046.             if (m_bFirst)
047.             {
048.                int handle = FileOpen(m_szFileName, FILE_TXT | FILE_WRITE);
049.                FileWriteString(handle, IdeRad);
050.                FileClose(handle);
051.             }
052.             if ((m_FileIn = FileOpen(m_szFileName, FILE_TXT | FILE_READ)) == INVALID_HANDLE) SetUserError(C_Terminal::ERR_FileAcess);
053.             if ((m_FileOut = FileOpen(m_szFileName + "_T", FILE_TXT | FILE_WRITE)) == INVALID_HANDLE) SetUserError(C_Terminal::ERR_FileAcess);
054.          }
055. //+------------------------------------------------------------------+
056.       ~C_AdjustTemplate()
057.          {
058.             FileClose(m_FileIn);
059.             FileClose(m_FileOut);
060.             FileMove(m_szFileName + "_T", 0, m_szFileName, FILE_REWRITE);
061.             ArrayResize(m_szName, 0);
062.             ArrayResize(m_szFind, 0);
063.             ArrayResize(m_szReplace, 0);
064.          }
065. //+------------------------------------------------------------------+
066.       void Add(const string szName, const string szFind, const string szReplace)
067.          {
068.             m_maxIndex++;
069.             ArrayResize(m_szName, m_maxIndex);
070.             ArrayResize(m_szFind, m_maxIndex);
071.             ArrayResize(m_szReplace, m_maxIndex);
072.             m_szName[m_maxIndex - 1] = szName;
073.             m_szFind[m_maxIndex - 1] = szFind;
074.             m_szReplace[m_maxIndex - 1] = szReplace;
075.          }
076. //+------------------------------------------------------------------+
077.       string Get(const string szName, const string szFind)
078.          {
079.             for (int c0 = 0; c0 < m_maxIndex; c0++) if ((m_szName[c0] == szName) && (m_szFind[c0] == szFind)) return m_szReplace[c0];
080.             
081.             return NULL;
082.          }
083. //+------------------------------------------------------------------+
084.       void Execute(void)
085.       bool Execute(void)
086.          {
087.             string sz0, tmp, res[];
088.             int count0 = 0, i0;
089.                         
090.             if ((m_FileIn != INVALID_HANDLE) && (m_FileOut != INVALID_HANDLE)) while ((!FileIsEnding(m_FileIn)) && (_LastError == ERR_SUCCESS))
091.             if ((m_FileIn == INVALID_HANDLE) || (m_FileOut == INVALID_HANDLE)) return false;
092.             while (!FileIsEnding(m_FileIn))
093.             {
094.                sz0 = FileReadString(m_FileIn);
095.                if (sz0 == "<object>") count0 = 1;
096.                if (sz0 == "</object>") count0 = 0;
097.                if (count0 > 0) if (StringSplit(sz0, '=', res) > 1)
098.                {
099.                   if ((m_bFirst) && ((res[0] == "bmpfile_on") || (res[0] == "bmpfile_off")))
100.                      sz0 = res[0] + "=\\Indicators\\Replay\\Chart Trade.ex5::" + def_PATH_BTN + res[1];
101.                      sz0 = res[0] + "=\\Indicators\\Chart Trade.ex5::" + def_PATH_BTN + res[1];
102.                   i0 = (count0 == 1 ? 0 : i0);
103.                   for (int c0 = 0; (c0 < m_maxIndex) && (count0 == 1); i0 = c0, c0++) count0 = (res[1] == (tmp = m_szName[c0]) ? 2 : count0);
104.                   for (int c0 = i0; (c0 < m_maxIndex) && (count0 == 2); c0++) if ((res[0] == m_szFind[c0]) && (tmp == m_szName[c0]))
105.                   {
106.                      if (StringLen(m_szReplace[c0])) sz0 =  m_szFind[c0] + "=" + m_szReplace[c0];
107.                      else m_szReplace[c0] = res[1];
108.                   }
109.                }
110.                if (FileWriteString(m_FileOut, sz0 + "\r\n") < 2) return false;
111.             };
112.             
113.             return true;
114.          }
115. //+------------------------------------------------------------------+
116. };
117. //+------------------------------------------------------------------+
118. #undef def_BTN_BUY
119. #undef def_BTN_SELL
120. #undef def_BTN_DT
121. #undef def_BTN_SW
122. #undef def_BTN_MAX
123. #undef def_BTN_MIN
124. #undef def_IDE_RAD
125. #undef def_PATH_BTN
126. //+------------------------------------------------------------------+

Código fonte do arquivo C_AdjustTemplate.mqh

Veja que existem linhas que foram riscadas neste código. Vamos então entender o motivo disto ter ocorrido. A linha 14, foi modificada. No seu lugar agora usamos o código visto na linha 13. O fato de isto ter ocorrido, implica que a localização do arquivo template, foi modificada para uma nova localização. Não se preocupe, no anexo você terá acesso a estes arquivos, caso já não os tenha. Tudo que você terá que fazer, será manter a mesma estrutura que se encontra no anexo. Assim os recursos declarados aqui, poderão ser encontrados sem problemas. Muito bem, além desta mudança, temos outras linhas que também foram removidas.

A linha 45 foi removida, pelo motivo que foi explicado nos artigos anteriores. Ou seja, as vezes a variável _LastError, contém um valor, mas não por conta de uma falha na execução do código, mas por outro motivo qualquer. Sendo assim, não irei de fato, me preocupar com valores presentes na variável _LastError, salvo em casos especiais.

Agora vamos ver o caso da linha 90. Por que esta linha foi removida? O motivo é que a variável _LastError, pode estar com algum valor diferente de ERR_SUCESS, mas que não foi causado pela nossa aplicação. No entanto, justamente para evitar possíveis conflitos de interesse, as coisas mudaram aqui.

Nisto que antes era um procedimento e agora passou a ser uma função. Então voltemos a linha 84. Note que ela está riscada, no seu lugar temos a linha 85. Mas por que desta mudança? O motivo é que podemos ter algumas falhas e não precisamos fazer uso massivo e direto da variável _LastError.

É preciso que você compreenda, que a coisa aqui, neste indicador é bastante tensa. Diferente de ordens pendentes, onde um pequeno erro pode as vezes, e digo as vezes por motivos que veremos no futuro, podem ser tolerados. Aqui neste indicador, não podemos tolerar certos erros. Isto por que aqui faremos uso de um sistema a mercado.

Além disto, existe um outro agravante ainda mais sério. Mas este será visto em outro momento. Então precisamos garantir que os dados que estarão no arquivo template, são realmente os corretos.

Desta forma, caso as linhas 91 e 110 indiquem que ocorreu uma falha. Devemos reportar isto ao chamador. Que se encontra em um outro local que veremos depois. Mas se tudo estiver correto, o arquivo template, será modificado e isto será indicado como sucesso na linha 113. Simples assim.

Mas antes de fechar a explicação, sobre este arquivo de cabeçalho, quero que você preste atenção ao seguinte conteúdo presente na linha 101. Note que a linha 100, foi removida e no lugar dela temos a linha 101. A parte que é importante frisar é a string. Ela indica exatamente a localização esperada para o indicador Chart Trade. Ou seja, a localização mudou.

Você agora precisa deixar o indicador exatamente neste local indicado na string, e com o nome indicado. Isto por que quando esta string é usada, estaremos na realidade, acessando os arquivos bitmaps que estão declarados como recursos dentro do indicador. Se você mudar qualquer coisa aqui, seja no código, seja no nome do indicador, ou seja, na sua localização. O Metatrader 5, não conseguirá acessar os arquivos de bitmap, impossibilitando assim que o indicador Chart Trade, seja corretamente apresentado no gráfico.

Apesar de normalmente eu mostrar todos os arquivos de cabeçalho, antes de mostrar o código principal, desta vez farei diferente. Vamos pular um arquivo de cabeçalho, que basicamente é o principal deste indicador, e vamos ver o código fonte do arquivo do indicador. Este é mostrado na íntegra logo abaixo.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. #property description "Chart Trade Base Indicator."
04. #property description "See the articles for more details."
05. #property version   "1.74"
06. #property icon "/Images/Market Replay/Icons/Indicators.ico"
07. #property link "https://www.mql5.com/pt/articles/12413"
08. #property indicator_chart_window
09. #property indicator_plots 0
10. #property indicator_buffers 1
11. //+------------------------------------------------------------------+
12. #include <Market Replay\Chart Trader\C_ChartFloatingRAD.mqh>
13. //+------------------------------------------------------------------+
14. #define def_ShortName "Indicator Chart Trade"
15. //+------------------------------------------------------------------+
16. C_ChartFloatingRAD *chart = NULL;
17. //+------------------------------------------------------------------+
18. input long     user00 = 0;          //ID
19. input ushort   user01 = 1;          //Leverage
20. input double   user02 = 100.1;      //Finance Take
21. input double   user03 = 75.4;       //Finance Stop
22. //+------------------------------------------------------------------+
23. double m_Buff[];
24. //+------------------------------------------------------------------+
25. int OnInit()
26. {
27.    bool bErr;
28.       
29.    chart = new C_ChartFloatingRAD(user00, "Indicator Chart Trade", new C_Mouse(user00, "Indicator Mouse Study"), user01, user02, user03);
30.    chart = new C_ChartFloatingRAD(def_ShortName, new C_Mouse(0, "Indicator Mouse Study"), user01, user02, user03);
31.    
32.    if (_LastError >= ERR_USER_ERROR_FIRST) return INIT_FAILED;
33. 
34.    if (bErr = (_LastError != ERR_SUCCESS)) Print(__FILE__, " - [Error]: ", _LastError);
35. 
36.    SetIndexBuffer(0, m_Buff, INDICATOR_DATA);
37.    ArrayInitialize(m_Buff, EMPTY_VALUE);
38.    
39.    return (bErr ? INIT_FAILED : INIT_SUCCEEDED);
40.    return INIT_SUCCEEDED;
41. }
42. //+------------------------------------------------------------------+
43. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[])
44. {
45.    (*chart).MountBuffer(m_Buff, rates_total);
46.    
47.    return rates_total;
48. }
49. //+------------------------------------------------------------------+
50. void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
51. {
52.    if (_LastError < ERR_USER_ERROR_FIRST) 
53.       (*chart).DispatchMessage(id, lparam, dparam, sparam);
54.    (*chart).MountBuffer(m_Buff);
55.    
56.    ChartRedraw();
57. }
58. //+------------------------------------------------------------------+
59. void OnDeinit(const int reason)
60. {
61.    switch (reason)
62.    {
63.       case REASON_INITFAILED:
64.          ChartIndicatorDelete(ChartID(), 0, def_ShortName);
65.          break;
66.       case REASON_CHARTCHANGE:
67.          (*chart).SaveState();
68.          break;
69.    }
70. 
71.    delete chart;
72. }
73. //+------------------------------------------------------------------+

Código fonte do Indicador Chart Trade

Olhando de forma rápida este código, ele pode parecer complicado, mas talvez seja por conta das linhas que estão riscadas. O motivo de se ter tantas linhas riscadas, é justamente pelo fato, de que este código é uma modificação do código original.

Se você não o viu, pode ver o original no artigo Desenvolvendo um sistema de Replay (Parte 47): Projeto do Chart Trade (VI), mas não fique tentado em usar o código visto naquele artigo. Este código daqui tem um funcionamento completamente diferente. E apesar de parecer complicado. Ele é na verdade, muito simples. O motivo desta simplicidade é o fato de que toda a complexidade foi colocada no arquivo de cabeçalho. Mas então vamos entender muito bem, como este código aqui funciona. Pois isto é extremamente necessário para compreender o arquivo de cabeçalho que veremos depois.

Vamos por partes, como diria Jack. Basicamente o que mais acontece aqui, são remoções do que modificações propriamente ditas. Então a primeira coisa que removemos é a linha 10. Você pode notar isto, ao ver que ela se encontra riscada.

Caramba, agora complicou tudo de vez. O fato de removermos do indicador, a propriedade que define a quantidade de buffers, que estamos usando, indica para o compilador, que não usaremos nenhum buffer. Isto por que o valor padrão desta propriedade é zero. Ou seja, o indicador não terá nenhum dado, sendo colocado dentro de buffer interno. Isto para que algum outro programa possa acessar os dados via CopyBuffer.

Por conta disto, muitos podem dizer que agora a coisa complicou de vez. Mas se ainda assim, você não entendeu, ou não compreende, o que a ausência de um buffer, pode causar em um indicador. Significa que você ainda, não entendeu, realmente como as coisas funcionam no MetaTrader 5 e no MQL5. Mas vou tentar explicar, para você, que ainda é um aspirante e deseja aprender a programar as coisas em MQL5.

Um indicador, basicamente serve para nós auxiliar, em alguma questão. Seja ela um cálculo, indicação ou como no caso, apresentar uma interface de interação com o usuário. Em qualquer um destes casos, mas principalmente no último, poderíamos usar outros tipos de programas como por exemplo: Scripts. O problema dos scripts, é que quando se muda o tempo gráfico, o script é removido e não retorna automaticamente. Precisando que você, ou o usuário, o recoloque no gráfico. Isto em alguns casos é um aborrecimento, que contornamos usando outros meios, e um destes é usando um indicador.

Porém indicadores não são adequados, quando precisamos temporizar as coisas. Isto por conta que, ao adicionar um temporizador em um indicador, ele irá, de fato afetar, todos os outros indicadores presentes no gráfico. Então quando precisamos temporizar algo e não queremos, ou não desejamos colocar o código em um script. Colocamos o código em um Expert Advisor ou em um serviço. A escolha de em qual colocar, dependerá única e exclusivamente do propósito da temporização.

Pois bem, este Chart Trade, poderia ser colocado em um serviço ou em um Expert Advisor. Não precisaria necessariamente ficar em um indicador. Mas colocar ele em um serviço, poderia ser interessante, caso desejássemos ter o Chart Trade sendo executado em todo e qualquer gráfico. Assim o próprio serviço iria de fato tomar conta, para que os objetos do Chart Trade, fossem mostrados no gráfico correto.

O problema deste tipo de abordagem, é justamente a questão dos eventos. Serviços não contam com nenhum tratador de eventos. Eles basicamente são scripts que não ficam atrelados a um gráfico. Então ao fazer uso de um serviço para implementar o Chart Trade, nos forçaria a ter de criar um indicador. Este indicador, iria apenas e somente fornecer o tratamento de eventos, a fim de tornar o serviço consciente de possíveis manobras executadas no Chart Trade. Isto quando o usuário, fizesse algo, como clicar em um dos botões, ou acionar algum evento relacionado ao Chart Trade.

Veja como uma coisa relativamente simples, pode muitas das vezes se tornar bastante complicada. Agora e quando usar o Chart Trade dentro de um Expert Advisor? Parece algo plausível. De fato, devo concordar em parte. Isto por que, colocar o Chart Trade entro de um Expert Advisor, é de fato plausível. Porém inviável.

E por que motivo isto seria inviável? O motivo é simples e atende pelo nome de diversificação. Vamos pensar um pouco: Se você decide colocar o Chart Trade, dentro de um Expert Advisor. Terá o Chart Trade, apenas e tão somente neste único Expert Advisor. Se você desejar criar um outro Expert Advisor, seja lá por que motivo for. Terá que adicionar todo o código do Chart Trade, neste outro Expert Advisor. Bem, mas você pode colocar isto facilmente, usando para isto a include que é mostrada na linha 12. Certamente que sim. E funcionaria perfeitamente bem. Mas e se você decidir melhorar algo no código do Chart Trade? Teria que fazer uma nova compilação de todos os Expert Advisores, a fim de que eles fossem atualizados. Isto seria muito mais trabalhoso, do que prático.

Muito bem, mas você poderia pensar em colocar o Chart Trade, ainda dentro de um Expert Advisor. E mesmo assim não precisar fazer uma nova compilação de todos os Expert Advisores, quando o Chart Trade, fosse melhorado. Sim isto também é algo que você pode pensar em fazer. Bastaria para isto usar algo parecido com uma DLL. Mas este tipo de coisa, mais complicaria a programação, do que traria resultados realmente interessantes. Por conta disto que ficou decidido colocar o Chart Trade, dentro de um indicador. Mas diferente do que era feito antes. Agora não mais teremos um buffer, que irá de fato conter os dados para serem lidos. A coisa aqui será feita de uma outra forma. Mas isto será visto depois. Então vamos continuar a explicação do código, pois ainda temos coisas a serem compreendidas, dentro deste código.

Agora quero chamar a sua atenção para a linha 14. O fato desta definição está sendo feita, após a inclusão que é feita na linha 12, faz muita diferença. Pois diferente de variáveis globais, uma definição que é colocada antes ou depois de um include, permite você controlar como as coisas acontecerão. Ou no mínimo, permitir que você teste algumas coisas, dentro ou fora do código presente nos arquivos de cabeçalho. Então atenção a isto.

Já que a definição, está sendo feita após a include do arquivo de cabeçalho C_ChartFloatingRAD.mqh. Isto implica, que ela não será vista e não poderá ser usada no arquivo de cabeçalho C_ChartFloatingRAD.mqh. No entanto, se esta mesma definição, presente na linha 14, fosse colocada antes do include, presente na linha 12. Ela poderia ser usada e seria visível, pelo código presente no arquivo de cabeçalho C_ChartFloatingRAD.mqh. Ou seja, a ordem dos fatores, afeta o produto ou resultado, quando o assunto é programação. Mas vamos continuar, pois existem algumas coisas ainda a serem vistas. E as mesmas podem lhe ser de interesse.

A linha 18 foi removida, pois não existe mais necessidade de fazer uso deste meio. Já que o usuário, é que será responsável por colocar o indicador Chart Trade no gráfico. Então não precisamos dizer qual é a ID do gráfico. Agora já a linha 23, foi removida, não por conta da remoção da linha 10. Uma coisa, não tem nenhuma relação com a outra. A linha 10, como expliquei antes, serve para dizer se existe, e quando existe, qual o número de buffers que podemos acessar fora do indicador. Isto fazendo uso da chamada CopyBuffer. Mas nada impediria de que internamente o indicador tivesse buffer. Porém, como eles não são necessários, a linha 23 foi riscada. A mesma coisa se dá em relação as linhas 36 e 37. Já que não estamos usando nenhum buffer, não precisamos destas linhas.

Dentro deste código OnInit, você pode ver que muito foi riscado. Grande parte por conta de mudanças que serão vistas no próximo artigo, onde explicarem em detalhes o código do arquivo de cabeçalho C_ChartFloatingRAD.mqh. Mas dentro de tantas linhas riscadas, apenas três linhas realmente fazem algo. Então vamos entender estas poucas linhas. Começando com a linha 30. Nesta linha iniciamos a classe C_ChartFloatingRAD. Isto é feito via constructor pela chamada do operador NEW. Porém como você já deve saber, constructores não retornam nenhum valor. A maneira como verificamos se o código do constructor falhou ou não é usando outro meio para isto.

Em programas mais, modulares em temos de estrutura de chamadas. O constructor, e este é o real trabalho dele, apenas inicializa corretamente algumas variáveis e dados dentro da classe. Porém como não existe uma proibição, e sim uma conversão, podemos fazer com que o constructor faça um pouco mais de coisas. E é neste ponto que a coisa pode desandar. Sem um meio de informar se o trabalho do constructor, falhou ou não. Ficamos sem ter como resolver os problemas de inicialização.

Felizmente o MQL5 nos permite fazer isto. É bem verdade que não é algo assim tão adequado, porém funciona. Então na linha 32 verificamos o valor da variável _LastError. Caso ela tenha recebido um valor, definido por nos. Indicará que a inicialização falhou. Não estou certo, que irei de fato manter as coisas desta maneira. Mas talvez o faça por conta da linha 52. Mas calma. Vamos chegar lá. Então se na linha 32, foi indicado que a inicialização falhou. Fazemos com que a função OnInit retorne ao MetaTrader 5, uma constante de erro. Ao receber esta constante, o MetaTrader 5, irá em algum momento, disparar a chamada OnDeInit, que removerá o indicador do gráfico. Isto é feito automaticamente. Se tudo funcionar, OnInit retornará uma constante indicando sucesso. Isto é feito na linha 40.

Agora observe as linhas 45 e 54. Ambas eram usadas para montar o buffer. Mas como agora não temos mais um buffer, as mesmas se tornaram obsoletas e por isto foram removidas. Você pode facilmente ver isto, ao notar que elas estão riscadas. No entanto, quero que olhe o teste na linha 52. Este não faz o mínimo sentido neste momento. Porém sem este teste a chamada da linha 53 irá com toda a certeza falhar em algum momento. Mas o motivo de que está chamada da linha 53 falhará, sem o teste na linha 52, somente será entendido no próximo artigo. Já que no próximo artigo é que explicarei a classe C_ChartFloatingRAD.

Para terminar, vamos olhar a última coisa presente neste código. Ou seja, o procedimento OnDeInit. Este procedimento é chamado pelo MetaTrader 5, automaticamente, quando o indicador tiver que ser removido do gráfico. Mas aqui temos algo muito, mas muito incomum em se tratando de OnDeInit. Estou falando da linha 64. Por que motivo, esta linha está sendo colocada no código? Isto não faz o menor sentido. De fato, não faz. Mas isto por que, você está apenas observando este código, sem conhecer o código da classe C_ChartFloatingRAD. Se você observar apenas e tão somente este código daqui. Existe somente um único motivo para que REASON_INITFAILED, seja a constante usada na chamada a OnDeInit. E este único motivo é a linha 32. Porém existem outros, que estão no código da classe C_ChartFloatingRAD. E como eu gostaria de centralizar a execução de certas coisas, a linha 64 surgiu. E o que esta linha 64 faz é exatamente a remoção do indicador Chart Trade do gráfico. Mas o verdadeiro motivo, será visto no próximo artigo.


Considerações finais

Neste artigo, apresentei, parte das mudanças que o indicador Chart Trade sofreu. Não tente entender, ou usar o código visto aqui, sem antes ver o código que será visto no próximo artigo. Já que sem entender e conhecer o código da classe C_ChartFloatingRAD, você acabará por fazer besteiras. Tenha um pouco de paciência e aguarde o próximo artigo. Pois o conteúdo que será explicado nele, realmente valerá a pena. Isto por que é naquela classe que se encontrar realmente o indicador Chart Trade.

De um modo ou de outro, caso queira compilar este código, não se esqueça que as informações usadas no arquivo de cabeçalho C_AdjustTemplate.mqh, se encontra no anexo. Mas nada impede de você criar as suas próprias imagens e modelo de template a ser usado no Chart Trade. Apenas garanta que eles sejam adequados, ao que é esperado pela classe C_AdjustTemplate. Então, é isto dai, e não se esqueça de ler o próximo artigo desta sequência.

Arquivos anexados |
Anexo.zip (9.92 KB)
Algoritmo de otimização por reações químicas — Chemical Reaction Optimization, CRO (Parte I): A química dos processos na otimização Algoritmo de otimização por reações químicas — Chemical Reaction Optimization, CRO (Parte I): A química dos processos na otimização
Na primeira parte deste artigo, mergulharemos no mundo das reações químicas e descobriremos uma nova abordagem para a otimização! O método de otimização por reações químicas (CRO) utiliza os princípios das leis da termodinâmica para alcançar resultados eficazes. Revelaremos os segredos da decomposição, síntese e outros processos químicos que servem de base para este método inovador.
Simplificando a negociação com base em notícias (Parte 2): Gerenciando riscos Simplificando a negociação com base em notícias (Parte 2): Gerenciando riscos
Neste artigo, adicionaremos herança ao código anterior e ao novo. Implementaremos uma nova estrutura de banco de dados para garantir um bom desempenho. Além disso, criaremos uma classe de gerenciamento de risco para calcular volumes.
Algoritmo de otimização por reações químicas — Chemical Reaction Optimisation, CRO (Parte II): Montagem e resultados Algoritmo de otimização por reações químicas — Chemical Reaction Optimisation, CRO (Parte II): Montagem e resultados
Na segunda parte do artigo, reuniremos os operadores químicos em um único algoritmo e apresentaremos uma análise detalhada de seus resultados. Descobriremos como o método de otimização por reações químicas (CRO) superou o desafio de resolver problemas complexos em funções de teste.
Redes neurais de maneira fácil (Parte 90): Interpolação Frequencial de Séries Temporais (FITS) Redes neurais de maneira fácil (Parte 90): Interpolação Frequencial de Séries Temporais (FITS)
Ao estudarmos o método FEDformer, abrimos uma porta para a área de representação de séries temporais no domínio da frequência. No novo artigo, continuaremos o tema iniciado, e analisaremos um método que permite não apenas conduzir uma análise, mas também prever estados futuros no domínio frequencial.