English Русский 中文 Español Deutsch 日本語
preview
Desenvolvendo um sistema de Replay (Parte 71): Acertando o tempo (IV)

Desenvolvendo um sistema de Replay (Parte 71): Acertando o tempo (IV)

MetaTrader 5Exemplos |
294 0
Daniel Jose
Daniel Jose

Introdução

No artigo anterior Desenvolvendo um sistema de Replay (Parte 70): Acertando o tempo (III), expliquei as modificações que foram necessárias no indicador de mouse. Tais mudanças, tem como objetivo permitir que o indicador de mouse, venha a receber eventos de book. Isto quando o indicador de mouse, estivesse sendo usado junto da aplicação de replay/simulação. Você caro leitor, pode ter ficado bastante indignado e confuso, com todas aquelas mudanças. Sei que muitas delas no primeiro momento, não fazem o mínimo sentido. Sendo muito mais confusas do que eu gostaria de fato mostrar. No entanto, será preciso que você tenha compreendido integralmente aquele conteúdo. Por mais confuso que o mesmo venha a se apresentar, no primeiro momento. Sei que muitos de vocês, irão de fato ter dificuldades, no início em compreender o que tentei explicar lá. Porém sem entender, aquele conteúdo, onde usei um serviço, consideravelmente mais simples, a fim de mostrar como a coisa funciona. Tentar entender o que será explicado aqui, será muito mais complicado. 

Então antes de tentar entender, o que estarei de fato fazendo, neste artigo. Entenda o que foi visto no artigo anterior. Principalmente a parte referente, ao fato de que ao adicionar eventos de book, no ativo customizado. Passamos a ter a capacidade, de usar a função OnCalculate de uma forma, que antes não era possível. Nos forçando a usar uma chamada iSpread, a fim de conseguir obter os dados que o MetaTrader 5, deixará disponível para nós.

Neste artigo, iremos de fato fazer, a transferência. Ou melhor dizendo: A transcrição de parte daquele código, visto no serviço de teste, para dentro do serviço de replay/simulação. A questão aqui não é nem é como podemos fazer isto. Mas sim como deveremos fazer isto.

Quero lembrar a você, caro leitor, que até o artigo passado, onde estávamos trabalhando no serviço de replay/simulador. O indicador de mouse, era carregado via template. No entanto, agora não farei isto mais. Você pode experimentar, tentar manter o indicador de mouse, sendo carregado pelo template. Mas devido a algumas questões práticas, passarei a colocar o indicador de mouse, de maneira manual no gráfico do ativo, que está sendo usado para gerar o replay/simulação. Então não estranhe, se em algum vídeo, eu mostrar as coisas desta maneira. Tenho meus motivos para fazer isto. Porém não entrarei em detalhes sobre eles. Então sem mais delongas, vamos começar a transcrever o código do serviço de teste, para o serviço de replay/simulação.


Iniciando a transcrição

A primeira coisa, que iremos de fato fazer, será modificar uma parte do código, do arquivo de cabeçalho C_Replay.mqh. Preste atenção ao seguinte fragmento:

197. //+------------------------------------------------------------------+
198.       bool InitBaseControl(const ushort wait = 1000)
199.          {
200.             Print("Waiting for Mouse Indicator...");
201.             Sleep(wait);
202.             while ((def_CheckLoopService) && (ChartIndicatorGet(m_Infos.IdReplay, 0, "Indicator Mouse Study") == INVALID_HANDLE)) Sleep(200);
203.             if (def_CheckLoopService)
204.             {
205.                AdjustViewDetails();
206.                Print("Waiting for Control Indicator...");
207.                if ((m_IndControl.Handle = iCustom(ChartSymbol(m_Infos.IdReplay), ChartPeriod(m_Infos.IdReplay), "::" + def_IndicatorControl, m_Infos.IdReplay)) == INVALID_HANDLE) return false;
208.                ChartIndicatorAdd(m_Infos.IdReplay, 0, m_IndControl.Handle);
209.                UpdateIndicatorControl();
210.             }
211.             
212.             return def_CheckLoopService;
213.          }
214. //+------------------------------------------------------------------+

Fragmento de código do arquivo C_Replay.mqh

Este fragmento é o código original. Agora quero que preste atenção ao seguinte fato. Este código, foi projetado para trabalhar, quando o indicador de mouse, estivesse em um template. Mas como irei de agora em diante, colocar o indicador de mouse, de forma manual. Este código já não é assim tão adequado. Na verdade, ele ainda funcionaria. Mas podemos melhorar o mesmo, a fim de ter uma configuração, tanto de mensagens quanto de execução mais adequada. Assim sendo, o novo código que será usado, pode ser visto no fragmento logo abaixo:

197. //+------------------------------------------------------------------+
198.       bool InitBaseControl(const ushort wait = 1000)
199.          {
200.             Sleep(wait);
201.             AdjustViewDetails();
202.             Print("Loading Control Indicator...");
203.             if ((m_IndControl.Handle = iCustom(ChartSymbol(m_Infos.IdReplay), ChartPeriod(m_Infos.IdReplay), "::" + def_IndicatorControl, m_Infos.IdReplay)) == INVALID_HANDLE) return false;
204.             ChartIndicatorAdd(m_Infos.IdReplay, 0, m_IndControl.Handle);
205.             Print("Waiting for Mouse Indicator...");
206.             while ((def_CheckLoopService) && (ChartIndicatorGet(m_Infos.IdReplay, 0, "Indicator Mouse Study") == INVALID_HANDLE)) Sleep(200);
207.             UpdateIndicatorControl();
208.             
209.             return def_CheckLoopService;
210.          }
211. //+------------------------------------------------------------------+

Fragmento do arquivo C_Replay.mqh

Basicamente, quase nada mudou em termos de código. Mas as mensagens apresentadas, demonstram de forma mais clara o que está acontecendo. Assim como o fato de que agora, invertemos a ordem de execução. Desta maneira, iremos primeiramente tentar carregar o indicador de controle, que é um recurso do aplicativo de replay/simulador. Isto por que ele se encontra, embutido no executável de replay/simulador. Para somente depois carregar o indicador de mouse. Perceba o seguinte fato. Se o indicador de controle, que está incluso no serviço não pode ser carregado, isto indica que temos uma falha grave. Porém se ele foi carregado, informar ao usuário que precisamos do indicador de mouse seja carregado. Ao meu ver isto é bem mais adequado. Porém sinta-se à vontade em colocar a ordem que desejar. De qualquer maneira, o indicador de controle não irá de fato funcionar, sem que o indicador de mouse esteja presente no gráfico.

Esta mudança, é quase apenas estética. Mas agora vamos as mudanças, que realmente darão suporte as mensagens de book. Novamente se você não entendeu o artigo, anterior, volte a ele e entenda usando aquele código. Não tente entender, como as coisas funcionam, usando este código que será visto a partir deste ponto. Se você tentar fazer isto, irá se enrolar tudinho e não entenderá absolutamente nada.

Precisamos adicionar uma nova linha no constructor da classe. Esta nova linha pode ser vista no fragmento de código logo abaixo:

149. //+------------------------------------------------------------------+
150.       C_Replay()
151.          :C_ConfigService()
152.          {
153.             Print("************** Market Replay Service **************");
154.             srand(GetTickCount());
155.             SymbolSelect(def_SymbolReplay, false);
156.             CustomSymbolDelete(def_SymbolReplay);
157.             CustomSymbolCreate(def_SymbolReplay, StringFormat("Custom\\%s", def_SymbolReplay));
158.             CustomSymbolSetDouble(def_SymbolReplay, SYMBOL_TRADE_TICK_SIZE, 0);
159.             CustomSymbolSetDouble(def_SymbolReplay, SYMBOL_TRADE_TICK_VALUE, 0);
160.             CustomSymbolSetDouble(def_SymbolReplay, SYMBOL_VOLUME_STEP, 0);
161.             CustomSymbolSetString(def_SymbolReplay, SYMBOL_DESCRIPTION, "Symbol for replay / simulation");
162.             CustomSymbolSetInteger(def_SymbolReplay, SYMBOL_DIGITS, 8);
163.             CustomSymbolSetInteger(def_SymbolReplay, SYMBOL_TICKS_BOOKDEPTH, 1);
164.             SymbolSelect(def_SymbolReplay, true);
165.             m_Infos.CountReplay = 0;
166.             m_IndControl.Handle = INVALID_HANDLE;
167.             m_IndControl.Mode = C_Controls::ePause;
168.             m_IndControl.Position = 0;
169.             m_IndControl.Memory._16b[C_Controls::eCtrlPosition] = C_Controls::eTriState;
170.          }
171. //+------------------------------------------------------------------+

Fragmento do arquivo C_Replay.mqh

A nova linha em questão, é justamente a linha 163. Feito isto, já podemos fazer uso das mensagens de book. Agora preste bastante atenção a um detalhe aqui. Na verdade, o detalhe não está no arquivo de cabeçalho C_Replay.mqh. Mas sim no indicador de mouse. Então vamos tomar emprestado um fragmento do indicador, para entender uma coisa. Pois é importante.

27. //+------------------------------------------------------------------+
28. int OnInit()
29. {
30.    Study = new C_Study(0, "Indicator Mouse Study", user02, user03, user04);
31.    if (_LastError >= ERR_USER_ERROR_FIRST) return INIT_FAILED;
32.    MarketBookAdd((*Study).GetInfoTerminal().szSymbol);
33.    OnBookEvent((*Study).GetInfoTerminal().szSymbol);
34.    m_Status = C_Study::eCloseMarket;
35.    SetIndexBuffer(0, m_Buff, INDICATOR_DATA);
36.    ArrayInitialize(m_Buff, EMPTY_VALUE);
37.    
38.    return INIT_SUCCEEDED;
39. }
40. //+------------------------------------------------------------------+

Fragmento do arquivo Indicador de mouse

Observe que na linha 34, estamos indicando um status inicial para o indicador de mouse. Este irá de fato, mostrar no indicador que o mercado se encontra fechado. Mas não estamos de fato lidando com o mercado físico. Estamos em uma aplicação, que tem como objetivo primário, nos permitir executar um replay ou simulação de possíveis movimentos de mercado. Então a mensagem que está sendo informada pelo indicador de mouse, quando estamos no ativo customizado para replay/simulação está errada. Mas isto é muito, mas muito simples de ser corrigido. Mas antes de corrigir isto, é preciso que você entenda, que no momento em que o indicador de controle é colocado no gráfico. O replay/simulação se encontra de fato em modo pause. Isto quando a aplicação está sendo inicializada do início. Agora temos que tomar uma decisão. Esta decisão afetará profundamente os próximos acontecimentos.

Vamos pensar o seguinte: Quando estivermos no modo pause, o indicador de mouse, deverá mostrar uma mensagem de leilão. Ou o tempo restante da barra? Se for mostrar o tempo da barra, queremos que isto seja informado, antes do primeiro play, ou apenas depois de ter dado o primeiro play? Talvez isto tenha ficado um pouco confuso. Então vamos pensar o seguinte: Antes do mercado de fato abrir, é feito um leilão, a fim de que os participantes, possam posicionar suas ordens no melhor preço. Este preço é onde eles de fato querem comprar ou vender. Então assim que a aplicação de replay/simulação, fizer com que o MetaTrader 5, abra o gráfico. E o indicador de mouse, seja visível, o que deveremos ver é uma mensagem de leilão. Isto é fato. Agora quando você, habilitar a simulação ou replay, qual a mensagem que deverá aparecer, quando for dado pause? Você gostaria de ver a mensagem de leilão? Ou a mensagem de tempo restante da barra atual? Esta é a questão da qual devemos pensar. De qualquer forma, a primeira coisa que temos de fazer, é garantir que no momento que a aplicação iniciar, apresentemos que estamos em leilão.

Fazer isto é algo bastante simples. Veja o fragmento abaixo.

212. //+------------------------------------------------------------------+
213.       bool LoopEventOnTime(void)
214.          {         
215.             int iPos, iCycles;
216.             MqlBookInfo book[1];
217.             
218.             book[0].price = 1.0;
219.             book[0].volume = 1;
220.             book[0].type = BOOK_TYPE_BUY_MARKET;
221.             CustomBookAdd(def_SymbolReplay, book, 1);            
222.             while ((def_CheckLoopService) && (m_IndControl.Mode != C_Controls::ePlay))
223.             {
224.                UpdateIndicatorControl();
225.                Sleep(200);
226.             }
227.             m_MemoryData = GetInfoTicks();
228.             AdjustPositionToReplay();
229.             iPos = iCycles = 0;
230.             while ((m_Infos.CountReplay < m_MemoryData.nTicks) && (def_CheckLoopService))
231.             {
232.                if (m_IndControl.Mode == C_Controls::ePause) return true;
233.                iPos += (int)(m_Infos.CountReplay < (m_MemoryData.nTicks - 1) ? m_MemoryData.Info[m_Infos.CountReplay + 1].time_msc - m_MemoryData.Info[m_Infos.CountReplay].time_msc : 0);
234.                CreateBarInReplay(true);
235.                while ((iPos > 200) && (def_CheckLoopService) && (m_IndControl.Mode != C_Controls::ePause))
236.                {
237.                   Sleep(195);
238.                   iPos -= 200;
239.                   m_IndControl.Position = (ushort)((m_Infos.CountReplay * def_MaxSlider) / m_MemoryData.nTicks);
240.                   UpdateIndicatorControl();
241.                   iCycles = (iCycles == 4 ? RateUpdate(false) : iCycles + 1);
242.                }
243.             }
244. 
245.             return ((m_Infos.CountReplay == m_MemoryData.nTicks) && (def_CheckLoopService));
246.          }
247. };
248. //+------------------------------------------------------------------+

Fragmento do arquivo C_Replay.mqh

Aqui é a parte fácil do que de fato teremos de implementar. Farei a implementação aos poucos, isto para que você de fato consiga acompanhar o que estará sendo feito. Veja que na linha 216, temos uma nova variável. Está na verdade é um array com o um comprimento de uma unidade. Agora vem a parte interessante.

Você muito provavelmente, deverá imaginar, que os valores a serem lançados em um evento de book, precisam ter algum significado. Bem, na verdade eles não precisam significar absolutamente nada. Temos apenas que fazer, com que os valores a dispararem o evento de book, tenham algum tipo de lógica. Eles de fato não precisam significar nada. Salvo o fato de você desejar simular o book. Mas não tenho esta intenção. Pelo menos no momento. Quem sabe no futuro.

De qualquer maneira, as linhas 218 e 219, serão utilizadas para dar ao MetaTrader 5 algo para o book. Estes valores não tem nenhum significado especial. Eles apenas servem para dar suporte, ao que realmente me interessa, que é a linha 220. Nesta linha estamos informando ao book que temos uma posição, indicativa de leilão. Se você não entendeu, veja novamente o artigo anterior para entender isto. Na linha 221, dizemos ao MetaTrader 5 para disparar um evento customizado de book. Este evento será capturado pela função OnEventBook, que no caso se encontra no indicador de mouse. Resultado: Toda a vez que a função LoopEventOnTime entra, o indicador de mouse, irá de fato mostrar que estamos em leilão. Existem dois casos em que temos uma execução do início da função LoopEventOnTime. O primeiro caso é quando a aplicação está sendo inicializada. O segundo caso, é quando o usuário interage com o indicador de controle, pressionando o botão que dá pause no sistema. Então a linha 232 é executada e logo em seguida a função LoopEventOnTime volta a ser executada. Notaram como a coisa é simples. Mas e agora, que já temos a mensagem de leilão sendo impressa. Como podemos mostrar a informação de tempo restante das barras? Bem esta é a parte ainda mais simples. Para isto teremos que modificar o fragmento acima para o fragmento logo abaixo.

212. //+------------------------------------------------------------------+
213.       bool LoopEventOnTime(void)
214.          {         
215.             int iPos, iCycles;
216.             MqlBookInfo book[1];
217.             
218.             book[0].price = 1.0;
219.             book[0].volume = 1;
220.             book[0].type = BOOK_TYPE_BUY_MARKET;
221.             CustomBookAdd(def_SymbolReplay, book, 1);
222.             while ((def_CheckLoopService) && (m_IndControl.Mode != C_Controls::ePlay))
223.             {
224.                UpdateIndicatorControl();
225.                Sleep(200);
226.             }
227.             m_MemoryData = GetInfoTicks();
228.             AdjustPositionToReplay();
229.             iPos = iCycles = 0;
230.             book[0].type = BOOK_TYPE_BUY;
231.             CustomBookAdd(def_SymbolReplay, book, 1);
232.             while ((m_Infos.CountReplay < m_MemoryData.nTicks) && (def_CheckLoopService))
233.             {
234.                if (m_IndControl.Mode == C_Controls::ePause) return true;
235.                iPos += (int)(m_Infos.CountReplay < (m_MemoryData.nTicks - 1) ? m_MemoryData.Info[m_Infos.CountReplay + 1].time_msc - m_MemoryData.Info[m_Infos.CountReplay].time_msc : 0);
236.                CreateBarInReplay(true);
237.                while ((iPos > 200) && (def_CheckLoopService) && (m_IndControl.Mode != C_Controls::ePause))
238.                {
239.                   Sleep(195);
240.                   iPos -= 200;
241.                   m_IndControl.Position = (ushort)((m_Infos.CountReplay * def_MaxSlider) / m_MemoryData.nTicks);
242.                   UpdateIndicatorControl();
243.                   iCycles = (iCycles == 4 ? RateUpdate(false) : iCycles + 1);
244.                }
245.             }
246. 
247.             return ((m_Infos.CountReplay == m_MemoryData.nTicks) && (def_CheckLoopService));
248.          }
249. };
250. //+------------------------------------------------------------------+

Fragmento do arquivo C_Replay.mqh

Notaram a diferença? Sim; Não; Talvez. Bem se você não notou a diferença é por estar muito distraído. Pois a diferença é justamente a inclusão das linhas 230 e 231. Estas duas singelas linhas fazem com que, no momento que o usuário vim a dar play no serviço de replay/simulação. O indicador de mouse receberá um evento customizado de book. Este evento informa que, saímos da condição de leilão e passamos para a condição de ativo em negociação. Assim o tempo restante da barra atual, passará a ser mostrado no indicador de mouse. Muito simples não é mesmo? Porém agora temos uma condição, um pouco mais complicada para resolver.

No mercado real, ou seja, quando estamos ligados ao servidor de negociação. Existem momentos em que pode ser do ativo, venha a ficar suspenso, ou entrar em leilão. Isto acontece, por conta de algumas regras bem específicas. Já expliquei sobre isto no artigo anterior. Mas aqui vamos fazer o seguinte: Vamos criar uma regra bastante simples. Se o ativo por ventura ter entre um tick e outro, um tempo igual ou superior a 60 segundos. Faremos com que o indicador de mouse, diga que o ativo entrou em leilão. Esta é a parte simples. A parte complicada é como fazer o indicador de mouse voltar a mostrar o tempo restante da barra?

Você pode dizer o seguinte: Quando o ativo entrar em leilão enviamos a constante BOOK_TYPE_BUY_MARKET para o book e quando ele sair enviaremos BOOK_TYPE_BUY. Sim. É isto que temos que fazer. Mas novamente. Como fazer isto? Pense o seguinte: Não queremos fazer a função LoopEventOnTime, venha a ser executada do início. Queremos manter o sistema rodando dentro do laço que se começa na linha 232 e termina na linha 245. Então se você fizer com que a constante BOOK_TYPE_BUY_MARKET e BOOK_TYPE_BUY sejam enviadas dentro deste laço terá que tomar alguns cuidados. Isto por que, cada chamada a CustomBookAdd, com estas diferentes constantes, irá com toda a certeza produzir um efeito desagradável para quem estiver observando o indicador de mouse. Isto por que ele ficará piscando e alternando entre o tempo restante e a palavra LEILÃO.

Então por conta disto, temos que ser criativos. E fazer uma implementação, que não cause este efeito. Mas que ao mesmo tempo consiga solucionar o nosso problema. A solução que proponho é vista no fragmento abaixo:

212. //+------------------------------------------------------------------+
213.       bool LoopEventOnTime(void)
214.          {         
215.             int iPos, iCycles;
216.             MqlBookInfo book[1];
217.             ENUM_BOOK_TYPE typeMsg;
218.             
219.             book[0].price = 1.0;
220.             book[0].volume = 1;
221.             book[0].type = BOOK_TYPE_BUY_MARKET;
222.             CustomBookAdd(def_SymbolReplay, book, 1);
223.             while ((def_CheckLoopService) && (m_IndControl.Mode != C_Controls::ePlay))
224.             {
225.                UpdateIndicatorControl();
226.                Sleep(200);
227.             }
228.             m_MemoryData = GetInfoTicks();
229.             AdjustPositionToReplay();
230.             iPos = iCycles = 0;
231.             book[0].type = BOOK_TYPE_BUY;
232.             CustomBookAdd(def_SymbolReplay, book, 1);
233.             while ((m_Infos.CountReplay < m_MemoryData.nTicks) && (def_CheckLoopService))
234.             {
235.                if (m_IndControl.Mode == C_Controls::ePause) return true;
236.                iPos += (int)(m_Infos.CountReplay < (m_MemoryData.nTicks - 1) ? m_MemoryData.Info[m_Infos.CountReplay + 1].time_msc - m_MemoryData.Info[m_Infos.CountReplay].time_msc : 0);
237.                if ((typeMsg = (iPos >= 60000 ? BOOK_TYPE_BUY_MARKET : BOOK_TYPE_BUY)) != book[0].type)
238.                {
239.                   book[0].type = typeMsg;
240.                   CustomBookAdd(def_SymbolReplay, book, 1);                  
241.                }
242.                CreateBarInReplay(true);
243.                while ((iPos > 200) && (def_CheckLoopService) && (m_IndControl.Mode != C_Controls::ePause))
244.                {
245.                   Sleep(195);
246.                   iPos -= 200;
247.                   m_IndControl.Position = (ushort)((m_Infos.CountReplay * def_MaxSlider) / m_MemoryData.nTicks);
248.                   UpdateIndicatorControl();
249.                   iCycles = (iCycles == 4 ? RateUpdate(false) : iCycles + 1);
250.                }
251.             }
252. 
253.             return ((m_Infos.CountReplay == m_MemoryData.nTicks) && (def_CheckLoopService));
254.          }
255. };
256. //+------------------------------------------------------------------+

Fragmento do arquivo C_Replay.mqh

Sei que não está muito bonito. Mas pelo menos, funciona. E se você desejar pode testar em diversas condições diferentes. Aumentando ou diminuindo o tempo. Você é livre para fazer isto. Mas antes de sair modificando as coisas, que tal entender o que está acontecendo neste fragmento?

Observe o seguinte fato: Na linha 217 estou declarando uma nova variável. Esta será usada, para comportar, uma das constantes possíveis a serem usadas no book. Na linha 237 fazemos uso do operador ternário para agilizar o nosso código, já que a ideia, é testar uma condição e em cima desta condição, atribuir um valor a variável typeMsg. Agora atenção, eu poderia adensar ainda mais este código, mas a explicação ficaria muito complicada de ser feita. E a explicação é a seguinte: Depois que uma das constantes tenha sido atribuída a typeMsg. Verificamos se o valor é diferente do último valor lançado como evento customizado de book. Se isto for verdadeiro, na linha 239, atribuímos a nova constante a ser utilizada e executamos na linha 240 uma chamada a CustomBookAdd. A parte que você de fato deve ter atenção é com relação ao valor a ser comparado com a variável iPos. Isto lá na linha 237. Repare que ali, no caso estou comparando com o valor 60000 ( sessenta mil ). Mas por que deste valor? Não estaríamos usando um limite de um minuto? Sim. Mas você deve estar se esquecendo do seguinte fato: um minuto são sessenta segundos. Agora observe que na linha 236, o valor a ser colocado em iPos, é na verdade, dado em milissegundos. E em um segundo temos mil milissegundos. Entendeu agora o por que, de estamos comparado iPos com o valor de sessenta mil? Isto se deve ao fato de que o valor é em milissegundos. Então se você for modificar, este valor, por um outro que você ache mais adequado, apenas tome o cuidado para colocar o valor correto. Caso contrário, a informação no indicador de mouse, ficará bastante fora do que você esperava de fato ver, quando o ativo viesse a ficar um certo período sem ticks sendo adicionados ao gráfico.

Com isto, finalmente temos a possibilidade, de ver o código final do arquivo C_Replay.mqh. Sendo que neste momento, tudo referente ao tempo, já se encontra adequadamente implementado. Pelo menos de forma que o resultado final é o visto no vídeo logo abaixo:


O código do arquivo de cabeçalho C_Replay.mqh, pode ser visto na íntegra logo a seguir:

001. //+------------------------------------------------------------------+
002. #property copyright "Daniel Jose"
003. //+------------------------------------------------------------------+
004. #include "C_ConfigService.mqh"
005. #include "C_Controls.mqh"
006. //+------------------------------------------------------------------+
007. #define def_IndicatorControl   "Indicators\\Market Replay.ex5"
008. #resource "\\" + def_IndicatorControl
009. //+------------------------------------------------------------------+
010. #define def_CheckLoopService ((!_StopFlag) && (ChartSymbol(m_Infos.IdReplay) != ""))
011. //+------------------------------------------------------------------+
012. #define def_ShortNameIndControl   "Market Replay Control"
013. #define def_MaxSlider             (def_MaxPosSlider + 1)
014. //+------------------------------------------------------------------+
015. class C_Replay : public C_ConfigService
016. {
017.    private   :
018.       struct st00
019.       {
020.          C_Controls::eObjectControl Mode;
021.            uCast_Double             Memory;
022.          ushort                     Position;
023.          int                        Handle;
024.       }m_IndControl;
025.       struct st01
026.       {
027.          long     IdReplay;
028.          int      CountReplay;
029.          double   PointsPerTick;
030.          MqlTick  tick[1];
031.          MqlRates Rate[1];
032.       }m_Infos;
033.       stInfoTicks m_MemoryData;
034. //+------------------------------------------------------------------+
035. inline bool MsgError(string sz0) { Print(sz0); return false; }
036. //+------------------------------------------------------------------+
037. inline void UpdateIndicatorControl(void)
038.          {
039.             double Buff[];
040.                                  
041.             if (m_IndControl.Handle == INVALID_HANDLE) return;
042.             if (m_IndControl.Memory._16b[C_Controls::eCtrlPosition] == m_IndControl.Position)
043.             {
044.                if (CopyBuffer(m_IndControl.Handle, 0, 0, 1, Buff) == 1)
045.                   m_IndControl.Memory.dValue = Buff[0];
046.                if ((m_IndControl.Mode = (C_Controls::eObjectControl)m_IndControl.Memory._16b[C_Controls::eCtrlStatus]) == C_Controls::ePlay)
047.                   m_IndControl.Position = m_IndControl.Memory._16b[C_Controls::eCtrlPosition];
048.             }else
049.             {
050.                m_IndControl.Memory._16b[C_Controls::eCtrlPosition] = m_IndControl.Position;
051.                m_IndControl.Memory._16b[C_Controls::eCtrlStatus] = (ushort)m_IndControl.Mode;
052.                m_IndControl.Memory._8b[7] = 'D';
053.                m_IndControl.Memory._8b[6] = 'M';
054.                EventChartCustom(m_Infos.IdReplay, evCtrlReplayInit, 0, m_IndControl.Memory.dValue, "");
055.             }
056.          }
057. //+------------------------------------------------------------------+
058.       void SweepAndCloseChart(void)
059.          {
060.             long id;
061.             
062.             if ((id = ChartFirst()) > 0) do
063.             {
064.                if (ChartSymbol(id) == def_SymbolReplay)
065.                   ChartClose(id);
066.             }while ((id = ChartNext(id)) > 0);
067.          }
068. //+------------------------------------------------------------------+
069. inline int RateUpdate(bool bCheck)
070.          {
071.             static int st_Spread = 0;
072. 
073.             st_Spread = (bCheck ? (int)macroGetTime(m_MemoryData.Info[m_Infos.CountReplay].time) : st_Spread + 1);
074.             m_Infos.Rate[0].spread = (int)(def_MaskTimeService | st_Spread);
075.             CustomRatesUpdate(def_SymbolReplay, m_Infos.Rate);
076.             
077.             return 0;
078.          }
079. //+------------------------------------------------------------------+
080. inline void CreateBarInReplay(bool bViewTick)
081.          {
082.             bool   bNew;
083.             double dSpread;
084.             int    iRand = rand();
085. 
086.             if (BuildBar1Min(m_Infos.CountReplay, m_Infos.Rate[0], bNew))
087.             {
088.                m_Infos.tick[0] = m_MemoryData.Info[m_Infos.CountReplay];
089.                if (m_MemoryData.ModePlot == PRICE_EXCHANGE)
090.                {                  
091.                   dSpread = m_Infos.PointsPerTick + ((iRand > 29080) && (iRand < 32767) ? ((iRand & 1) == 1 ? m_Infos.PointsPerTick : 0 ) : 0 );
092.                   if (m_Infos.tick[0].last > m_Infos.tick[0].ask)
093.                   {
094.                      m_Infos.tick[0].ask = m_Infos.tick[0].last;
095.                      m_Infos.tick[0].bid = m_Infos.tick[0].last - dSpread;
096.                   }else if (m_Infos.tick[0].last < m_Infos.tick[0].bid)
097.                   {
098.                      m_Infos.tick[0].ask = m_Infos.tick[0].last + dSpread;
099.                      m_Infos.tick[0].bid = m_Infos.tick[0].last;
100.                   }
101.                }
102.                if (bViewTick)
103.                   CustomTicksAdd(def_SymbolReplay, m_Infos.tick);
104.                RateUpdate(true);
105.             }
106.             m_Infos.CountReplay++;
107.          }
108. //+------------------------------------------------------------------+
109.       void AdjustViewDetails(void)
110.          {
111.             MqlRates rate[1];
112. 
113.             ChartSetInteger(m_Infos.IdReplay, CHART_SHOW_ASK_LINE, GetInfoTicks().ModePlot == PRICE_FOREX);
114.             ChartSetInteger(m_Infos.IdReplay, CHART_SHOW_BID_LINE, GetInfoTicks().ModePlot == PRICE_FOREX);
115.             ChartSetInteger(m_Infos.IdReplay, CHART_SHOW_LAST_LINE, GetInfoTicks().ModePlot == PRICE_EXCHANGE);
116.             m_Infos.PointsPerTick = SymbolInfoDouble(def_SymbolReplay, SYMBOL_TRADE_TICK_SIZE);
117.             CopyRates(def_SymbolReplay, PERIOD_M1, 0, 1, rate);
118.             if ((m_Infos.CountReplay == 0) && (GetInfoTicks().ModePlot == PRICE_EXCHANGE))
119.                for (; GetInfoTicks().Info[m_Infos.CountReplay].volume_real == 0; m_Infos.CountReplay++);
120.             if (rate[0].close > 0)
121.             {
122.                if (GetInfoTicks().ModePlot == PRICE_EXCHANGE)
123.                   m_Infos.tick[0].last = rate[0].close;
124.                else
125.                {
126.                   m_Infos.tick[0].bid = rate[0].close;
127.                   m_Infos.tick[0].ask = rate[0].close + (rate[0].spread * m_Infos.PointsPerTick);
128.                }               
129.                m_Infos.tick[0].time = rate[0].time;
130.                m_Infos.tick[0].time_msc = rate[0].time * 1000;
131.             }else
132.                m_Infos.tick[0] = GetInfoTicks().Info[m_Infos.CountReplay];
133.             CustomTicksAdd(def_SymbolReplay, m_Infos.tick);
134.          }
135. //+------------------------------------------------------------------+
136.       void AdjustPositionToReplay(void)
137.          {
138.             int nPos, nCount;
139.             
140.             if (m_IndControl.Position == (int)((m_Infos.CountReplay * def_MaxSlider) / m_MemoryData.nTicks)) return;
141.             nPos = (int)((m_MemoryData.nTicks * m_IndControl.Position) / def_MaxSlider);
142.             for (nCount = 0; m_MemoryData.Rate[nCount].spread < nPos; m_Infos.CountReplay = m_MemoryData.Rate[nCount++].spread);
143.             if (nCount > 0) CustomRatesUpdate(def_SymbolReplay, m_MemoryData.Rate, nCount - 1);
144.             while ((nPos > m_Infos.CountReplay) && def_CheckLoopService)
145.                CreateBarInReplay(false);
146.          }
147. //+------------------------------------------------------------------+
148.    public   :
149. //+------------------------------------------------------------------+
150.       C_Replay()
151.          :C_ConfigService()
152.          {
153.             Print("************** Market Replay Service **************");
154.             srand(GetTickCount());
155.             SymbolSelect(def_SymbolReplay, false);
156.             CustomSymbolDelete(def_SymbolReplay);
157.             CustomSymbolCreate(def_SymbolReplay, StringFormat("Custom\\%s", def_SymbolReplay));
158.             CustomSymbolSetDouble(def_SymbolReplay, SYMBOL_TRADE_TICK_SIZE, 0);
159.             CustomSymbolSetDouble(def_SymbolReplay, SYMBOL_TRADE_TICK_VALUE, 0);
160.             CustomSymbolSetDouble(def_SymbolReplay, SYMBOL_VOLUME_STEP, 0);
161.             CustomSymbolSetString(def_SymbolReplay, SYMBOL_DESCRIPTION, "Symbol for replay / simulation");
162.             CustomSymbolSetInteger(def_SymbolReplay, SYMBOL_DIGITS, 8);
163.             CustomSymbolSetInteger(def_SymbolReplay, SYMBOL_TICKS_BOOKDEPTH, 1);
164.             SymbolSelect(def_SymbolReplay, true);
165.             m_Infos.CountReplay = 0;
166.             m_IndControl.Handle = INVALID_HANDLE;
167.             m_IndControl.Mode = C_Controls::ePause;
168.             m_IndControl.Position = 0;
169.             m_IndControl.Memory._16b[C_Controls::eCtrlPosition] = C_Controls::eTriState;
170.          }
171. //+------------------------------------------------------------------+
172.       ~C_Replay()
173.          {
174.             SweepAndCloseChart();
175.             IndicatorRelease(m_IndControl.Handle);
176.             SymbolSelect(def_SymbolReplay, false);
177.             CustomSymbolDelete(def_SymbolReplay);
178.             Print("Finished replay service...");
179.          }
180. //+------------------------------------------------------------------+
181.       bool OpenChartReplay(const ENUM_TIMEFRAMES arg1, const string szNameTemplate)
182.          {
183.             if (SymbolInfoDouble(def_SymbolReplay, SYMBOL_TRADE_TICK_SIZE) == 0)
184.                return MsgError("Asset configuration is not complete, it remains to declare the size of the ticket.");
185.             if (SymbolInfoDouble(def_SymbolReplay, SYMBOL_TRADE_TICK_VALUE) == 0)
186.                return MsgError("Asset configuration is not complete, need to declare the ticket value.");
187.             if (SymbolInfoDouble(def_SymbolReplay, SYMBOL_VOLUME_STEP) == 0)
188.                return MsgError("Asset configuration not complete, need to declare the minimum volume.");
189.             SweepAndCloseChart();
190.             m_Infos.IdReplay = ChartOpen(def_SymbolReplay, arg1);
191.             if (!ChartApplyTemplate(m_Infos.IdReplay, szNameTemplate + ".tpl"))
192.                Print("Failed apply template: ", szNameTemplate, ".tpl Using template default.tpl");
193.             else
194.                Print("Apply template: ", szNameTemplate, ".tpl");
195. 
196.             return true;
197.          }
198. //+------------------------------------------------------------------+
199.       bool InitBaseControl(const ushort wait = 1000)
200.          {
201.             Sleep(wait);
202.             AdjustViewDetails();
203.             Print("Loading Control Indicator...");
204.             if ((m_IndControl.Handle = iCustom(ChartSymbol(m_Infos.IdReplay), ChartPeriod(m_Infos.IdReplay), "::" + def_IndicatorControl, m_Infos.IdReplay)) == INVALID_HANDLE) return false;
205.             ChartIndicatorAdd(m_Infos.IdReplay, 0, m_IndControl.Handle);
206.             Print("Waiting for Mouse Indicator...");
207.             while ((def_CheckLoopService) && (ChartIndicatorGet(m_Infos.IdReplay, 0, "Indicator Mouse Study") == INVALID_HANDLE)) Sleep(200);
208.             UpdateIndicatorControl();
209.             
210.             return def_CheckLoopService;
211.          }
212. //+------------------------------------------------------------------+
213.       bool LoopEventOnTime(void)
214.          {         
215.             int iPos, iCycles;
216.             MqlBookInfo book[1];
217.             ENUM_BOOK_TYPE typeMsg;
218.             
219.             book[0].price = 1.0;
220.             book[0].volume = 1;
221.             book[0].type = BOOK_TYPE_BUY_MARKET;
222.             CustomBookAdd(def_SymbolReplay, book, 1);
223.             while ((def_CheckLoopService) && (m_IndControl.Mode != C_Controls::ePlay))
224.             {
225.                UpdateIndicatorControl();
226.                Sleep(200);
227.             }
228.             m_MemoryData = GetInfoTicks();
229.             AdjustPositionToReplay();
230.             iPos = iCycles = 0;
231.             book[0].type = BOOK_TYPE_BUY;
232.             CustomBookAdd(def_SymbolReplay, book, 1);
233.             while ((m_Infos.CountReplay < m_MemoryData.nTicks) && (def_CheckLoopService))
234.             {
235.                if (m_IndControl.Mode == C_Controls::ePause) return true;
236.                iPos += (int)(m_Infos.CountReplay < (m_MemoryData.nTicks - 1) ? m_MemoryData.Info[m_Infos.CountReplay + 1].time_msc - m_MemoryData.Info[m_Infos.CountReplay].time_msc : 0);
237.                if ((typeMsg = (iPos >= 60000 ? BOOK_TYPE_BUY_MARKET : BOOK_TYPE_BUY)) != book[0].type)
238.                {
239.                   book[0].type = typeMsg;
240.                   CustomBookAdd(def_SymbolReplay, book, 1);                  
241.                }
242.                CreateBarInReplay(true);
243.                while ((iPos > 200) && (def_CheckLoopService) && (m_IndControl.Mode != C_Controls::ePause))
244.                {
245.                   Sleep(195);
246.                   iPos -= 200;
247.                   m_IndControl.Position = (ushort)((m_Infos.CountReplay * def_MaxSlider) / m_MemoryData.nTicks);
248.                   UpdateIndicatorControl();
249.                   iCycles = (iCycles == 4 ? RateUpdate(false) : iCycles + 1);
250.                }
251.             }
252. 
253.             return ((m_Infos.CountReplay == m_MemoryData.nTicks) && (def_CheckLoopService));
254.          }
255. };
256. //+------------------------------------------------------------------+
257. #undef def_SymbolReplay
258. #undef def_CheckLoopService
259. #undef def_MaxSlider
260. //+------------------------------------------------------------------+

Código fonte do arquivo C_Replay.mqh


Uma falha bem engraçada. Porém inofensiva

Muito bem. Apesar deste sistema, visto e mostrado acima, funcionar maravilhosamente bem. Temos um problema. Mesmo que no vídeo, eu não tenha mostrado isto. Acredito que se você observar e pensar um pouco, notará que existe uma falha aqui. Mas antes de falar qual é a falha que existe neste sistema. Vamos ver se você de fato, tem compreendido como o MetaTrader 5 funciona. Se você não tem a noção de como o MetaTrader 5, trabalha, nos diferentes tipos de cenário. Você muito provavelmente, não conseguiu notar, a falha que existe nesta programação feita até o momento. Isto por que, a falha está no fato, de que você NÃO PODERÁ MUDAR O TEMPO GRÁFICO. Isto durante todo o uso da aplicação de replay/simulação.

Você agora deve estar se questionando: Mas como assim? Como não posso trocar o tempo gráfico? O que acontece, ser por um acaso eu tentar modificar o tempo gráfico? O que irá, e isto com toda a certeza acontecer, será o disparo da falha que existe neste sistema. No entanto, esta falha que logo explicarei como corrigir, acontece em cenários bem específicos. Você somente irá de fato disparar ela, se o serviço de replay/simulação, estiver no modo play. Se ele estiver no modo pausado, ou se o sistema detectar que o ativo esteja em leilão, por conta do número de negócios que definimos. A falha não será disparada. Novamente, ela somente será disparada em um cenário que estivermos em modo play e os ticks estiverem sendo adicionados no gráfico.

Agora novamente irei lhe perguntar: Você, que tem acompanhado destes artigos, de como desenvolver um sistema de replay/simulador. Tem alguma ideia dê por que, e qual é a falha que estou mencionando? Se sim. Ótimo. Significa que você tem estudado e se dedicado a entender cada vez mais o MQL5 e como o MetaTrader 5 funciona. Agora se a resposta for não. Significa que você ainda está em um estágio bem inicial de aprendizado. Não se sinta mal por isto. Pelo contrário, que isto lhe sirva de motivação para estudar ainda mais.

Mas vamos ver que falha é esta. Que apesar de existir, é totalmente inofensiva. E que apenas será disparada, se você estiver no modo play e que se a liquidez for suficiente para que não seja disparado o leilão. Faz com que ao mudar o tempo gráfico, algo engraçado aconteça. A falha é justamente esta: Se as condições acima, especificadas, satisfazerem o sistema. Assim que você modificar o tempo gráfico, o indicador de mouse passará a indicar que o mercado está fechado. E você não poderá ver o tempo restante da barra. Terá que acionar o modo pause, e logo depois acionar o modo play.


Você pode estar agora, totalmente confuso. Mas como assim. Se eu trocar o tempo gráfico, o indicador de mouse passará a indicar que o mercado está fechado? Isto não faz sentido algum. De fato, devo concordar com você, caro leitor. Mas se você for um pouco mais experiente, saberá que quando modificamos o tempo gráfico. O MetaTrader 5, irá de fato remover todo e qualquer indicador, além de outras coisas do gráfico. Irá logo em seguida abrir o gráfico e plotará as barras, seguindo o critério do novo tempo gráfico. É assim que o MetaTrader 5, funciona. Então, assim que o indicador de mouse, for recolocado no gráfico, ele na verdade irá lhe mostrar a sua configuração inicial. Para saber que configuração é esta. Basta olhar o fragmento abaixo, que foi retirado do indicador de mouse:

27. //+------------------------------------------------------------------+
28. int OnInit()
29. {
30.    Study = new C_Study(0, "Indicator Mouse Study", user02, user03, user04);
31.    if (_LastError >= ERR_USER_ERROR_FIRST) return INIT_FAILED;
32.    MarketBookAdd((*Study).GetInfoTerminal().szSymbol);
33.    OnBookEvent((*Study).GetInfoTerminal().szSymbol);
34.    m_Status = C_Study::eCloseMarket;
35.    SetIndexBuffer(0, m_Buff, INDICATOR_DATA);
36.    ArrayInitialize(m_Buff, EMPTY_VALUE);
37.    
38.    return INIT_SUCCEEDED;
39. }
40. //+------------------------------------------------------------------+

Fragmento do Indicador de Mouse

Agora observe o seguinte: Na linha 34 deste fragmento, iniciamos o valor do status. Este irá de fato dizer que o mercado está fechado. Mas os ticks continuam chegando, vindos do serviço de replay/simulação. Então é aqui que reside a falha. Veja que ela é inofensiva, e não nos causa grandes problemas. Apenas é um inconveniente, do qual para solucionar, temos que dar pause no serviço e logo depois dar play. Que tudo voltará ao normal.

Você pode pensar em mil e uma forma de resolver isto. Mas a solução que mostrarei, será bem mais inusitada do que você possa imaginar. Mas antes de ver a solução. Você saberia me dizer, por que ao dar pause, e logo depois play a falha desaparece? Se você não sabe, vamos entender o motivo de isto fazer com que a falha desapareça. Para entender, é preciso voltar no código do arquivo de cabeçalho C_Replay.mqh. Para ser mais específico, temos que ir na função LoopEventOnTime. Assim que a falha acontece, o indicador de mouse, irá nos informar que o mercado está fechado. Ao acionarmos o modo pause, a linha 235 irá nos tirar do laço da linha 233. Isto fará com que a função retorne ao código principal. Mas como o retorno da função foi verdadeiro, o código principal do serviço chamará, novamente a função LoopEventOnTime. Neste momento a linha 222 fará uma chamada a fim de adicionar um evento customizado no book. Este evento usa o valor indicado na linha 221. Ou seja, agora o indicador de mouse, mudará a informação mostrada de mercado fechado, para mercado em leilão. Quando você, ou o usuário, vim a habilitar novamente o serviço dando play no mesmo. A linha 232, fará uma nova chamada, adicionando um novo evento customizado de book. Só que agora o valor da constante usada é o da linha 231. Este valor irá de fato permitir que o indicador de mouse, mostre novamente o tempo restante da barra atual.

Por isto que, quando a falha acontece, pelo motivo de você mudar de tempo gráfico. O simples fato de dar pause, e logo em seguida dar play, faz com que tudo volte ao normal.

Mas apesar de esta falha descrita, não afetar tanto o indicador de mouse. Ela é bem chata, no que diz respeito a um outro indicador. Estou falando do indicador de controle. Neste caso não tem como. Já que teremos de esperar que o teste efetuado na linha 42 do código presente no arquivo de cabeçalho C_Replay.mqh. Venha a falhar. E por que precisamos que este teste da linha 42, venha a falhar, para que o indicador de controle volte a ser visto no gráfico? O motivo disto é justamente o fato, de que apenas e somente quando este teste falha, é que a linha 54 é executada. Precisamos que esta linha 54, seja executada, para que o indicador de controle possa ser atualizado. Quando esta atualização se dá, o indicador de controle voltará a ser plotado no gráfico. Isto se ele estiver oculto, por qualquer motivo.

Muito bem. Agora você deve ter notado que o bicho pegou. Se a falha percebida no indicador de mouse, podia ser resolvida apenas pressionando o botão de controle a fim de trocar do modo play para o modo pause, e logo depois dar play novamente. Agora se o indicador de controle não estiver visível. Como poderemos sanar a falha do indicador de mouse. Isto por que não poderemos pausar a aplicação, de forma que o serviço pare de lançar ticks. Mas se o serviço não parar de lançar ticks, teremos que esperar até que o teste da linha 42 venha a falhar. E isto somente irá de fato acontecer, quando uma determinada quantidade de ticks for colocada no gráfico. Ui. De fato, agora temos um baita de um problema.

Aí você pode pensar: Tudo que tenho que fazer de fato, é observar o tempo gráfico no serviço. Assim se ele for modificado, farei com que os indicadores de controle e de mouse recebam dados, adequados para que sejam reinicializados de maneira adequada. Ok. Mas você sabe como fazer para o serviço, detectar que houve mudança no tempo do gráfico? Talvez até exista alguma forma. Mas lhe garanto, que será bem mais complicada. Trabalhosa. Difícil de ser implementada do que a mostrada. Não neste artigo. Mas no próximo. Já que quero deixar você caro leitor, tentando achar uma solução para este problema.


Conclusão

Neste artigo, mostrei como você faz para conseguir, aliar um código que foi usado, no artigo anterior. Para testar e verificar o funcionamento do sistema de mensagens customizadas do book. Em um serviço, que já vem sendo implementado a algum tempo. Mostrei também que muitas das vezes, existem falhas dentro da implementação, que apesar de parecerem inofensivas, podem nos dar uma baita dor de cabeça. 

Mas também deixei, e acredito bastante, curiosos com relação, a como irei de fato sanar o problema do tempo. Isto fazendo com que o serviço consiga detectar que o tempo do gráfico, no qual o serviço está acompanhando, foi modificado de alguma forma. Este tipo de solução será visto no próximo artigo. Já que não quero lhe deixar completamente louco. Tentando entender por que as coisas funcionam, ou por que, elas não funcionam.

Ser programador é isto: Encontrar uma solução, quando todos não conseguem ver uma solução. Problemas sempre irão de fato existir. Se não fosse por eles, programar não teria a menor graça. Então, quanto mais problemas, melhor. Quando mais difíceis eles forem de ser resolvidos, melhor ainda. Pois isto nos faz pensar fora da caixa. Sair do marasmo de sempre fazer as mesmas coisas e do mesmo jeito. 

Então nos vemos no próximo artigo. E tentem pensar em uma solução para o problema da troca do tempo gráfico. Isto antes de ler o próximo artigo.

Arquivos anexados |
Anexo.zip (420.65 KB)
Data Science e Machine Learning (Parte 24): Previsão de Séries Temporais no Forex Usando Modelos de IA Clássicos Data Science e Machine Learning (Parte 24): Previsão de Séries Temporais no Forex Usando Modelos de IA Clássicos
Nos mercados de forex, é muito desafiador prever a tendência futura sem ter uma ideia do passado. Poucos modelos de machine learning são capazes de fazer previsões futuras considerando valores passados. Neste artigo, vamos discutir como podemos usar modelos clássicos (não específicos para séries temporais) de Inteligência Artificial para superar o mercado.
Do básico ao intermediário: Array (III) Do básico ao intermediário: Array (III)
Neste artigo iremos ver como trabalhar com arrays no MQL5, a ponto de transferir informações entre funções e procedimentos, utilizando arrays para isto. O objetivo aqui é lhe preparar para o que será visto e explicado em artigos futuros. No entanto, é extremamente recomendado que você estude muito bem o que será mostrado neste artigo. O conteúdo exposto aqui, visa e tem como objetivo, pura e simplesmente a didática. De modo algum deve ser encarado como uma aplicação final, onde o objetivo não seja o estudo dos conceitos aqui mostrados.
As modificações mais conhecidas do algoritmo de busca cooperativa artificial (Artificial Cooperative Search, ACSm) As modificações mais conhecidas do algoritmo de busca cooperativa artificial (Artificial Cooperative Search, ACSm)
Neste artigo, examinamos a evolução do algoritmo ACS: três modificações visando melhorar as características de convergência e eficácia do algoritmo. A transformação de um dos principais algoritmos de otimização. Das modificações de matrizes a abordagens revolucionárias para a formação de populações.
Criação de Previsões de Séries Temporais Usando Redes Neurais LSTM: Normalizando Preço e Tokenizando o Tempo Criação de Previsões de Séries Temporais Usando Redes Neurais LSTM: Normalizando Preço e Tokenizando o Tempo
Este artigo descreve uma estratégia simples para normalizar os dados de mercado usando o intervalo diário e treinar uma rede neural para aprimorar as previsões de mercado. Os modelos desenvolvidos podem ser utilizados em conjunto com estruturas de análise técnica existentes ou de forma independente para auxiliar na previsão da direção geral do mercado. A estrutura delineada neste artigo pode ser ainda mais refinada por qualquer analista técnico para desenvolver modelos adequados para estratégias de negociação manuais e automatizadas.