Indicadores-parte3: Programação de robôs de trade (videoaula)

Na terceira e última parte da programação de indicadores (nos próximos falaremos sobre o EA – Expert Advisor), veremos uma versão evoluída do exemplo anterior (baseado na Média Móvel), incluindo controles de tradenúmero de operações com ganho, número máximo de trades, prejuízo máximo, estimativa de ganho e etc.

A base para escolha de uma posição (comprada ou vendida) é bastante semelhante, mas incluímos algumas opções mais avançadas.

O exemplo demonstrado está disponíveis através da url:
http://aprendizfinanceiro.com.br/indicador-aulas3.zip

Conforme exposto no vídeo, a primeira diferença foi a codificação de um controle de trade (basicamente um controle de risco):

// Controle de risco para novas aberturas de posição - por isto !trade_open ou trade_open==0
if (!trade_open){
   //--- Critérios principais e globais
   // 1. Encerra ao atingir 20 pts
   if (trade_sum>20) close_trades=1;
   // 2. Encerra ao atingir o limite diário de trades
   else if (trade_ct>max_daytrades-1) close_trades=1;
   // 3. Encerra ao atingir o prejuízo diário máximo
   else if (trade_sum<=max_tradeloss) close_trades=1;
   //--- Critérios a partir de 3 pts
   else if (trade_ct>=3) {
      if (trade_ct>fail_trades-1 && gain_ct<1) close_trades=1;
      else if (trade_ct>gain_ct && trade_sum>=5) close_trades=1;
      else if (trade_ct==3 && gain_ct==3) close_trades=1;
   }
}

Em seguida, a base do código está na identificação do momento “ideal” para abertura ou fechamento de posição…

Este controle foi implementado através da variável trade_open. Quando trade_open for 0, verificaremos a possibilidade de abrir uma nova posição. Por outro lado, caso seja 1, avaliaremos as possibilidades de fechar a posição (desviando o processamento para o bloco else).

Também limitamos a capacidade de abrir novas operações através da variável close_trades – ao atribuir o valor 1, encerramos as operações no dia e fechamos qualquer posição em aberto.

//--- Verifica se existe um trade em aberto (trade_open):
// 1. Caso não exista operação em aberto, verifica se a próxima barra está prestes a ser desenha e libera o processamento (isNewBar)
// 2. Caso exista, verifica a possibilidade de fechar a posição (desviará para o bloco "else")
if (!trade_open && !close_trades) { 
    // Código para abertura de posição
    if (isNewBar(time[i], start, LM_OPEN)==true) {
       trade_dir=0;
       bars_trade=0;
       buf_color_line[i]=0;
       ...

       //--- Coloque aqui seu código para abertura de posição

    }
}
else {
    // Código para fechamento de posição
              
    // atualiza buf_color_line pelo último valor de trade_dir
    buf_color_line[i]=trade_dir;
    ...
    if (isNewBar(time[i], start, LM_CLOSE)==true && buf_color_line[i]>0) {
        ...

        //--- Coloque aqui os critérios para fechar a posição

        // 1. Fecha posição depois de 5 barras sem ganho superior a 2 pts
        // 2. Atualiza buf_color_line pelo valor de trade_dir
        if (close_trades) trade_dir=0;
        else if (bars_trade>5 && trade_maxgain<2) trade_dir=0;
        buf_color_line[i]=trade_dir;
        ...
    } // encerramento isNewBar
} // encerramento do bloco else (tenta fechar o trade)

Para facilitar no entendimento, coloquei vários comentários em todo código. Acredito que qualquer ajuste possa ser feito sem grandes dificuldades.

Caso você perceba algum bug ou tenha alguma ideia para acrescentar, por favor entre em contato!

Tenham consciência de que poucos *investidores* sobrevivem aos trades. Vende-se muita ilusão na Internet. Seja qual for a sua escolha, faça consciente!

Indicadores-parte2: Programação de robôs de trade (videoaula)

Nesta segunda parte, da série de vídeos sobre indicadores, optei por tratar sobre a codificação da mudança de cor do candlestick em função da média móvel exponencial.

Conforme exposto anteriormente, meu primeiro contato com a codificação do indicador foi através de um vídeo da DeltaTrader. Mas, a base para manipular as cores do candlestick foi a partir de um projeto gratuito, desenvolvido por Kourosh Davallou:
https://www.mql5.com/pt/code/1349

Confiram a segunda parte:

Os exemplos demonstrados estão disponíveis através da url:
http://aprendizfinanceiro.com.br/indicador-aulas2.zip

Conforme prometido, também disponibilizarei para download o código para implementação da VWAP

A VWAP é a representação do Preço Médio Ponderado por Volume (Volume Weighted Average Price) e costuma ser vista como uma opção para visualizar como os grandes players estão agindo.

Em relação aos trades, a VWAP pode ser utilizada como uma referência de suporte ou resistência. Existem várias observações. É fácil perceber que uma reversão pode acontecer quando o preço toca a VWAP. Porém, caso o preço rompa de forma expressiva (rompendo um suporte ou resistência), o movimento dentro da tendência pode acontecer de forma mais expressiva (ao acionar stops, por exemplo).

Compreendi melhor a formula da VWAP através deste artigo (em inglês):
https://stockcharts.com/school/doku.php?id=chart_school:technical_indicators:vwap_intraday

O bloco de código é basicamente este:

   sumPrice    += (double) (((high[i]+low[i]+close[i])/3) * volume[i]);
   sumVol      += (double) volume[i];
   buf_VWAP[i] = NormalizeDouble(sumPrice/sumVol,2);

A seguir, o link para download:
http://aprendizfinanceiro.com.br/vwap.zip

No momento, é a última versão que tenho utilizado. Caso você tenha alguma sugestão ou faça alterações, por favor nos informe e compartilhe o código!

Gostaria de deixar claro que minha atuação principal permanece como holder. O que estou compartilhando é uma experiência pessoal e, caso bem sucedido, pretendo apenas reforçar os aportes mensais. Não estou muito convicto de que realmente vale a pena.

Tenham consciência de que poucos *investidores* sobrevivem aos trades. Vende-se muita ilusão na Internet. Seja qual for a sua escolha, faça consciente!

Desejo sucesso a todos… infelizmente, sei que serão poucos! 😉

Indicadores-parte1: Programação de robôs de trade (videoaula)

Finalmente, disponibilizei uma demonstração da codificação de um indicador no Metatrader5 (linguagem MQL5). Resolvi dividir, em pelo menos, duas partes. Na primeira, tratei sobre a estrutura básica e a lógica fundamental para criação de um indicador.

No vídeo seguinte, pretendo demonstrar a codificação de um indicador VWAP e, se possível, finalizarei demonstrando como criar um indicador que ajuste as cores do candlestick de acordo com alguns critérios da análise técnica – será referência para nosso EA.

Caso você não tenha experiência com programação, recomendo a leitura do artigo sobre algoritmos:

Vamos a primeira videoaula sobre a codificação do indicador:

Os exemplos demonstrados estão disponíveis através da url:
http://aprendizfinanceiro.com.br/indicador-aulas1.zip

Na explicação da média móvel, estava com pressa para finalizar (antes de minha câmera digital encerrar o vídeo) e não expliquei corretamente o cálculo da média móvel. Mas, resumindo:

1. Somando preço de fechamentos das últimas 20 barras (period): 
   for (int j=0; j<period; j++) media+=close[i-j]; 

Este código faria algo como 
   media=media+close[i-0]; 
   media=media+close[i-1];
... 
   media=media+close[i-period];

2. A média é o valor da soma dividido pelo período:
   media=media/period;

Procurei ser o mais objetivo possível, cobrindo os pontos principais para codificação.

Vi, em outros vídeos, uma demonstração de codificação voltada para “traders” e não, necessariamente, para programadores

Infelizmente, não acredito que isto seja possível.

Quem não abstrair a lógica de programação, fatalmente terá uma capacidade de codificação muito limitada. Desenhar linhas, por si só, não serve para nada. Portanto, não desprezem os aspectos técnicos demonstrados.

Para auxiliar no entendimento, recomendo assistir o seguinte vídeo:

O vídeo anterior foi produzido pela equipe da DeltaTrader e é bastante didático. Aliás, foi por onde me orientei para começar.

Sei que não é tão simples como muitos gostariam, mas sejam pacientes. Ao abstrair a base de codificação, os próximos passos se tornam cada vez mais fáceis.

Então, cada coisa ao seu tempo! 😉

Sucesso para todos!

Programação de Indicadores: Identificando os últimos negócios antes de desenhar a próxima barra!

Aproveitando que tenho compartilhado informações sobre a codificação de robôs no Metatrader5 (ainda em “indicadores“) e algumas dúvidas ou curiosidades estão surgindo, resolvi demonstrar o código que utilizo para identificar os últimos negócios ou nova barra.

A função isNewBar foi definida, inicialmente, para permitir a identificação de uma nova barra – o meu objetivo era abrir os cálculos a cada nova barra.

Parecia simples, bastava comparar “last_time!=lastbar_time” (ou seja, comparar valor atual com o anterior e retornar true quando os valores não forem iguais).

bool isNewBar(const datetime lastbar_time, const int prev_calc) {
   ...
   if (last_time==0 || init_time==0 || last_time!=lastbar_time) {
      last_time=lastbar_time;
      init_time=init_auxtime;
      if (last_time==0) return(false);
      return(true);
   }
   ...
   return(false);
}

O valor de lastbar_time é o horário da barra atual (baseado na abertura, e fornecido pela variável time[i]) – mudará apenas na próxima barra. E last_time é o último horário capturado.

Funciona perfeitamente para a primeira execução do indicador, quando prev_calculated for 0 (com dados históricos). Porém, a lógica não pode ser a mesma quando o indicador estiver analisando os negócios em tempo real.

Suponhamos que você queira trocar a cor do candle quando o preço de abertura for igual ao preço de fechamento (para fechar posição)…

Com os dados históricos (prev_calculated 0), a barra não é processada ticket a ticket. Então, se compararmos open com close assim que a função isNewBar retornar true, teremos a certeza de que open[i] representa o primeiro negócio e close[i] o último (no intervalo de tempo representado pela barra).

Pois é, mas o comportamento não será o mesmo quando prev_calculated for maior que 0 (em tempo real). Neste caso, assim que a próxima barra for desenhada, para o primeiro ticket, teremos open igual a close. Ou seja, a comparação será SEMPRE verdadeira logo que surgir a próxima barra.

Por esta razão, inclui o controle de tempo decorrido (time_match):

   ...
   datetime init_auxtime=TimeCurrent();
   ...
   // 5 minutos
   limit_time=300;
   time_match=(limit_time-(init_auxtime-init_time));
   ...
   if (last_time==0 || init_time==0 || last_time!=lastbar_time) {
      last_time=lastbar_time;
      init_time=init_auxtime;
      if (last_time==0) return(false);
   }

   if (prev_aux==0) return(true);
   else if (time_match<=1) {
      if (time_match<=0) {
         last_time=lastbar_time;
         init_time=init_auxtime;
         return(false);
      }
      return(true);
    }
    ...

Esta é uma das várias pegadinhas deste tipo de programação! 😉

Confiram, logo a seguir, a função completa:

...
int time_punish=0;
...
bool isNewBar(const datetime lastbar_time, const int prev_calc)
  {
//--- memorize the time of opening of the last bar in the static variable
   static datetime last_time=0;
   static datetime init_time=0;
   
   datetime init_auxtime=TimeCurrent();

   int limit_time=0,prev_aux=prev_calc;
   long time_match=0;
   
   limit_time=300;
   time_match=(limit_time-(init_auxtime-init_time));
   if (time_match<0) time_match=0;
   
   string label_name1="Seconds", label_text="Seconds... "+(string) (long)time_match;
   ObjectDelete(0, label_name1);
   ObjectCreate(0, label_name1, OBJ_LABEL, 0, 0, 0);
   //ObjectSetInteger(0,label_name1,OBJPROP_XDISTANCE,960);
   ObjectSetInteger(0,label_name1,OBJPROP_XDISTANCE,ChartGetInteger(0,CHART_WIDTH_IN_PIXELS,0)-100);
   ObjectSetInteger(0,label_name1,OBJPROP_YDISTANCE,30);
   ObjectSetInteger(0,label_name1,OBJPROP_COLOR,YellowGreen);
   ObjectSetString(0,label_name1,OBJPROP_TEXT,label_text);
   
//--- if it is the first call of the function or new bar
   if (last_time!=lastbar_time && trade_open>0) bars_trade++;
   if (last_time==0 || init_time==0 || last_time!=lastbar_time) {
      if (init_auxtime>=init_time+limit_time && init_time>0) prev_aux=0;
      time_punish=1;
      last_time=lastbar_time;
      init_time=init_auxtime;
      if (last_time==0) return(false);
   }

//--- allow after 5 minutes - 1s
   if (time_match>2 && time_match<250) time_punish=0;
   if (prev_aux==0) return(true);
   else if (time_match<=1) {
      if (time_match<=0) {
         last_time=lastbar_time;
         init_time=init_auxtime;
         time_punish=1;
         return(false);
      }
      if (time_punish==0) return(true);
   }
   
//--- if we passed to this line, then the bar is not new; return false
   return(false);
  }

"A primeira definição, com a criação de um objeto do tipo LABEL, exibirá o contador decrescente (time_match) dos segundos decorridos (300s ou 5min)"

O código responsável pelos cálculos fica limitado pela função isNewBar:

if (isNewBar(time[i], last)==true) {
   ...
   // codificação para mudança de cor do candlestick
   if (open[i]==close[i]) buf_color_line[i]=0;
   ...
}


Resultado do mês de março (2019)

Apesar das “pequenas turbulências” no cenário político-econômico (em torno da proposta para a reforma da previdência), o resultado do mês foi excelente – provavelmente o melhor do ano (contamos com rendimentos “generosos”). Pela primeira vez conferimos o índice IBov romper os 100.000 pts. O clima de tensão atual fez com que o índice recuasse, mas existe a influência do ímpeto de realização de lucros também. Sem muitas delongas, vamos aos resultados.

Estamos entrando no último mês para a entrega para declaração anual do Imposto de Renda (IRPF), terei bastante trabalho para os próximos dias. Sendo assim, desta vez, serei mais direto. Para quem investe em renda variável, recomendo a contratação de alguma calculadora de IR, como o IRPFBolsa – lhe asseguro, quanto mais adiar, maior será seu arrependimento no futuro (é muito trabalhoso, risos).


Apesar de pequenas turbulências, o otimismo no mercado de capitais prevalece. Se avaliarmos o período de 6 meses, estamos com uma vantagem de 16.790,90 pts.

Fonte: Google

Um “pequeno atrito” entre o Presidente da Câmara e representantes do atual governo geraram incertezas momentâneas para o mercado. Seja como for, acredito que um movimento corretivo era esperado.

Como de costume, confiram os principais números e acontecimentos que sacudiram o país e o mundo (do redator chefe da Modal):

Para quem tem interesse em aperfeiçoar o conhecimento sobre o mercado financeiro, surgiu uma oportunidade bastante interessante: a BTG Pactual abriu inscrições (até 7 de abril) para um curso de graduação – será ministrado pelos sócios do Banco.

Para ter acesso ou acompanhar os balanços, recomendo o seguinte link:
https://www.acionista.com.br/agenda/resultados-das-cias.html

Quanto aos investimentos…

Recebi proventos de BBAS3, EGIE3, ITSA3, ITUB3, WEGE3, BRCR11 (9,95%), FCFL11 (0,555%), PQDP11 (0,495%), KNRI11 (0,484%), RNGO11 (0,585%), SAAG11 (0,740%), GGRC11 (0,634%), MXRF11 (0,629%), KNCR11 (0,515%), HGRE11 (0,493%), FLMA11 (0,374%), HGBS11 (0,560%) e FIGS11 (1,358%). O mês foi simplesmente impressionante (risos). Finalizada a negociação com a Brookfield, o fundo BRCR11 distribuiu o rendimento de 9,95% (R$ 10,57 por cota) – portanto, não foi um evento recorrente, mas a previsão é que o fundo apresente uma performance melhor no ano (até pela diminuição da vacância). De maneira geral, o rendimento da carteira permanece excelente, sendo reforçado (e que reforço) com o pagamento de dividendos e JCP de BBAS3, EGIE, ITSA3, ITUB3 e WEGE3.

O rendimento da carteira quebrou qualquer expectativa para o ano. É óbvio que foi um resultado atípico e acho pouco provável que os próximos meses superem. E agora… Entendem porque a atuação como holder é praticamente obrigatória.

Com o rendimento da própria carteira, somado ao capital que me prontifico separar para investir mensalmente, comprei mais ações (ou cotas) de BBAS3, ITSA3, ITUB3, WEGE3, FLRY3, BBSE3, HYPE3, EGIE3, ODPV3, BRCR11 e KNRI11. Os menores aportes foi para ODPV3, BBAS3 e BRCR11, e os maiores para ITUB3, WEGE3 e KNRI11 (de maneira geral, foram bem equilibrados). Como o rendimento foi bastante expressivo, decidi “distribuir melhor” os aportes.

Confiram a distribuição dos ativos, segundo o portal CEI (NÃO inclui o Fundo DI):

A proporção em ações continua bastante expressiva em decorrência da forte valorização do índice Ibov

A composição atual ficou assim (gráfico do IrpfBolsa):

Vale lembrar que o gráfico acima representa uma distribuição baseada no custo de aquisição, não no valor de mercado

O resultado mensal foi MUITO surpreendente. Fiquei extremamente satisfeito, pois minha capacidade de aporte foi maior. É preciso saber aproveitar bem estes momentos, pois não são frequentes.

O robô de trade abriu o mês com vários gains, mas, infelizmente, finalizou com prejuízo de R$20. Já estou na 22 revisão do código e o índice de acerto está melhorando bastante – ainda não coloquei em produção a última revisão.

De maneira geral, estou bastante satisfeito. Vale lembrar que, no curto prazo, oscilações são naturais e esperadas (com movimentos de repique, por exemplo). Dentro de qualquer tendência, os papeis não se movimentam em linha reta.

Estou apenas demonstrando o potencial de crescimento, isto não é recomendação de investimento.