English Русский 中文 Español Deutsch 日本語 한국어 Français Italiano Türkçe
preview
Desenvolvendo um EA de negociação do zero (Parte 13): Times And Trade (II)

Desenvolvendo um EA de negociação do zero (Parte 13): Times And Trade (II)

MetaTrader 5Sistemas de negociação | 5 maio 2022, 10:54
1 468 0
Daniel Jose
Daniel Jose

Introdução

No artigo anterior Times & Trade (I) apresentei um sistema alternativo para montar um gráfico de forma a você ter um indicador que lhe permitisse interpretar os negócios que foram executados no mercado de forma o mais rápido possível, mas aquele sistema não esta totalmente completo, faltou mostrar como você pode ter acesso a algumas informações e assim ter um melhor entendimento sobre o que esta acontecendo, estas informações não tem como serem apresentadas diretamente em um gráfico, na verdade até daria, mas a interpretação fica muito confusa, desta forma o melhor é ter os dados apresentados em uma forma clássica, ou seja valores em formato de texto, só que o nosso EA não conta com nenhum sistema capaz de fazer tal tarefa, sendo necessário implementar isto.

Não querendo complicar o artigo anterior com informações que talvez não fossem de todo necessário para alguns, já que da forma como o sistema foi montado, já será possível interpretar com grande precisão o que esta acontecendo, decidi fazer a expansão do sistema para algo mais completo, neste artigo, algumas coisas ficaram faltando, ou melhor dizendo, não fazem parte do sistema que foi proposto no artigo anterior, mas é preciso em alguns momento o devido conhecimento de tais informações sobre o que de fato esta sendo feito no mercado.


Planejamento

Vamos entender uma coisa, são detalhes, mas como o ditado diz : "O diabo mora nos detalhes", então é algo que devemos prestar muita atenção, veja a imagem abaixo:

Você consegue notar algo estranho nesta imagem ?!?! algo que talvez não faça muito sentido, mas esta ali ... observe com bastante atenção ...

Se você ainda não notou nada de estranho, olhe com mais calma a região que esta destacada na mesma imagem,


Agora talvez você consiga de fato ver o que esta acontecendo, note que neste ponto houve mudanças no valor tanto do BID quanto do ASK, mas só ocorreu um único negocio neste ponto, mesmo que de fato tenha ocorrido modificações do valor de BID ou ASK não faz muito sentido ter ocorrido apenas um único negocio, mas isto de fato é mais comum do que parece, este tipo de coisa não é visível quando você esta utilizando o modo de leitura visto a seguir:

Nesta forma de analisar o mercado ficamos cegos aos movimentos do BID e ASK, dar-se a impressão que o mercado esta sempre negociando e que todos estão ávidos a fecharem negócio, o que de fato não é verdadeiro, o que de fato acontece é que os players montam suas posições em determinados pontos, e aguardam o mercado se mover, quando a posição é capturada eles tentam tirar proveito e assim ganhar dinheiro no movimento, por conta disto é que muitas vezes o BID ou ASK se movimentam sem de fato acontecer nenhum negócio, isto é um fato real e pode ser visto na plataforma, mas é algo ignorado por grande maioria por achar que esta informação não é de fato importante.

Por conta disto nosso sistema de Times & Trade fica conforme mostrado na figura abaixo:

Mas se você observar com atenção verá que existem 4 configurações de candles no gráfico, na verdade seriam 5 mas as ordens diretas são excluídas do sistema, isto por elas não movimentarem de fato o mercado, então temos de fato 4 configurações que podem ser vistas com mais detalhes abaixo:

Ai você pensa, mas por que em alguns casos o pavio não toca o corpo do candle ?!?! Por que isto acontece ?!?! Bem, o fato é que o pavio é conseguido usando justamente o valor de SPREAD, e este valor é obtido pela diferença entre o BID e o ASK, mas caso um negocio ocorresse dentro deste SPREAD, como seria de fato o candle ?!?! Bem, este seria o 5 tipo que é visto abaixo:

Ou seja um DOJI, por este motivo as ordens diretas não são vistas no sistema, mas isto não explica o por que de em alguns casos o corpo não tocar o pavio. Mas a explicação esta no fato de que ocorreu algo que vez o preço se mover muito rapidamente somente por isto acontece de o corpo não tocar no pavio, mas você pode pensar que isto é uma falha do sistema, que não faz sentido o preço fazer isto, mas sim faz todo o sentido, e isto acontece justamente quando ordens de stop são acionadas, para ver isto observem a imagem abaixo:

Vejam que acontece uma serie de momentos em que temos ordens na qual nem o BID e nem o ASK estão sendo tocados, todos estes pontos foram ordens de stop que foram atingidas, e quando isto acontece o preço normalmente da um salto e isto pode ser visto no gráfico, mas no Times & Trade isto só será de fato notado caso você esteja usando um modo gráfico para avaliar os movimentos, senão você fica cego a este acionamento de stops e acha que agora o movimento tomou força, quando na verdade ele pode voltar rapidamente e você pode ser a vitima do stop.

Bem, sabendo disto quando você ver uma serie grande de candles sendo plotados sem que o pavio toque no corpo, saberá que são ordens de stop que foram acionadas, não dá de fato para capturar este movimento durante o período que ele acontece, já que é algo muito rápido, mas você pode usar uma interpretação dos valores de BID e ASK para saber o por que disto de acontecido, aqui vai a experiencia de mercado de cada um, não vou entrar em detalhes sobre isto, mas é algo que você deve focar caso queira de fato usar o Tape Reading como um indicador.

Mas agora vem o detalhe: Se estas informações podem ser vistas apenas usando os candles e elas já são suficientes para saber varias coisas, por que se torna necessário termos mais informações ?!?!

O grande detalhe é que tem momentos em que o mercado fica mais lento, esperando alguma informação que pode sair em um dado momento, e apenas olhar o Times & Trade com candles não nos dá este tipo de noção, precisamos de algo a mais, e estas informações já estão no próprio sistema mas é difícil interpreta-las da forma como elas vem, devemos modelar os dados de forma a deixar a coisa mais simples de serem de fato analisadas.

Esta modelagem é o motivo deste artigo, depois desta modelagem ter sido feita, o Times & Trade irá mudar e ficar conforme mostrado na imagem abaixo:

Ou seja teremos total conhecimento do que esta acontecendo, e isto de forma extremamente rápida, coisa que é importante para quem deseja usar a leitura de fluxo como uma forma de operar.


Implementação

Para implementar o sistema temos que adicionar algumas variáveis novas na classe C_TimesAndTrade, e isto pode ser visto no fragmento abaixo:

#include <NanoEA-SIMD\Auxiliar\C_FnSubWin.mqh>
#include <NanoEA-SIMD\Auxiliar\C_Canvas.mqh>
//+------------------------------------------------------------------+
class C_TimesAndTrade : private C_FnSubWin
{
//+------------------------------------------------------------------+
#define def_SizeBuff 
2048 
#define macro_Limits(A) (A & 0xFF)
#define def_MaxInfos 257
//+------------------------------------------------------------------+
        private :
                string          m_szCustomSymbol,
                                m_szObjName;
                char            m_ConnectionStatus;
                datetime        m_LastTime;
                ulong           m_MemTickTime;
                int             m_CountStrings;
                struct st0
                {
                        string  szTime;
                        int     flag;
                }m_InfoTrades[def_MaxInfos];
                struct st1
                {
                        C_Canvas Canvas;
                        int      WidthRegion,
                                 PosXRegion,
                                 MaxY;
                        string   szNameCanvas;
                }m_InfoCanvas;

Todos os pontos em destaque são partes que foram adicionadas ao código original, deu pra notar que precisaremos usar a classe C_Canvas, mas ela não tem todos os elementos que precisamos, na verdade temos que adicionar 4 rotinas a esta classe C_Canvas, e estas rotinas são vistas logo no fragmento abaixo:

// ... Código da classe C_Canvas

inline void FontSet(const string name, const int size, const uint flags = 0, const uint angle = 0)
{
        if(!TextSetFont(name, size, flags, angle)) return;
        TextGetSize("M", m_TextInfos.width, m_TextInfos.height);
}
//+------------------------------------------------------------------+
inline void TextOutFast(int x, int y, string text, const uint clr, uint alignment = 0)
{
        TextOut(text, x, y, alignment, m_Pixel, m_width, m_height, clr, COLOR_FORMAT_ARGB_NORMALIZE);
}
//+------------------------------------------------------------------+
inline int TextWidth(void) const { return m_TextInfos.width; }
//+------------------------------------------------------------------+
inline int TextHeight(void) const { return m_TextInfos.height; }
//+------------------------------------------------------------------+

// ... Restante do código ...

O que estas linhas fazem é criar um texto pra nos, algo bem simples, nada de muita frescura.

A próxima rotina que merece destaque na classe C_TimesAndTrade é vista logo a seguir:

void PrintTimeTrade(void)
{
        int ui1;
        
        m_InfoCanvas.Canvas.Erase(clrBlack, 220);
        for (int c0 = 0, c1 = m_CountStrings - 1, y = 2; (c0 <= 255) && (y < m_InfoCanvas.MaxY); c0++, c1--, y += m_InfoCanvas.Canvas.TextHeight())
        if (m_InfoTrades[macro_Limits(c1)].szTime == NULL) break; else
        {
                ui1 = m_InfoTrades[macro_Limits(c1)].flag;
                m_InfoCanvas.Canvas.TextOutFast(2, y, m_InfoTrades[macro_Limits(c1)].szTime, macroColorRGBA((ui1 == 0 ? clrLightSkyBlue : (ui1 > 0 ? clrForestGreen : clrFireBrick)), 220));
        }
        m_InfoCanvas.Canvas.Update();
}

Esta rotina irá imprimir os valores para nos em uma área reservada para isto, já a rotina de inicialização também sofreu pequenas mudanças que pode ser visto abaixo em destaque:

void Init(const int iScale = 2)
{
        if (!ExistSubWin())
        {
                m_InfoCanvas.Canvas.FontSet("Lucida Console", 13);
                m_InfoCanvas.WidthRegion = (18 * m_InfoCanvas.Canvas.TextWidth()) + 4;
                CreateCustomSymbol();
                CreateChart();
                m_InfoCanvas.Canvas.Create(m_InfoCanvas.szNameCanvas, m_InfoCanvas.PosXRegion, 0, m_InfoCanvas.WidthRegion, TerminalInfoInteger(TERMINAL_SCREEN_HEIGHT), GetIdSubWinEA());
                Resize();
                m_ConnectionStatus = 0;
        }
        ObjectSetInteger(Terminal.Get_ID(), m_szObjName, OBJPROP_CHART_SCALE, (iScale > 5 ? 5 : (iScale < 0 ? 0 : iScale)));
}

Bem deu para notar que precisamos modificar a rotina de mudanças nas dimensões do Times & Trade, e as mudanças também merecem destaque e podem ser vista no fragmento abaixo:

void Resize(void)
{
        static int MaxX = 0;
        int x = (int) ChartGetInteger(Terminal.Get_ID(), CHART_WIDTH_IN_PIXELS, GetIdSubWinEA());
        
        m_InfoCanvas.MaxY = (int) ChartGetInteger(Terminal.Get_ID(), CHART_HEIGHT_IN_PIXELS, GetIdSubWinEA());
        ObjectSetInteger(Terminal.Get_ID(), m_szObjName, OBJPROP_YSIZE, m_InfoCanvas.MaxY);
        if (MaxX != x)
        {
                MaxX = x;
                x -= m_InfoCanvas.WidthRegion;
                ObjectSetInteger(Terminal.Get_ID(), m_szObjName, OBJPROP_XSIZE, x);
                ObjectSetInteger(Terminal.Get_ID(), m_InfoCanvas.szNameCanvas, OBJPROP_XDISTANCE, x);
        }
        PrintTimeTrade();
}

Com tudo isto, o sistema esta praticamente pronto, mas ainda falta uma rotina que é o coração do sistema e que também sofreu mudanças.

inline void Update(void)
{
        MqlTick Tick[];
        MqlRates Rates[def_SizeBuff];
        int i0, p1, p2 = 0;
        int iflag;
        long lg1;
        static int nSwap = 0;
        static long lTime = 0;

        if (m_ConnectionStatus < 3) return;
        if ((i0 = CopyTicks(Terminal.GetFullSymbol(), Tick, COPY_TICKS_ALL, m_MemTickTime, def_SizeBuff)) > 0)
        {
                for (p1 = 0, p2 = 0; (p1 < i0) && (Tick[p1].time_msc == m_MemTickTime); p1++);
                for (int c0 = p1, c1 = 0; c0 < i0; c0++)
                {
                        lg1 = Tick[c0].time_msc - lTime;
                        nSwap++;
                        if (Tick[c0].volume == 0) continue;
                        iflag = 0;
                        iflag += ((Tick[c0].flags & TICK_FLAG_BUY) == TICK_FLAG_BUY ? 1 : 0);
                        iflag -= ((Tick[c0].flags & TICK_FLAG_SELL) == TICK_FLAG_SELL ? 1 : 0);
                        if (iflag == 0) continue;
                        Rates[c1].high = Tick[c0].ask;
                        Rates[c1].low = Tick[c0].bid;
                        Rates[c1].open = Tick[c0].last;
                        Rates[c1].close = Tick[c0].last + ((Tick[c0].volume > 200 ? 200 : Tick[c0].volume) * (Terminal.GetTypeSymbol() == C_Terminal::WDO ? 0.02 : 1.0) * iflag);
                        Rates[c1].time = m_LastTime;
                        m_InfoTrades[macro_Limits(m_CountStrings)].szTime = StringFormat("%02.d.%03d ~ %02.d <>%04.d", ((lg1 - (lg1 % 1000)) / 1000) % 60 , lg1 % 1000, nSwap, Tick[c0].volume);
                        m_InfoTrades[macro_Limits(m_CountStrings)].flag = iflag;
                        m_CountStrings++;
                        nSwap = 0;
			lTime = Tick[c0].time_msc;
                        p2++;
                        c1++;
                        m_LastTime += 60;
                }
                CustomRatesUpdate(m_szCustomSymbol, Rates, p2);
                m_MemTickTime = Tick[i0 - 1].time_msc;
        }
        PrintTimeTrade();
}

Todas as linhas em destaque são códigos adicionados a rotina de forma a modelar os dados que queremos, o fragmento

lg1 = Tick[c0].time_msc - lTime;
nSwap++;

irá verificar quanto tempo se passou entre as operações, isto em milissegundos, e quantas operações que não promoveram mudanças no preço ocorreram, se estes números forem grandes você notará que o volume de negócios estará minguando ou seja antes de outras notarem, você já estará percebendo isto com base nestas informações.

Ja o fragmento

m_InfoTrades[macro_Limits(m_CountStrings)].szTime = StringFormat("%02.d.%03d ~ %02.d <>%04.d", ((lg1 - (lg1 % 1000)) / 1000) % 60 , lg1 % 1000, nSwap, Tick[c0].volume);
m_InfoTrades[macro_Limits(m_CountStrings)].flag = iflag;
m_CountStrings++;
nSwap = 0;                                      
lTime = Tick[c0].time_msc;

irá modelar os valores para serem apresentados para nos, notem que não me preocupo com o fato de testar o contador m_CountStrings, isto por que ele esta limitado, então não precisamos testa-lo, vamos simplesmente incrementando ele a cada nova informação, isto é um truque que as vezes dá para ser feito, eu mesmo uso isto sempre que é possível, já que economiza em termos de processamento, e sendo o sistema de negociação algo a ser usado em tempo real, temos que tentar sempre que possível otimizar o sistema, mesmo que um pouco de cada vez, no montante faz uma grande diferença.

Com tudo isto implementado, executamos a compilação do EA e obtemos algo como mostrado abaixo:


Observem os movimentos que foram descritos acima no gráfico do Times & Trade, pode ser notado que começa a surgir micro estruturas no próprio Times & Trade mas eu não consegui mesmo depois de estudar tais micro estruturas tirar qualquer proveito no fato de elas existirem, mas eu não sou um operador de mercado tão experiente assim, então quem sabe alguém com uma experiencia maior consiga de fato fazer isto.

Este indicador é tão poderoso e tão informativo que decidi fazer um video mostrando uma pequena comparação entre ele e os dados REAIS que o ativo estava fazendo no momento da gravação ... quero que vocês entendam que ele filtra muitas das informações de forma que a leitura fica muito mais rápida e o entendimento do momento é bem mais simples ... Espero que gostem e tirem proveito deste FANTASTICO e PODEROSO indicador.



Conclusão

O sistema aqui proposto é simplesmente uma modificação do próprio sistema gráfico presente no MT5, mas com uma modelagem de dados um pouco diferente, pode ser algo curioso ver como os negócios que estão sendo fechados influencia a direção dos preços formando micro estruturas dentro do timeframe de menor valor disponível nas plataformas que é o de 1 minuto, muita gente gosta de falar que opera no 1 minuto como se isto significa-se que ela tem um alto nível em conhecimento de operações de mercado, mas quando olhamos bem e conhecemos os processos de negociação, vemos que em 1 minuto acontece muita coisa, e que apesar de parecer se um tempo curto ele é algo que deixa passar muitas operações potencialmente lucrativas. Lembre-se que neste sistema de Times & Trade não estamos olhando o que acontece em 1 minuto, os valores que estão na tela são cotados em milissegundos ....


Arquivos anexados |
EA_-_Times_m_Trade.zip (5983.76 KB)
Desenvolvendo um EA de negociação do zero (Parte 14): Volume at Price (II) Desenvolvendo um EA de negociação do zero (Parte 14): Volume at Price (II)
Aqui vamos adicionar recursos diversos no nosso EA. Este artigo vai ser bastante interessante, podendo direcionar você a novas ideias e métodos de apresentar informações e ao mesmo tempo corrigir pequenas falhas nos seus projetos.
Como e por que desenvolver seu próprio sistema de negociação algorítmica Como e por que desenvolver seu próprio sistema de negociação algorítmica
Neste artigo, abordaremos os conceitos básicos da linguagem de programação MQL. O objetivo do artigo é ajudar os programadores iniciantes a desenvolver seu próprio sistema de negociação algorítmico (Expert Advisor).
Desenvolvendo um EA de negociação do zero( Parte 15): Acessando dados na WEB (I) Desenvolvendo um EA de negociação do zero( Parte 15): Acessando dados na WEB (I)
Como ter acesso a dados na WEB dentro do MetaTrader 5. Na WEB temos diversos sites e locais onde uma grande e vasta quantidade de informações estão disponíveis e ficam acessíveis a aqueles que sabem onde procurar e como melhor utilizar estas informações.
Gráficos na biblioteca DoEasy (Parte 93): preparando a funcionalidade para criar objetos gráficos compostos Gráficos na biblioteca DoEasy (Parte 93): preparando a funcionalidade para criar objetos gráficos compostos
Neste artigo, vamos começar a desenvolver a funcionalidade para a criação de objetos gráficos compostos. Nossa biblioteca terá suporte para a criação de objetos gráficos compostos complexos, sendo que tais objetos podem ter qualquer hierarquia de relações. Prepararemos todas as classes necessárias para a posterior geração de tais objetos.