Neo traderBot

Neo traderBot

Você sabia?

A NeoTraderBot é a primeira comunidade aberta no Brasil com foco em compartilhar informações sobre automatização de estratégias

leaf leftleaf right

Versão LIGHT

FRAMEWORK-ntsl-light

Esta é a primeira versão de framework lançada pela Comunidade NeoTraderBot. É uma versão gratuita e simples, mas que possui algumas funcionalidades básicas de gestão de robô e de operações.

A ideia principal do Framework NTSL LIGHT é que o usuário entenda como se utiliza um framework e como ele pode se beneficiar de funcionalidades já implementadas, bastando programar os sinais desejados de abertura de posição, reversão e encerramento.

FRAMEWORK NTSL LIGHT é uma versão de demonstração, sem custo e com o código fonte aberto. Ele foi concebido para ser executado em gráficos temporais e os sinais fornecidos pelo usuário serão executados com ordens a mercado.

FRAMEWORK NTSL LIGHT

Coded by NeoTraderBot
R$ 0 Sem custo
  • Modo Daytrade e Swing Trade
  • Gerenciamento de abertura de posição de tamanho fixo
  • Administração de trade via sinal de reversão ou encerramento
  • Administração de trade com Risco/Ganho pré-definido
  • Ordens OCO de Stoploss e TakeProfit
  • Plot das linhas de Alvo/Stoploss/Gatilho Breakeven
  • Limitação de quantidade de trades por dia
  • Janela de negociação para abertura de posição
  • Encerramento de posição em horário limite
CÓD ABERTO

Como instalar/remover ferramentas, indicadores e estratégias da Trader Evolution

Nesse tutorial vamos ver o passo-a-passo para instalação e remoção de ferramentas, estratégias e indicadores na Plataforma Trader Evolution.

Todas as ferramentas, indicadores ou estratégias automatizadas desenvolvidas pela NeoTraderBot, independente de serem pagas ou gratuitas, são autenticadas antes de iniciarem sua execução. Assim é imprescindível que você instale a biblioteca de Autenticação da NeoTraderBot em sua plataforma Trader Evolution.

Instalando o Biblioteca de Autenticação da NeoTraderBot

Este é um procedimento bem simples, basta clicar aqui para baixar a versão mais recente da biblioteca de autenticação da NeoTraderBot. Por se tratar de um arquivo com extensão dll, seu navegador pode alertar para algum risco no download. Certifique-se de que conseguiu baixar o arquivo sem problemas.

Em seguida, mova o arquivo baixado para o diretório principal da TraderEvolution. Sigas os passos abaixo para identificar o diretório principal da plataforma TraderEvolution.

Passo 1: Abra uma janela do Windows Explorer (atalho WINDOWS + E) e na barra de endereço, (no lado esquerdo e superior da tela, logo abaixo do menu), digite “%APPDATA%” e pressione ENTER.

Passo 2: Será aberto um diretório contendo os programas instalados em seu PC, localize a pasta “Trader Evolution Brasil” e acesse-a.

Passo 3: Você está agora dentro do diretório principal da Trader Evolution. A biblioteca de autenticação deve ser copiada para dentro do diretório principal.

OBS: A sua plataforma Trader Evolution deve estar preferencialmente fechada.

Instalando Indicadores e Estratégias na TraderEvolution

A instalação de indicadores e Estratégias consiste basicamente em copiar as estratégias para dentro das pastas apropriadas dentro do diretório TraderEvolution, ou criar um diretório para concentrar códigos e referenciar esta pasta dentro da TraderEvolution.

Abaixo vamos demonstrar as duas maneiras de fazer a TraderEvolution listar os indicadores e estratégias dentro da plataforma.

Forma 1: Incluindo indicadores e estratégias nas pastas nativas da TraderEvolution

Passo 1: Abra uma janela do Windows Explorer (atalho WINDOWS + E) e na barra de endereço, (no lado esquerdo e superior da tela, logo abaixo do menu), digite “%APPDATA%” e pressione ENTER.

Passo 2: Será aberto um diretório contendo os programas instalados em seu PC, localize a pasta “Trader Evolution Brasil” e acesse-a.

Passo 3: Você está agora dentro do diretório principal da Trader Evolution. Acesse a pasta “Scripts”.

Passo 4: Dentro da pasta “Scripts”, você terá a pasta “Indicators” e “Strategies”. Basta copiar os indicadores/estratégias para dentro das respectivas pastas e a TraderEvolution passará a listá-los.

OBS: Esta cópia pode ser feita com a plataforma aberta. No entanto, recomendamos que feche-a antes de substituir arquivos.

Passo 5: Ao clicar sobre um gráfico o botão direito -> “Indicadores” -> “Adicionar Indicador”, você notará que os arquivos acrescentados na pasta “Indicators” são listados adequadamente.

OBS: Os arquivos são listados pelo nome do arquivo do código. Todos os arquivos da NeoTraderBot possuem em seu nome as iniciais NTB, facilitando assim a pesquisa pelo campo de busca. Observe que os novos indicadores não são listados dentro das categorias apresentadas pela plataforma.

Forma 2: Importando os códigos a partir de uma pasta ou arquivos individuais

Iremos demonstrar abaixo o processo para importação de indicadores. O procedimento é análogo no caso de estratégias, sendo a única diferença que o processo de importação de estratégias ocorre dentro do “Strategy Manager” ao tentar adicionar uma estratégia.

Passo 1: Crie uma pasta no local que desejar e copie para dentro dessa pasta os códigos que deseja que sejam listados dentro da plataforma TraderEvolution. Uma boa prática é manter um diretório para indicadores e outro para estratégias.

OBS: No exemplo abaixo, preferimos criar as pastas “NeoTraderBot_Indicators” e “NeoTraderBot_Strategies” dentro da pasta “Scripts” da TraderEvolution (conforme pode ser visto abaixo).

Passo 2: Ao clicar sobre um gráfico da TraderEvolution com o botão direito -> “Indicadores” -> “Adicionar Indicador”, será aberta uma janela para seleção de indicadores. Clique em “Importar”.

Passo 3: Será aberta uma janela de “Importar Script”, a qual você poderá selecionar uma pasta ou arquivos de maneira individual. Escolha uma das opções e localize os arquivos/pasta que deseja importar.

Passo 4: Ao acrescentar os arquivos, eles serão identificados pelo seu respectivo tipo e listados conforme figura abaixo. A coluna “Destino” por padrão seleciona a opção de copiar os arquivos para um diretório da TraderEvolution do usuário da máquina em “Documents\Trader Evolution Brasil\My scripts”.

Selecione a opção desejada na coluna “Destino” e, em seguida, clique em “Importar”.

Passo 5: Os arquivos serão importados e serão listados no grupo “Personalizado” na janela de “Pesquisa de Indicadores”.

Removendo Indicadores e Estratégias na TraderEvolution

A remoção de indicadores e Estratégias consiste basicamente em excluir os indicadores e estratégias das pastas nas quais eles foram copiados ou importados.

Conforme apresentado nos roteiro anteriores, a depender da forma como o usuário importou/copiou as ferramentas, elas podem estar no diretório principal da Trader Evolution (Passo 1 do roteiro de instalação da biblioteca de autenticação), ou na pasta do usuário windows referente ao programa Trader Evolution (em “Documents\TraderEvolution Brasil\My scripts”).

Em “My scripts” o usuário irá localizar tanto os códigos compilados (pasta bin) como código-fonte que foram criados pelo EvoCode localmente (arquivos cs, nas pastas “Indicators” e “Strategies”).

Snippets para Localização Temporal

Introdução

Esta seção visa apresentar trechos de códigos com funcionalidades relativas à localização temporal da estratégia. Por exemplo, identificar se a atual barra é a primeira barra do dia para verificar gap diário.

Você pode acessar os Snippets diretamente pelo menu lateral direito, ou fazendo CTRL+F (CTRL+L) para localizar algum texto específico na página, uma vez que o conteúdo tende a crescer ao longo do tempo, dificultando a navegação pelo menu.

Caso tenham sugestões de código para acrescentar à lista, gentileza deixar o código nos comentários com o link para seu perfil em rede social (para devido crédito de autoria).

Snippets

Identificação do primeiro candle de cada dia

Reproduzir vídeo

Algumas estratégias necessitam da identificação da primeira barra do dia (candle) para executar determinada ação ou calcular o gap em relação ao fechamento do dia anterior.

				
					var
  bPrimeiraBarraDoDia : boolean;
  iDataAtual          : integer;
begin
  if (Date() <> iDataAtual) then
    begin
      iDataAtual := Date();
      bPrimeiraBarraDoDia := true;
    end;
  if bPrimeiraBarraDoDia then
    begin
      bPrimeiraBarraDoDia := false;
      //Faz alguma coisa na primeira barra do dia
      paintBar(clGreen);
    end;
end;
				
			

Identificação de barra por data e hora específicos

Este código localiza a barra (candle ou box) por uma data e hora desejados. Onde a hora é referente ao horário de abertura do candle desejado. Observa-se que existe uma parte do código comentada para utilização em backtesting de gráficos de renko.

OBS: As variáveis pDataDesejada e pHorarioDesejado não foram declaradas como parâmetros para facilitar o teste do Snippet, uma vez que não é possível alterar parâmetro dentro do Editor de Estratégias.

				
					var
  bBarraDesejada                 : boolean;
  pDataDesejada,pHorarioDesejado : integer;
begin
  pDataDesejada := 20220928;
  pHorarioDesejado := 1200;
  if (Date() = ELDate_Consol(pDataDesejada)) And (Time() = pHorarioDesejado) then
    begin
      bBarraDesejada := true;
      //Faz alguma coisa na barra identificada
      paintBar(clGreen);
    end
  else 
    bBarraDesejada := false;
end;
				
			

Identificação do primeiro tick de uma barra

Reproduzir vídeo

Este código identifica o primeiro tick de uma barra. Este Snippet tem aplicação apenas quando a estratégia é utlizada em tempo real.

OBS: É importante ressaltar que em backtesting com dados históricos não há dados tick a tick. Desta forma, este Snippet não possui aplicação em backtesting com dados de barra a barra.

				
					var
  bPrimeiroTickDaBarra : boolean;
  iBarraAtual          : integer;
begin
  if LastBarOnChart then
    if (CurrentBar <> iBarraAtual) then
      begin
        iBarraAtual := CurrentBar;
        bPrimeiroTickDaBarra := true;
      end
  else 
    bPrimeiroTickDaBarra := false;
  if bPrimeiroTickDaBarra then
    begin
      //Faz alguma coisa no primeiro tick da barra
      //Aplicável apenas em execução de tempo real
      paintBar(clGreen);
    end
  else 
    begin
      //Faz alguma coisa nos demais ticks da barra atual
      //Aplicável apenas em execução de tempo real
      paintBar(clYellow);
    end;
end;
				
			

Contador de Candles do dia

Este código realiza a contagem de barras dentro de um mesmo dia.

				
					var
  bPrimeiraBarraDoDia : boolean;
  iDataAtual          : integer;
  iCurrentBarIntraday, iFirstBarOfDay : integer;
begin
  if (Date() <> iDataAtual) then
    begin
      iDataAtual := Date();
      bPrimeiraBarraDoDia := true;
      iFirstBarOfDay := CurrentBar;
    end;
  if bPrimeiraBarraDoDia then
    begin
      bPrimeiraBarraDoDia := false;
      //Faz alguma coisa na primeira barra do dia
      paintBar(clGreen);
    end;

    iCurrentBarIntraday := CurrentBar - iFirstBarOfDay + 1;
    plotText(iCurrentBarIntraday, clWhite,0, 12);

end;
				
			

Plataformas

Conhecendo o Profit Chart

Nesta seção iremos abordar todos detalhes relativos à programação de estratégias dentro do Profit Chart.

Primeiro contato com o Profit

Reproduzir vídeo

Para ter sucesso em qualquer área de conhecimento é preciso saber utilizar bem as ferramentas do seu trabalho. Um marceneiro precisa saber usar muito bem o formão, a serra e o maquinário de madeira para fazer bons móveis. Um cirurgião não conseguiria conduzir uma cirurgia com sucesso em um paciente se não manipulasse muito bem o bisturi, o equipamento de microgravação, a medicação que precisa ser dosada, etc… Por que seria diferente para quem opera no mercado financeiro?

O objetivo desse texto é falar um pouco sobre a plataforma Profit Chart, comercializada pela empresa Nelogica no Brasil. As plataformas de negociação são imprescindíveis para quem deseja se especializar e aprofundar no assunto de operações e investimento no mercado financeiro. É a ferramenta do dia a dia do trader!

Existem outras plataformas profissionais disponíveis para se operar, mas certamente as duas com maior capilaridade para quem opera ativos da B3 é o Profit Chart e o MetaTrader da empresa MetaQuotes. Aqui na Comunidade decidimos começar a explorar o universo de automatização de estratégias para negociação de ativos na plataforma Profit Chart por algumas razões que detalhamos neste artigo do blog e nesse vídeo do nosso Canal no Youtube.

Quais são as funcionalidades que uma plataforma profissional de trading pode te oferecer? Antes de falar sobre as funcionalidades temos que definir muito bem o que se espera de uma plataforma profissional. Na minha opinião, parte dos requisitos esperados seriam:

  1. Funcionalidades que permitam análisar os movimentos do mercado e fluxo de negociação:
    • Multiplas janelas abertas de dados de ativos e outras informações;
    • Diferentes tipos de gráficos e plotagens;
    • Possibilidade de visualizar em qualquer tempo gráfico desejado (1 min, 5 min, 12 min, 60 min, etc…);
    • Informações detalhadas do Book de ofertas;
    • Informações detalhadas das negociações realizadas;
    • Possibilidade de personalizar a aparência dos gráficos;
    • entre outras…
  2. Facilidade para abrir posições, administrar e encerrar operações:
    • Operar diretamente no gráfico do ativo visando agir com maior tempestividade;
    • Funcionalidades de stoploss tanto para limitar prejuízos quanto para proteger ganhos;
    • Acompanhamento do desempenho das operações, quantidade, relação risco/ganho;
    • Evolução de patrimônio;
  3. Plataforma leve e que não trave e tampouco apresente falhas que execução que possam comprometer o desempenho das operações em andamento (Sem bugs);
  4. Possibilidade de operar múltiplas contas de corretoras;
  5. Possibilidade de configurar limites de gestão de risco a fim de proteger patrimônio contra atitudes com prudentes;
  6. Possibilidade de automatizar setups operacionais;
  7. Possibilidade de simular o mercado financeiro para determinada data e ativo.

Sabendo o que esperamos encontrar em uma plataforma profissional, gravamos o vídeo abaixo para quem está iniciando agora e ainda não viu uma plataforma ou apenas opera pelo home broker de sua corretora. Assista e deixe seu comentário!

Não estamos querendo pintar o quadro de que o software Profit Chart é perfeito. Pois o Profit Chart não é perfeito. É um software muito bom pelas ferramentas que oferece para analisar e ler o mercado, mas também possui algumas limitações importantes quanto à automatização de estratégias, principalmente por não permitir a e execução de robôs programados pelo próprio usuário em conta real. Ainda assim, o Profit pode ser considerado um bom ponto de partida para iniciarmos a jornada de conhecimento para automatização de estratégias na negociação de ativos! Com o tempo, naturalmente iremos abordar também a automatização em plataformas como MetaTrader, TradingView, e utilização de APIs em python para realizar estudos estatísticos e implementar algoritmos mais complexos para operar na bolsa!

Bom, por ora, no próximo documento vamos ensinar como utilizar o ambiente de edição de estratégias do Profit Chart. Esta será a principal ferramenta que iremos utilizar para criar códigos para automatizar diversas tarefas atinentes a operação na bolsa de valores, desde a criação de indicadores, regras de coloração, filtros de seleção de ativos até backtesting de estratégias de execução (robôs de investimento) e muito mais!

Editor de estratégias

Reproduzir vídeo

Este documento irá abordar todos os detalhes importantes sobre a ambiente de edição de estratégias do Profit Chart: Editor de Estratégias.

A linguagem utilizada pelo Profit Chart é a NTSL (Nelogica Trading System Language). É uma linguagem com uma sintaxe muito semelhante a Pascal, porém com uma restrição nos comandos. A linguagem NTSL também aceita comandos em português, embora não seja uma boa prática, dado que todas as linguagens com grande abrangência são em inglês. Logo, é melhor o usuário já se acostumar com os termos em inglês visando maior facilidade em uma transição futura para outra linguagem de programação.

Vamos às questões práticas…

Como acessar o Editor de Estratégias?

Após abrir o Profit, basta acessar o menu principal na parte superior, clicar em “Estratégias” e em seguida na opção “Editor de estratégias”.

O Editor de estratégias aparecerá conforme a figura abaixo.

Modos de exibição do Editor de Estratégias

Note que na parte superior temos 4 modos de exibição do editor de estratégias, que são:
  • Editor: apresenta apenas a tela de edição do código fonte e de debug (debug é uma funcionalidade para depurar seu código fonte, ou seja, executar passo a passo para verificar se tudo está rodando corretamente);
  • Gráfico: apresenta apenas o gráfico no qual está sendo testada a estratégia em edição;
  • Misto: apresenta tanto a tela de edição do código fonte e debug, quanto o gráfico no qual a estratégia em edição está sendo testada;
  • Estatísticas: este modo aplica-se apenas às estratégias de execução, ou seja, estratégias que realizam ordens de compra/venda para fins de backtest.

Vamos detalhar abaixo o modo de exibição mais utilizado, o modo “Editor”. O modo “Estatísticas” será bastante trabalhado nos documentos relacionados à backtesting.

Modo "Editor"

O modo editor possui três áreas principais: a barra de ferramentas, a área de edição de código e a área de compilação/debug.

Note que o editor pode ter múltiplas estratégias abertas em edição ao mesmo tempo. A barra inferior apresentará abas diferentes para cada estratégia. Uma estratégia que foi criada mas ainda não foi salva constará na aba “NoName”, conforme pode ser visto na figura abaixo.

Barra de ferramentas

Vamos detalhar a função de cada ícone da barra de ferramentas:

Ícone Função

Nova estratégia: abre janela para seleção de modelos do Profit para criar uma nova estratégia;

Abrir estratégia: abre uma janela para seleção de estratégias salvas no Profit;

Fechar estratégia: fecha a edição da estratégia atual. O usuário será perguntado se deseja salvar as alterações, caso haja alguma alteração não salva;

Salvar: salva as alterações existentes na estratégia. Caso haja algum erro de sintaxe, o sistema irá perguntar ao usuário se deseja salvar assim mesmo;

Salvar como: permite salvar a estratégia em edição como um novo arquivo de estratégia, podendo configurar um novo nome e descrição;

Verificar sintaxe: o sistema realiza uma verificação da sintaxe da estratégia e indica eventuais erros;

Step over (debug): uma vez em modo de depuração e a execução para em determinada linha de código, este botão executa a linha e para na próxima;

Trace into (debug): uma vez em modo de depuração e a execução para em uma determinada linha que realiza a chamada de uma função ou procedure criada pelo usuário, o depurador irá executar linha a linha o código fonte dentro da função/procedure chamada;

Executar estratégia: o editor de estratégia passa para o modo de exibição misto e apresenta o resultado da execução da estratégia no gráfico ao lado da área de edição do código-fonte. O depurador irá parar na primeira linha a ser executada que tenha breakpoint;

Parar estratégia: interrompe a execução da estratégia;

Propriedades da estratégia: permite , no caso de indicadores, configurar a aparência das séries plotadas (cor, espessura e tipo de tracejado, tipo de gráfico: linha/histograma), linhas guias e suas aparências (linhas horizontais com valor fixo) e configurar tipo de preenchimento entre as séries plotadas;

Formatação automática do código: realiza a identação (configuração de espaços) e quebras de linhas do código de forma automática e uniforme. (Nem sempre funciona direito!)

Lista de funções: apresenta listagem de funções disponíveis no editor de estratégias agrupadas por tema;

Lista de constantes: apresenta listagem de constantes definidas pelo Profit agrupadas por tema;

Linhas no Gráfico Principal: alterna a plotagem das séries entre um subgráfico ou dentro do gráfico principal do ativo;

Configurações do editor: abre janela para personalização do editor de estratégias, podendo alterar a fonte do editor, tamanho, cores e etc...

Área de edição de código

Na área de edição de código é apresentado o código fonte da estratégia. Note que há uma numeração das linhas a esquerda para facilitar a identificação do código quando houver sinalização de erro de sintaxe.

O usuário pode criar breakpoints para depuração do código (debug) clicando no vão entre a númeração da linha e a coluna em cinza. A criação do breakpoint será indicada por um ícone circular azul, bem como o preenchimento da linha de código na mesma cor.

Área de compilação/debug

Nesta área, é apresentado o resultado da verificação de sintaxe, bem como os erros existentes no código-fonte da estratégia.

Quando a estratégia é “debugada” (depurada), aparece nesta área também o valor das variáveis declaradas na estratégia.

Gerenciador de estratégias

O Gerenciador de estratégias apresenta todas as estratégias existentes no Profit, tanto aquelas criadas pelo usuário, quanto as estratégias importadas. O Gerenciador pode ser acessado pelo menu principal, clicando em “Estratégias” e em seguida, “Gerenciador de estratégias”, conforme figura abaixo.

O gerenciador deve se apresentar conforme figura a seguir. Será apresentado ao usuário uma relação de estratégias com a indicação do tipo a que pertence. É importante ressaltar que uma estratégia, pode estar associada a mais de um tipo. Por exemplo, pode haver uma estratégia que realiza tanto uma coloração de gráfico como também realiza o filtro do ativo (screening).

Para cada linha referente a cada estratégia, o usuário pode editar a estratégia (ícone de lápis), compartilhar a estratégia pelo Connect Chat com um outro usuário do Profit ou grupo (Ícone com 3 pontos) ou excluir a estratégia.

Pelo gerenciador de estratégias é possível também fazer a importação de estratégias criadas por outras pessoas e a exportação das estratégias existentes no Profit da máquina.

Como importar ou exportar estrategias?

A importação e exportação de estratégias é realizada por meio de arquivos com extensão psf (Profit strategies file). Esses arquivos podem conter uma ou mais estratégias, com ou sem o código fonte associado.

Quando o usuário não tem acesso ao código-fonte da estratégia, chamamos a estratégia de caixa-preta, uma vez que o usuário não tem informação sobre detalhes da programação, apenas pode informar parâmetros e ter acesso à saída da estratégia, seja ela um indicador ou uma coloração de gráfico. As estratégias caixa-branca são aquelas nas quais o usuário consegue visualizar todo o código fonte.

Para exportar uma estratégia, basta clicar no botão “Exportar” no canto inferior esquerdo do Gerenciador de estratégia. Será aberta uma janela conforme figura abaixo.

O usuário deverá selecionar o nome de um arquivo e uma pasta para realizar a exportação, bem como indicar por meio da caixa de seleção, quais estratégias serão exportadas para o arquivo psf. Note que a opção padrão do sistema é exportar sem código fonte. No entanto, caso o usuário deseje, poderá marcar a opção para exportar a estratégia e o código fonte associado.

O processo de importação de estratégia é análogo à exportação. O usuário deve selecionar um arquivo psf em seu computador e o Profit irá listar as estratégias contidas no arquivo para que o usuário selecione quais serão importadas.

Outra forma de compartilhar estratégias é pelo Connect Chat, sendo o processo mais natural para o usuário, pois ocorrerá dentro da interface do chat da plataforma Profit.

No próximo documento, iremos abordar quais são os tipos de estratégias que podem ser automatizadas na plataforma Profit Chart! 

Tipos de estratégias

Reproduzir vídeo

Neste documento vamos conhecer os tipos de estratégias que podem ser automatizadas no Profit Chart, para que serve cada estratégia, se é possível automatizá-las sem programação e serão apresentados exemplos para que fique bem clara a explicação. A ideia é que você tenha um panorama geral das possibilidades dentro do Profit Chart, pois em outros documentos iremos aprofundar em detalhes sobre como programar cada tipo de estratégia!

Caso tenha algum interesse por um tipo específico de estratégia, utilize o menu lateral direito para ir direto ao ponto desejado.

Então vamos começar tentando estruturar de uma forma mais simples o que seriam as estratégias principais e secundárias. Esta divisão foi criada por mim apenas para facilitar o entendimento. As estratégias principais são aquelas que estão diretamente relacionadas a setups operacionais, motivo que as tornam bastante difundidas e utilizadas. Já as estratégias secundárias, as quais são tão importantes quanto as principais, são relacionadas a outros aspectos de trading, tais como seleção de ativos,  gestão de risco, alarmes e tarefas mais simples como escrever texto em gráficos. Gostaria de ressaltar que as estratégias secundárias são tão importantes quanto às principais, sendo esta classificação adotada apenas para fins didáticos.

Estratégias Principais:

Estratégias Secundárias:

Vamos apresentar a seguir a definição e informações de cada tipo  de estratégia do Profit Chart.

Estratégia de Coloração

As estratégias de coloração são utilizadas para pintar os gráficos de acordo com a lógica que o trader desejar. Você pode pintar gráficos de preço, tais como candles, linhas, renko, ponto, o que quiser e também de volume! Você pode pintar o corpo dos candles, ou se preferir, o fundo do gráfico referente àquele candle!

Para que serve uma estratégia de coloração? Uma estratégia de coloração serve para automatizar uma análise que você faz manualmente. Serve para te liberar o tempo, atenção e foco que você dá para fazer esta análise…E o que você ganha com isso? Você ganha tempo e atenção para dedicar a algo mais importante…para entender o que de fato está acontecendo com o mercado e que se reflete nos movimentos de preço.

Exemplo 1: Colorindo InsideBar (Harami)

Este exemplo ilustra a coloração de candles classificados como InsideBar ou Harami (em japonês). E o que é um InsideBar? É um padrão gráfico no qual um candle possui o preço máximo menor que o preço máximo do candle anterior, bem como o preço mínimo maior que o preço mínimo do candle anterior.

A identificação de InsideBar é importante para alguns setup operacionais que utilizam esse padrão gráfico para iniciar posições. O gráfico abaixo exemplifica a aplicação de uma estratégia de coloração que pinta a barra de InsideBar na cor amarela.

Exempo 2: Double Crossover

Os setups de cruzamento de média (crossover) são amplamente utilizados em análise técnica e foram criados muito antes do uso intensivo de computadores no mercado financeiro.

Neste exemplo clássico de cruzamento de duas médias (double crossover), vamos colorir um gráfico de preço baseado no cruzamento de duas médias do preço de fechamento dos candles. Uma média rápida sobre os preços dos últimos 9 períodos e uma média lenta baseada no preços dos últimos 20 períodos. Obs: as quantidades de períodos das médias podem ser configuradas nos setup operacionais e  otimizadas de acordo com o ativo ou momento de mercado.

Quando a média rápida estiver acima da média lenta, isso sugere um movimento de alta e o gráfico será colorido de verde. Quando a média rápida estiver abaixo da média lenta, isso sugere um movimento de baixa e o gráfico será colorido de vermelho. Na figura abaixo, utilizamos a estratégia de coloração para pintar os candles do gráfico.

Na figura abaixo, utilizamos a mesma estratégia de coloração de cruzamento de média, mas dessa vez colorindo o fundo do gráfico.

Exemplo 3: Volume de agressão

Neste terceiro exemplo, vamos aplicar uma estratégia de coloração à um gráfico de saldo de agressão (que na verdade é um indicador!).

A estratégia de coloração consiste em identificar os momentos nos quais o saldo de agressão supera em duas unidades o desvio padrão da amostra dos últimos N períodos. Onde N para gráficos de 1 minuto poderia ser o valor de 2400 (5 dias x 8 horas x 60 minutos), o que abrange os últimos 5 dias de negociação.

Ou seja, se o saldo de agressão for comprador e for maior do que duas unidades de desvio padrão, a barra de saldo de agressão será pintada de verde. Se o saldo de agressão for vendedor e maior (em valor absoluto) que duas unidades de desvio padrão, a barra de saldo de agressão será pintada de vermelho.

A figura abaixo demonstra a aplicação da estratégia de coloração baseada em volume de agressão.

Estratégia de Indicador

As estratégias de indicadores plotam em um gráfico determinada série calculada com a lógica que o trader desejar. Pode ser tanto no gráfico de preço do próprio ativo, como em um subgráfico separado, geralmente abaixo do gráfico principal.

Criar um indicador que seja útil para tomar decisões não é uma tarefa muito fácil…Você precisa conhecer muito bem a lógica do mercado financeiro, as particularidades do tipo de ativo que está operando e transcrever em fórmulas matemáticas o cálculo de uma variável (o indicador) que lhe traga informação com valor agregado, informação útil para tomada de decisão. Geralmente, os indicadores estão muito vinculados a um determinado padrão de operação e são baseados em análise técnica. São exemplos de indicadores técnicos já consagrados pelo uso, as médias móveis, MACD, Índice de força relativa (IFR), entre outros.

Exemplo 1: Acumulação de Volume Agressor

Neste exemplo de indicador, vamos plotar um histograma em um subgráfico com a acumulação do saldo de agressão enquanto o saldo de agressão da barra permanecer do mesmo lado.

Por exemplo, uma vez que o saldo de agressão é comprador, a acumulação de saldo de agressão inicia. Para cada novo dado, se o saldo de agressão continuar sendo comprador, o indicador continuará acumulando o saldo. Caso haja um saldo vendedor de agressão, a acumulação é zerada e começa a acumular as agressões de venda, até que haja uma reversão de saldo de agressão para compra.

Veja a figura abaixo do indicador implementado de acumulação de Volume Agressor.

Exemplo 2: Administração de stoploss pela volatilidade média

Neste segundo exemplo de estratégia de indicador, vamos plotar no gráfico principal um limite de preço para administração manual de stoploss.

O usuário fornecerá como parâmetro o preço de entrada de uma operação de compra ou venda, bem como o horário de abertura da posição. O usuário também deve fornecer um múltiplo N da volatilidade média (a estratégia usa internamente o indicador ATR) para posicionar a linha área limite para posicionamento do stoploss.

Para cada candle fechado, o qual o preço tenha andado a favor da operação, o stoploss é atualizado para refletir o preço de fechamento deslocado de N ATRs.

Observe na figura abaixo, que o usuário sinalizou ao indicador uma compra às 13:58 no preço de R$ 31,11 no ativo PETR4. O stoploss foi configurado na estratégia para ficar 2 ATRs atrás do preço de fechamento dos candles. Observe que a operação deveria ser stopada manualmente no preço de R$ 31,13 conforme os parâmetros fornecidos.

Na próxima figura, é apresentado o caso de uma venda à R$ 31,28 às 15:47 no ativo PETR4. Nesse momento o usuário optou por um distanciamento de 3 ATRs do preço de fechamento para cálculo do stoploss.

Estratégia de Execução (Robôs)

Até semana passada eu diria que o nome estratégia de execução é uma nomenclatura ruim…porque no Profit a estratégia de execução não executa nada em conta real. Mas quem assistiu ao nosso vídeo falando sobre o novo módulo de Automação de Estratégias viu que tem novidades surgindo no Profit Chart! A estratégia de execução, ou os chamados robôs, já podem ser rodados em conta de simulador e em breve poderão rodar em conta real!

Então, além de poder fazer backtest em dados históricos, para verificar estatisticamente o desempenho de determinado setup operacional, em pouco tempo, vamos poder transformar essas estratégias de execução em robôs para rodar em conta real. Para os mais afoitos, isso não significa que você vai ficar rico pegando qualquer robô por aí na internet….Encontrar um robô lucrativo é uma tarefa muito exaustiva.

Os robôs talvez sejam o tipo de estratégia mais fácil de imaginar, pois todo mundo já visualiza ordens sendo colocadas no book de forma automática e toda administração das operações também sendo realizada de forma autônoma. E é exatamente para isso que se propõe os robôs, para automatizar um setup operacional e garantir consistência na execução do setup.

Vou apresentar a seguir um exemplo clássico e didático, que não representa nenhuma recomendação de uso, serve apenas para exemplificar as estratégias de execução ou robôs.

Exemplo: Cruzamento de 3 médias móveis (Triple crossover)

Nesse tipo de setup temos 3 médias móveis: uma média móvel rápida, uma intermediária e uma lenta. Cada média atuará sobre uma quantidade de períodos diferentes, sendo a rápida sobre menor quantidade de períodos, refletindo o movimento de preço mais recente suavizado e a média lenta englobando maio quantidade de períodos, representando a tendência principal do ativo em janelas gráficas maiores.

Assim, a quantidade de períodos são parâmetros que devem ser otimizados na estratégia. Por ora, vamos arbitrar a utilização dos seguintes valores 5, 10 e 20.

Observe que a estratégia foi implementada para que os sinais de compra sejam ativados quando a média rápida estiver acima da média intermediária e esta última cruzar para cima a média lenta. O sinal de liquidação da posição de compra ocorrerá quando a média rápida cruzar para baixo a média intermediária.

O sinal de venda é análogo e ocorre quando a média rápida estiver abaixo da média intermediária e houver o cruzamento para baixo desta última com a média lenta. O sinal de liquidação da posição vendida ocorre quando houver um cruzamento da média rápida acima da média intermediária.

Estratégia de Seleção (Screening)

Screening significa manter em tela, no seu campo de visão, alguma informação para monitoramento…Com as Estratégias de Seleção (screenings) podemos monitorar , em tempo real, todos os ativos da B3, ou um subconjunto que o trader escolher, por um padrão de movimentação ou situação também determinado pelo trader.

Ou seja, com os screenings poderemos automatizar a seleção das melhores oportunidades entre os ativos da B3 que se enquadrem em determinado operacional. Isto liberará o trader de tarefas manuais e repetitivas para poder se dedicar foco e atenção à analise dos movimentos do mercado e outras atividades que julgar importantes.

Os screenings podem ser aplicados em periodicidades de dados de 1 minuto, 15 minutos, dias, semanas….ou seja, pode usar dessa automação tanto para daytrading quanto para suas operações de swing trade.

Exemplo 1: Seleção de ativos em valorização nos últimos 3 dias

Nesse primeiro exemplo, ilustro a aplicação de um Screening para listar os ativos do índice IBOV que em periodicidade diária apresentaram valorização nos últimos 3 períodos, ou seja, 3 dias. É um caso de utilização das Estratégias de Seleção para filtrar oportunidades de swing trade.

As figuras abaixo ilustram a definição da regra de screening pela interface gráfica e a lista de ativos gerada a partir da regra definida.

Exemplo 2: Seleção de ativos em condição de InsideBar para operações de daytrading

Nesse segundo exemplo, verificamos a utilização de uma estratégia de seleção de InsideBar para aplicação de um Screening sobre uma lista de 6 ativos da B3 na periodicidade de dados de 1 minuto. É um exemplo de aplicação de screening para operações de daytrading.

As figuras abaixo demonstram a utilização de uma regra de alarme que também contém seleção no Screening e a lista de ativos gerada a partir da estratégia de seleção.

Estratégia de Alarme

Alarmes não tem a ver somente com tempo! Podemos até criar alarmes 10 minutos antes da liberação de dados importantes como Payroll…Mas o verdadeiro ganho das Estratégias de Alarme é exibir uma notificação em tela, geralmente acompanhado de um som, quando determinada situação ocorrer em um ativo específico!

As Estratégias de Alarme são configuradas no Profit por ativo dentro do Gerenciador de Alarmes. É necessário incluir as estratégias para cada ativo que desejar, e podem basear-se em periodicidades de 1 minuto, 15 minutos, 1 dia…a periodicidade de dados desejada! Assim, o trader não precisa ficar o tempo todo com as janelas dos ativos que está monitorando abertas, consumindo processamento do computador. O trader será notificado assim que ocorrer a condição programada por ele na estratégia de alarme, no ativo e na periodicidade de dado configurada.

As estratégias de alarme podem ser usadas de duas formas! Configurando no Gerenciador de Alarmes ou incluindo alarmes dentro de uma estratégia de coloração ou de execução. As estratégias podem estar associadas a mais de um tipo! Podemos ter uma estratégia de coloração que também gera alarmes! Porém, nesse caso, diferentemente do gerenciador de alarmes, é preciso deixar o gráfico aberto em tela para poder gerar o alarme.

Exemplo: Estratégia de alarme baseada em InsideBar (Gerenciador de Alarmes)

A figura abaixo demonstra a configuração no Gerenciador de Alarmes de um alarme baseado em uma Estratégia de Alarme de InsideBar para o ativo WINV22 na periodicidade de 1 minuto, quando o candle fechar. Em seguida, a próxima figura apresenta a notificação gerada pela estratégia de alarme.

Estratégia de Texto

As estratégias de texto são bastante simples e são utilizadas para apresentar determinado texto em uma barra (Candle ou Renko) quando a condição programada pelo trader ocorrer.

As estratégias de texto podem estar associadas às estratégias de indicadores ou estratégias de coloração. A figura abaixo apresenta um exemplo simples de apresentação do texto “IB” quando há identificação do padrão gráfico de InsideBar.

Estratégia de Negociação

Em resumo, as Estratégias de Negociação permitem definir ordens de stoploss e take profit, com saídas parciais ou não, para automatizar o posicionamento de ordens quando o trader abrir uma posição em um ativo.

As Estratégias de Negociação são configuradas poela interface gráfica, dentro do “Chart Trading” e é um excelente primeiro passo para automatização de setup operacional em conjunto com as Estratégias de Stoploss. Assista ao vídeo que explica o passo-a-passo de como configurar as estratégias de negociação publicado no Canal Youtube da Comunidade.

É importante ressaltar que quando se está implementando Robôs (Estratégias de Execução) no Profit, as Estratégias de Negociação ficam entrelaçadas no código-fonte. Dentro do código há muito mais liberdade para definir uma estratégia de negociação  porque depende apenas de como o código é estruturado. A administração de um trade aberto, pode ser feito usando breakeven, stop fixo ou stop móvel, basta  programar a gestão das posições da maneira que o trader desejar.

Reproduzir vídeo

Estratégia de Stoploss

Por fim, o último tipo de estratégia passível de automatização que iremos abordar são as Estratégias de Stoploss. Estas podem ser configuradas pela interface gráfica utilizando as técnicas de Autobreakeven e Stop móvel, sem necessidade de código fonte, e utilizadas em conjunto com as Estratégias de Negociação.

Assim como as estratégias de negociação, também é possível programar ordens de breakeven e stop móvel no código fonte das Estratégias de Execução (Robôs). Assista ao vídeo do Canal explicando como configurar uma estratégia de stoploss, pela interface gráfica, utilizando as técnicas de Autobreakeven e stop móvel em conjunto.

Reproduzir vídeo

Finalizando...

Este documento apresentou um panorama geral das estratégias que podem ser automatizadas no Profit Chart. 

Percebe-se que há muitas possibilidades de automação, desde pequenas tarefas pontuais como a possibilidade de automatizar todo o setup operacional.

O trader que deseja especializar-se no mercado financeiro precisa dominar as ferramentas de automatização para liberar seu tempo de tarefas rotineiras e manuais, permitindo ter atenção para analisar e estudar os movimentos de preço dos ativos, aprimorando assim seu conhecimento sobre o mercado financeiro.

Espero que tenha aproveitado o conteúdo!, pois nos próximos documentos iremos implementar  passo a passo cada tipo de estratégia!

Automatizando SEM programação

Espera aí! É possível automatizar sem programar? Então para que eu vou perder meu tempo aprendendo a programar!? Aposto que você deve ter pensado isso….rsrsrs…Ok! É um argumento bem válido…Mas vou te mostrar alguns pontos que talvez ajudem você a enxergar melhor a médio e longo prazo.

Para regras muito simples de coloração, estratégias de negociação e stoploss, ou um Screening (se não souber do que estou falando…leia o documento sobre Tipo de Estratégias), você pode recorrer a interface gráfica do Profit e criar a sua própria regra sem a necessidade de escrever código.

Se você não sabe programação (AINDA!!!) acho que vale a pena explorar essas funcionalidades! Fizemos vários vídeos explicando as estratégias e automatizações que você pode fazer no Profit Chart sem a necessidade de programar e criamos essa playlist no Youtube!

Mas em pouco tempo, você encontrará dificuldades para criar regras ou pouco mais sofisticadas pela interface gráfica. Além disso, perceberá que não acha lugar nenhum explicando o que gostaria de saber e tampouco conteúdos de qualidade na internet (exceto os materiais da NeoTraderBot…kkkk). Para ser muito sincero, a documentação da Nelogica, que é a empresa que desenvolve e mantém o Profit Chart,  é muito “minimalista” (estou tentando ser político para não falar um português mais claro!).

Além disso, a interface gráfica do Profit também te obriga a descrever suas regras de uma forma que pode dificultar a manutenção e ajustes futuros. E para fazer algumas coisas, você precisa saber exatamente o mesmo comando que precisaria saber se estivesse programando! Ou seja, não há vantagem nessa situação…é melhor programar mesmo!

Então para resumir, recomendamos fortemente que aprenda a programar o quanto antes! Aqui na NeoTraderBot você tem acesso a tudo que precisa para aprender a automatizar suas estratégias, desde o Curso Básico de Lógica de Programação e o passo-a-passo para fazer todas automatizações na plataforma Profit, até exemplos completos da implementação de estratégias de execução (robôs)!

Mas se ainda não sabe nada de programação e tem algumas ideias de coisas simples que pode fazer para te ajudar no seu operacional, então tente implementar pela interface gráfica, enquanto investe parte do seu tempo para também aprender programação. Se você não conseguir fazer pela interface gráfica é porque não é tão simples quanto imaginava!

E o que podemos automatizar no Profit sem escrever código? Segue a lista abaixo e a nossa playlist ensinando como automatizar cada etapa do seu operacional!

  1. Estratégias de negociação: automatização de ordens de ganho, saidas parciais e stoploss na abertura de posições;
  2. Estratégias de stoploss: Autobreakeven (desloca stoploss uma vez atingido um lucro mínimo, evitando assim que o trade resulte em prejuízo em um movimento contrário à posição) e Stop móvel (Trailing stop) que é uma técnica para proteger ganhos já alcançados a medida que o preço do ativo anda a favor da operação;
  3. Screening: filtro de ativos que estejam na condição adequada, de acordo com o seu operacional, para abrir posição, liquidar posição existente, etc…
  4. Regras de alarme: configuração de alarmes sonoros e visuais para alertar o trader sobre um condição específica em um ativo determinado.
  5. Regras de coloração: configuração de coloração de gráficos e barras de acordo com a preferência do trader para indicar situações específicas ou gatilhos para seu setup operacional;
  6. Regras de execução (robôs): em resumo são regras para criação de um robô. Apesar de poder criar robôs sem escrever código eu recomendo criá-los apenas por meio de código fonte.
 
 

No próximo documento vamos abordar as melhores práticas de programação, para que possa evoluir de forma assertiva, em um bom ritmo, escrevendo códigos-fonte organizados legíveis (fáceis de entender para você e para outros…no futuro você vai entender essa frase!) e mantendo uma curadoria adequada de suas estratégias.

Limitações da Plataforma

Não existe perfeição…e quando falamos de software é difícil acharmos um que não tenha bugs ou pontos de melhoria (que as vezes tem uma análise mais subjetiva…uma melhoria para um usuário pode não ser para outro).

Este documento visa abordar as limitações conhecidas da plataforma Profit Chart referentes a automatização de estratégias e backtesting. Trata-se de uma base de dados em constante evolução, que pode crescer ou diminuir (assim esperamos) a medida que os membros da comunidade apresentarem novos itens, ou se a Nelógica lançar atualizações da plataforma para tratar as questões apresentadas.

Primeiramente, antes de começarmos precisamos fazer justiça e ressaltar que em termos de disponibilização de ferramentas para análise de mercado, a Plataforma Profit Chart entrega muitas funcionalidades interessantes e é uma plataforma muito bem aceita pelos traders! Nosso papel é um pouco cruel, pois vamos ser bem críticos neste documento, mas sem desmerecer a qualidade do software Profit Chart!

Nossos olhares estarão direcionados ao módulo de Editor de Estratégias que vinha recebendo pouca atenção até meados de Agosto/2022, quando a Nelógica começou a lançar atualizações referentes à automação de estratégias.

A primeira atualização do Editor de estratégias que nos chamou a atenção foi a possibilidade de usar dados de preço de múltiplos ativos nas estratégias. Isso era algo desejado há muito tempo e apesar de ainda haver algumas limitações nessa funcionalidade, a atualização já abriu várias oportunidades para elaborar novas estratégias. Se quiser saber mais sobre isso, assista ao vídeo que fizemos sobre estratégia baseada em múltiplos ativos no Youtube da Comunidade.

Recentemente, ainda tivemos a disponibilização da versão 5.2.2.121 na qual foi lançado o módulo de Automação de Estratégias, permitindo rodar Estratégias de Execução (robôs) em conta simulada. Esta também era outra funcionalidade há muito tempo demandada à Nelógica (clique aqui para conhecer o módulo de automação de estratégias), que em breve permitirá rodar os robôs em conta real! Será uma revolução!

Estamos vendo com muito bons olhos o esforço da Nelógica em melhorar as funcionalidades relacionadas à automatização das estratégias! Assim, esperamos que este documento também alcance a equipe de desenvolvimento da Nelógica e que possamos contribuir para o aprimoramento da Plataforma por meio das sugestões apresentadas!

Sem mais delongas, veja abaixo as limitações da Plataforma Profit Chart listadas pela Comunidade NeoTraderBot, bem como observações sobre a evolução da situação de cada item.

Limitações conhecidas da Plataforma Profit Chart

Legenda:

O código fonte desenvolvido para backtesting não pode ser exatamente o mesmo que será executado como robô no Módulo de Automação.

Seria interessante se houvesse compatibilidade entre os dois contextos, evitando assim retrabalhos e erros de tradução de código para que este funcione em áreas distintas dentro do mesmo software.


Sugestões:

  1. Implementar um gestor de ordens em ambiente backtesting para que as ordens sejam tratadas da mesma forma em Backtesting e no Módulo de Automação;
  2. Tratamento das ordens de cobertura no Módulo de Automação, pois não são reconhecidas nesse contexto;
  3. Estratégias com multi-objetivos (coloração, indicador e execução) quando utilizadas no Módulo de Automação ou em gráficos em tempo real são incluídas como diferentes instâncias, que dependendo do objetivo também são processadas de formas diferentes, gerando descasamento de informações.
 

Embora haja dados tick a tick, as ordens são enviadas apenas no fechamento dos Candles e este comportamento não pode ser alterado.


Sugestões:

  1. Refatorar as funções de ordens para que permitam execução no tick ou no fechamento da barra, cabendo essa decisão ao programador.

USERVOICE: CRIAR parâmetro de funções de ROTEAMENTO DE ORDENS para serem executadas NO TICK ou fechamento da Barra [NeoTraderBot]

Para backtesting de estratégias baseadas em renko, não é possível garantir encerramento de posição de daytrade porque as ordens são executadas apenas no fechamento do box.


Sugestões:

  1. Reestruturar o modelo de simulação de renko para que o backtesting permita encerrar posição dentro do box que contiver o horário desejado.

USERVOICE: GARANTIR ENCERRAMENTO DE POSIÇÃO por horário para Gráficos não temporais em Backtesting (ex: Renko) [NeoTraderBot]

Seguem abaixo os pontos observados em relação ao recém lançado Módulo de Automação de Estratégias (lançamento oficial em 29/set/2022)

  1. Velocidade de replay impacta preço de abertura de posição. Se executa replay em 1x, o preço de abertura de uma posição é diferente se fosse executado em 10x, para todas as demais condições de código e simulação iguais. Por que acontece isso em replay?
  2. Estratégias que possuem indicadores são inseridos como uma instância separada da instância que realiza a execução de ordens. Isso gera problemas de consistência entre um plot baseado em preço de posição com o preço efetivamente realizado na instância de execução da estratégia;
  3. Processamento de replay é muito lento. Mesmo em 10x. Seria possível aprimorar isso? Executar o processamento dos dados em maior frequencia do que a renderização (amostrando renderização).
  4. Não há funções NTSL para retornar resultado bruto no momento.

USERVOICE: Velocidade de REPLAY NÃO DEVE IMPACTAR execução de ordens em estratégias/robôs no Módulo de Automação [NeoTraderBot]

O acesso a dados de 1 minutos (por exemplo) é muito limitado . A plataforma consegue recuperar apenas os últimos 3 (três) meses de dados de preço com frequência de 1 minuto. Para desenvolvimento de estratégias de alta frequência, otimização e backtesting, esse é um volume muito pequeno de dados.

Felizmente, à medida que utiliza-se dados com menor frequência (5, 15 60 minutos, 1 dia) é possível obter uma janela maior de dados históricos. Por exemplo, se o usuário demandar dados de 15 minutos, a plataforma recupera 6 anos. O que nesses casos demonstra-se adequado.


Sugestões:

  1. Permitir que o usuário puxe mais dados da base, quando for conveniente;
  2. Permitir carregar série de dados OHLCV (Open, High, Low, Close, Volume) para fins de backtesting.

USERVOICE: PERMITIR IMPORTAÇÃO DE DADOS OHLCV e Tick PARA FINS DE BACKTESTING [NeoTraderBot]

Para desenvolvimento de estratégia o trader/programador não possui acesso à dados de negociação (times & trades) com granularidade suficiente para implementar lógicas que se baseiem na forma como as negociações estão ocorrendo no mercado.

Tampouco, há acesso para a informações do Book de ofertas, quantidade de ordens por nível de preço, volume  das ordens, corretora, etc…Não ter esse tipo de dado disponível também cria limitação na implementação de estratégias que se baseiem em fundamentos diferentes da análise técnica.


Sugestões:

  1. Criar funções no editor de estratégia para obter acesso amplo à negociações realizadas no último tick;
  2. Criar funções no editor de estratégia para obter acesso às informações do book de ofertas.

A plataforma não apresenta funcionalidade para auxiliar a tarefa de otimização de parâmetros de estratégias.

Por exemplo, caso o usuário implemente um robô baseado em cruzamento de média, a plataforma poderia auxilia-lo na definição do número de períodos mais adequado para a média por meio da maximização ou minimização de alguma métrica, tal como maximização do percentual de operações vencedoras, ou minimização do drawdown médio das operações.


Sugestões:

  1. Criar funcionalidade para otimizar “parâmetros” das estratégias em função de uma métrica escolhida pelo usuário.

USERVOICE: CRIAR OTIMIZADOR de Estratégias no Profit [NeoTraderBot]

No Profit, toda estratégia de execução precisa estar vinculada a um gráfico de um ativo. Desta forma, não é possível criar ordens em um ativo baseado em sua posição em outros ativos. Ou seja, não há possibilidade de criar uma estratégia para operar uma correlação entre múltiplos ativos.

Esta limitação do Profit impede, por exemplo, de se criar uma estratégia para gestão de portfolio ou  estratégias de arbitragem, entre outras…


Sugestões:

  1. Alterar funções de Backtesting (IsBought, IsSold, SellPrice, BuyPrice, etc…) para que o usuário informe o código do ativo. Por default, o código seria o ativo no qual a estratégia de execução está rodando;
  2. Permitir executar em conta real estratégias que não estejam vinculadas a nenhum ativo específico;

USERVOICE: PERMITIR CRIAÇÃO DE ESTRATÉGIAS que envie ordens em DIFERENTES ATIVOS [NeoTraderBot]

Antes da versão beta 5.2.2.121 do Profit Chart, o debug do editor de estratégias não possuía opção de “continuar”. Ou seja, uma vez pausado o código em um breakpoint, o usuário tinha que percorrer linha a linha ou terminar de executar tudo de uma vez. Não era possível executar o código de uma vez até o próximo breakpoint.

Outra limitação era o fato de não haver a possibilidade de criação de breakpoint condicional. A atualização mencionada passou a permitir criar breakpoint baseados em timestamp (horário), o que já representou um avanço na ferramenta.


Sugestões:

  1. Permitir criação de breakpoints baseados em valor específico de uma variável;
  2. Permitir inspeção de expressões com base nos valores atuais das variáveis quando o código estiver pausado em um breakpoint;

USERVOICE:MELHORAR poder de Depuração da NTSL – MELHORAR DEBUG [NeoTraderBot]

Segue abaixo uma relação de ítens a serem melhorados no Editor de estratégias. A medida que forem sendo resolvidos pelas atualizações da plataforma, iremos sinalizar com a tag RESOLVIDO (Versão XXX).

    1. Não é possível alterar o valor dos parâmetros da estratégia no modo de exibição misto;
    2. Não é possível utilizar funções de indicadores passando como parâmetro o ativo no qual se deseja calcular o indicador;
    3. No desenvolvimento de indicadores, não é possível via código definir preenchimento e cor de preenchimento entre duas séries de dados. Isto invialibiliza preencher entre séries quando há mais do que 2 séries plotadas;
    4. Não há uma forma sistematizada de inicializar variáveis globais;
    5. Na linguagem NTSL, não há comando “break”   para os controles de repetição (for e while);
    6. Não há constantes definidas para valores máximos e mínimos de integer e float;
    7. Não há função built-in (já implementada) para manipulação básica de arrays, tais como obter valor máximo, valor mínimo, ordenar…etc)
    8. Ao utilizar o depurador estando o mercado aberto, a medida que chega novos dados, ainda que você esteja parado em um breakpoint, os plots se movimentam, dificultando a depuração

Sugestões:

  1. Criar função para preenchimento entre séries;
  2. Refatorar as funções de indicadores para que haja um parâmetro da série do ativo que se deseja calcular o indicador;
  3. Adicionar aba de “Parâmetros” às “Propriedades da Estratégia” para configurar valores dos parâmetros da estratégia no modo de exibição misto;
  4. Padronizar função OnInit para o usuário poder inicializar da forma que desejar as variáveis antes da estratégia começar a rodar;
  5. Incluir comando de break na linguagem NTSL para os controles de repetição;
  6. Definir constantes de valores máximos e mínimos dos tipos de dados Integer e Float;
  7. Criar algumas funções embutidas para manipulação de array, tais como: max, min e sort.

USERVOICE:MELHORIAS DIVERSAS em NTSL [NeoTraderBot]

USERVOICE:AUMENTAR PRECISÃO da função TIME, CURRENTTIME para segundos e CRIAR função de TempoRestante [NeoTraderBot]

USERVOICE:Refatoração de TODOS os indicadores da plataforma para aceitar como parâmetro a série de dados [NeoTraderBot]

USERVOICE:Criação de Bloco de INICIALIZAÇÃO na linguagem NTSL [NeoTraderBot]

USERVOICE: Criar nova ABA de ORDENS na seção de Estatística do Editor de Estratégias [NeoTraderBot]

USERVOICE:Criar função para retornar preço e quantidade de contratos/lotes negociados desde abertura da posição [NeoTraderBot]

USERVOICE: Criar  EXPORTAÇÃO /IMPORTAÇÃO DE ESTRATÉGIA AUTOMATIZADA configurada no MÓDULO DE AUTOMAÇÃO [NeoTraderBot]

Antes da versão beta 5.2.2.121 do Profit Chart, as estratégias de execução (robôs) só podiam ser usados para fins de backtesting, análise de desempenho em dados históricos e visualização nos gráficos de recomendação de operação, cabendo ao trader efetuar as operações sinalizadas pela estratégia.

O novo Módulo de Automação de Estratégias, lançado na versão beta mencionada, passou a permitir a execução de robôs em tempo real nas contas de simulação. Isto foi um grande avanço e que já prepara a plataforma para permitir rodar os robôs em conta real.

Acredito que essa atualização do Profit mais conservadora seja motivada para corrigir eventuais bugs do módulo antes de liberar para contas reais (acho isso bem responsável por parte da Nelógica!).

 


Sugestões:

  1. Permitir execução de robôs programados pelo próprio usuário em contas reais.

Caso tenham verificado outras limitações da plataforma Profit Chart, gentileza escrever nos comentários desse artigo, bem como sua sugestão de melhoria. Iremos, sempre que possível, complementar a lista com as observações dos membros da Comunidade.

Documentação NTSL (Nelogica)

A documentação apresentada abaixo é elaborada pela Nelogica e disponibilizada neste link. O documento abaixo foi baixado do link informado em 31/05/2023.

Curso Básico - Lógica de Programação

Este curso foi criado para fornecer o conhecimento básico para quem deseja começar a implementar suas próprias estratégias automatizadas de negociação de ativos, ou até mesmo compreender melhor o código de estratégias implementadas por outras pessoas.

Reproduzir vídeo

Aula 01 - Conceitos básicos

Nesta aula abordaremos as definições básicas de programação.

Se cheguei até aqui foi porque me apoiei no ombro dos gigantes.

Isaac Newton
Reproduzir vídeo

1. Introdução

Programação está se tornando (se já não for) um pré-requisito para qualquer pessoa do século 21. Cada dia que passa mais e mais de nossas atividades cotidianas e trabalhos são facilitados com a ajuda de softwares ou até inteiramente automatizadas por eles.

Ao contrário do que muita gente pensa, programação não é um bicho de sete cabeças! Se fosse fazer uma comparação, diria que é como aprender um idioma diferente, mas talvez seja até mais simples. Para os computadores não existe subjetividade…ou é ou não é… ou é zero ou é um!

Como tudo na vida (e Newton já sabia disso…), o conhecimento precisa ser construído de forma incremental para que com o tempo possamos compreender assuntos mais complexos. Assim, pretendo apresentar a você os conceitos básicos de programação sem os formalismos do meio acadêmico. Isto é um ponto de partida e o objetivo é que você entenda as ideias! Falarei sobre todos os conceitos básicos? Não, pois tem muito conceito! Contudo, falarei sobre o que você precisa saber neste momento para iniciar sua jornada de aprendizado. Conte comigo e com a comunidade para tirar suas dúvidas por meio do nosso fórum ou dos demais canais.

Então comecemos pelo começo, é claro! E ele inicia com o conceito de ALGORITMO 

2. O que são Algoritmos?

A noção de algoritmo foi identificada formalmente pela primeira vez na tradução de trabalhos de um matemático persa do século XII. Fique tranquilo porque não vamos aprofundar na história do desenvolvimento humano! Queria apenas ressaltar que o conceito de algoritmo surgiu quando não existia sequer a ideia de computadores e, no entanto, é amplamente empregado na área de computação.

Para ser objetivo, um ALGORITMO é uma sequência finita de ações que visam resolver um problema. Esta sequência de ações deve ser PRECISA (dizer exatamente o que precisa ser feito), não pode ser ambígua (não pode haver dúvidas sobre o que cada ação significa), CORRETA (deve resolver o problema) e, de preferência, EFICIENTE (quanto menos ações ou recursos forem exigidos para resolver o problema, melhor!).

Vamos a um exemplo clássico para você não esquecer: uma receita de bolo é um algoritmo! Veja bem…a receita começa dizendo o que você precisa (quais recursos são necessários) e, em seguida, te orienta passo a passo o que fazer com cada ingrediente para ao final obter um bolo.

Outro exemplo seria se alguem te parasse no meio da rua e te perguntasse onde fica determinada loja, você certamente responderia com um algoritmo: siga esta rua, vire à direita no 3º quarteirão, pega a esquerda na próxima rotatória, a loja está no lado direito da rua.

Acho que você já entendeu o que é um algoritmo e naturalmente está pensando que existem algoritmos simples, como os exemplos que dei, mas também existem algoritmos complexos, quando os problemas a serem resolvidos são mais dasafiadores. É verdade, mas a forma como são escritos os algoritmos é sempre a mesma.

Não existe um padrão único de como escrever um algoritmo e cada livro adota um padrão mais conveniente. No entanto, todos os padrões atendem a definição que vimos. Vamos ver um exemplo de algoritmo? Veja abaixo:

				
					Algoritmo calibrarPneusDoCarro:
para i := 1 até 4 passo 1:
início:
   enquanto Pneu_i.obterPressao() <= 30:
   inicio:
      Pneu_i.adicionarPressao(1 psi);
   fim;
fim;

				
			

O algoritmo calibrarPneusDoCarro é um exemplo muito simples. Ele começa pelo primeiro pneu do carro (linha 2, i =1) e enquanto a pressão do pneu for menor que 30 psi, é adicionado 1 psi ao pneu (linha 6) até que o presente pneu tenha pressão igual a 30 psi. Daí, o algoritmo passa para o próximo pneu e repete o processo até que os 4 pneus estejam com pressão igual a 30.

3. Estruturas de Dados

No Globo Repórter de hoje...

 

Se tem algo que não podemos deixar de falar quando falamos sobre algoritmos são as ESTRUTURA DE DADOS. As estruturas de dados são mecanismos para armazenar etapas e resultados intermediários ao longo da execução do algoritmo, ou até mesmo a solução final do problema.

Vamos deixar isso mais claro…Se eu te pedisse para me dizer o resultado da soma dos números de 1 a 10 e você não lembrasse da fórmula de somatório de PA (Progressão aritmética), você iria possivelmente começar somando 1 com 2 e memorizando o número 3. Em seguida, somaria 3 com 3, e memorizaria o número 6, seguiria esse processo iterativamente até o número 10 e chegaria ao resultado da soma que é 55.

Perceba neste exemplo que você precisou manter sempre em sua memória uma soma intermediária até chegar à última operação. Este resultado intermediário é uma estrutura de dados muito simples, é apenas um número inteiro. Mas as estruturas de dados podem ser tão complexas quanto sejam necessárias para resolver um problema. Em cursos de computação, todos os alunos aprendem estruturas de dados como vetores, matrizes, listas, filas, pilhas, árvores, grafos… Mas para começar a automatizar estratégias de negociação você não precisará saber sobre tudo isso. Com o tempo e necessidade, você irá acabar estudando mais a fundo as estruturas de dados. Por enquanto, vamos manter simples e complicar à medida que for preciso.

4. Linguagem de Programação

Como vimos até agora, os algoritmos e estrutura de dados existem independentemente da linguagem de programação e este é o conceito que abordaremos agora. O que é linguagem de programação? Senta que lá vem um pouco de história…mas espero que seja interessante para você!

Linguagem de programação é a forma pela qual você se comunicará com o seu computador. O computador é extremamente veloz, consegue guardar muita informação…mas tem um problema…ele só faz o que você ordena ele fazer!

No início da computação, as linguagens eram muito rudimentares, ou em termos mais técnicos, de baixo nível. Isso significa que o programador precisava transcrever seus algoritmos em uma sequência de 0 e 1, no que denominamos código de máquina. Tipo isso:

				
					0000101110101110111000011101100001101110101000110101101101101001010 
1011010101.....e por aí vaí milhares de zeros e uns.
				
			

Eram tempos difíceis para a comunicação homem-máquina…ainda bem que a tecnologia permitiu o incremento do poder de processamento dos computadores e a sua capacidade de memória. Com o tempo vieram os cartões perfurados, depois começaram a surgir linguagens que permitiam comandos em palavras de 3 letras, tipo: ADD (soma), MOV (move um número de uma posição de memória para outra), STO (grava isso na memória), etc. E de forma gradativa, a computação foi evoluindo para chegar nas linguagens de alto nível, que são as linguagens que temos contato hoje!

Intitulamos as linguagens de alto nível aquelas linguagens que nos permitem abstrair do que realmente acontece dentro do computador…ou seja não utilizamos comandos muito primitivos, como aqueles zeros e uns ou comandos com três letras…Em analogia, é como pedir para você escrever o seu nome numa folha…eu não precisaria te dizer letra a letra e como fazer cada letra para escrevê-lo. Eu simplesmente peço, escreva seu nome e você o fará de uma forma que eu não preciso saber como.

Tem muitas linguagens diferentes, elas podem ter propósito geral, tais como Pascal, Java, C, C++, Pyhton etc, com as quais você pode fazer qualquer tipo de programa, ou pode ser desenvolvida para um fim específico, por exemplo, renderizar as páginas que você acessa na internet (HTML).

5. Código fonte, Síntaxe e Compilador

O que os algoritmos têm a ver com as linguagens de programação? Ora, a gente como programador precisa transcrever os passos do algoritmo para uma linguagem que o seu computador entenda. E cada linguagem tem uma sintaxe (forma como escrevemos) bastante rígida! Não podemos escrever diferente da sintaxe esperada porque o computador não vai entender!

Assim, o texto transcrito a partir do nosso algoritmo para uma linguagem de programação é o que chamamos de CÓDIGO FONTE. Espero que esteja entendendo até aqui….já estamos finalizando os conceitos básicos que precisa saber sobre programação.

Depois que transcrevemos o nosso algoritmo de acordo com a sintaxe da linguagem de programação, geralmente existe um programa chamado COMPILADOR que irá traduzir os seus comandos de alto nível para uma sequencia de zeros e uns (código de máquina) para ser executado pelo computador!

Pense no compilador como um professor(a) que irá corrigir sua redação (seu código-fonte), mas muito rigoroso(a) ! Ele(a) só irá transformar seu código fonte em código de máquina se não houver nenhum erro de sintaxe!

Enfim, sua tarefa de programador termina quando tiver um código executável que resolva o problema que desejava. Ou não…talvez isso seja só o começo como programador!

6. Recapitulando...

Começamos com os conceitos de algoritmos e estrutura de dados. Em seguida, apresentamos o que são as linguagens de programação e como elas se relacionam com os algoritmos. Entendemos que o código fonte nada mais é do que seu algoritmo transcrito e precisa ter a sintaxe exigida pela linguagem de programação utilizada. Por fim, explicamos que o seu código fonte precisa ser compilado para um código de máquina que poderá ser executado pelo computador.

Aula 02 - Tipos de Dados e Operações

Aprenda os tipos básicos de dados e operações.

Reproduzir vídeo

1. Introdução

Programação é como brincar de lego…não é por acaso que até a empresa lego faz kits de programação para ensinar às crianças. A forma de pensar ao resolver um problema e programar a solução é sempre de encaixar blocos sequencialmente para obter o resultado desejado. Desta forma, temos que saber o que cada bloco faz para fazermos o melhor uso dele em nossos programas.

A seguir vamos aprender quais são os tipos básicos de dados e como podemos manipulá-los, ou seja, quais operações podemos realizar com eles. Por quanto ainda vamos tentar evitar ao máximo entrar em detalhes de linguagens de programação específicas e nos ater aos conceitos. Em breve, você poderá iniciar o estudo de uma linguagem de programação com os conceitos básicos já absorvidos.

2. Quais são os tipos básicos de dados?

Os primeiros blocos que precisamos conhecer são os tipos de dados. Em todas as linguagens de programação você irá encontrar três tipos basícos de dados, que podem ser números inteiros (que nas linguagens serão apresentados como integer ou int), números com casas decimais (ou ponto flutuante, que podem se apresentar como float, real, double) e dados booleanos (um tipo de dado que apresenta apenas dois valores possíveis: verdadeiro/falso, ou em inglês, true/false). Não se preocupe em decorar as nomenclaturas, pois cada linguagem pode chamar os tipos de dados de forma diferente e quando você obtiver fluência esse será um detalhe que não representará nenhuma dificuldade. Há ainda um tipo de dados conhecido como string, que são os dados de texto, mas que não iremos abordar nesse curso introdutório para restringir o conteúdo ao que é realmente essencial.

Um termo técnico muito comum em programação é a declaração de variáveis. O que siginifica isso? O seu código fonte certamente exigirá que você crie variáveis para armazenar informação. Para cada variável, o programador precisar atribuir um nome e o tipo de dados que aquela variável armazena. O processo de definir a variável é o que se chama “declarar variável”

3. Operações com dados numéricos

Vamos falar então sobre as operações que podemos fazer com os dados numéricos, sejam inteiros ou com casas decimais. Obviamente você já aprendeu isso na escola! É possível somar, subtrair, multiplicar, dividir, exponenciar, tirar a n-ésima raiz, obter resto de uma divisão, obter o valor absoluto do número, entre outras…

A diferença na programação quando usamos dados inteiros e dados com casas decimais ocorre quando tentamos armazenar o resultado de uma das operações acima mencionadas em uma variável com tipo de dado incompatível. 

Lembra que vimos na primeira aula que os computadores só fazem o que a gente pede!? Então, ao escrever seu programa você precisará declarar o tipo das variáveis que utilizará. Vamos supor que você tenha declarado uma variável inteira para armezar o número da sua residência em sua rua: num_residencia. Logo, se em algum momento você tentar atribuir um valor à variável num_residencia, este valor deverá ser um inteiro. Poderíamos atribuir valores por meio de vários tipos de operações:

				
					// Atribuição direta
num_residencia = 8;
				
			
				
					// Atribuição por divisão
num_residencia = 16/2;
				
			
				
					// Atribuição por multiplicação
num_residencia = 2*4;
				
			
				
					// Atribuição por exponenciação (2 elevado a 3)
num_residencia = 2**3;
				
			
				
					// Atribuição por n-ésima raiz (no caso, raiz quadrada)
num_residencia = 64**(1/2);
				
			

Para todas as atribuições acima não haveria problema, porque o resultado é sempre um número inteiro e a variável num_residencia é do tipo inteiro. Mas e se o resultado da operação fosse um número com casas decimais, ex: 10/3?

Nesse caso, dependeria de cada linguagem! Há linguagens que iriam fazer a conversão automática do resultado (técnicamente conhecida como conversão implícita), truncando as casas decimais e atribuiria o valor 3 à variável num_residencia. Outras poderiam gerar um erro durante a compilação do programa ou durante a execução. Assim, o mais adequado é você garantir que a variável receberá um valor do mesmo tipo que foi declarada.

Vamos supor agora que você declare uma variável chamada minha_altura como do tipo Real, ou seja, um número com casas decimais, para armazenar minha altura em metros. Observe que a variável minha_altura poderá receber tantos valores inteiros como valores com casas decimais.

Daí você pensa, quantas casas decimais o computador pode guardar? Se eu armazenasse em minha_altura o resultado da operação 5/3. A variável minha altura teria o valor 1,66 ou 1,66667, ou 1,666666….? Isto já começa a ficar um pouco técnico e você nem precisa se preocupar em profundidade com isso. Mas vou tentar lançar um pouco de luz para que entenda melhor. 

Cada tipo de dado numérico com casas decimais pode ter uma precisão diferente a depender da quantidade de bits que este tipo de dado ocupa na memória. Assim, quanto mais bits ele ocupar na memória, mais casas decimais ele pode armazenar. É correto você pensar que em casos de resultados com infinitas casas decimais o computador nunca terá o resultado exato e sim aproximado com maior ou menor precisão, dependendo do tipo de dado que esteja utilizando. Mas para efeitos práticos, a precisão numérica que temos hoje é tão grande que isso não representa problemas para a imensa maioria das aplicações!

4. Ordem de precedência das operações

Algo importante para se prestar atenção ao escrever uma fórmula para uma variável é a ordem de precedência das operações. Você já estudou isso em matemática, mas não custa nada lembrar:

  1. Parênteses;
  2. Expoentes;
  3. Multiplicações e divisões (da esquerda para direita);
  4. Somas e subtrações (da esquerda para direita).

Nada melhor do que eu exemplo para deixar as coisas mais claras! Vamos pensar na variável minha_altura, que é do tipo Real. Se eu atribuísse a fórmula abaixo à variável, qual seria o seu valor? Tente fazer antes de expandir a resposta!

  • minha_altura = (9 – 2*((2)*(5-4)))/3
  • minha_altura = (9 – 2*((2)*(1)))/3
  • minha_altura = (9 – 2*(2))/3
  • minha_altura = (9 – 4)/3
  • minha_altura = 5/3

Você deve estar pensando: para que alguém iria programar um código para fazer essa conta? Basta usar a calculadora! E você tem razão! Não teria sentido algum programar uma atribuição de variável dessa forma, foi apenas um exemplo didático!

Em programação, o que possivelmente você iria programar é uma fórmula que baseada em outras variáveis, possa calcular ou estimar sua altura. Assim, poderíamos reescrever a fórmula de minha_altura como:

 

				
					minha_altura = (A - 2*((B-2)*(C-D**2)))/3
				
			

Inserindo os valores de A, B, C e D, o programa iria calcular minha_altura. Note que você precisa programar apenas uma vez a fórmula, o resultado dependerá apenas das variáveis inseridas no programa.

Bom, por ora, acho que estamos satisfeitos sobre operações com dados numéricos. Vamos passar agora para o outro tipo de dado: dados booleanos.

5. Operações com dados booleanos

A denominação booleano foi realizada em homenagem ao matemático inglês George Boole, um dos país da lógica booleana. As operações booleanas ou lógica booleana estão presentes em todos os circuitos eletrônicos que puder imaginar, ou seja, é a base para todos os eletrônicos que conhecemos, desde o controle do portão eletrônico até o seu celular! Não vamos abordar a lógica booleana em profundidade explorando todas as suas propriedades, mas vamos falar do necessário para que possa aprender a programar.

Como já disse na introdução, uma variável booleana pode ter apenas um de dois valores possíveis: true ou false. Vou usar os termos em inglês daqui para frente, pois assim serão apresentados para você nas linguagens de programação que vier a estudar. Para as variáveis booleanas, podemos realizar três operações básicas booleanas:

  1. NOT;
  2. AND (E);
  3. OR (OU).

Vamos começar pela operação mais simples: NOT. Se A for uma variável do tipo booleana e seu valor for true. A operação (NOT A) resulta em false. Se B é uma variável booleana e seu valor é false. A operação (NOT B) resulta em true. Simples, não!? Vamos ver isso em um formato de tabela para estruturar o raciocínio (são as famosas tabelas da verdade que já vimos no ensino médio):

A NOT A
false
true
true
false

A operação AND (E) exige que todos os operandos sejam verdadeiros para que resulte em verdadeiro, senão o valor resultante será falso. Vejamos a tabela da verdade no caso de apenas dois operandos:

A B A AND B
false
false
false
false
true
false
true
false
false
true
true
true

Por fim, a operação OR (OU) exige que pelo menos um dos operandos seja verdadeiro para que o resultado seja verdadeiro. Se nenhum operando for verdadeiro, o resultado será falso. A tabela da verdade no caso de dois operandos é a seguinte:

A B A OR B
false
false
false
false
true
true
true
false
true
true
true
true

6. Praticando a lógica booleana

Agora que já vimos o básico da lógica booleana, vamos testar se realmente aprendemos. Veja abaixo a declaração de algumas variáveis e em seguida, calcule o resultado de cada expressão. Olhe as respostas só depois de ter tentado resolver!

 

				
					int A = 10
int B = 15
boolean C = false
real D = 35,5
int E = 2
				
			

R: true

R: false

R: false

R: true AND false

R: false

R: false OR false

R: false

R: false OR false OR true

R: true

R: true AND true

R: true

R: NOT(NOT(false))

R: NOT(true)

R: false

R: (100 – 106,5) < 0

R: true

R: (50 > 35,5) AND NOT(false)

R: true AND true

R: true

7. Tipo de dados especial: Arrays

Vamos agora falar de um tipo de dado muito útil em programação: os arrays (difícil encontrar uma tradução para essa palavra! Vamos usar em inglês mesmo!)

Os arrays não são um tipo de dado básico, tais como um número inteiro, real ou booleano, mas são extremamente relevantes. Os arrays são, na verdade, uma sequência de tamanho definido de algum tipo de dado básico. Por exemplo, suponhamos que precisássemos declarar 10 variáveis inteiras. Ao invés de criar 10 nomes diferentes, podemos declarar uma única variável (um array de números inteiros) com tamanho igual a 10, conforme figura abaixo. Vamos nomear o array abaixo de array_teste.

A variável array_teste teve seus valores inicializados de forma aleatória para fins didáticos. Podemos acessar cada valor do array por meio de um indexador/índice, um número inteiro que irá se referir à posição desejada do array.

Desta forma, se quisermos nos referir ao número 15, que ocupa a primeira posição da variável array_teste, iremos utilizar a seguinte convenção array_teste[1]. Da mesma forma, a última posição do array_teste possui o valor 10 e é referenciado como array_teste[10].

Um ponto importante de ressaltar é que a referencia para o primeiro elemento do array depende da linguagem. Algumas linguagens consideram os índices iniciando por 0. Se fosse este o caso, array_teste[0] retornaria o primeiro elemento da sequência, no caso 15, enquanto array_teste[1] iria se referir na verdade ao segundo elemento da lista, no caso 4, e o último elemento da lista seria array_teste[9], que teria o valor 10.

 

8. Recapitulando

Nesta aula começamos conhecendo os tipos básicos de dados comuns em todas as linguagens de programação. Em seguida, vimos as operações que podemos aplicar sobre os dados numéricos e a ordem de precedência no cálculo de fórmulas. Também vimos as operações básicas booleanas e realizamos alguns exercícios para fixar o conteúdo. Por fim, vimos que os arrays são uma sequência de dados de um mesmo tipo declarado como uma única variável indexada, e sua importância para programação.

Aula 03 - Controles de Fluxo

Controles de fluxo (Loops) são essenciais em programação. Nesta aula veremos:

Reproduzir vídeo

1. Introdução

Se na vida sempre chega uma hora que não dá para seguir o fluxo e temos que tomar decisões importantes, na programação isso acontece quase o tempo todo!

Lembra-se da parte da definição de algoritmo que diz ser uma sequência finita de ações!? Então…os programas são estruturados para serem executados de forma sequencial, eles seguem um fluxo que inicia na primeira linha de código e vai executando cada linha até chegar a última linha (a sequência precisa ser finita, ou seu computador vai ficar travado….rsrsrs)!

Se não pudéssemos alterar este fluxo, certamente a nossa capacidade de resolver problemas por meio de algoritmos seria muito reduzida. Assim, sistematizou-se a programação com estruturas básicas de controle de fluxo (ou Loops em inglês), as quais dividem-se em dois grandes grupos: CONTROLES DE SELEÇÃO e CONTROLES DE REPETIÇÃO. Vamos ver a seguir o que significa cada tipo de controle e como é sua estrutura.

2. Controles de seleção

Em nossas vidas, é muito comum condicionarmos as nossas ações à determinadas situações ou eventos. Você já deve ter pego a si mesmo dizendo algo do tipo: “Se eu ganhar na megasena eu compraria …”? Isso é um exemplo de controle de fluxo de seleção porque existe uma condição que é “ganhar na megasena”. SE essa condição for verdadeira, iremos SELECIONAR uma ação ou mais para serem executadas, no caso: “comprar alguma coisa”. Naturalmente que é muito improvável que este exemplo de condição seja verdadeira…mas não custa nada sonhar!

Sempre que dissermos condição podemos estar tratando na verdade de uma fórmula booleana tão complexa quanto fosse necessário…por exemplo: Se eu ganhar na megasena E (não tivesse filhos OU não fosse casado(a)), eu iria viajar 2 anos pelo mundo!

Dizem que para entendermos melhor basta desenhar…vamos tentar então! Veja a figura abaixo, ela é a estrutura básica de um controle de seleção. É a famosa estrutura if, em português: se!

A estrutura de fluxo do tipo if serve para realizar alguma ação dada que uma condição foi satisfeita, ou seja, é verdadeira. Se a condição for falsa, o programa continuará sua execução até o fim.

Podemos elaborar um pouco mais essa estrutura de seleção resultando na estrutura if..else (se…senão). Nessa estrutura além de um conjunto de ações ser executado se a condição for verdadeira, caso a condição seja falsa, é executado outro conjunto de ações, antes que o programa continue até o fim. Em diagrama, a estrutura if…else é representada da seguinte forma:

A partir dessa estrutura básica if…else, poderíamos colocar estruturas if…else dentro de uma estrutura if…else. Isso é o que chamamos em programação de aninhar (veja um exemplo na figura abaixo).

Ou seja, poderíamos aninhar uma estrutura if…else na parte else de outra estrutura, quantas vezes desejássemos (também poderia-se aninhar na parte if). Vamos a um exemplo abaixo em homenagem ao dia dos pais:

				
					definirPresenteDiaDosPais(Idade_pai: Integer:
  IF Idade_pai >= 20 AND Idade_pai <= 25:
     presente = comprar(“carteira”);
  ELSE
    IF Idade_pai > 25 AND Idade_pai <= 35:
      presente = comprar(“camiseta/calça”);
    ELSE
      IF Idade_pai > 35 AND Idade_pai <= 45:
        presente = comprar(“kit_ferramentas”);
      ELSE
        IF Idade_pai > 45 AND Idade_pai <= 55:
          presente = comprar(“conjunto_churrasco”);
        ELSE
          IF Idade_pai > 55 AND Idade_pai <= 65:
            presente = comprar(“sapato”);
          ELSE
            presente = comprar(“meias”);

  return presente;
				
			

Nada muito complicado, certo!? Mas o aninhamento descrito acima poderia ser escrito em uma sintaxe de melhor compreensão, que é a estrutura switch. É importante ressaltar que esse tipo de estrutura não está presente em todas as linguagens. Se fossemos reescrever o algoritmo acima utilizando a estututura switch, seria assim:

				
					definirPresenteDiaDosPais(Idade_pai: Integer:
  switch(Idade_pai):
    case Idade_pai >= 20 AND Idade_pai <= 25:
      presente = comprar(“carteira”);
    case Idade_pai > 25 AND Idade_pai <= 35:
      presente = comprar(“camiseta/calça”);
    case Idade_pai > 35 AND Idade_pai <= 45:
      presente = comprar(“kit_ferramentas”);
    case Idade_pai > 45 AND Idade_pai <= 55:
      presente = comprar(“conjunto_churrasco”);
    case Idade_pai > 55 AND Idade_pai <= 65:
      presente = comprar(“sapato”);
    default:
      presente = comprar(“meias”);
   end switch;

  return presente;
				
			

Com isso encerramos o que precisamos saber sobre estruturas de controle de fluxo de seleção. Espero que tenha entendido os conceitos até o momento!

3. Controles de repetição

Às vezes, para resolver determinado problema, precisamos repetir uma sequência de ações até que uma situação seja alcançada. Para estes casos, iremos utilizar os controles de repetição, cuja ideia geral está apresentada na figura abaixo:

Basicamente, enquanto uma condição for verdadeira, iremos executar algumas ações repetidamente. Após cada execução desse conjunto de ações, iremos verificar novamente se a condição é verdadeira, se for falsa o interromperá o loop de repetição e seguirá sua execução. Os tipos mais comuns de controles de repetição que encontramos nas linguagens de programação são: FOR e WHILE.

A estrutura FOR é geralmente utilizada quando queremos passar por uma sequência de dados e fazer algum tipo de operação para cada elemento. Em linguagem mais técnica, o processo de percorrer uma sequência de dados chama-se iterar.

No caso da estrutura FOR, geralmente temos uma variável inteira que inicia com determinado valor, e a cada execução do controle FOR esse valor é somado/subtraído de um passo (valor constante) até que chegue a um valor limite. Ou seja a quantidade de repetições é dada em função dessa variável que chamamos de iterador e seus limites inferior, superior e passo.

Por exemplo, vamos supor que tenhamos um array chamado NATURAIS, de números inteiros de 1 a 10, ou seja 10 elementos. Vamos supor ainda que tenhamos uma variável inteira chamada i, que é um índice para iterarmos sobre os valores do array. O primeiro elemento do array pode ser referenciado como NATURAIS[i] se i for igual a 1, e o valor de NATURAIS[1] é 1. Logicamente, o último elemento da lista será NATURAIS[10] e seu valor será 10.

Caso desejássemos obter o somatório de todos elementos do array, poderíamos utilizar o seguinte algoritmo:

				
					
soma = 0;
for i=1 until 10 step 1 do:
  soma = soma + NATURAIS[i];
				
			

Fácil, né!? Em linguagens de programação mais antigas, os iteradores eram apenas números inteiros. Algumas linguagens mais recentes permitem iterar de maneiras mais naturais e você certamente aprenderá esses detalhes mais específicos quando escolher uma linguagem para trabalhar.

A segunda estrutura de controle que utilizamos com frequência é WHILE. Nessa estrutura não temos um iterador explícito. Temos apenas a avaliação de uma condição que enquanto for verdadeira irá executar as ações previstas dentro do controle WHILE. Quando a condição se tornar falsa, o programa voltará ao seu fluxo de execução até o final.

Vamos a um exemplo simples…Suponha que queiramos “imprimir” na tela os números de 1 a 100. Você certamente pensou que podemos fazer isso facilmente com um controle FOR, mas vamos exercitar fazer isso com um controle WHILE:

				
					i = 1;
WHILE(i <= 100)
{
  Imprimir(i);
  i = i + 1;
}

				
			

Nas linguagens mais antigas havia variações da estrutura WHILE. Por exemplo, tem uma estrutura que se chama DO…WHILE, a qual executa primeiro as ações do controle WHILE antes de fazer a verificação da condição. Com isso, o controle de repetição é executado sempre ao menos uma vez. Novamente, não precisamos nos preocupar com essas peculiaridades, pois cada linguagem, embora haja muita semelhança entre elas, possuí sintaxes e características diferentes. E é mais oportuno aprofundar nisso quando você decidir por uma linguagem de programação para estudar.

4. Recapitulando

Tentamos ao longo dessa aula passar os conceitos gerais do que são os controles de fluxo sem entrar em detalhes específicos de linguagem de programação. É muito importante que tenhamos o entendimento do que são os controles de fluxo e como podemos utilizá-los para resolver problemas. Enquanto os controles de seleção nos permitem executar ações quando determinada condição (ou expressão booleana) for verdadeira, os controles de repetição nos permitirão repetir a execução de ações enquanto uma condição for verdadeira.

Ressaltei que neste momento, você não precisa se preocupar com peculiaridades de programação, pois você terá a oportunidade de aprender em maior profundidade quando escolher uma linguagem específica para trabalhar.

Aula 04 - Reutilizando código

Funções são essenciais na programação.

No mundo da programação há um constante esforço por tornar as linguagens cada vez mais naturais para nós seres humano (mais fáceis de programar), bem como mais eficientes (consumirem menos recursos computacionais).

Para o programador não é diferente, ele sempre está tentando programar cada vez melhor e mais rápido tendo em vista sua experiência acumulada, refletindo em códigos mais concisos (menos linhas de código) e mais eficientes.

A forma mais primitiva de ganhar velocidade em sua programação seria COPIAR e COLAR o que já fez no passado para resolver um problema e adaptá-lo para o problema que está tentando resolver. Acredite! Como programadores, fazemos muito isso! Mas uma forma mais estruturada de reutilizar código é por meio da criação de funções, o que veremos a seguir.

Reproduzir vídeo

O que são funções?

Antes de definirmos as funções vamos pensar melhor sobre o que é um programa! Um programa é a transcrição de um algoritmo em um código fonte que pode receber parâmetros, executar um conjunto de ações e retornar um resultado.

As funções também fazem exatamente isso, talvez pela única exceção de que elas estão contidas dentro dos programas. As funções são pedaços de código fonte que podem receber parâmetros, executam um conjunto de ações e podem retornar um resultado.

E quando é que criamos funções? Quando queremos fazer exatamente uma coisa que já fizemos em outro momento no nosso programa, ou seja, reutilizar código.

Qual a vantagem de usar funções? A gente economiza linhas de código e se precisar alterar as ações executadas, precisaremos mudar apenas em um lugar (dentro da função), ou seja, para facilitar a menutenção do código. Caso não tivesse uma função, o mesmo pedaço de código poderia estar replicado em vários lugares do seu programa! Tornando mais trabalhoso e susceptível a erros uma correção no código.

Assim, as funções servem também para generalizar em função dos parâmetros. Dentro delas podemos ter declaração de variáveis que serão conhecidas como variáveis locais, ou seja, são apenas utilizadas dentro da função.

Vamos a um exemplo para ilustrar isso melhor. Suponha que tenhamos um programa que calcule área de uma circunferência diversas vezes, o que você sabe que basta fazer a seguinte conta: pi*r**2 (onde r é o raio da circunferência). Assim, eu poderia criar uma função para realizar esse cálculo:

				
					
calculaAreaCircunferencia(raio: Real)
  real área;
  area = 3.1415*raio**2;
  
  return área;
				
			

Quando precisássemos calcular a área de uma circunferência com raio 10, apenas iríamos chamar a função calculaAreaCircunferencia(10) que ela retornaria o valor desejado.

É importante ressaltar que uma função pode receber mais de um parâmetro, mas geralmente retorna apenas uma estrutura de dados. Eu disse geralmente porque também há linguagens de programação que permitem às funções retornarem mais de uma estrutura.

Em algumas linguagens de programação são dados nomes diferentes para funções, a depender se retornam ou não valores. Por exemplo, tem linguagem que dá o nome procedure quando não há retorno de valor e function quando retorna…Novamente ressalto que estas especificidades de cada linguagem e é algo que será estudado quando você for se aprofundar em alguma delas. Para o momento, basta que tenha compreendido o diagrama abaixo que representa uma função.

Concluindo...

Ao longo das últimas quatro aulas, vimos de forma bem objetiva e prática os conceitos mais básicos da programação, passando por algoritmos, estrutura de dados, código fonte, compiladores, tipos básicos de dados, estruturas de controle e funções.

Com a informação apresentada até o momento, você já tem uma base inicial para implementarmos seus primeiros programas em uma linguagem específica. Isto é o que faremos na próxima aula! Nos vemos lá!

Aula 05 - Hands-on: Primeiros programas em Pascal

Nesta última aula iremos implementar dois programas de exemplo para consolidar o que vimos no curso básico e preparar o caminho para começarmos a implementação de estratégias automatizadas.

Reproduzir vídeo

1. Por onde "começar"?

Se você assistiu/leu as aulas do curso básico até aqui, deve estar se perguntando: por qual linguagem de programação devo “começar” a estudar e implementar meus primeiros programas/estratégias?

Eu penso que para aprender uma linguagem de programação, é necessário atender a um propósito, a uma finalidade prática, para não corrermos o risco de perder a motivação no meio do caminho. Como nesta comunidade nosso objetivo é compartilhar conhecimento e experiências sobre automatização de estratégias para negociação de ativos, iremos selecionar uma linguagem que facilite alcançar esse objetivo.

Neste contexto, existem duas plataformas com maior capilaridade no mercado: Profit Chart (Empresa Nelogica) e MetaTrader (Empresa MetaQuotes Software), quando se trata de negociação de ativos na B3. Ainda tem outras plataformas disponíveis por aí como TradingView e outras que também podem atuar na B3 quanto em criptoativos.

O Profit Chart baseia-se na linguagem Pascal, enquanto o MetaTrader baseia-se na linguagem C.

Iremos iniciar a construção das bases de conhecimento desta comunidade abordando inicialmente implementações de estratégias no Profit Chart. Por que? Porque eu acredito que seja uma plataforma mais amigável para quem está iniciando e com uma curva de aprendizado menor. Está certo que a plataforma é mais limitada em termos de implementação de estratégias do que o MetaTrader. Mas para quem está iniciando, ainda há muito espaço para aprender, testar seu conhecimento e implementar diversas estratégias.

O caminho natural em um segundo momento será abordarmos também a programação em C visando utilização do MetaTrader, software que apresenta uma interface gráfica menos amigável e uma curva de aprendizado maior, embora tenha uma comunidade mundial ativa desenvolvendo soluções.

Assim, visando reduzir nosso nível de preocupação com o que é essencial utilizaremos para esta aula um console virtual e compilador hospedado na web. Faremos isso para evitar passarmos pelo processo de baixar na internet um compilador de Pascal, instalarmos uma API para programar (nada mais é que um editor de texto específico para escrever código fonte). Pois este processo não será necessário para programar as estratégias no Profit Chart, não agregando informação relevante nesse momento.

Então clique em uma das opções de compiladores online abaixo para abrir em uma nova aba o console e compilador online de Pascal para prosseguirmos com esta aula!

      1. Onlinegdb.com;
      2. JDoodle;
      3. Rextester.com
      4. Tutorialspoint.com

Em todos os compiladores onlines haverá uma seção na página onde você poderá editar o código-fonte, e outra seção que será o terminal de comando no qual você irá visualizar o resultado da execução do seu programa. Cada compilador tem um botão para executar o código que pode estar sinalizado como “Run”, “Run code”, “Execute”, etc…

2. Entendendo a estrutura básica de um programa em Pascal

Ao abrir qualquer um dos links acima, você verá no editor de código fonte, possivelmente, o famoso programa “HelloWorld” que qualquer curso de programação irá ensinar como primeira lição! Vamos entender o que está escrito!?

				
					Program HelloWorld(output);
begin
  writeln('Hello, world!');
end.
				
			

Em Pascal todo programa começa com a declaração do nome do programa: Program HelloWorld. Em parentêses são fornecidos os parâmetros do programa. O parâmetro output é uma variável especial que se refere ao terminal de comando, e que especifica que neste programa os comandos de escrita (writeln, abreviação de write line) serão direcionados para o terminal (tela à direita do compilador virtual).

Entre as linhas 2 e 4 está o corpo do programa HelloWorld, que deve estar entre as palavras reservadas begin  e end. (não esqueça do ponto!).

Este é um programa muito simples! A única coisa que ele faz é escrever em tela a string (sequencia de caracteres) “Hello, world!”.

Clique no botão “Execute” no compilador virtual. Observe que o código do programa Hello World será compilado, e caso não haja nenhum erro de compilação, será executado! Nas últimas linhas do lado direito da tela, você deve visualizar o seguinte resultado, demonstrando que seu código foi compilado e o resultado da execução.

Parabéns! Você acabou de compilar e executar seu primeiro programa na linguagem Pascal! Agora vamos explorar um pouco mais os conceitos que você aprendeu até o momento, implementando alguns programas em Pascal. 

3. Hello, market! Uma versão um pouco mais elaborada...

Entre as linhas 1 e 2 do código fonte que vimos anteriormente, o Pascal nos permite realizar algumas coisas:

  • Declarar bibliotecas que serão utilizadas pelo programa (comando uses);
  • Declarar constantes (comando const);
  • Declarar variáveis globais (comando var);
  • Declarar functions/procedures.

As bibliotecas (library) são um repositório de funções e tipos de dados que permitem facilitar escrever um programa para determinada finalidade. Por exemplo, a biblioteca strings possui algumas funcionalidades para facilitar a manipulação de dados de texto. Toda biblioteca possui uma documentação com descrição de como utilizar os tipos de dados e funções.

As constantes são definições de dados que não podem ter seu valor alterado dentro do programa.

As variáveis globais são variáveis que podem ser utilizadas em qualquer lugar de seu programa principal e, naturalmente, podem ter seu valor modificado durante a execução do programa.

As funções (functions) são pedaços reutilizáveis de código fonte que retornam algum valor, enquanto os procedimentos (procedures) não retornam nenhum valor.

A seguir vamos complicar o código fonte de forma incremental para explorarmos a linguagem Pascal.

3.1 Declarando constantes

Vamos mudar o nome do programa para “HelloMarket” e declarar uma constante chamada “dizerHello” do tipo boolean e que tenha o valor verdadeiro. Vamos escrever “Hello, market” apenas se “dizerHello” for verdadeira. Veja abaixo como fica o código fonte:

				
					Program HelloMarket(output);
const
  dizerHello = true;
  
begin
  if dizerHello = true then
    writeln('Hello, market!');   
end.
				
			

Vamos nos atentar para alguns detalhes:

  • A atribuição de valor às constantes na seção const se dá utilizando o sinal “=”;
  • O operador de igualdade para condição do if também utiliza o sinal “=”, mas não trata de uma atribuição de valor e sim de uma expressão booleana;
  • Quando há apenas um comando a ser executado dentro de um controle de decisão/repetição, não há necessidade de utilizar os delimitadores begin…end;

Ao executar o código acima, você irá verificar que o resultado é o mesmo. Você pode tentar mudar a atribuição da constante “dizerHello” para false e verificar o resultado do programa.

3.2 Utilizando biblioteca sysutils

Vamos utilizar a biblioteca sysutils que possui várias funções interessantes para ajudar a escrever programas em Pascal. Como todo programador, você terá que se acostumar a ler a documentação das bibliotecas para aprender a utilizar as funções e até mesmo ver exemplos de uso. A documentação da biblioteca sysutils pode ser acessada aqui.

Agora vamos declarar uma variável do tipo string, chamada “frase”, contendo o texto que iremos imprimir na tela, na seção var do nosso programa. Também vamos usar a função Concat para concatenar (unir) duas strings: “Hello, ” e “market!”. Em seguida vamos usar a função UpperCase para transformar o resultado da concatenção em letras maiuscúlas e armazenar na variável “frase”. Vamos lá!?

				
					Program HelloMarket(output);
uses sysutils;
const
  dizerHello = true;
var 
  frase : string;
begin
  frase := UpperCase(Concat('Hello, ', 'market!'));
  if dizerHello = true then
    writeln(frase);   
end.
				
			

Você observará que o resultado do programa ainda será o mesmo, exceto que as letras estarão em maiúsculo.

3.3 Imprimindo "Hello, market!" n vezes

Bom, agora vamos utilizar um controle de repetição para imprimir o texto “Hello, market!” quantas vezes desejarmos.

Para isso vamos utilizar o controle for e também precisaremos declarar duas variáveis auxiliares do tipo inteiro, uma para fazer a contagem (variável i) e outra para dizer quantas vezes devemos repetir o texto (n_vezes). Veja como seria o código abaixo.

				
					Program HelloMarket(output);
uses sysutils;
const
  dizerHello = true;
var 
  frase : string;
  i, n_vezes : integer;
begin
  n_vezes := 5;
  frase := UpperCase(Concat('Hello, ', 'market!'));
  if dizerHello = true then
    for i := 1 to n_vezes do
        writeln(i, ') ', frase);   
end.
				
			

O resultado esperado da execução do programa segue abaixo:

3.4 Criando uma procedure

Vamos agora implementar uma procedure que recebe como parâmetro uma string e uma quantidade. Esses parâmetros servirão para dizer o texto que deve ser impresso e quantas vezes isso deve ocorrer.

Iremos implementar uma procedure porque em Pascal é esse nome que se dá a uma “função” que não retorna nenhum resultado para o programa principal. Veja abaixo como implementamos! O resultado esperado deve ser exatamente o mesmo da seção anterior.

				
					Program HelloMarket(output);
uses sysutils;
const
  dizerHello = true;
var 
  frase : string;
  i, n_vezes : integer;
  
procedure printHello(texto: string; t: integer);
begin
    for i:=1 to t do
        writeln(i, ') ', frase);
end;

begin
  n_vezes := 5;
  frase := UpperCase(Concat('Hello, ', 'market!'));
  if dizerHello = true then
    printHello(frase, n_vezes);  
end.
				
			

Note que no corpo principal do programa, existem duas variáveis chamadas n_vezes e frase, as quais são passadas como parâmetro para a procedure printHello. Dentro dessa procedure, os parâmetros podem possuir nomes diferentes, que é exatamente o caso. Dentro de printHello, a variável frase é chamada texto e a variável n_vezes é chamada de t. Qualquer alteração nos valores das variáveis texto e t não refletirão mudança no valor das variáveis frase e n_vezes. Isto deve-se ao fato dos parâmetros serem passados para as funções/procedures como valores.

Caso o programador deseja-se modificar os valores das variáveis fornecidas como parâmetros no escopo que chamou a função, ou seja, passando a referência das variáveis originais, bastaria definir os parâmetros precedidos com o comando var.

Esses mecanismos de passagem de parâmetros como valor ou como referência para funções ocorre em todas as linguagens de programação.

3.5 Obtendo dados do usuário

Obter dados externos é uma tarefa muito comum em programação. Ora o programa pode receber dados via terminal de comando, quando o dado a ser inserido é relativamente simples, ora o programa pode receber dados via arquivo de texto com um padrão definido, quando o volume e complexidade dos dados a serem recebidos justificar.

A última parte desse primeiro exercício de programação, será obtermos do usuário a quantidade de vezes que a frase “Hello, market!” deve ser impressa. Desta forma, vamos programar para que o programa peça esta informação e atue com este dado. Vamos lá!? Veja o código abaixo:

				
					Program HelloMarket(output);
uses strings;

const
  hello = 'Hello, market!';

var
  i, vezes: integer;
  
  dizerHello: boolean;

procedure printHello(print: boolean; t: integer);
begin
    for i:=1 to t do
        if (print = true) then
            writeln(i, ' - ', hello);
end;

begin
  dizerHello := true;
  
  writeln('Digite a quantidade de vezes que deseja dizer ''Hello, market!'':');
  readln(vezes);

  printHello(dizerHello, vezes);
    
end.
				
			

O resultado da execução do programa, inserindo o número 7 (seguido de ENTER) segue abaixo:

4. Implementando Bubble Sort

Este segundo exercício de programação consistirá em entendermos um algoritmo e implementarmos um programa que o execute.

Utilizaremos um algoritmo clássico de ordenação, chamado Bubble sort. Já aviso que não é o algoritmo mais eficiente para realizar tal tarefa, mas foi um dos primeiros desenvolvidos e tem o seu valor didático. Se você se interessar em conhecer algoritmos de ordenação, veja esse vídeo aqui (Bubble sort está no minuto 4:00)!

Veja abaixo o algoritmo Bubble sort (fonte: wikipedia). Tente entender o algoritmo antes de passarmos para implementação.

				
					procedure bubbleSort(A : list of sortable items)
    n := length(A)
    repeat
        newn := 0
        for i := 1 to n - 1 inclusive do
            if A[i - 1] > A[i] then
                swap(A[i - 1], A[i])
                newn := i
            end if
        end for
        n := newn
    until n ≤ 1
end procedure
				
			

Vou tentar lhe dar uma ideia de como funciona o algoritmo Bubble sort. Pense em uma lista “A” de números inteiros aleatórios. O algoritmo irá começar comparando os dois primeiros elementos da lista, A[0] e A[1]. Se A[0] for maior que A[1], esses elementos serão trocados na lista, de tal forma que A[1] ficará na segunda posição e A[0] na primeira posição da lista. Em seguida, o algoritmo compara A[1] com A[2], e troca de posição se A[1] for maior que A[2]. Esse processo irá se repetir até chegar na comparação de A[n-i] e A[n], sendo n a quantidade de elementos da lista.

Perceba que ao iterar de 1 até n, o maior elemento da lista estará ao final desse controle (linhas 5 a 10 do algoritmo) na posição n-1. Mas o restante da lista ainda não está ordenada!

Portanto, repete-se a iteração na lista de 1 até n-1 (linhas 5 a 10), fazendo com que o segundo maior elemento da lista agora ocupe a posição n-2. Essas iterações vão ocorrer sucessivamente, até que a última iteração será apenas para comparar o elemento da primeira posição com o elemento da segunda posição. Essas repetições são controlados pelo comando repeat (linha 3) e sua condição de parada na linha 12.

O nome Bubble sort vem da analogia de um copo com refrigerante, as bolhas vão subindo, asssim como os maiores elementos também vão subindo de posição dentro da lista.

Veja abaixo a implementação do algoritmo e tente entender um pouco cada parte antes de prosseguirmos.

				
					program programaOrdenacao;
uses SysUtils;

type
  IntegerArray = array of Integer;
var 
    listaNaoOrdenada: IntegerArray;
    listaOrdenada: IntegerArray;
    i, tamanhoLista: integer;

procedure swap( var a, b:integer);
var
  temp : integer;
begin
  temp := a;
  a := b;
  b := temp;
end;

function BubbleSort(a: IntegerArray): IntegerArray;
var
  n, newn, i:integer;
begin
  n := high( a );
  repeat
    newn := 0;
    for i := 1 to n   do
      begin
        if a[ i - 1 ] > a[ i ] then
          begin
            swap( a[ i - 1 ], a[ i ]);
            newn := i ;
          end;
      end ;
    n := newn;
  until n = 0;
  
BubbleSort := a;
end;

begin
  Write('Insira o tamanho da lista que deseja ordenar (pressione ENTER):');
  readln(tamanhoLista);

  SetLength(listaNaoOrdenada, tamanhoLista);
  SetLength(listaOrdenada, tamanhoLista);

  writeln('Digite ', tamanhoLista, ' números inteiros separados ENTER:');
  for i:= 0 to tamanhoLista-1 do
    readln(listaNaoOrdenada[i]);

  writeln();
  Write('Lista inserida: ');
  for i:= 0 to tamanhoLista-1 do
    Write(listaNaoOrdenada[i], '   ');
  Write(sLineBreak);
  
  listaOrdenada := BubbleSort(listaNaoOrdenada);
  
  Write('Lista ordenada: ');
  for i:= 0 to tamanhoLista-1 do
    Write(listaOrdenada[i], '   ');
  Write(sLineBreak);
end.


				
			

Perceba que a implementação de um algoritmo simples já começa a apresentar detalhes particulares de implementação. Vamos explorar um pouco o código fonte para explicá-lo.

As linhas 1 e 2 são bem objetivas, nomeia o programa como “programaOrdenacao” e informa que será utilizada a biblioteca SysUtils. A documentação do compilador FreePascal que é utilizado nos links dos compiladores online, bem como a documentação das bibliotecas está disponível no site freepascal.org.

Nas linhas 4 e 5, a gente irá declarar um tipo de dado chamado IntegerArray que será um array de Integer (vimos o que era array na segunda aula!). Essa declaração de tipo é uma exigência da linguagem para utilizarmos este tipo de dados como retorno da função BubbleSort.

Entre as linhas 6 e 9, vamos declarar as variáveis que o programa irá utilizar: uma lista não ordenada que será informada pelo usuário, uma lista ordenada que será o resultado da função BubbleSort, uma variável de iteração i e o tamanho da lista a ser informada pelo usuário.

A procedure swap (entre as linhas 11 e 18) realiza apenas a troca de valores entre dois elementos. Essa procedure foi criada devido à recorrência desse tipo de operação no algoritmo BubbleSort. Note que os parâmetros foram passados como referência, o que permite, portanto, a manipulação de seus valores e reflexo no escopo que chamou a procedure swap, no caso, a função BubbleSort.

Entre as linhas 20 e 39, você verá a função BubbleSort que implementa o algoritmo visto anteriormente A função recebe como parâmetro um array de inteiros por valor, e retorna outro array de inteiros ordenado.

Entre as linhas 41 e 64 está o corpo principal do programa. O programa começa solicitando ao usuário o tamanho da lista que será ordenada. Assim, o usuário deve fornecer um número inteiro positivo ao programa.

Com base nessa informação, as linhas 45 e 46 definem o tamanho dos arrays listaNaoOrdenada e listaOrdenada. Em seguida, nas linhas 48 a 50, o programa pede que o usuário insira cada um dos números da lista de tamanho que ele definiu. Ao tempo que os valores são informados, eles são gravados nas posições do array listaNaoOrdenada (linha 49 e 50).

Entre as linhas 52 e 56, o programa irá imprimir na tela qual foi a lista de valores inseridas pelo usuário.

Na linha 58, é executada a chamada da função BubbleSort e o resultado é armazenado na variável listaOrdenada.

Por fim, a lista ordenada é impressa em tela (linha 60 a 63).

Talvez você cometa o erro de inserir uma letra quando o programa solicitar o tamanho da lista. Você observará que ocorrerá um erro no programa, pois o valor inserido pelo usuário seria do tipo string e o programa está tentando armazenar em uma variável do tipo inteiro.

Esses erros em programação são conhecidos como erros de execução e ocorrem sempre que o usuário realiza uma ação diferente do esperado. Em programação, o programador sempre tenta prever estes casos de “exceção” parar que o programa trate de forma correta. Por exemplo, o programa poderia informar que o valor inserido não é um número inteiro e solicitar novamente a inserção da informação até que ela venha correta. Assim, não haveria erro de execução e o programa continuaria sua execução até o fim. Situação análoga poderia ocorrer no momento de informar os elementos da lista.

Próximos passos

Bom, chegamos ao fim do curso básico de lógica de programação e espero que tenham conseguido entender os principais conceitos e ideias por trás da programação.

Esta última aula, na qual entramos em detalhes específicos da linguagem Pascal demonstra um pouco como é a vida de um programador…Especializar-se em uma linguagem específica leva tempo, exige horas de leitura de documentação, inúmeras pesquisas no google sobre erros de compilação, exemplos de código fonte, etc. É um trabalho de pesquisa e estudo que exige proativdade para achar as soluções para os problemas. As dificuldades em programação sempre vão existir! No início você irá se deparar com dificuldade em tarefas simples que com o tempo se tornarão naturais de se programar, mas surgirão novas dificuldades em tarefas mais complexas.

O importante no final das contas, é manter-se motivado, sentir-se realizado pelas pequenas conquistas e buscar suporte e materiais de qualidade para consulta. A intenção do site Neo traderBot é justamente ter um ambiente colaborativo com materiais de relevância e pessoas interessadas em ajudar umas as outras na busca por soluções.

Espero que tenha gostado do curso, mas se há alguma sugestão ou critíca para que possamos melhorar o conteúdo, não hesite em comentar abaixo.

Muito obrigado e sucesso para você nessa jornada de conhecimento!

Conhecendo a Trader Evolution

Conheça a plataforma e suas funcionalidades da Interface gráfica.

Introdução a Plataforma TraderEvolution

Reproduzir vídeo

Neste vídeo vamos iniciar uma série sobre a plataforma TraderEvolution.

Apresentaremos informações básicas sobre a plataforma, como contratar e custo de utilização.

Nos próximos vídeos iremos nos aprofundar nas funcionalidades da plataforma, cobrindo desde configuração de gráficos, Times & Sales, Grade de cotações, etc…O nosso objetivo é entender em profundidade a plataforma para que possamos iniciar nossas implementações de robôs e estratégias em EvoCode (C#).

CHART TRADING - Operando pelo Gráfico na Trader Evolution

Reproduzir vídeo

Neste vídeo da séria “Conhecendo a Trader Evolution” vamos explorar a funcionalidade CHART TRADING, em outras palavras, vamos operar pelo gráfico. Esta é uma funcionalidade bem interessante na plataforma devido à sua facilidade de uso e possiblidade de abrir posições ou enviar ordens com apenas um clique.

Explorando a Interface Gráfica e PRINCIPAIS FUNCIONALIDADES da Trader Evolution

Reproduzir vídeo

Neste segundo vídeo da séria “Conhecendo a Trader Evolution” vamos explorar de maneira geral a interface gráfica da Plataforma, para que tenhamos uma noção de onde encontrar as ferramentas principais.

Sinalize na plataforma o código “NEOTRADERBOT” para indicar que faz parte da Comunidade e podermos verificar benefícios especiais aos membros! (No menu principal, vá em “Mais”, em seguida “Indique parceiro”)

Gráficos na TraderEvolution [PARTE 1- Configuração e Funcionalidades]

Reproduzir vídeo

Neste vídeo da séria “Conhecendo a Trader Evolution” vamos explorar as configurações e funcionalidades básicas de Gráficos. Vamos ver como configurar a série de dados do gráfico, a representação gráfica, o tamanho da janela histórica, como personalizar as cores de barras, fundo e outra propriedades.

Também veremos como incluir o volume das barras, adicionar o Volume Profile e Livro visual no gráfico. Ao final, demonstraremos como salvar um modelo de gráfico para ser reutilizado posteriormente e onde os arquivos de templates ficam armazenados.

Caso queira fazer o download da configuração realizada nesse vídeo, basta baixar o arquivo abaixo e descompactar na pasta indicada no vídeo.

      🤖 https://github.com/johnathas/NeoTrade…

Gráficos na TraderEvolution [PARTE 2- Configuração e Funcionalidades]

Reproduzir vídeo

Neste vídeo da séria “Conhecendo a Trader Evolution” vamos explorar as configurações e funcionalidades básicas de Gráficos.

Nesta segunda parte iremos demonstrar como incluir estudos em gráficos, criar e gerenciar alarmes, inserir indicadores, operar pelo gráfico e exibir os trades realizados no gráfico.

Grade de Gráficos na TraderEvolution [Monitorando o mercado]

Reproduzir vídeo

Neste vídeo da séria “Conhecendo a Trader Evolution” vamos explorar a funcionalidade GRADE DE GRÁFICOS, por meio da qual você poderá monitorar o mercado. Esta funcionalidade é análoga a “Visão de Mercado” do Profit Chart e do “Market Watch” da Ninja Trader.

Grid de Cotações na TraderEvolution [Aprenda a criar vinculo com um gráfico]

Reproduzir vídeo

Neste vídeo da séria “Conhecendo a Trader Evolution” vamos explorar a funcionalidade GRID DE COTAÇÕES, por meio da qual você poderá criar uma lista com ativos a serem acompanhados e vincular esta tabela com um gráfico para inspeção rápida.

CRIE ALERTAS E DISPARE ORDENS AUTOMATICAMENTE na Trader Evolution

Reproduzir vídeo

Neste vídeo da séria “Conhecendo a Trader Evolution” vamos explorar a funcionalidade do GERENCIADOR DE ALARME, o qual nos permite criar alertas de som, pop-up ou até mesmo disparar ordens automaticamente quando o alerta for emitido. Detalhe importante é que a ordem pode ser emitida em outro ativo diferente do ativo que gerou o alerta.

RELATÓRIO DE DESEMPENHO – Acompanhe os resultados das suas operações na Trader Evolution

Reproduzir vídeo

Neste vídeo da séria “Conhecendo a Trader Evolution” vamos explorar o Relatório de Desempenho no qual o trader pode avaliar as operações (trades) realizados na plataforma, de maneira individual (por ativo negociado) e agregada.

COMO CONFIGURAR E OPERAR PELO BOOK DE OFERTAS [Trader Evolution]

Reproduzir vídeo

Neste vídeo da séria “Conhecendo a Trader Evolution” vamos explorar o BOOK DE OFERTAS. Esta ferramenta nos permite ter uma visão do segundo nível do mercado, vendo o interesse de compra e venda por nível de preço ou por participante do mercado. Além disso é possível operar diretamente pelo Book de Ofertas, conforme demonstração realizada nesse vídeo.

Não se esqueça de indicar a Comunidade NeoTraderBot como parceiro na Plataforma TraderEvolution. Vá no menu superior em “Mais” – “Extensões” – “Indique parceiro” e digite o código “NEOTRADERBOT”.

Assim, você reforça sua participação na Comunidade e nos ajuda a pleitear novas funcionalidades e melhorias na plataforma visando o benefício de todos os membros em suas automatizações e desenvolvimento de estratégias.

EXPLORANDO O TIMES & SALES da Trader Evolution [Monitore as negociações do mercado]

Reproduzir vídeo

Neste vídeo da séria “Conhecendo a Trader Evolution” vamos explorar a ferramenta de TIMES & SALES. Esta ferramenta nos permite visualizar as negociações realizadas entre os participantes de mercado. Podemos realizar filtros de quantidade de lotes por negócio de forma a enxergar movimentações maiores e que se observadas na atuação de vários participantes pode sinalizar um interesse predominante do mercado em uma direção.

Não se esqueça de indicar a Comunidade NeoTraderBot como parceiro na Plataforma TraderEvolution. Vá no menu superior em “Mais” – “Extensões” – “Indique parceiro” e digite o código “NEOTRADERBOT”.

Assim, você reforça sua participação na Comunidade e nos ajuda a pleitear novas funcionalidades e melhorias na plataforma visando o benefício de todos os membros em suas automatizações e desenvolvimento de estratégias.

SuperDOM na Trader Evolution [Conheça o mercado em profundidade]

Reproduzir vídeo

Neste vídeo da séria “Conhecendo a Trader Evolution” vamos explorar a ferramenta de SuperDOM. A sigla DOM vem do inglês “Depth of Market”. É uma expressão para os dados de book de ofertas que são os registros de ordens limitadas de compra e venda (o interesse aberto dos participantes do mercado). Pelo SuperDOM é possível realizar operações de abertura e fechamento de posição, bem como administrar uma operação aberta.

Não se esqueça de indicar a Comunidade NeoTraderBot como parceiro na Plataforma TraderEvolution. Vá no menu superior em “Mais” – “Extensões” – “Indique parceiro” e digite o código “NEOTRADERBOT”.

Assim, você reforça sua participação na Comunidade e nos ajuda a pleitear novas funcionalidades e melhorias na plataforma visando o benefício de todos os membros em suas automatizações e desenvolvimento de estratégias.

Boleta e Matrix na Trader Evolution [+1 ferramenta para analisar o nível II do mercado]

Reproduzir vídeo

Neste vídeo da séria “Conhecendo a Trader Evolution” vamos explorar a BOLETA e a ferramenta MATRIX. Pela ferramenta MATRIX, o trader possui mais uma opção para visualizar os dados de Nível II do mercado.

Não se esqueça de indicar a Comunidade NeoTraderBot como parceiro na Plataforma TraderEvolution. Vá no menu superior em “Mais” – “Extensões” – “Indique parceiro” e digite o código “NEOTRADERBOT”.

Assim, você reforça sua participação na Comunidade e nos ajuda a pleitear novas funcionalidades e melhorias na plataforma visando o benefício de todos os membros em suas automatizações e desenvolvimento de estratégias.

Ferramenta SCALPER da Trader Evolution

Reproduzir vídeo

Neste vídeo da séria “Conhecendo a Trader Evolution” vamos explorar a ferramenta de SCALPER.

Não se esqueça de indicar a Comunidade NeoTraderBot como parceiro na Plataforma TraderEvolution. Vá no menu superior em “Mais” – “Extensões” – “Indique parceiro” e digite o código “NEOTRADERBOT”.

Assim, você reforça sua participação na Comunidade e nos ajuda a pleitear novas funcionalidades e melhorias na plataforma visando o benefício de todos os membros em suas automatizações e desenvolvimento de estratégias.

Ferramenta MESTRE DE OPÇÕES da Trader Evolution

Reproduzir vídeo

Neste vídeo da séria “Conhecendo a Trader Evolution” vamos explorar a ferramenta MESTRE DE OPÇÕES.

Não se esqueça de indicar a Comunidade NeoTraderBot como parceiro na Plataforma TraderEvolution. Vá no menu superior em “Mais” – “Extensões” – “Indique parceiro” e digite o código “NEOTRADERBOT”.

Assim, você reforça sua participação na Comunidade e nos ajuda a pleitear novas funcionalidades e melhorias na plataforma visando o benefício de todos os membros em suas automatizações e desenvolvimento de estratégias.

Como configurar ativos sintetizados na Trader Evolution

Reproduzir vídeo

Neste vídeo da séria “Conhecendo a Trader Evolution” vamos explorar a possibilidade de criação de um ativo personalizado: um ativo sintetizado. Com este ativo é possível operar vários papeis ou contratos ao mesmo tempo, operacionar estratégias de LONG & SHORT, operar arbitragem, entre outras possibilidades.

Não se esqueça de indicar a Comunidade NeoTraderBot como parceiro na Plataforma TraderEvolution. Vá no menu superior em “Mais” – “Extensões” – “Indique parceiro” e digite o código “NEOTRADERBOT”.

Assim, você reforça sua participação na Comunidade e nos ajuda a pleitear novas funcionalidades e melhorias na plataforma visando o benefício de todos os membros em suas automatizações e desenvolvimento de estratégias.

Como utilizar o IBOV ONLINE [Cálculo do IBOV em tempo real native na Trader Evolution]

Reproduzir vídeo

Neste vídeo da séria “Conhecendo a Trader Evolution” vamos explorar o cálculo nativo de IBOV online, o qual pode ser incluído em um gráfico para comparação visual do valor calculado como justo para os futuros e o valor de futuros atualmente negociado.

Não se esqueça de indicar a Comunidade NeoTraderBot como parceiro na Plataforma TraderEvolution. Vá no menu superior em “Mais” – “Extensões” – “Indique parceiro” e digite o código “NEOTRADERBOT”.

Assim, você reforça sua participação na Comunidade e nos ajuda a pleitear novas funcionalidades e melhorias na plataforma visando o benefício de todos os membros em suas automatizações e desenvolvimento de estratégias.

Ferramenta Saldo Agressor da Trader Evolution

Reproduzir vídeo

Neste vídeo da séria “Conhecendo a Trader Evolution” vamos explorar a ferramenta de SALDO AGRESSOR para verificação de agressão dos participantes do mercado em determinado ativo.

Não se esqueça de indicar a Comunidade NeoTraderBot como parceiro na Plataforma TraderEvolution. Vá no menu superior em “Mais” – “Extensões” – “Indique parceiro” e digite o código “NEOTRADERBOT”.

Assim, você reforça sua participação na Comunidade e nos ajuda a pleitear novas funcionalidades e melhorias na plataforma visando o benefício de todos os membros em suas automatizações e desenvolvimento de estratégias.

Notícias e RSS na Trader Evolution [MANTENHA-SE INFORMADO DENTRO DA PLATAFORMA]

Reproduzir vídeo

Neste vídeo da séria “Conhecendo a Trader Evolution” vamos explorar a configuração de Notícias e RSS dentro da plataforma.

Não se esqueça de indicar a Comunidade NeoTraderBot como parceiro na Plataforma TraderEvolution. Vá no menu superior em “Mais” – “Extensões” – “Indique parceiro” e digite o código “NEOTRADERBOT”.

Assim, você reforça sua participação na Comunidade e nos ajuda a pleitear novas funcionalidades e melhorias na plataforma visando o benefício de todos os membros em suas automatizações e desenvolvimento de estratégias.

Conceitos básicos

Aprenda sobre os métodos de otimização, técnicas para segregação de dados e otimização.

Introdução a Otimização

Reproduzir vídeo

O processo de desenvolvimento de uma estratégia automatizada demanda a execução de algumas etapas importantes visando aumentar a chance de sucesso ou lucratividade de uma estratégia.

Podemos pensar neste processo como um filtro, no qual iniciamos implementando o código fonte dos algoritmos selecionados que vislumbramos ter maior chance de sucesso na exploração de padrões estatísticos na negociação de ativos. Essa implementação é um desafio inicial e os ajustes que realizamos no código fonte visando melhorar a execução do algoritmo, podem acabar gerando graus de liberdade adicionais à estratégia. Por exemplo, além de parâmetros de médias e outros indicadores próprios do setup operacional, podemos incluir outros indicadores para filtrar situações de mercado. Esses novos indicadores precisarão ser ajustados para que a estratégia funcione bem.

Além disso, é recomendável (para não dizer imprescindível) que toda estratégia tenha uma gestão de risco adequada: definição de tipos e parâmetros de stoploss e definição de alvo das operações (caso não seja feito pelas regras da própria estratégia).

E onde entra a otimização nesse processo? Tendo o código fonte da estratégia implementado, a otimização é o processo pelo qual iremos definir os valores mais apropriados para os graus de liberdade da estratégia! A seguir, vamos entender o que é a otimização para que possamos avançar para a realização prática desse processo sobre uma estratégia.

O que é Otimização?

Otimização é uma área da matemática aplicada que busca selecionar a melhor solução para um problema com relação a um determinado critério dentro de um conjunto de alternativas. Percebam que não estamos falando de problemas teóricos que podem ser modelados por expressões matemáticas lineares ou que podem ser resolvidos por cálculos diferenciais. A otimização aplica-se a problemas nos quais não é possível modelar por equações matemáticas ou ainda que tenhamos as equações não conseguimos resolvê-las pelo cálculo, mas apenas por métodos numéricos ou simulações.

Vamos contextualizar a otimização para o universo das estratégias automatizada. Percebam que não temos fórmulas matemáticas para este problema., mas podemos utilizar um simulador com dados históricos que são os registros do funcionamento do mercado, da oscilação de preços ao longo do tempo e volume negociado, no caso do modelo OHLCV. Podemos ter modelos de simulação que consideram dados com maior ou menor frequência, dados de Book de ofertas ou até informações das ordens executadas. O modelo de simulação pode se tornar mais complexo do que um simples OHLCV e o que é que vai ponderar o nível de complexidade do modelo é a disponibilidade de dados e custo computacional!

Vamos agora formalizar alguns conceitos para seguirmos adiante!

Espaço amostral

Espaço amostral ou espaço de busca…se formos estudar o assunto, cada área de conhecimento atribui um nome diferente para a mesma coisa…o que importa é o conceito!

O espaço de busca ou espaço amostral é o conjunto de todas as possibilidades de valores possíveis para cada variável de entrada do modelo, ou seja, dos graus de liberdade do nosso modelo. Para cada conjunto desse, se aplicarmos a nossa estratégia em uma janela histórica teremos um resultado diferente das operações realizadas.

Na figura acima, visualizamos do lado esquerdo exemplos de graus de liberdade de uma estratégia, que podem ser parâmetros de indicadores (quantidade de períodos de médias móveis, tipos de médias, qtde de períodos do MACD, IFR, sensibilidade de um indicador de topos e fundos), pode ser a opção de uso de uma técnica de stop (fixo, móvel) e todos os parâmetros relacionados: tamanho do stop, tamanho do passo de um stop móvel discreto, utilização de breakeven, valor do gatilho do breakeven, tamanho do alvo das operações (isso também pode ser uma variável de entrada do modelo!).

Do lado direito você visualizará o conjunto de métricas do resultado da execução do modelo de simulação para uma dada configuração de variáveis de entrada. Ou seja, temos um mapeamento do conjunto de dados de entrada para um conjunto de métricas de execução.

O modelo de simulação é que realiza o mapeamento das variáveis de entrada para  as métricas de desempenho! É nele e nos dados históricos utilizados que estão contidas as regras de simulação, bem como as restrições de execução.

Tipos de variáveis de entrada

As variáveis do espaço amostral podem ter tipos diferentes…podem ser números inteiros, por exemplo, a quantidade de períodos das médias. Podem ser números reais, tal como a sensibilidade de um indicador de topos e fundos ou tamanho inicial do stop. Podem ser dados categóricos ou booleanos: tipo de stop, com ou sem breakeven.

A importância de compreender o tipo das variáveis de entrada reside na definição do espaço amostral de cada variável de entrada que irá impactar o tamanho total do espaço amostral do problema de otimização e o esforço computacional demandado.

Calculando o tamanho do espaço amostral

Para cada variável de entrada do modelo de simulação, precisamos definir seu espaço amostral. 

No caso de variáveis que são números inteiros ou reais, precisamos definir um valor inicial, um valor final e o passo entre cada amostra. Cada variável sensibiliza o resultado em determinada magnitude, assim não faz sentido variar os valores em uma escala muito pequena. Por exemplo: não tem sentido simular um stop inicial de 1,37525 %…é muita precisão numérica….não faz diferença na otimização porque o preço de uma ação por exemplo vai até a segunda casa decimal (centavos). O que talvez seja mais factível para esta variável é estabelecer um espaço amostral entre 0,3% até 1,5%, variando em 0,1%, ou 0,2%….Isto é você quem vai decidir! Se fossemos varia entre 0,3 e 1,5% a cada 0,1%…isso daria 13 valores possíveis.

Após definir o espaço amostral para cada variável, iremos calcular a permutação de todos valores possíveis para obter o tamanho do espaço amostral….ou seja, basta multiplicarmos a quantidade de possibilidades de cada variável de entrada e realizar a soma quando uma determinada opção de variável de entrada impacte em alterações da quantidade de variáveis de entrada. Neste último caso, possivelmente estaremos trabalhando com códigos fontes distintos.

Vamos fazer um exemplo de cálculo do tamanho do espaço amostral para uma estratégia de cruzamento triplo de média, só para fixar esta parte do conteúdo. Vejas as figuras abaixo com o passo-a-passo do cálculo:

Existem algumas combinações de variáveis de entrada que não fazem sentido na permutação…por exemplo: quantidade de períodos da media rápida maior que media intermediaria. Então a quantidade de conjuntos viáveis é menor que isso…vamos supor para simplificação que seja 50% do teto calculado do tamanho do espaço amostral….estaríamos falando ainda de cerca de 7 milhões e 800 mil simulações aproximadamente.

Ainda é um número bem grande! Quanto tempo leva para rodar cada simulação? 3 segundos? E para armazenar o resultado em uma planilha? Isso é feito manualmente ou automaticamente? Vamos supor que o armazenamento das métricas da execução do modelo seja automatizado e gaste 0 segundos…se fossemos rodar todas as possibilidade seria 7,8 milhoes veze 3 segundos….o que daria: 270 dias de execução direta em uma única máquina…Isto certamente não é viável!

Ainda vamos falar dos métodos de otimização e se é necessário rodar 7,8 milhões de testes ou não em próximos documentos aqui no site…O que eu queria deixar claro aqui é que há restrições computacionais e por isso precisamos ser criteriosos em relação ao tamanho do espaço amostral que iremos mapear…por uma questão de tempo!

Função objetivo

A função objetivo ou função de custo ou função utilidade é apenas uma fórmula a qual tentaremos minimizar ou maximizar. Ou seja, iremos selecionar as configurações das variáveis de entrada do espaço amostral que minimizam ou maximizam determinada métrica de desempenho da estratégia, ou fórmula matemática.

Podemos definir otimizar o lucro líquido da estratégia ou a taxa de acerto (em outras palavras, o percentual de operações lucrativas).  Poderíamos até otimizar a relação de risco ganho da estratégia, que seria o quanto a estratégia tem de lucro médio nas operações vencedoras em relação ao prejuízo médio das operações perdedoras. O objetivo de otimização também poderia ser minimizar o drawdown da estratégia, que é o decaimento máximo de patrimônio.

A relação de métricas mais comuns como objetivo de otimização estão listadas abaixo, bem como sua definição:

Métrica Definição
Lucro bruto/líquido
Refere-se ao somatório do resultado dos trades realizados. Se positivo, significa que a soma do lucro dos trades vencedores superou a soma do prejuízo dos trades perdedores. Se negativo, significa que a soma do prejuízo dos trades perdedores superou a soma do lucro dos trades vencedores. O lucro pode ser em termos brutos (sem considerar custos de operação: taxas e emolumentos) ou líquido quando a plataforma já considera tais custos.
Taxa de acerto
Trata-se da divisão da quantidade de trades vencedores (que obtiveram lucro) pelo número total de trades realizados.
Drawdown
Refere-se ao maior decaimento de patrimônio ocorrido durante a simulação ou seja, a maior diferença entre um topo do valor de patrimônio e o próximo fundo.
Relação Risco/Ganho
É definida como a divisão entre lucro médio dos trades vencedores e prejuízo médio dos trades não vencedores. Uma sutileza do cálculo é que o lucro médio é calculado como o lucro total dos trades vencedores dividido pela quantidade de trades não perdedores, ou seja, inclui os trades que foram zerados. Já o prejuízo médio é a divisão entre o prejuízo total dos trades perdedores e a quantidade de trades perdedores. Este cálculo é mais conservador e recomendável para análise.
Fator de recuperação
É calculado dividindo o lucro final da simulação maior drawdown da simulação. Mede, portanto, a resiliência da estratégia, o quanto ele consegue recuperar de uma sequência de resultados ruins de trades.
Índice de Sharpe
A análise dessa métrica pressupõe que o retorno da estratégia é uma distribuição normal, uma vez que são utilizados apenas os dois primeiros momentos da distribuição, média e desvio padrão. É calculado como (retorno_est - retorno_livre)/desvio_pad. Onde retorno_est é o retorno da estratégia em uma determinada base temporal: anual, mensal, semanal, diária. retorno_livre é a taxa de retorno livre de risco. O usuário pode arbitrar entre usar IBOV ou taxa de juros de título do tesouro, na mesma base temporal. Por fim, desvio_pad refere-se ao desvio padrão da série de retorno da estratégia.

Imagino que você deve estar se perguntando…eu só posso otimizar uma métrica? E se eu quisesse maximizar o lucro líquido e ao mesmo tempo minimizar o Drawdown? É possível?

Sim, claro…é possível! Estamos falando neste caso de uma otimização multiobjetivo e existem algumas formas para se resolver este problema. Eu vou falar de apenas uma forma pois não é foco deste material, mas sinta-se a vontade para pequisar sobre o assunto.

Uma forma de fazer otimização multiobjetivo é criar uma função linear das métricas desejadas, atribuindo pesos para cada métrica. Estes pesos servirão tanto para ponderar as métricas mais importantes quanto para normalizar o valor das métricas que podem ser de escalas diferentes. Por exemplo, Lucro líquido é em unidades monetárias, enquanto Taxa de acerto é percentual (ou seja varia de 0 a 1). O peso atribuído a taxa de acerto deve ser tal que distribua de forma adequada a importância da otimização entre lucro líquido e taxa de acerto.

Recapitulando

Vimos neste documento os conceitos básicos sobre otimização e como eles se aplicam ao universo das estratégias automatizadas. No próximo documento veremos em maior profundidade como funcionam dois métodos de otimização: Grid Search e Algoritmos Genéticos, bem como iremos abordar questões importantes relacionadas aos dados utilizados para otimização.

Algoritmos, Segregação de dados e Overfitting

Reproduzir vídeo

Antes de falarmos sobre algoritmos de otimização, precisamos abordar o tema de segregação de dados dados históricos disponíveis para permitir a adequada realização de otimização e de backtesting.

A separação de dados é fundamental e precisa ser realizada antes de iniciar a otimização. Normalmente, deixamos os dados mais recentes reservados para o backtesting e um intervalo de tempo que permita uma quantidade suficiente de operações para analisar o resultado do backtesting com significância estatística. Ainda abordaremos aspectos a backtesting em outros materiais…por enquanto, é preciso entender que backtesting é um processo de validação executado após a otimização.

Não existe uma fórmula mágica ou um percentual específico dos dados para separar para backtesting. Na literatura, vemos sugestão de percentuais entre 15% a 30%…isso geralmente depende de vários fatores e também da quantidade de dados históricos que se tem disponível. Por exemplo, se uma estratégia opera daytrade, seria recomendável ter, no mínimo, 100 dias de operação no backtesting. Para que haja uma significância estatística na validação, ou seja para que a estratégia tenha a oportunidade de  experimentar situações distintas de alta, baixa, correção, lateralização… Se o intervalo médio entre as operações de uma estratégia é de 2 dias…então é preciso, no mínimo, 200 dias. Observe que no primeiro caso, haverá possivelmente mais operações do que no segundo caso. Quanto maior a amostra de operações no backtesting melhor, o problema é que há uma limitação de tamanho dos dados de backtesting e, geralmente,  precisamos de mais dados para a otimização do que para backtesting.

O conjunto de dados que separamos para backtesting nós vamos esquecer que existe enquanto estivermos fazendo a otimização e vamos chamar de OUT OF SAMPLE… a razão disso vai ficar mais clara no decorrer da explicação sobre otimização. Os dados que iremos utilizar para otimizar vamos chamar de IN SAMPLE.

Vamos agora falar sobre dois algoritmos muito empregados na otimização de estratégias.

Grid Search

O primeiro algoritmo que vamos tratar se chama Grid Search. Isto é só um nome bonito para um processo de exploração do espaço de busca por força bruta! Ou seja, este algoritmo simula todas as possibilidades de combinação dos parâmetros da estratégia. Você viu no exemplo do vídeo anterior que uma estratégia de cruzamento triplo de média, com 7 graus de liberdade gerou aproximadamente 7 milhões de possibilidades.

É coisa pra caramba! Não dá pra simular isso tudo…fica muito caro! Imagina a quantidade de tempo, o custo de máquinas ou de aluguel de cloud computing para se obter os parâmetros otimizados de uma estratégia que pode no final resultar em uma estratégia não lucrativa.

A primeira lição é ponderar sobre os recursos que se tem a disposição para realizar a otimização. Você vai fazer a simulação e tabelamento dos resultados de forma automática, sem intervenção humana….tudo bem…você pode simular mais possibilidades. Se você vai fazer na mão o processo de otimização com Grid Search, você vai ter que reduzir o espaço de busca.

Vou te dar um exemplo básico de Grid Search. Suponha que iremos otimizar apenas 2 variáveis da nossa estratégia, sendo 5 possibilidades para a primeira variável X e 5 para a segunda variável Y. Têm-se então 25 pontos que representam as combinações dos valores das variáveis X e Y. O Grid Search consiste em rodar a estratégia para cada um desses 25 pontos. Mas em qual ordem? Como iremos testar tudo de qualquer  forma, achar a solução na força bruta, então tanto faz! Mas nada impede também de rodar e coletar o resultado em uma planilha ou aplicativo web em uma ordem que julgar mais interessante.

O Profit Chart, na versão de hoje (12/12/2022), não oferece nenhum funcionalidade de suporte ao processo de otimização. Ou seja, se você só usar o Profit, só poderá fazer uma otimização bem limitada com um espaço de busca pequeno. Para ampliar o espaço de busca e automatizar o processo você precisará utilizar outra plataforma ou framework.

A próxima pergunta que você deve estar fazendo é se existem formas mais elaboradas de se otimizar uma estratégia do que simular na força bruta cada possibilidade? Sim! E uma resposta é algoritmo genético!

Algoritmo Genético

Os algoritmos genéticos baseiam-se nos processos de evolução genética e seleção natural que observamos na natureza e consistem em uma forma de percorrer o espaço de busca.

Em uma explicação com termos bem simples….o algoritmo inicia com uma população de indivíduos gerados aleatoriamente que é a primeira geração. Cada individuo possui em seu DNA uma codificação de alguma possibilidade das variáveis de entrada. Cada individuo terá um resultado associado na simulação. Essa população irá reproduzir, escolhendo aleatoriamente casais, que devido à combinação genética dos pais, irão gerar filhos que terão em seu DNA uma codificação que é uma mistura do DNA de seus pais, consistindo em uma outra possibilidade de variáveis de entrada. Os filhos também terão um resultado associado na simulação, sendo a segunda geração do algoritmo. Daí, como acontece na vida, podem haver mutações nos indivíduos que nascerem, consistindo em pequenas alterações aleatórias e alguns indivíduos irão “morrer”, não passando para futuras gerações seu código genético, que são os indivíduos com pior resultado.

Ou seja, parte da população da geração atual vai permanecer, parte não irá prosseguir para futuras gerações, novos indivíduos serão gerados por combinação dos pais, alguns dos novos indivíduos sofrerão mutações permitindo maior variabilidade genética. Na próxima etapa, os filhos já irão reproduzir, e esse processo irá ocorrer de forma iterativa, regido pela seleção natural daqueles que apresentarem melhores resultados, até que uma condição de parada seja atingida, por exemplo, não tenha surgido nenhum individuo nas últimas 5 gerações com resultado melhor do que o melhor resultado já encontrado.

Qual é o benefício almejado pelos algoritmos genéticos? Reduzir o esforço computacional exigido na força bruta, reduzindo a probabilidade de ter que calcular todas as possibilidades do espaço de busca, pois o algoritmo genético irá percorrer o espaço de forma mais eficiente! Uma vez encontrado a solução ótima, é improvável que haja uma solução melhor do que aquela, no espaço de busca não explorado.

Explicados os dois algoritmos mais utilizados para otimização de estratégias, vamos falar enfim do principal risco da otimização: Overfitting.

Overfitting

Como o nome diz overfitting é um ajuste excessivo ou sobre-ajuste. No caso da otimização é a obtenção de variáveis de entrada da estratégia que funcionam muito bem para os dados IN SAMPLE, mas quando executado o backtesting a estratégia apresenta uma deterioração muito significativa do resultado. Ou seja, o ajuste do modelo encontrado possui baixa capacidade de generalização.

Este é o maior risco da otimização: deterioração de desempenho com dados novos. E quais são as possíveis causas de overfitting? Excesso de graus de liberdade e dados com viés. Vamos entender isso melhor:

Quanto mais variáveis de entrada a otimização estiver calculando, mais graus de liberdade você estamos dando para que a otimização ajuste a estratégia aos dados apresentados. Isto significa que podemos estar otimizando um modelo muito específico que utilize mais indicadores do que precisa ou colocando na otimização muitas variáveis. As configurações que apresentarem os melhores resultados em otimização podem ter chance grande de estarem com overfitting. Algumas pessoas recomendam descartar os melhores resultados, mas é recomendável rodar todas eles em backtesting para certificar se realmente houve ou não overfitting.

Outra forma de incorrer em overfitting é fazer a otimização em um conjunto de dados muito específico, ou seja, dados que tenham, por exemplo, apenas uma tendência de alta no plano mais macro e baixa volatilidade. A otimização vai gerar a melhor configuração para esta situação. Se o backtesting tiver dados, por exemplo, de uma tendência de baixa ou maior volatilidade, é bem provável que o modelo não terá bom desempenho porque a otimização não presenciou esse tipo de situação no ajuste das variáveis.

É bom ressaltar a diferença entre overfitting e otimização focada em situação de mercado. Haverá situações em que desejamos que uma estratégia tenha desempenho equilibrado tanto em mercado de alta como de baixa ou lateralizado. E pra isso precisamos garantir que os dados in sample contenham essa diversidade de cenários.

Mas também podem haver situações, em que queremos fazer a otimização apenas com dados de mercado em alta, por exemplo. Porque iremos colocar para rodar o robô apenas nesta situação. Então é interessante fazer a otimização focada neste cenário, mas sem incorrer em overfitting. O overfitting nesse caso seria ter um desempenho ruim, mesmo quando o backtesting é aplicado em cenário semelhante aos dados de otimização. Isto significa que a otimização fez um sobreajuste para a situação de mercado de alta dos dados de treino, apresentando pouca capacidade de generalização.

É importante observar que a identificação de overfitting é feita no backtesting com dados OUT OF SAMPLE, ou seja, não utilizados na otimização. E por isto a importância de separarmos os dados no início do processo!

O problema do overfitting é que quando ele não é percebido, o elaborador da estratégia cria a falsa expectativa de desempenho da estratégia baseado em resultados de otimização que não vão se repetir com dados novos, o que pode representar prejuízos financeiros que apenas cessarão quando decidir-se parar de rodar a estratégia. E talvez a causa desse prejuízo nem seja corretamente identificada pelo elaborador da estratégia.

Conclusão

Muito bem! Vimos assuntos importantes tais como algoritmos de otimização, cuidados devidos a segregação de dados e o problema mais temido da otimização: overfitting.

Vamos lançar uma pergunta para motivar o próximo texto sobre otimização. Uma vez que tenhamos econtrado uma configuração ótima para a estratégia sem overfitting. Até quando esta configuração deve ser utilizada De quanto em quanto tempo devemos reavaliar a configuração dos parâmetros da estratégia?

Veja o próximo material de otimização para aprender mais sobre robustez no processo de otimização por meio de técnicas de validação cruzada.

Técnicas de Otimização robusta

Reproduzir vídeo

Introdução

Até o presente documento vimos os conceitos básicos de otimização. Abordamos dois algoritmos bastante utilizados para otimizar estratégias baseadas em indicadores técnicos: Grid Search e Algoritmo Genético – e abordamos sobre segregação de dados e overfitting.

Aqui vamos avançar um pouco mais e falaremos sobre técnicas de otimização robusta. Tais técnicas consistem em realizar a otimização e verificar o quão sensível é o desempenho de uma dada estratégia a diferentes situações de mercado e variações dos parâmetros ótimos.

O domínio de técnicas de otimização robusta é fundamental para execução de um processo de otimização de estratégias de maneira mais consistente, fornecendo mais informações para análise do possível desempenho e identificação de estratégia com maior potencial de serem lucrativas quando submetidas a dados novos.

A técnica de otimização robusta mais difundida é denominada Walk Forward Optimization.

Walk Forward Optimization (WFO)

A técnica de Walk Forward Optimization (WFO) foi apresentada inicialmente por Robert Pardo em seu livro “The Evaluation and Optimization of Trading Strategies” de janeiro/2008. Pra quem entende de aprendizado de máquina, é bastante claro que se trata de uma técnica baseada em validações cruzadas (como um k-fold).

A técnica WFO consiste em utilizar os dados históricos e simular como se a estratégia estivesse fazendo trading real. Ou seja, os dados históricos são fatiados em períodos de duração fixa, onde uma parte será utilizada para otimização (dados in sample) e outra parte para realização de backtesting (dados out of sample).

Iniciando pelos dados mais antigos, realizamos uma otimização simples (da maneira tradicional) e obtemos os parâmetros ótimos para avaliar o desempenho da estratégias nos dados out of sample do primeiro período.

Daí simulamos que o tempo passou e obtemos mais dados históricos. Isso equivale a arrastar a janela de dados pela mesma duração do backtesting em direção aos dados mais recentes. Esta nova configuração de dados da janela deslizante será o Período 2, o qual terá uma interseção dos dados in sample do período 1. No entanto, não terá interseção entre os dados de backtesting dos períodos 1 e 2.

A duração (fixa) dos dados de backtesting de cada período e a duração total dos dados históricos irão permitir calcular quantas janelas distintas de otimização poderão ser executadas nos dados históricos. A figura abaixo ilustra o conceito das janelas deslizantes.

Observe que, ao invés de procedermos uma única otimização nos dados históricos disponíveis, a técnica WFO visa realizar múltiplas otimizações para que seja possível realizar uma análise do desempenho da estratégia otimizada de maneira geral levando em consideração o desempenho em cada janela de backtesting. A esse processo de análise se dá o nome de Walk Forward Analysis (WFA).

Walk Forward Analysis (WFA)

Espero que tenha ficado claro na seção anterior que a estratégia é reotimizada para cada período de dados. A análise, portanto, consiste em comparar o desempenho da estratégia reotimizada no dados de backtesting do período atual, com o desempenho nesses mesmos dados utilizando a estratégia otimizada no período anterior, e portanto, não reotimizada para o período atual de dados.

A pergunta a ser respondida pela WFA é: vale a pena reotimizar a estratégia periodicamente? Em outras palavras, é possível um resultado final melhor do que não reotimizar a estratégia?

Intuitivamente, ao reotimizarmos uma estratégia utilizando uma janela deslizante estamos focando a otimização apenas nos dados mais recentes, que podem representar recortes distintos da dinâmica de negociação do ativo. Pode ser que um período seja marcado por uma tendência de alta, enquanto o próximo período terá um comportamento de retração (correção de preço), seguido pelo próximo período de consolidação…e assim por diante.

Perceba que a ideia de utilizar janelas deslizantes é permitir a obtenção de parâmetros ótimos mais adequados a situação recente dando possibilidade a estratégia de se ajustar as diferentes dinâmicas. Diferentemente de uma otimização simples sobre todos os dados históricos que buscaria uma configuração média que seria ótima globalmente, mas que não poderia ser ótima para diferentes subconjuntos desses dados históricos.

O que nos permitirá comparar o desempenho de duas configurações diferentes da estratégias em dados de backtesting (reotimizada e não reotimizada) é a Eficiência da estratégia, que definiremos a seguir.

Cálculo de Eficiência

A Eficiência consiste na razão entre o desempenho da estratégia nos dados out of sample (backtesting) e o desempenho nos dados in sample. O desempenho deve ser medido, preferencialmente, utilizando a mesma métrica utilizada como função objetivo da otimização, a fim de manter a consistência do processo.

Vale ressaltar que a janela de dados de backtesting é bem menor (geralmente) que a janela de dados in sample, e por isso, para tecer uma comparação de desempenho justa, torna-se necessário normalizar a medida de desempenho.

A normalização sempre será necessária quando os valores possíveis para a métrica de desempenho puderem ter limites mínimos e máximos diferentes dependendo do tamanho da janela de dados (ex: lucro líquido). A normalização não é necessária, por exemplo, se a métrica for taxa de acerto, pois o seu valor estará sempre entre 0 e 100%, independentemente do tamanho da janela de dados.

Veja na figura abaixo, um exemplo de cálculo de normalização de lucro líquido e eficiência em diferentes períodos de otimização de uma estratégia.

Estas perguntas nos levam a próxima técnica conhecida como Walk Forward Matix (WFM).

Observa-se que no Período 2 e 3, a estratégia reotimizada apresentou melhor eficiência do que a estratégia não reotimizada. Ao passo que no Período 4, a estratégia não reotimizada é que apresentou melhor eficiência.

A técnica de WFA consiste exatamente em verificar se há predominância de melhor eficiência nas estratégias reotimizadas para concluir se vale a pena reotimizar períodicamente a estratégia.

Caso identifique-se que não é interessante reotimizar a estratégia periodicamente, esse achado não é conclusivo. Pois poderíamos realizar a seguinte pergunta: será que se utilizassemos uma janela de otimização diferente com uma janela de backtesting menor poderíamos obter um resultado melhor em relação à reotimização de estratégias? Ou mesmo se concluíssemos que para o tamanho da janela atual é interessante reotimizar periodicamente, será que esta periodicidade é a periodicidade ótima?

Walk Forward Matrix (WFM)

A técnica WFM nada mais é do que rodar o processo de WFA para diferentes possibilidades de tamanho da janela de dados e percentual de dados out of sample desta janela, utilizando o algoritmo de já vimos de grid search.

Em outras palavras, consiste em realizar a otimização da técnica WFA. É importante ressaltar que a execução de WFM é bastante cara computacionalmente e, portanto, recomenda-se não gerar muitas possibilidades no processo. Além disso, a automatização do processo de WFM é praticamente um pré-requisito, são tantos dados que precisam ser armazenados para se realizar a adequada análise dos resultados, que torna-se fundamental ter um fluxo automatizado para execução do WFM.

Ao final das contas, queremos verificar se a estratégia é robusta a diferentes janelas de otimização e backtesting, bem como identificar o tamanho ótimo da janela de dados de otimização e periodicidade de reotimização.

Conclusão

Neste documento exploramos os conceitos e ideias por trás das técnicas de otimização robusta: WFA e WFM, a qual estão cobertas pelo conceito de Walk Forward Optimization.

Como sugestão, recomenda-se sempre iniciar de maneira simples e complicar a medida que for necessário. Assim, não é recomendável já iniciarmos a otimização de uma estratégia com WFM, pois seria como dar um tiro de canhão em uma mosca.

Comece realizando um otimização simples e verificando se a estratégia é lucrativa em backtesting. Em seguida, pode-se verificar pela aplicação da técnica WFA se há benefício em reotimizar a estratégia períodicamente em uma janela que o trader julgar pertinente. Caso seja observado um potencial de melhoria na otimização da janela de dados e de backtesting, aí sim, deve-se proceder com a técnica WFM.

Espero que este conteúdo tenha sido esclarecedor para o leitor e tenha contribuído para ampliar o conhecimento a respeito do tema otimização de estratégias.

Acompanhe a publicação de vídeos no Canal do Youtube da Comunidade, pois nos próximos conteúdos nós iremos aplicar passo a passo cada técnica apresentada na prática e otimizar estratégias utilizando diferentes plataformas e soluções.

Conhecendo a NinjaTrader

Esta é uma série de vídeos para apresentar as principais funcionalidades da interface gráfica da plataforma NinjaTrader.

Lançamento da NinjaTrader para operações na B3

Reproduzir vídeo

Após um longo período de espera, finalmente, a Plataforma NinjaTrader foi homologada para operar na B3. Desde o dia 03/jan/2023 é possível contratar esta Plataforma pela Corretora Órama.

Conforme antecipado nos planos da Comunidade @neotraderbot, iremos gerar conteúdo informativo de diferentes plataformas de trading para que os membros da comunidade tenham informações do que é possível realizar em outros ambientes. Reforço que não estamos realizando nenhuma recomendação para mudança de Plataforma e que a decisão de migrar parte ou todo o processo de desenvolvimento e execução das estratégias automatizadas é muito pessoal e cabe apenas ao trader decidir sobre tal assunto.

Neste primeiro video sobre a Plataforma NinjaTrader vamos abordar as principais características do software: modelo de negócios, modularização do software, ecosistema de desenvolvimento, custos de contratação, detalhes gerais relacionados à automatização de estratégias.

Nas próximas semanas iremos gerar quase diariamente, seg a sexta, conteúdo sobre essa Plataforma antes de abordarmos em profunidade o desenvolvimento de estratégias em NinjaTrader Script!

Instalando NT8 e Configurando Market Data

Reproduzir vídeo

Neste video iremos apresentar passo a passo para instalar a Plataforma NinjaTrader e realizar a configuração o Market Data, tanto para acesso a dados das Bolsas Americanas (NYSE, NASDAQ, CME, etc…) e B3.

Após um longo período de espera, finalmente, a Plataforma NinjaTrader foi homologada para operar na B3. Desde o dia 03/jan/2023 é possível contratar esta Plataforma pela Corretora Órama.

Conforme antecipado nos planos da Comunidade @neotraderbot, iremos gerar conteúdo informativo de diferentes plataformas de trading para que os membros da comunidade tenham informações do que é possível realizar em outros ambientes.

Reforço que não estamos realizando nenhuma recomendação para mudança de Plataforma e que a decisão de migrar parte ou todo o processo de desenvolvimento e execução das estratégias automatizadas é muito pessoal e cabe apenas ao trader decidir sobre tal assunto.

Explorando o Control Center

Reproduzir vídeo

Neste video iremos explicar tudo sobre a principal janela do NinjaTrader: Centro de Controle (Control Center). Esta é a janela mais importante do NinjaTrader, por onde o usuário terá acesso a todas as funcionalidades da Plataforma.

Assista nesse video uma explicação didática de como utilizar a Plataforma para operá-la como um professional!

Após um longo período de espera, finalmente, a Plataforma NinjaTrader foi homologada para operar na B3. Desde o dia 03/jan/2023 é possível contratar esta Plataforma pela Corretora Órama.

Conforme antecipado nos planos da Comunidade @neotraderbot, iremos gerar conteúdo informative de diferentes plataformas de trading para que os membros da comunidade tenham informações do que é possível realizar em outros ambientes.

Reforço que não estamos realizando nenhuma recomendação para mudança de Plataforma e que a decisão de migrar parte ou todo o processo de desenvolvimento e execução das estratégias automatizadas é muito pessoal e cabe apenas ao trader decidir sobre tal assunto.

Como manipular gráficos na NT8 (Funcionalidades básicas)

Reproduzir vídeo

Neste video iremos apresentar todas as funcionalidades básicas relacionadas a gráficos na Plataforma NinjaTrader.

Este é um conteúdo informativo sobre NinjaTrader para que os membros da comunidade tenham informações do que é possível realizar em outros ambientes.

Reforço que não estamos realizando nenhuma recomendação para mudança de Plataforma e que a decisão de migrar parte ou todo o processo de desenvolvimento e execução das estratégias automatizadas é muito pessoal e cabe apenas ao trader decidir sobre tal assunto.

Recursos avançados de Subgráficos e Multigráficos na NT8

Reproduzir vídeo

Neste video iremos apresentar as funcionalidades avançadas relacionadas a gráficos na Plataforma NinjaTrader.

Você perceberá como o NinjaTrader possui funcionalidades que não se encontra em outras plataformas, como a capacidade de plotar mais de um ativo no mesmo gráfico, ou de até mesmo plotar tempos gráficos diferentes do mesmo ativo no mesmo gráfico.

Por exemplo, em um mesmo gráfico ver o box de 15 minutos e candles de 1 minuto. A Plataforma permite configurar e personalizar todas formas diferentes de subgráficos e multigráficos que expande bastante a capacidade analítica na leitura de gráficos e permite uma flexibilidade muito grande para plotagem de indicadores customizados.

Este é um conteúdo informativo sobre NinjaTrader para que os membros da comunidade tenham informações do que é possível realizar em outros ambientes.

Reforço que não estamos realizando nenhuma recomendação para mudança de Plataforma e que a decisão de migrar parte ou todo o processo de desenvolvimento e execução das estratégias automatizadas é muito pessoal e cabe apenas ao trader decidir sobre tal assunto.

Como adicionar Indicadores aos gráficos

Reproduzir vídeo

Neste video iremos demonstrar passo-a-passo como incluir indicadores em gráficos na Plataforma NinjaTrader.

Iremos apresentar exemplos de indicadores técnicos disponíveis na versão gratuita. A Plataforma permite configurar e personalizar todas formas diferentes de subgráficos e multigráficos que expande bastante a capacidade analítica na leitura de gráficos e permite uma flexibilidade muito grande para plotagem de indicadores customizados.

Este é um conteúdo informativo sobre NinjaTrader para que os membros da comunidade tenham informações do que é possível realizar em outros ambientes.

Reforço que não estamos realizando nenhuma recomendação para mudança de Plataforma e que a decisão de migrar parte ou todo o processo de desenvolvimento e execução das estratégias automatizadas é muito pessoal e cabe apenas ao trader decidir sobre tal assunto.

Como desenhar estudos nos gráficos da NinjaTrader

Reproduzir vídeo

Neste video iremos demonstrar passo-a-passo como incluir estudos ou desenhar elementos nos gráficos na Plataforma NinjaTrader.

A Plataforma permite configurar e personalizar todas formas diferentes de subgráficos e multigráficos que expande bastante a capacidade analítica na leitura de gráficos e permite uma flexibilidade muito grande para plotagem de indicadores customizados.

Este é um conteúdo informativo sobre NinjaTrader para que os membros da comunidade tenham informações do que é possível realizar em outros ambientes. Reforço que não estamos realizando nenhuma recomendação para mudança de Plataforma e que a decisão de migrar parte ou todo o processo de desenvolvimento e execução das estratégias automatizadas é muito pessoal e cabe apenas ao trader decidir sobre tal assunto.

Monitore o mercado com o Market Analyzer e Market Watch

Reproduzir vídeo

Neste video iremos demonstrar passo-a-passo como analisar o mercado de maneira global utilizando a ferramenta MARKET ANALYZER E MARKET WATCH na NinjaTrader.

Vamos ensinar PASSO-A-PASSO como configurar esta ferramenta poderosa de análise disponível na Ninja Trader e que permite a inclusão de indicadores customizados que poderão agregar muito valor ao seu operacional, permitindo a realização de screenings muito mais sofisticados do que estamos acostumados a criar em plataformas brasileiras.

Este é um conteúdo informativo sobre NinjaTrader para que os membros da comunidade tenham informações do que é possível realizar em outros ambientes.

Reforço que não estamos realizando nenhuma recomendação para mudança de Plataforma e que a decisão de migrar parte ou todo o processo de desenvolvimento e execução das estratégias automatizadas é muito pessoal e cabe apenas ao trader decidir sobre tal assunto.

Como agrupar gráficos/janelas e utilizar Crosshair

Reproduzir vídeo

Neste video iremos demonstrar passo-a-passo como agilizar a sua navegação entre gráficos na NinjaTrader.

Vamos ensinar PASSO-A-PASSO como configurar o Market Analyzer para ao selecionar um ativo, modificar a exibição em múltiplas janelas ao mesmo tempo, permitindo mais velocidade ao analisar o mercado.

Também demonstraremos como vincular janelas diferentes a um mesmo ativo, ou até mesmo como vincular gráficos de ativos diferentes a um mesmo tempo gráfico, de tal forma que uma alteração em um gráfico reflita nas demais janelas.

Por fim, iremos apresentar a funcionalidade de CROSSHAIR a qual permite realizar inspeção gráfico em diferentes janelas de ativos de maneira muito prática, inclusive em gráficos com séries de dados distintas, ex: entre um gráfico de renko e outro de candle.

Estas funcionalidades disponíveis na NinjaTrader são um diferencial em termos de uso e navegação pelo sistema, que não estão disponíveis com este potencial em outras plataformas.

Este é um conteúdo informativo sobre NinjaTrader para que os membros da comunidade tenham informações do que é possível realizar em outros ambientes.

Reforço que não estamos realizando nenhuma recomendação para mudança de Plataforma e que a decisão de migrar parte ou todo o processo de desenvolvimento e execução das estratégias automatizadas é muito pessoal e cabe apenas ao trader decidir sobre tal assunto.

Alertas e Serviços de Compartilhamento (Envio de E-mail)

Reproduzir vídeo

Neste video iremos demonstrar DIVERSAS FORMAS de CRIAR ALERTAS na NinjaTrader, sejam pop-ups, avisos sonoros, envio de e-mail, publicação de post no Twitter ou envio de ordens.

Começaremos apresentando formas de gerar alertas no Market Analyzer. O que permite criar alertas para ativos individuais ou para toda uma carteira de ativos.

Com os alertas também é possível criar screenings sofisticados com a utilização de indicadores, principalmente customizados.

Em seguida apresentarei os recursos avançados de criação de alertas sobre figuras e elementos de estudos inseridos em gráficos. Iremos demonstrar também como enviar e-mails quando um alerta for acionado.

Por fim, será apresentada a tela de Log de Alertas que reúne todos os alertas sinalizados pela plataforma com informações de ativo, origem, criticidade, data e hora.

A utilização de alertas na plataforma NinjaTrader é bastante abrangente e integrado com serviços de e-mails e redes sociais, o que permitirá ao trader criar mecanismos sofisticados para monitoramento e sinalização de situações de mercado em múltiplos ativos e com indicadores complexos.

Este é um conteúdo informativo sobre NinjaTrader para que os membros da comunidade tenham informações do que é possível realizar em outros ambientes.

Reforço que não estamos realizando nenhuma recomendação para mudança de Plataforma e que a decisão de migrar parte ou todo o processo de desenvolvimento e execução das estratégias automatizadas é muito pessoal e cabe apenas ao trader decidir sobre tal assunto.

Como importar dados históricos para NT8 (OHLCV 1 min e Ticks)

Reproduzir vídeo

Neste video irei demonstrar como IMPORTAR DADOS HISTÓRICOS OHLCV (1 MIN) e de TICKS para plataforma NINJATRADER.

No decorrer do vídeo farei a conversão dos dados exportados a partir da MetaTrader para o formato aceito para importação na plataforma NinjaTrader. Você perceberá que é possível fazer os ajustes necessários tanto com excel e um bloco de notas ou automatizando a conversão por um código em Python, caso a quantidade de arquivos a ser importada seja muito grande.

O benefício de ter mais dados históricos é poder realizar o BACKTESTING de sua estratégia ou robô em uma janela histórica mais longa, permitindo maior significância estatística nos resultados encontrados.

Reforço que não estamos realizando nenhuma recomendação para mudança de Plataforma e que a decisão de migrar parte ou todo o processo de desenvolvimento e execução das estratégias automatizadas é muito pessoal e cabe apenas ao trader decidir sobre tal assunto.

Rodando e gravando dados de Replay de Mercado

Reproduzir vídeo

Neste video irei demonstrar como HABILITAR A GRAVAÇÃO de DADOS DE MERCADO em seu computador utilizando a plataforma NINJATRADER.

Com a gravação de dados habilitada, você poderá criar uma base de dados de replay de mercado contendo informação de Book de Oferta.

Outra opção disponível na plataforma é solicitar o download de MARKET REPLAY do seu provedor de MARKET DATA.

Por fim, também demonstrarei como executar um REPLAY DE MERCADO com os dados históricos de tick na sua base da NinjaTrader. Estes dados podem inclusive terem sido importados para dentro da plataforma.

Como criar robô/estratégia do ZERO com o Strategy Builder

Reproduzir vídeo

Neste vídeo irei demonstrar como CRIAR um ROBÔ ou ESTRATÉGIA do ZERO, e sem programar nenhuma linha de código, com a ferramenta STRATEGY BUILDER da plataforma NINJATRADER (em português: Construtor de Estratégia).

Você perceberá que mesmo sendo uma ferramenta gráfica NO CODE, o usuário tem muita flexibilidade para configurar e definir a estratégia a ser criada.

Há muita liberdade para configurar indicadores, funções prontas pra verificar cruzamento de séries no instante atual ou passado recente, lucro/prejuízo realizado pela estratégia ou em aberto, configuração de cálculo da estratégia (fechamento de barra, tick ou mudança de preço) e etc.

Além disso, é possível utilizar séries de dados de outros ativos ou até o mesmo ativo em outra escala de tempo ou tipo de série.

A estratégia pode disparar a criação todos os objetos de estudo dentro dos gráficos, rotear ordens, enviar e-mails, criar alertas visuais sonoros e muito mais.

Como rodar backtesting na NinjaTrader

Reproduzir vídeo

Neste video irei demonstrar como rodar BACKTESTING de ESTRATÉGIAS e ROBÔS na plataforma NINJATRADER.

Você verá a riqueza de funcionalidades, métricas e personalização do ambiente de backtesting da NinjaTrader. O que demonstra o cuidado do desenolvimento da plataforma para usuários que desejam automatizar seus setups operacionais.

Por fim, demonstrarei a vantagem de poder carregar dados históricos para plataforma e poder realizar backtesting em uma janela adequada de dados.

Como liberar o meu acesso às ferramentas NeoTraderBot?

Estamos sempre buscando otimizar código, estratégias e processos, visando gastar nosso tempo com o que realmente agrega valor. Assim, esperamos em breve poder tornar esse processo de obtenção de senha para uso das ferramentas NeoTraderBot mais integrado em um futuro próximo.

No momento, o procedimento para obtenção de senha para liberação de uso individual das ferramentas, indicadores e estratégias, pagas ou gratuitos, consiste em enviar o formulário abaixo.

Nós iremos responder em um prazo máximo de 24 horas (dia útil) com os dados de acesso.

Liberação de uso Ferramentas/ Indicadores/ Estratégias - TraderEvolution
Este formulário visa recepcionar a conta na qual o usuário irá executar as ferramentas e códigos desenvolvidos pela NeoTraderBot, que são comercializados para uso individual (apenas uma conta). Caso o usuário deseje executar em mais de uma conta ao mesmo tempo, deverá adquirir outra licença de uso. Entre em contato conosco para condições diferenciadas a partir da 2a licença do mesmo produto.
No caso de ferramentas pagas, utilize o mesmo e-mail fornecido no momento da compra da ferramenta.
Algumas ferramentas possuem funcionalidades liberadas para traders membros da Comunidade NeoTraderBot e que sinalizam o código da NeoTraderBot na plataforma Trader Evolution.
Clique aqui para ver o passo-a-passo de como se cadastrar como parceiro.
Realize o cadastro antes de enviar esse formulário...só leva 1 minuto!

Recebi um e-mail informando a liberação de uso da ferramenta. O que faço agora?

Caso ainda não tenha instalado a ferramenta na sua plataforma Trader Evolution, sigas os passos do roteiro neste link.

Ao adicionar um indicador ou estratégias, sempre haverá um parâmetro de autenticação: email (conforme figura abaixo). Forneça seu email cadastrado. Caso haja algum problema na autenticação, a ferramenta irá exibir mensagem em tela e o indicador ou ferramenta não será executada.

Caso tenha algum problema nesse processo de autenticação, entre em contato conosco pelo e-mail NeoTraderBot@gmail.com, fornecendo seu número de telefone de contato que iremos fornecer o suporte necessário.

Versão THUNDER

FRAMEWORK ntsl THUNDER

O FRAMEWORK NTSL THUNDER é uma versão com mais funcionalidades que a versão gratuita e direito a suporte técnico. Com a versão THUNDER o trader terá ainda mais possibilidades para realizar seus backtests! 

Esta versão também foi concebida para ser executada em gráficos temporais e, além das funcionalidades da versão LIGHT, ela também possui os seguintes diferenciais:

      • Possibilidade de configuração do tamanho das posições;
      • Possibilidade de roteamento de ordens stop e limitadas;
      • Filtro de posição comprada/vendida;
      • Interrupção diária da estratégia em função da qtde de trades com prejuízo (total e/ou consecutivos);
      • Stoploss temporizado em função da qtde de barras transcorridas após abertura da posição;
      • Gestão de risco financeiro com limite de perda e objetivo de ganho;
      • Possibilidade de aplicação de técnica de Stop móvel (individualmente ou em conjunção com RG Fixo e Breakeven);
      • Configuração de até 4 janelas de negociação;

Um quadro comparativo completo das funcionalidades das versões de framework pode ser visto nesta página.

FRAMEWORK NTSL THUNDER

Coded by NeoTraderBot
R$ 649 pagamento único
  • Direito a suporte técnico
  • Direito a atualizações da versão
  • Desconto do valor pago em caso de upgrade de versão
* Após a compra, você receberá um e-mail com o link para download do Framework.

Introdução ao NinjaScript Editor

Reproduzir vídeo

Este vídeo visa apresentar o ambiente de programação NinjaScript Editor da NinjaTrader, bem como a integração com a IDE Visual Studio da Microsoft.

Todos os programas em NT8 são escritos na linguagem NinjaScript que é baseada em C#, possuindo orientação à objeto e permitindo tratamento de eventos.

Recomendamos a leitura da Documentação NinjaTrader no link a seguir, de preferência em inglês: https://ninjatrader.com/support/helpG…

Link para baixar a IDE Visual Studio: https://visualstudio.microsoft.com/pt…

Programando em MQL5

Nesta seção iremos abordar os conceitos básicos e necessários para implementação de programas em MQL5 para plataforma MetaTrader.

Conhecendo a IDE Meta Editor

Reproduzir vídeo

Este vídeo visa apresentar o ambiente de programação MQL5 da MetaTrader: o MetaEditor 5.

O MetaEditor é uma IDE (Integrated Development Environment), um ambiente no qual os usuários podem escrever código fonte e desenvolver robôs, indicadores, scripts, serviços e outros programas em MQL5.

Todos os códigos são escritos em MQL5 (MetaQuotes Language 5), uma linguagem baseada em C++ que suporta orientação a objeto e tratamento de eventos. Recomendamos a leitura da Documentação MQL5 no link  https://www.mql5.com/en/docs.

Caso deseje antecipar seus estudos para os conteúdos dos próximos vídeos, indico a leitura dos itens “MQL5 Programs” e “Program running”, no link a seguir. Caso deseje, alterne o idioma para português. https://www.mql5.com/en/docs/runtime

Tipos de Programas, Fluxo de execução e Eventos Pré-definidos

Reproduzir vídeo

Este vídeo visa apresentar os tipos de programas possíveis da plataforma MetaTrader e como eles são executados.

Os tipos de programas possíveis de codificar em MQL5 são: serviço, script, expert advisor (EA) e indicador. Iremos abordar detalhes relacionados a forma de execução, single thread ou multi-thread, bem como explicar como é o fluxo de execução desses programas.

Explicaremos o conceito de fila de eventos, o seu funcionamento e quais são os eventos pré-definidos na linguagem para o utilização pelos programas.

Saber como um código é processado, suas características e como é o fluxo de execução é fundamental para que um programador e trader possa desenvolver um código fonte de qualidade e alcançar seus objetivos de maneira eficiente na criação de robôs e indicadores.

Sempre recomendamos a leitura da Documentação MQL5, no link abaixo, pois há muita informação relevante sobre a plataforma MetaTrader. https://www.mql5.com/en/docs.

Conhecendo a IDE Meta Editor

Reproduzir vídeo

Este vídeo visa apresentar o ambiente de programação MQL5 da MetaTrader: o MetaEditor 5.

O MetaEditor é uma IDE (Integrated Development Environment), um ambiente no qual os usuários podem escrever código fonte e desenvolver robôs, indicadores, scripts, serviços e outros programas em MQL5.

Todos os códigos são escritos em MQL5 (MetaQuotes Language 5), uma linguagem baseada em C++ que suporta orientação a objeto e tratamento de eventos. Recomendamos a leitura da Documentação MQL5 no link  https://www.mql5.com/en/docs.

Caso deseje antecipar seus estudos para os conteúdos dos próximos vídeos, indico a leitura dos itens “MQL5 Programs” e “Program running”, no link a seguir. Caso deseje, alterne o idioma para português. https://www.mql5.com/en/docs/runtime

Introdução a Otimização

Reproduzir vídeo

O processo de desenvolvimento de uma estratégia automatizada demanda a execução de algumas etapas importantes visando aumentar a chance de sucesso ou lucratividade de uma estratégia.

Podemos pensar neste processo como um filtro, no qual iniciamos implementando o código fonte dos algoritmos selecionados que vislumbramos ter maior chance de sucesso na exploração de padrões estatísticos na negociação de ativos. Essa implementação é um desafio inicial e os ajustes que realizamos no código fonte visando melhorar a execução do algoritmo, podem acabar gerando graus de liberdade adicionais à estratégia. Por exemplo, além de parâmetros de médias e outros indicadores próprios do setup operacional, podemos incluir outros indicadores para filtrar situações de mercado. Esses novos indicadores precisarão ser ajustados para que a estratégia funcione bem.

Além disso, é recomendável (para não dizer imprescindível) que toda estratégia tenha uma gestão de risco adequada: definição de tipos e parâmetros de stoploss e definição de alvo das operações (caso não seja feito pelas regras da própria estratégia).

E onde entra a otimização nesse processo? Tendo o código fonte da estratégia implementado, a otimização é o processo pelo qual iremos definir os valores mais apropriados para os graus de liberdade da estratégia! A seguir, vamos entender o que é a otimização para que possamos avançar para a realização prática desse processo sobre uma estratégia.

O que é Otimização?

Otimização é uma área da matemática aplicada que busca selecionar a melhor solução para um problema com relação a um determinado critério dentro de um conjunto de alternativas. Percebam que não estamos falando de problemas teóricos que podem ser modelados por expressões matemáticas lineares ou que podem ser resolvidos por cálculos diferenciais. A otimização aplica-se a problemas nos quais não é possível modelar por equações matemáticas ou ainda que tenhamos as equações não conseguimos resolvê-las pelo cálculo, mas apenas por métodos numéricos ou simulações.

Vamos contextualizar a otimização para o universo das estratégias automatizada. Percebam que não temos fórmulas matemáticas para este problema., mas podemos utilizar um simulador com dados históricos que são os registros do funcionamento do mercado, da oscilação de preços ao longo do tempo e volume negociado, no caso do modelo OHLCV. Podemos ter modelos de simulação que consideram dados com maior ou menor frequência, dados de Book de ofertas ou até informações das ordens executadas. O modelo de simulação pode se tornar mais complexo do que um simples OHLCV e o que é que vai ponderar o nível de complexidade do modelo é a disponibilidade de dados e custo computacional!

Vamos agora formalizar alguns conceitos para seguirmos adiante!

Espaço amostral

Espaço amostral ou espaço de busca…se formos estudar o assunto, cada área de conhecimento atribui um nome diferente para a mesma coisa…o que importa é o conceito!

O espaço de busca ou espaço amostral é o conjunto de todas as possibilidades de valores possíveis para cada variável de entrada do modelo, ou seja, dos graus de liberdade do nosso modelo. Para cada conjunto desse, se aplicarmos a nossa estratégia em uma janela histórica teremos um resultado diferente das operações realizadas.

Na figura acima, visualizamos do lado esquerdo exemplos de graus de liberdade de uma estratégia, que podem ser parâmetros de indicadores (quantidade de períodos de médias móveis, tipos de médias, qtde de períodos do MACD, IFR, sensibilidade de um indicador de topos e fundos), pode ser a opção de uso de uma técnica de stop (fixo, móvel) e todos os parâmetros relacionados: tamanho do stop, tamanho do passo de um stop móvel discreto, utilização de breakeven, valor do gatilho do breakeven, tamanho do alvo das operações (isso também pode ser uma variável de entrada do modelo!).

Do lado direito você visualizará o conjunto de métricas do resultado da execução do modelo de simulação para uma dada configuração de variáveis de entrada. Ou seja, temos um mapeamento do conjunto de dados de entrada para um conjunto de métricas de execução.

O modelo de simulação é que realiza o mapeamento das variáveis de entrada para  as métricas de desempenho! É nele e nos dados históricos utilizados que estão contidas as regras de simulação, bem como as restrições de execução.

Tipos de variáveis de entrada

As variáveis do espaço amostral podem ter tipos diferentes…podem ser números inteiros, por exemplo, a quantidade de períodos das médias. Podem ser números reais, tal como a sensibilidade de um indicador de topos e fundos ou tamanho inicial do stop. Podem ser dados categóricos ou booleanos: tipo de stop, com ou sem breakeven.

A importância de compreender o tipo das variáveis de entrada reside na definição do espaço amostral de cada variável de entrada que irá impactar o tamanho total do espaço amostral do problema de otimização e o esforço computacional demandado.

Calculando o tamanho do espaço amostral

Para cada variável de entrada do modelo de simulação, precisamos definir seu espaço amostral. 

No caso de variáveis que são números inteiros ou reais, precisamos definir um valor inicial, um valor final e o passo entre cada amostra. Cada variável sensibiliza o resultado em determinada magnitude, assim não faz sentido variar os valores em uma escala muito pequena. Por exemplo: não tem sentido simular um stop inicial de 1,37525 %…é muita precisão numérica….não faz diferença na otimização porque o preço de uma ação por exemplo vai até a segunda casa decimal (centavos). O que talvez seja mais factível para esta variável é estabelecer um espaço amostral entre 0,3% até 1,5%, variando em 0,1%, ou 0,2%….Isto é você quem vai decidir! Se fossemos varia entre 0,3 e 1,5% a cada 0,1%…isso daria 13 valores possíveis.

Após definir o espaço amostral para cada variável, iremos calcular a permutação de todos valores possíveis para obter o tamanho do espaço amostral….ou seja, basta multiplicarmos a quantidade de possibilidades de cada variável de entrada e realizar a soma quando uma determinada opção de variável de entrada impacte em alterações da quantidade de variáveis de entrada. Neste último caso, possivelmente estaremos trabalhando com códigos fontes distintos.

Vamos fazer um exemplo de cálculo do tamanho do espaço amostral para uma estratégia de cruzamento triplo de média, só para fixar esta parte do conteúdo. Vejas as figuras abaixo com o passo-a-passo do cálculo:

Existem algumas combinações de variáveis de entrada que não fazem sentido na permutação…por exemplo: quantidade de períodos da media rápida maior que media intermediaria. Então a quantidade de conjuntos viáveis é menor que isso…vamos supor para simplificação que seja 50% do teto calculado do tamanho do espaço amostral….estaríamos falando ainda de cerca de 7 milhões e 800 mil simulações aproximadamente.

Ainda é um número bem grande! Quanto tempo leva para rodar cada simulação? 3 segundos? E para armazenar o resultado em uma planilha? Isso é feito manualmente ou automaticamente? Vamos supor que o armazenamento das métricas da execução do modelo seja automatizado e gaste 0 segundos…se fossemos rodar todas as possibilidade seria 7,8 milhoes veze 3 segundos….o que daria: 270 dias de execução direta em uma única máquina…Isto certamente não é viável!

Ainda vamos falar dos métodos de otimização e se é necessário rodar 7,8 milhões de testes ou não em próximos documentos aqui no site…O que eu queria deixar claro aqui é que há restrições computacionais e por isso precisamos ser criteriosos em relação ao tamanho do espaço amostral que iremos mapear…por uma questão de tempo!

Função objetivo

A função objetivo ou função de custo ou função utilidade é apenas uma fórmula a qual tentaremos minimizar ou maximizar. Ou seja, iremos selecionar as configurações das variáveis de entrada do espaço amostral que minimizam ou maximizam determinada métrica de desempenho da estratégia, ou fórmula matemática.

Podemos definir otimizar o lucro líquido da estratégia ou a taxa de acerto (em outras palavras, o percentual de operações lucrativas).  Poderíamos até otimizar a relação de risco ganho da estratégia, que seria o quanto a estratégia tem de lucro médio nas operações vencedoras em relação ao prejuízo médio das operações perdedoras. O objetivo de otimização também poderia ser minimizar o drawdown da estratégia, que é o decaimento máximo de patrimônio.

A relação de métricas mais comuns como objetivo de otimização estão listadas abaixo, bem como sua definição:

Métrica Definição
Lucro bruto/líquido
Refere-se ao somatório do resultado dos trades realizados. Se positivo, significa que a soma do lucro dos trades vencedores superou a soma do prejuízo dos trades perdedores. Se negativo, significa que a soma do prejuízo dos trades perdedores superou a soma do lucro dos trades vencedores. O lucro pode ser em termos brutos (sem considerar custos de operação: taxas e emolumentos) ou líquido quando a plataforma já considera tais custos.
Taxa de acerto
Trata-se da divisão da quantidade de trades vencedores (que obtiveram lucro) pelo número total de trades realizados.
Drawdown
Refere-se ao maior decaimento de patrimônio ocorrido durante a simulação ou seja, a maior diferença entre um topo do valor de patrimônio e o próximo fundo.
Relação Risco/Ganho
É definida como a divisão entre lucro médio dos trades vencedores e prejuízo médio dos trades não vencedores. Uma sutileza do cálculo é que o lucro médio é calculado como o lucro total dos trades vencedores dividido pela quantidade de trades não perdedores, ou seja, inclui os trades que foram zerados. Já o prejuízo médio é a divisão entre o prejuízo total dos trades perdedores e a quantidade de trades perdedores. Este cálculo é mais conservador e recomendável para análise.
Fator de recuperação
É calculado dividindo o lucro final da simulação maior drawdown da simulação. Mede, portanto, a resiliência da estratégia, o quanto ele consegue recuperar de uma sequência de resultados ruins de trades.
Índice de Sharpe
A análise dessa métrica pressupõe que o retorno da estratégia é uma distribuição normal, uma vez que são utilizados apenas os dois primeiros momentos da distribuição, média e desvio padrão. É calculado como (retorno_est - retorno_livre)/desvio_pad. Onde retorno_est é o retorno da estratégia em uma determinada base temporal: anual, mensal, semanal, diária. retorno_livre é a taxa de retorno livre de risco. O usuário pode arbitrar entre usar IBOV ou taxa de juros de título do tesouro, na mesma base temporal. Por fim, desvio_pad refere-se ao desvio padrão da série de retorno da estratégia.

Imagino que você deve estar se perguntando…eu só posso otimizar uma métrica? E se eu quisesse maximizar o lucro líquido e ao mesmo tempo minimizar o Drawdown? É possível?

Sim, claro…é possível! Estamos falando neste caso de uma otimização multiobjetivo e existem algumas formas para se resolver este problema. Eu vou falar de apenas uma forma pois não é foco deste material, mas sinta-se a vontade para pequisar sobre o assunto.

Uma forma de fazer otimização multiobjetivo é criar uma função linear das métricas desejadas, atribuindo pesos para cada métrica. Estes pesos servirão tanto para ponderar as métricas mais importantes quanto para normalizar o valor das métricas que podem ser de escalas diferentes. Por exemplo, Lucro líquido é em unidades monetárias, enquanto Taxa de acerto é percentual (ou seja varia de 0 a 1). O peso atribuído a taxa de acerto deve ser tal que distribua de forma adequada a importância da otimização entre lucro líquido e taxa de acerto.

Recapitulando

Vimos neste documento os conceitos básicos sobre otimização e como eles se aplicam ao universo das estratégias automatizadas. No próximo documento veremos em maior profundidade como funcionam dois métodos de otimização: Grid Search e Algoritmos Genéticos, bem como iremos abordar questões importantes relacionadas aos dados utilizados para otimização.

Aula 01 - Conceitos básicos

Nesta aula abordaremos as definições básicas de programação.

Se cheguei até aqui foi porque me apoiei no ombro dos gigantes.

Isaac Newton
Reproduzir vídeo

1. Introdução

Programação está se tornando (se já não for) um pré-requisito para qualquer pessoa do século 21. Cada dia que passa mais e mais de nossas atividades cotidianas e trabalhos são facilitados com a ajuda de softwares ou até inteiramente automatizadas por eles.

Ao contrário do que muita gente pensa, programação não é um bicho de sete cabeças! Se fosse fazer uma comparação, diria que é como aprender um idioma diferente, mas talvez seja até mais simples. Para os computadores não existe subjetividade…ou é ou não é… ou é zero ou é um!

Como tudo na vida (e Newton já sabia disso…), o conhecimento precisa ser construído de forma incremental para que com o tempo possamos compreender assuntos mais complexos. Assim, pretendo apresentar a você os conceitos básicos de programação sem os formalismos do meio acadêmico. Isto é um ponto de partida e o objetivo é que você entenda as ideias! Falarei sobre todos os conceitos básicos? Não, pois tem muito conceito! Contudo, falarei sobre o que você precisa saber neste momento para iniciar sua jornada de aprendizado. Conte comigo e com a comunidade para tirar suas dúvidas por meio do nosso fórum ou dos demais canais.

Então comecemos pelo começo, é claro! E ele inicia com o conceito de ALGORITMO 

2. O que são Algoritmos?

A noção de algoritmo foi identificada formalmente pela primeira vez na tradução de trabalhos de um matemático persa do século XII. Fique tranquilo porque não vamos aprofundar na história do desenvolvimento humano! Queria apenas ressaltar que o conceito de algoritmo surgiu quando não existia sequer a ideia de computadores e, no entanto, é amplamente empregado na área de computação.

Para ser objetivo, um ALGORITMO é uma sequência finita de ações que visam resolver um problema. Esta sequência de ações deve ser PRECISA (dizer exatamente o que precisa ser feito), não pode ser ambígua (não pode haver dúvidas sobre o que cada ação significa), CORRETA (deve resolver o problema) e, de preferência, EFICIENTE (quanto menos ações ou recursos forem exigidos para resolver o problema, melhor!).

Vamos a um exemplo clássico para você não esquecer: uma receita de bolo é um algoritmo! Veja bem…a receita começa dizendo o que você precisa (quais recursos são necessários) e, em seguida, te orienta passo a passo o que fazer com cada ingrediente para ao final obter um bolo.

Outro exemplo seria se alguem te parasse no meio da rua e te perguntasse onde fica determinada loja, você certamente responderia com um algoritmo: siga esta rua, vire à direita no 3º quarteirão, pega a esquerda na próxima rotatória, a loja está no lado direito da rua.

Acho que você já entendeu o que é um algoritmo e naturalmente está pensando que existem algoritmos simples, como os exemplos que dei, mas também existem algoritmos complexos, quando os problemas a serem resolvidos são mais dasafiadores. É verdade, mas a forma como são escritos os algoritmos é sempre a mesma.

Não existe um padrão único de como escrever um algoritmo e cada livro adota um padrão mais conveniente. No entanto, todos os padrões atendem a definição que vimos. Vamos ver um exemplo de algoritmo? Veja abaixo:

				
					Algoritmo calibrarPneusDoCarro:
para i := 1 até 4 passo 1:
início:
   enquanto Pneu_i.obterPressao() <= 30:
   inicio:
      Pneu_i.adicionarPressao(1 psi);
   fim;
fim;

				
			

O algoritmo calibrarPneusDoCarro é um exemplo muito simples. Ele começa pelo primeiro pneu do carro (linha 2, i =1) e enquanto a pressão do pneu for menor que 30 psi, é adicionado 1 psi ao pneu (linha 6) até que o presente pneu tenha pressão igual a 30 psi. Daí, o algoritmo passa para o próximo pneu e repete o processo até que os 4 pneus estejam com pressão igual a 30.

3. Estruturas de Dados

No Globo Repórter de hoje...

 

Se tem algo que não podemos deixar de falar quando falamos sobre algoritmos são as ESTRUTURA DE DADOS. As estruturas de dados são mecanismos para armazenar etapas e resultados intermediários ao longo da execução do algoritmo, ou até mesmo a solução final do problema.

Vamos deixar isso mais claro…Se eu te pedisse para me dizer o resultado da soma dos números de 1 a 10 e você não lembrasse da fórmula de somatório de PA (Progressão aritmética), você iria possivelmente começar somando 1 com 2 e memorizando o número 3. Em seguida, somaria 3 com 3, e memorizaria o número 6, seguiria esse processo iterativamente até o número 10 e chegaria ao resultado da soma que é 55.

Perceba neste exemplo que você precisou manter sempre em sua memória uma soma intermediária até chegar à última operação. Este resultado intermediário é uma estrutura de dados muito simples, é apenas um número inteiro. Mas as estruturas de dados podem ser tão complexas quanto sejam necessárias para resolver um problema. Em cursos de computação, todos os alunos aprendem estruturas de dados como vetores, matrizes, listas, filas, pilhas, árvores, grafos… Mas para começar a automatizar estratégias de negociação você não precisará saber sobre tudo isso. Com o tempo e necessidade, você irá acabar estudando mais a fundo as estruturas de dados. Por enquanto, vamos manter simples e complicar à medida que for preciso.

4. Linguagem de Programação

Como vimos até agora, os algoritmos e estrutura de dados existem independentemente da linguagem de programação e este é o conceito que abordaremos agora. O que é linguagem de programação? Senta que lá vem um pouco de história…mas espero que seja interessante para você!

Linguagem de programação é a forma pela qual você se comunicará com o seu computador. O computador é extremamente veloz, consegue guardar muita informação…mas tem um problema…ele só faz o que você ordena ele fazer!

No início da computação, as linguagens eram muito rudimentares, ou em termos mais técnicos, de baixo nível. Isso significa que o programador precisava transcrever seus algoritmos em uma sequência de 0 e 1, no que denominamos código de máquina. Tipo isso:

				
					0000101110101110111000011101100001101110101000110101101101101001010 
1011010101.....e por aí vaí milhares de zeros e uns.
				
			

Eram tempos difíceis para a comunicação homem-máquina…ainda bem que a tecnologia permitiu o incremento do poder de processamento dos computadores e a sua capacidade de memória. Com o tempo vieram os cartões perfurados, depois começaram a surgir linguagens que permitiam comandos em palavras de 3 letras, tipo: ADD (soma), MOV (move um número de uma posição de memória para outra), STO (grava isso na memória), etc. E de forma gradativa, a computação foi evoluindo para chegar nas linguagens de alto nível, que são as linguagens que temos contato hoje!

Intitulamos as linguagens de alto nível aquelas linguagens que nos permitem abstrair do que realmente acontece dentro do computador…ou seja não utilizamos comandos muito primitivos, como aqueles zeros e uns ou comandos com três letras…Em analogia, é como pedir para você escrever o seu nome numa folha…eu não precisaria te dizer letra a letra e como fazer cada letra para escrevê-lo. Eu simplesmente peço, escreva seu nome e você o fará de uma forma que eu não preciso saber como.

Tem muitas linguagens diferentes, elas podem ter propósito geral, tais como Pascal, Java, C, C++, Pyhton etc, com as quais você pode fazer qualquer tipo de programa, ou pode ser desenvolvida para um fim específico, por exemplo, renderizar as páginas que você acessa na internet (HTML).

5. Código fonte, Síntaxe e Compilador

O que os algoritmos têm a ver com as linguagens de programação? Ora, a gente como programador precisa transcrever os passos do algoritmo para uma linguagem que o seu computador entenda. E cada linguagem tem uma sintaxe (forma como escrevemos) bastante rígida! Não podemos escrever diferente da sintaxe esperada porque o computador não vai entender!

Assim, o texto transcrito a partir do nosso algoritmo para uma linguagem de programação é o que chamamos de CÓDIGO FONTE. Espero que esteja entendendo até aqui….já estamos finalizando os conceitos básicos que precisa saber sobre programação.

Depois que transcrevemos o nosso algoritmo de acordo com a sintaxe da linguagem de programação, geralmente existe um programa chamado COMPILADOR que irá traduzir os seus comandos de alto nível para uma sequencia de zeros e uns (código de máquina) para ser executado pelo computador!

Pense no compilador como um professor(a) que irá corrigir sua redação (seu código-fonte), mas muito rigoroso(a) ! Ele(a) só irá transformar seu código fonte em código de máquina se não houver nenhum erro de sintaxe!

Enfim, sua tarefa de programador termina quando tiver um código executável que resolva o problema que desejava. Ou não…talvez isso seja só o começo como programador!

6. Recapitulando...

Começamos com os conceitos de algoritmos e estrutura de dados. Em seguida, apresentamos o que são as linguagens de programação e como elas se relacionam com os algoritmos. Entendemos que o código fonte nada mais é do que seu algoritmo transcrito e precisa ter a sintaxe exigida pela linguagem de programação utilizada. Por fim, explicamos que o seu código fonte precisa ser compilado para um código de máquina que poderá ser executado pelo computador.

Como instalar/remover as ferramentas na NinjaTrader?

Este tutorial visa apresentar o passo a passo para instalação e remoção de uma add-on na plataforma NinjaTrader, o que aplica-se às ferramentas e códigos compilados da NeoTraderBot.

Instalando as ferramentas da NeoTraderBot na NinjaTrader

Passo 1: No Control Center, clique em “Tools” -> “Import” -> “NinjaScript Add-On…”

Passo 2: Em seguida, selecione o arquivo “.zip” da ferramenta de deseja instalar na sua NinjaTrader

Passo 3: Caso a importação ocorra com sucesso, você deve visualizar uma mensagem semelhante a da imagem abaixo.

Se houver algum problema na importação, a NinjaTrader irá sinalizar uma mensagem de erro.

Acesse o Control Center e vá na aba “Log” (conforme imagem abaixo). Copie a mensagem de erro relacionada à importação da ferramenta e encaminhe um email para neotraderbot@gmail.com.

Removendo ferramentas (Add-ons) da NinjaTrader

Passo 1: No Control Center, clique em “Tools” -> “Remove NinjaScript Assembly”

Passo 2: Selecione o Add-on que deseja remover da sua plataforma

Passo 3: Uma caixa de diálogo irá aparecer para solicitar a confirmação da remoção. Certifique-se de que está removendo o add-on correto antes de confirmar.

Passo 4: Uma vez removido o Add-on, será exibida uma janela de confirmação da remoção (conforme imagem abaixo).

Introdução a Plataforma TraderEvolution

Reproduzir vídeo

Neste vídeo vamos iniciar uma série sobre a plataforma TraderEvolution.

Apresentaremos informações básicas sobre a plataforma, como contratar e custo de utilização.

Nos próximos vídeos iremos nos aprofundar nas funcionalidades da plataforma, cobrindo desde configuração de gráficos, Times & Sales, Grade de cotações, etc…O nosso objetivo é entender em profundidade a plataforma para que possamos iniciar nossas implementações de robôs e estratégias em EvoCode (C#).

CHART TRADING - Operando pelo Gráfico na Trader Evolution

Reproduzir vídeo

Neste vídeo da séria “Conhecendo a Trader Evolution” vamos explorar a funcionalidade CHART TRADING, em outras palavras, vamos operar pelo gráfico. Esta é uma funcionalidade bem interessante na plataforma devido à sua facilidade de uso e possiblidade de abrir posições ou enviar ordens com apenas um clique.

Primeiro contato com o Profit

Reproduzir vídeo

Para ter sucesso em qualquer área de conhecimento é preciso saber utilizar bem as ferramentas do seu trabalho. Um marceneiro precisa saber usar muito bem o formão, a serra e o maquinário de madeira para fazer bons móveis. Um cirurgião não conseguiria conduzir uma cirurgia com sucesso em um paciente se não manipulasse muito bem o bisturi, o equipamento de microgravação, a medicação que precisa ser dosada, etc… Por que seria diferente para quem opera no mercado financeiro?

O objetivo desse texto é falar um pouco sobre a plataforma Profit Chart, comercializada pela empresa Nelogica no Brasil. As plataformas de negociação são imprescindíveis para quem deseja se especializar e aprofundar no assunto de operações e investimento no mercado financeiro. É a ferramenta do dia a dia do trader!

Existem outras plataformas profissionais disponíveis para se operar, mas certamente as duas com maior capilaridade para quem opera ativos da B3 é o Profit Chart e o MetaTrader da empresa MetaQuotes. Aqui na Comunidade decidimos começar a explorar o universo de automatização de estratégias para negociação de ativos na plataforma Profit Chart por algumas razões que detalhamos neste artigo do blog e nesse vídeo do nosso Canal no Youtube.

Quais são as funcionalidades que uma plataforma profissional de trading pode te oferecer? Antes de falar sobre as funcionalidades temos que definir muito bem o que se espera de uma plataforma profissional. Na minha opinião, parte dos requisitos esperados seriam:

  1. Funcionalidades que permitam análisar os movimentos do mercado e fluxo de negociação:
    • Multiplas janelas abertas de dados de ativos e outras informações;
    • Diferentes tipos de gráficos e plotagens;
    • Possibilidade de visualizar em qualquer tempo gráfico desejado (1 min, 5 min, 12 min, 60 min, etc…);
    • Informações detalhadas do Book de ofertas;
    • Informações detalhadas das negociações realizadas;
    • Possibilidade de personalizar a aparência dos gráficos;
    • entre outras…
  2. Facilidade para abrir posições, administrar e encerrar operações:
    • Operar diretamente no gráfico do ativo visando agir com maior tempestividade;
    • Funcionalidades de stoploss tanto para limitar prejuízos quanto para proteger ganhos;
    • Acompanhamento do desempenho das operações, quantidade, relação risco/ganho;
    • Evolução de patrimônio;
  3. Plataforma leve e que não trave e tampouco apresente falhas que execução que possam comprometer o desempenho das operações em andamento (Sem bugs);
  4. Possibilidade de operar múltiplas contas de corretoras;
  5. Possibilidade de configurar limites de gestão de risco a fim de proteger patrimônio contra atitudes com prudentes;
  6. Possibilidade de automatizar setups operacionais;
  7. Possibilidade de simular o mercado financeiro para determinada data e ativo.

Sabendo o que esperamos encontrar em uma plataforma profissional, gravamos o vídeo abaixo para quem está iniciando agora e ainda não viu uma plataforma ou apenas opera pelo home broker de sua corretora. Assista e deixe seu comentário!

Não estamos querendo pintar o quadro de que o software Profit Chart é perfeito. Pois o Profit Chart não é perfeito. É um software muito bom pelas ferramentas que oferece para analisar e ler o mercado, mas também possui algumas limitações importantes quanto à automatização de estratégias, principalmente por não permitir a e execução de robôs programados pelo próprio usuário em conta real. Ainda assim, o Profit pode ser considerado um bom ponto de partida para iniciarmos a jornada de conhecimento para automatização de estratégias na negociação de ativos! Com o tempo, naturalmente iremos abordar também a automatização em plataformas como MetaTrader, TradingView, e utilização de APIs em python para realizar estudos estatísticos e implementar algoritmos mais complexos para operar na bolsa!

Bom, por ora, no próximo documento vamos ensinar como utilizar o ambiente de edição de estratégias do Profit Chart. Esta será a principal ferramenta que iremos utilizar para criar códigos para automatizar diversas tarefas atinentes a operação na bolsa de valores, desde a criação de indicadores, regras de coloração, filtros de seleção de ativos até backtesting de estratégias de execução (robôs de investimento) e muito mais!

Apresentação

A Biblioteca NeoTraderBot foi desenvolvida com o objetivo de facilitar a implementação de estratégias e indicadores em EvoCode.

Assim, o trader pode dedicar mais tempo ao desenvolvimento de estratégias do que quebrando a cabeça para resolver problemas de código fonte ou tentando descobrir como executar determinadas tarefas.

Neste repositório você irá encontrar a documentação de todas as funções da Biblioteca com exemplos de uso.

Aguarde…em implementação!

 

Tutoriais sobre Estrutura do código

Introdução

Esta seção visa apresentar trechos de códigos com funcionalidades relativas à estrutura do código de indicadores e estratégias. Por exemplo, como criar parâmetros de entrada.

Você pode acessar os Snippets/Tutoriais diretamente pelo menu lateral direito, ou fazendo CTRL+F (CTRL+L) para localizar algum texto específico na página, uma vez que o conteúdo tende a crescer ao longo do tempo, dificultando a navegação pelo menu.

Caso tenham sugestões de código para acrescentar à lista, gentileza deixar o código nos comentários com o link para seu perfil em rede social (para devido crédito de autoria).

Snippets/Tutoriais

Como criar parâmetros no meu indicador/estratégia?

Os parâmetros de uma estratégia ou indicador são declarados como atributos da classe.

O que diferencia esses atributos dos demais atributos são as anotações (em C# chama-se Annotations e são contidas entre [ ]) que realizamos imediatamente antes da definição dos atributos. Vamos ver abaixo como criar diferentes tipos de parâmetros, como definir seu valor padrão, qual texto será exibido na interface de configuração da estratégia/indicador e pré-validações.

A primeira anotação que realizamos é invocar a função InputParameter. Esta função recebe 3 parâmetros: Tipo do parâmetro da estratégia, Texto a ser exibido na interface de configuração e a ordem de apresentação.

Os tipos de parâmetros possíveis em EvoCode são: Combobox, Checkbox, Numeric ,Color, Instrument, Account, String, DateTime e TimeSpan. Sendo Numeric e ComboBox os mais utilizados. O texto a ser exibido consiste em uma string de sua livre escolha e a ordem deve ser um inteiro iniciando em zero o qual irá ordenar a exibição dos parâmetros na janela de configuração da estratégia.

Existe também uma sobrecarga da função InputParameter, na qual não é necessário informar o parâmetro de ordem. Ao utilizar essa função, os parâmetros da estratégia terão exatamente a ordem na qual são criados no código-fonte.

A segunda anotação que pode ser utilizada é um validador. O usuário pode ver no dicionário EvoCode que existem uma função de validação para parâmetros numéricos chamada SimpleNumericAttribute. Este método é sobrecarregado, ou seja, possui diferentes combinações de parâmetros que realizam diferentes validações. Nos exemplos abaixo, ficará claro o uso desse método.

A terceira anotação possível é utilizada no caso de parâmetros exibidos no formato de ComboBox, ou seja, caixa de seleção. Nesse caso, podem ser inseridas quantas anotações forem necessárias para cada opção do ComboBox, invocando a função ComboBoxItem e passando como parâmetro a chave e o valor. Entenda chave como a string que será apresentada no combobox e valor como a representação da opção selecionada, que pode ser um número inteiro ou um enum.

Veja a seguir alguns exemplos de definição de parâmetros para estratégia:

Parâmetro Inteiro (Exemplo: Qtde de períodos de uma média móvel)

No código abaixo a tela de configuração da estratégia/indicador apresentará como primeiro parâmetro a ser definido a “Média rápida – Qtde de periodos” que é do tipo numérico e inteiro, variando entre 1 e 9999. Dentro do código esse parâmetro é reconhecido pelo nome fastestPeriod e a caixa de texto da tela de configuração já irá exibir o valor padrão igual a 5, conforme definido no código.

				
					[InputParameter(InputType.Numeric, "Média rápida - Qtde de periodos", 0)]
		[SimpleNumeric(1D,9999D)]
		public int fastestPeriod = 5;
				
			
Parâmetro ComboBox (Exemplo: Tipo da média móvel)

No código abaixo a tela de configuração da estratégia/indicador apresentará como segundo parâmetro a ser definido a “Média rápida – Tipo da média”, que apresentará em um comboBox as seguintes opções: SMA, EMA, SMMA, LWMA. O valor padrão desse parâmetro será a média aritmética. Observe que dentro do código, esse parâmetro de tipo de média utiliza um eNum pré-definido do EvoCode chamado MAMode.

Caso haja até 3 opções de seleção, a renderização desse componente na interface gráfica da plataforma será no formato de RadioBox ou invés de ComboBox (Caixa de seleção).

				
							[InputParameterAttribute(InputType.Combobox, "Média rápida - Tipo da média", 1)]
		[ComboboxItem("Aritmética (SMA)", MAMode.SMA)]
		[ComboboxItem("Exponencial (EMA)", MAMode.EMA)]
		[ComboboxItem("Amortecida (SMMA)", MAMode.SMMA)]		
		[ComboboxItem("Ponderada Linear (LWMA)", MAMode.LWMA)]		
		public MAMode fastestAvgType = MAMode.SMA;
				
			
Parâmetro Percentual

No código abaixo a tela de configuração da estratégia/indicador apresentará como primeiro parâmetro a ser definido a “bandPct”, que apresentará em uma caixa de texto com valor padrão igual a 2. É um parâmetro do tipo double e observe a anotação de validação possui 4 parâmetros, o que validará: valor mínimo (0.0), valor máximo (9999) precisão numérica (1 casa decimal) e incremento mínimo (0.1).

				
					        [InputParameter(InputType.Numeric, "bandPct", 0)]
        [SimpleNumeric(0.0D, 9999D, 1, 0.1)]
        public double bandPct = 2;
				
			
Código de um indicador com TODOS os tipos de parâmetros em EvoCode

No código abaixo você encontrará um exemplo de um indicador com todos os tipos de parâmetros possíveis em EvoCode.

				
					using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using Runtime.Script;
using TradeApi;
using TradeApi.History;
using TradeApi.Indicators;
using TradeApi.Instruments;
using TradeApi.ToolBelt;
using TradeApi.Trading;


namespace NeoTraderBot
{
    /// <summary>
    /// Indicator
    /// 
    /// </summary>
    public class TestingParameters : IndicatorBuilder 
    {
    	//Exemplo de parâmetro numérico inteiro
		[InputParameter(InputType.Numeric, "Periods", 0)]
		[SimpleNumeric(1D,9999D)]
		public int periods = 5;

		//Exemplo de parâmetro numérico percentual		
		[InputParameter(InputType.Numeric, "Percentage band (%)", 1)]
		[SimpleNumeric(0.0D, 9999D, 1, 0.1)]
		public double bandPct = 2.3;		

		//Exemplo de parâmetro ComboBox		
		[InputParameterAttribute(InputType.Combobox, "Average type", 2)]
		[ComboboxItem("Aritmética (SMA)", MAMode.SMA)]
		[ComboboxItem("Exponencial (EMA)", MAMode.EMA)]
		[ComboboxItem("Amortecida (SMMA)", MAMode.SMMA)]
		[ComboboxItem("Ponderada Linear (LWMA)", MAMode.LWMA)]
		public MAMode avgType = MAMode.SMA;
		
		[InputParameterAttribute(InputType.Checkbox, "Daytrade mode", 3)]
		public Boolean dayTradeMode;
		
		[InputParameterAttribute(InputType.String, "Input message", 4)]
		public string msg = "Hello EvoCode!";
		
		[InputParameterAttribute(InputType.Color, "Color", 5)]
		public Color someColor = Color.Orange;
		
		[InputParameterAttribute(InputType.Instrument, "Symbol", 6)]
		public Instrument instrument;		
		
		[InputParameterAttribute(InputType.DateTime, "Trading start on:", 7)]
		public DateTime startDateTime = DateTime.Now.AddDays(-3);
		
		[InputParameterAttribute(InputType.TimeSpan, "Open position after:", 8)]
		public TimeSpan openPosAfter = DateTime.Now.TimeOfDay;
    	
        public TestingParameters()
            : base()
        {
			#region Initialization
            Credentials.Author = "";
            Credentials.Company = "";
            Credentials.Copyrights = "";
            Credentials.DateOfCreation = new DateTime(2023, 7, 21);
            Credentials.ExpirationDate = DateTime.MinValue;
            Credentials.Version = "";
            Credentials.Password = "66b4a6416f59370e942d353f08a9ae36";
            Credentials.ProjectName = "TestingParameters";
            #endregion 
            
            Lines.Set("indicator");
			Lines["indicator"].Color = Color.Blue;

            SeparateWindow = false;
        }
        
        /// <summary>
        /// This function will be called after creating
        /// </summary>
		public override void Init()
		{
			string param = "Parâmetros:\n";
			param += "Periods: " + periods.ToString() + "\n";
			param += "Percentage band (%): " + bandPct.ToString() + "\n";
			param += "Average type: " + avgType.ToString() + "\n";
			param += "Daytrade mode: " + dayTradeMode.ToString() + "\n";
			param += "Input message: " + msg + "\n";
			param += "Color: " + someColor.Name + "\n";
			param += "Symbol: " + instrument.Symbol.ToString() + "\n";
			param += "Trading start on: " + startDateTime.ToLongDateString() + "\n";
			param += "Open position after: " + openPosAfter.ToString() + "\n";
		
			Notification.Comment(param);
			
		}        
 
        /// <summary>
        /// Entry point. This function is called when new quote comes or new bar created
        /// </summary>
        public override void Update(TickStatus args)
        {
			Lines["indicator"].SetValue(HistoryDataSeries.GetValue(PriceType.Close));
        }
        
        /// <summary>
        /// This function will be called before removing
        /// </summary>
		public override void Complete()
		{
			
		} 
     }
}

				
			

O que são as credenciais do meu código?

As credenciais servem para identificar a sua estratégia com os atributos de Autor, Empresa, Direitos Autorais (se for o caso), Data de criação do código, Data de Expiração, Versão do código, Senha e Nome do Projeto (este é o nome que irá aparecer nas listagens dentro da plataforma). 

A utilização de #region não tem nenhum impacto sobre o código, sendo apenas uma funcionalidade .NET para poder expandir ou colapsar blocos de código na IDE (ambiente de desenvolvimento).

OBS: É importante ressaltar que se você configurar a data de expiração para um valor diferente de “DateTime.MinValue”, compilar o seu código e compartilhar ele com alguém, o código executará apenas até a data de expiração.

				
					#region Initialization
Credentials.Author = "Johnathas Carvalho";
Credentials.Company = "Comunidade NeoTraderBot";
Credentials.Copyrights = "";
Credentials.DateOfCreation = new DateTime(2023, 5, 16);
Credentials.ExpirationDate = DateTime.MinValue;
Credentials.Version = "1.0";
Credentials.Password = "66b4a6416f59370e942d353f08a9ae36";
Credentials.ProjectName = "NTB_TripleCrossoverIndicator";
Credentials.Description = "Descrição";
#endregion 
				
			

Como definir texto a ser apresentado no cabeçalho do gráfico o indicador?

A definição do texto a ser apresentado no cabeçalho do gráfico, quando seu indicador for aplicado deve ser realizada no método Init. Conforme exemplo abaixo.

É importante dizer que ScriptShortName é um atributo da Classe IndicatorBuilder e o que estamos fazendo é simplesmente atribuir valor a essa variável com uma string. Utilizou-se também a função de formatação de string que permite colocar placeholders (reserva de espaço) dentro da string e definir seus valores nos próximos parâmetros da função string.Format. A sequencia {0} é um placeholder que irá ser substituída pelo primeiro parâmetro, no caso, fastestAvgType.

 

				
					public override void Init()
{

ScriptShortName = (string.Format("NTB Crossover: {0}({1}) | {2}({3}) | {4}({5})",
                              fastestAvgType, fastestPeriod, fastAvgType, fastPeriod, slowAvgType, slowPeriod));

}  
				
			

Quais são os principais eventos que serão tratados pelo método Update?

As classes de indicador e estratégia (IndicatorBuilder e StrategyBuilder) podem lidar com diferentes tipos de eventos. Não obstante, existem 3 eventos que são comuns nessas duas classes e que exigem a implementação de 3 métodos, a saber: Init, Update e Complete.

O Método Init será executado sempre que um indicador/estratégia for inicializado dentro da plataforma TraderEvolution. Ou seja, quando o indicador for incluído em um gráfico um uma estratégia iniciar sua execução.

De maneira análoga, o método Complete é chamado ao final da execução do indicador ou estratégia.

Assim, resta falar do método Update que podemos dizer se tratar do coração do indicador/estratégia. Todos eventos durante a execução do seu código devem ser tratados no método Update, o qual recebe como parâmetro um objeto do tipo TickStatus chamado args).

O valor de args pode ser um dos três valores possíveis do eNum TickStatus: IsBar, IsQuote e IsHistory. Vamos explicar cada um desses eventos abaixo:

      • isBar: quando uma barra é encerrada, gera-se uma chamada ao método Update com o valor de args igual a isBar. Assim, o programador pode definir o que fazer no fechamento das barras no código dentro de Update. Sempre após um evento isBar, o método Update é chamado com um evento isQuote.
      • isQuote: este evento é sempre disparado para cada negociação recebida pela sua plataforma cliente (seu programa TraderEvolution). Assim, o programador pode definir o que fazer no tick. Nos dados históricos, isQuote é disparado 4 vezes para cada barra.
      • isHistory: este evento é disparado para cada barra enquanto seu código processa os dados históricos. Uma vez em tempo real, esse evento não é mais disparado.

Quais são as informações que consigo obter da conta do usuário logado pelo código?

Todas as estratégias/indicador tem acesso às informações da conta logada por meio da classe AccountManager, a qual pode retornar a conta atual e seus detalhes. O código abaixo demonstra como obter o e-mail do usuário que está executando o código.

Posição do DicionárioPropriedade
[0]Conta
[1]Saldo
[2]Saldo bloqueado
[3]L/P líquido aberto
[4]L/P bruto aberto
[5]Saldo projetado
[6]Nº de ordens
[7]Nº de posições
[8]Margem Inicial
[9]Nível de risco
[10]Nível de alerta de margem
[11]Nível “Stop Out”
[12]Fundos disponíveis
[13]Alerta de margem
[14]Manutenção de Margem
[15]Disponível para Retirada
[16]ID do usuário
[17]Login do usuário
[18]Cliente
[19]E-mail
[20]Bruto de hoje
[21]Taxas de hoje
[22]Líquido de hoje
[23]Volume de hoje
[24]Nº de negociações de hoje
[25]Valor da Ação
[26]Saldo em dinheiro
[27]Número do telefone
[28]Margem inicial
[29]Saldo + Risco total
[30]Situação da negociação
[31]Limite diário de perda
[32]Contagem máxima de ordens por dia
[33]Nº máximo de posições
[34]Nº máximo de ordens pendentes
[35]Capital de ordem máximo
[36]Margem disponível
[37]Valor de crédito
[38]Modo da conta
[39]Ativo
[40]Descrição do Ativo
[41]Tipo de conta
[42]Tipo de Ativo
[43]Taxa de juros
[44]Descontos de hoje
[45]Bloqueado para ‘Ações’
[46]Ganho incerto
[47]Modificar nivel de rebaixamento
[48]Quantidade máxima da posição
[49]Limite de perda semanal
[50]Perda diária
[51]Perda semanal
[52]Ordens de ações
[53]Valor da Opção
[54]Liquidez de Ações
[55]Perda não realizada
[56]Limite de perda não realizado
[57]Objetivo de lucro diário
[58]Limite de volume de ações
[59]Limite de volume futuro
[60]Limite de volume de opções
[61]Procuração
[62]Valor da ordem máximo
[63]Req. de prêmio de opção
[64]Rebaixamento Máximo
[65]Margem isenta
[66]Warn. margin req.
[67]Warn. margin req.%
[68]Margin before warning
Obtendo e-mail do usuário
				
					Dictionary<string, string> detalhesConta = AccountManager.Current.GetAccountDetails();
string email = "";
if (detalhesConta.TryGetValue("E-mail", out email))
{
    Notification.Print(email);
}
				
			

Como identificar se o código está rodando em conta real ou conta demo?

				
					string tipoConta = "";
Boolean contaReal = false;

Dictionary<string, string> detalhesConta = AccountManager.Current.GetAccountDetails();
if (detalhesConta.TryGetValue("Conta", out tipoConta))
{
    if (!tipoConta.Contains("demo"))
    {
        contaReal = true;
    }
}
				
			

Tutoriais sobre Estrutura de Código

Introdução

Esta seção visa apresentar trechos de códigos com funcionalidades relativas à estrutura do código de indicadores e estratégias. Por exemplo, como criar parâmetros de entrada.

Você pode acessar os Snippets/Tutoriais diretamente pelo menu lateral direito, ou fazendo CTRL+F (CTRL+L) para localizar algum texto específico na página, uma vez que o conteúdo tende a crescer ao longo do tempo, dificultando a navegação pelo menu.

Caso tenham sugestões de código para acrescentar à lista, gentileza deixar o código nos comentários com o link para seu perfil em rede social (para devido crédito de autoria).

Snippets/Tutoriais

Como criar parâmetros no meu indicador/estratégia?

Reproduzir vídeo

Os parâmetros de uma estratégia ou indicador são declarados como atributos da classe.

O que diferencia esses atributos dos demais atributos são as anotações (em C# chama-se Annotations e são contidas entre [ ]) que realizamos imediatamente antes da definição dos atributos. Vamos ver abaixo como criar diferentes tipos de parâmetros, como definir seu valor padrão, qual texto será exibido na interface de configuração da estratégia/indicador e pré-validações.

Os tipos de parâmetros possíveis em NinjaScript são: bool, int, double, string, DateTime e Brush. Ainda é possível utilizar eNum renderizando em formato de dropdown na GUI (veremos mais detalhes no exemplo completo).

A primeira anotação que realizamos é [NinjaScriptProperty]. Esta anotação irá informar ao pré-processador que no momento da compilação que o atributo deve ser exibido na interface de configuração do Indicador ou estratégia como parâmetro.

 

A segunda anotação que pode ser utilizada é um validador [Range()]. A função Range permite definir o valor mínimo e máximo no caso de parâmetros do tipo inteiro e double, permitindo a validação do valor inserido pela interface gráfica. No caso de parâmetros de data ou horário (DateTime), ao invés de utilizarmos Range, podemos fazer a anotação [PropertyEditor(“NinjaTrader.Gui.Tools.DateTimeEditorKey”)], onde “DateTimeEditorKey” será usado quando você quiser renderizar um seletor de datas e “TimeEditorKey” caso deseje-se renderizar um seletor de horário.

A terceira anotação é a chamada a função Display, que nos permitirá atribuir um nome ao parâmetro na interface gráfica, juntamente com um texto a ser apresentado como Tooltip (ou seja, quando o mouse passar sobre o nome do parâmetro), a ordem de exibição e o grupo no qual o parâmetro será exibido na tela de configuração.

Os valores padrão dos parâmetros devem ser definidos no estado SetDefaults quando chamado o método OnStateChange.

 

Veja a seguir alguns exemplos de definição de parâmetros para estratégia:

Parâmetro Inteiro (Exemplo: Qtde de períodos de uma média móvel)

No código abaixo a tela de configuração da estratégia/indicador apresentará como segundo parâmetro do grupo “Setup (by NeoTraderBot)” a ser definido a “Média rápida – Qtde de periodos” que é do tipo numérico e inteiro, variando entre 1 e o maior valor inteiro possível.

				
							[NinjaScriptProperty]
		[Range(1, int.MaxValue)]
		[Display(Name="Periods", Description="Number of period for MA", Order=2, GroupName="Setup (by NeoTraderBot)")]
		public int period
		{ get; set; }
				
			
Parâmetro Brush (Paleta de cores)

No código abaixo a tela de configuração da estratégia/indicador apresentará como segundo parâmetro do grupo “Appereance (by NeoTraderBot)” a ser definido o texto “Plot color”, que apresentará em uma caixa de seleção de paleta de cor. Observe a existência da anotação XmlIgnore, cujo propósito é evitar a serialização desse parâmetro ao salvar um template do indicador, pois isto poderia gerar erro na plataforma (esta anotação é incluída automaticamente pelo NinjaScript Wizard).

				
							[NinjaScriptProperty]
		[XmlIgnore]
		[Display(Name="Plot color", Description="Example how to use brush as a parameter", Order=2, GroupName="Appearence (by NeoTraderBot)")]
		public Brush plotColor
		{ get; set; }
				
			
Código de um indicador com TODOS os tipos de parâmetros em NinjaScript

No código abaixo você encontrará um exemplo de um indicador com todos os tipos de parâmetros possíveis em NinjaScript.

				
					#region Using declarations
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Xml.Serialization;
using NinjaTrader.Cbi;
using NinjaTrader.Gui;
using NinjaTrader.Gui.Chart;
using NinjaTrader.Gui.SuperDom;
using NinjaTrader.Gui.Tools;
using NinjaTrader.Data;
using NinjaTrader.NinjaScript;
using NinjaTrader.Core.FloatingPoint;
using NinjaTrader.NinjaScript.DrawingTools;
#endregion

//This namespace holds Indicators in this folder and is required. Do not change it. 
namespace NinjaTrader.NinjaScript.Indicators
{
	[Gui.CategoryOrder("Setup (by NeoTraderBot)", 1)]
	[Gui.CategoryOrder("Trading intervals (by NeoTraderBot)", 2)]
	[Gui.CategoryOrder("Appearence (by NeoTraderBot)", 3)]		
	public class _NTB_UserDefinedParameters : Indicator
	{
		protected override void OnStateChange()
		{
			if (State == State.SetDefaults)
			{
				Description									= @"Just a demonstration on how to include User Defined Parameters";
				Name										= "_NTB_UserDefinedParameters";
				Calculate									= Calculate.OnBarClose;
				IsOverlay									= false;
				DisplayInDataBox							= true;
				DrawOnPricePanel							= true;
				DrawHorizontalGridLines						= true;
				DrawVerticalGridLines						= true;
				PaintPriceMarkers							= true;
				ScaleJustification							= NinjaTrader.Gui.Chart.ScaleJustification.Right;
				//Disable this property if your indicator requires custom values that cumulate with each new market data event. 
				//See Help Guide for additional information.
				IsSuspendedWhileInactive					= true;
				
				avgType					= NeoTraderBot.MAType.SMA;
				period					= 9;
				percBand				= 2.0;
				msg						= @"Example of a msg to display on the chart!";
				daytradingMode			= true;
				DontTradeOn				= DateTime.Now;
				TradingStartAfter		= DateTime.Parse("09:00", System.Globalization.CultureInfo.InvariantCulture);
				TradingCloseAt			= DateTime.Parse("12:00", System.Globalization.CultureInfo.InvariantCulture);				
				plotColor				= Brushes.Orange;
				
			}
			else if (State == State.Configure)
			{
			}
		}

		protected override void OnBarUpdate()
		{
			//Add your custom indicator logic here.
		}

		#region Properties
		[Display(Name="MA Type", Description="Example of Dropbox parameter with enum", Order=1, GroupName="Setup (by NeoTraderBot)")]
		public NeoTraderBot.MAType avgType
		{ get; set; }	
		
		[NinjaScriptProperty]
		[Range(1, int.MaxValue)]
		[Display(Name="Periods", Description="Number of period for MA", Order=2, GroupName="Setup (by NeoTraderBot)")]
		public int period
		{ get; set; }

		[NinjaScriptProperty]
		[Range(1, double.MaxValue)]
		[Display(Name="% band around VWAP", Description="Just an example of double parameter", Order=3, GroupName="Setup (by NeoTraderBot)")]
		public double percBand
		{ get; set; }

		[NinjaScriptProperty]
		[Display(Name="Enable Daytrading mode", Order=4, GroupName="Setup (by NeoTraderBot)")]
		public bool daytradingMode
		{ get; set; }


		[NinjaScriptProperty]
		[PropertyEditor("NinjaTrader.Gui.Tools.DateTimeEditorKey")]
		[Display(Name="Dont Trade on", Description="Just an example of Date parameter", Order=1, GroupName="Trading intervals (by NeoTraderBot)")]
		public DateTime DontTradeOn
		{ get; set; }		
		
		[NinjaScriptProperty]
		[PropertyEditor("NinjaTrader.Gui.Tools.TimeEditorKey")]
		[Display(Name="Start trading after", Description="Time after the strategy will start to trade", Order=2, GroupName="Trading intervals (by NeoTraderBot)")]
		public DateTime TradingStartAfter
		{ get; set; }
		
		[NinjaScriptProperty]
		[PropertyEditor("NinjaTrader.Gui.Tools.TimeEditorKey")]
		[Display(Name="Trading close at", Description="Time at the strategy will stop trading and close open positions", Order=3, GroupName="Trading intervals (by NeoTraderBot)")]
		public DateTime TradingCloseAt
		{ get; set; }		


		
		
		[NinjaScriptProperty]
		[Display(Name="Display message", Description="Just an example of string parameter", Order=1, GroupName="Appearence (by NeoTraderBot)")]
		public string msg
		{ get; set; }		
		
		[NinjaScriptProperty]
		[XmlIgnore]
		[Display(Name="Plot color", Description="Example how to use brush as a parameter", Order=2, GroupName="Appearence (by NeoTraderBot)")]
		public Brush plotColor
		{ get; set; }

		[Browsable(false)]
		public string Teste6Serializable
		{
			get { return Serialize.BrushToString(plotColor); }
			set { plotColor = Serialize.StringToBrush(value); }
		}			
		#endregion

	}
}

namespace NeoTraderBot
{
	public enum MAType
	{
		SMA,
		EMA,
		WMA,
	}
}

#region NinjaScript generated code. Neither change nor remove.

namespace NinjaTrader.NinjaScript.Indicators
{
	public partial class Indicator : NinjaTrader.Gui.NinjaScript.IndicatorRenderBase
	{
		private _NTB_UserDefinedParameters[] cache_NTB_UserDefinedParameters;
		public _NTB_UserDefinedParameters _NTB_UserDefinedParameters(int period, double percBand, bool daytradingMode, DateTime dontTradeOn, DateTime tradingStartAfter, DateTime tradingCloseAt, string msg, Brush plotColor)
		{
			return _NTB_UserDefinedParameters(Input, period, percBand, daytradingMode, dontTradeOn, tradingStartAfter, tradingCloseAt, msg, plotColor);
		}

		public _NTB_UserDefinedParameters _NTB_UserDefinedParameters(ISeries<double> input, int period, double percBand, bool daytradingMode, DateTime dontTradeOn, DateTime tradingStartAfter, DateTime tradingCloseAt, string msg, Brush plotColor)
		{
			if (cache_NTB_UserDefinedParameters != null)
				for (int idx = 0; idx < cache_NTB_UserDefinedParameters.Length; idx++)
					if (cache_NTB_UserDefinedParameters[idx] != null && cache_NTB_UserDefinedParameters[idx].period == period && cache_NTB_UserDefinedParameters[idx].percBand == percBand && cache_NTB_UserDefinedParameters[idx].daytradingMode == daytradingMode && cache_NTB_UserDefinedParameters[idx].DontTradeOn == dontTradeOn && cache_NTB_UserDefinedParameters[idx].TradingStartAfter == tradingStartAfter && cache_NTB_UserDefinedParameters[idx].TradingCloseAt == tradingCloseAt && cache_NTB_UserDefinedParameters[idx].msg == msg && cache_NTB_UserDefinedParameters[idx].plotColor == plotColor && cache_NTB_UserDefinedParameters[idx].EqualsInput(input))
						return cache_NTB_UserDefinedParameters[idx];
			return CacheIndicator<_NTB_UserDefinedParameters>(new _NTB_UserDefinedParameters(){ period = period, percBand = percBand, daytradingMode = daytradingMode, DontTradeOn = dontTradeOn, TradingStartAfter = tradingStartAfter, TradingCloseAt = tradingCloseAt, msg = msg, plotColor = plotColor }, input, ref cache_NTB_UserDefinedParameters);
		}
	}
}

namespace NinjaTrader.NinjaScript.MarketAnalyzerColumns
{
	public partial class MarketAnalyzerColumn : MarketAnalyzerColumnBase
	{
		public Indicators._NTB_UserDefinedParameters _NTB_UserDefinedParameters(int period, double percBand, bool daytradingMode, DateTime dontTradeOn, DateTime tradingStartAfter, DateTime tradingCloseAt, string msg, Brush plotColor)
		{
			return indicator._NTB_UserDefinedParameters(Input, period, percBand, daytradingMode, dontTradeOn, tradingStartAfter, tradingCloseAt, msg, plotColor);
		}

		public Indicators._NTB_UserDefinedParameters _NTB_UserDefinedParameters(ISeries<double> input , int period, double percBand, bool daytradingMode, DateTime dontTradeOn, DateTime tradingStartAfter, DateTime tradingCloseAt, string msg, Brush plotColor)
		{
			return indicator._NTB_UserDefinedParameters(input, period, percBand, daytradingMode, dontTradeOn, tradingStartAfter, tradingCloseAt, msg, plotColor);
		}
	}
}

namespace NinjaTrader.NinjaScript.Strategies
{
	public partial class Strategy : NinjaTrader.Gui.NinjaScript.StrategyRenderBase
	{
		public Indicators._NTB_UserDefinedParameters _NTB_UserDefinedParameters(int period, double percBand, bool daytradingMode, DateTime dontTradeOn, DateTime tradingStartAfter, DateTime tradingCloseAt, string msg, Brush plotColor)
		{
			return indicator._NTB_UserDefinedParameters(Input, period, percBand, daytradingMode, dontTradeOn, tradingStartAfter, tradingCloseAt, msg, plotColor);
		}

		public Indicators._NTB_UserDefinedParameters _NTB_UserDefinedParameters(ISeries<double> input , int period, double percBand, bool daytradingMode, DateTime dontTradeOn, DateTime tradingStartAfter, DateTime tradingCloseAt, string msg, Brush plotColor)
		{
			return indicator._NTB_UserDefinedParameters(input, period, percBand, daytradingMode, dontTradeOn, tradingStartAfter, tradingCloseAt, msg, plotColor);
		}
	}
}

#endregion

				
			

Quando é chamado o método OnBarUpdate?

Reproduzir vídeo

Como criar estratégias/indicadores em múltiplos tempos gráficos (MTF)?

O código de exemplo abaixo apresenta um exemplo completo para você criar indicadores e estratégias em múltiplos tempos gráficos. Assista ao vídeo acima para entender o passo a passo da estruturação de um código MTF (multi Timeframe).

				
					#region Using declarations
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Xml.Serialization;
using NinjaTrader.Cbi;
using NinjaTrader.Gui;
using NinjaTrader.Gui.Chart;
using NinjaTrader.Gui.SuperDom;
using NinjaTrader.Gui.Tools;
using NinjaTrader.Data;
using NinjaTrader.NinjaScript;
using NinjaTrader.Core.FloatingPoint;
using NinjaTrader.NinjaScript.Indicators;
using NinjaTrader.NinjaScript.DrawingTools;
#endregion

//This namespace holds Strategies in this folder and is required. Do not change it. 
namespace NinjaTrader.NinjaScript.Strategies
{
	public class MTF_ExemploNeoTraderBot : Strategy
	{
		protected override void OnStateChange()
		{
			if (State == State.SetDefaults)
			{
				Description									= @"Example of NeoTraderBot";
				Name										= "MTF_ExemploNeoTraderBot";
				Calculate									= Calculate.OnBarClose;
				EntriesPerDirection							= 1;
				EntryHandling								= EntryHandling.AllEntries;
				IsExitOnSessionCloseStrategy				= true;
				ExitOnSessionCloseSeconds					= 30;
				IsFillLimitOnTouch							= false;
				MaximumBarsLookBack							= MaximumBarsLookBack.TwoHundredFiftySix;
				OrderFillResolution							= OrderFillResolution.Standard;
				Slippage									= 0;
				StartBehavior								= StartBehavior.WaitUntilFlat;
				TimeInForce									= TimeInForce.Gtc;
				TraceOrders									= false;
				RealtimeErrorHandling						= RealtimeErrorHandling.StopCancelClose;
				StopTargetHandling							= StopTargetHandling.PerEntryExecution;
				BarsRequiredToTrade							= 20;
				// Disable this property for performance gains in Strategy Analyzer optimizations
				// See the Help Guide for additional information
				IsInstantiatedOnEachOptimizationIteration	= true;
				
				AddPlot(new Stroke(Brushes.White, DashStyleHelper.Dash, 1), PlotStyle.Line, "EMA_CHART");
				AddPlot(new Stroke(Brushes.Yellow, DashStyleHelper.Solid, 1), PlotStyle.Line, "EMA_5MIN");
				AddPlot(new Stroke(Brushes.Blue, DashStyleHelper.Dash, 2), PlotStyle.Line, "EMA_15MIN");
				AddPlot(new Stroke(Brushes.Orange, DashStyleHelper.Solid, 2), PlotStyle.Line, "EMA_60MIN");
				
				
			}
			else if (State == State.Configure)
			{
				AddDataSeries(BarsPeriodType.Minute, 5);
				AddDataSeries(BarsPeriodType.Minute, 15);
				AddDataSeries(BarsPeriodType.Minute, 60);
			}
		}

		protected override void OnBarUpdate()
		{
			if (CurrentBars[0] < BarsRequiredToPlot || CurrentBars[1] < BarsRequiredToPlot || CurrentBars[2] < BarsRequiredToPlot
				|| CurrentBars[3] < BarsRequiredToPlot)
				return;
			
			Values[0][0] = EMA(Closes[0], 20)[0];
			Values[1][0] = EMA(Closes[1], 20)[0];
			Values[2][0] = EMA(Closes[2], 20)[0];
			Values[3][0] = EMA(Closes[3], 20)[0];
			
			if (BarsInProgress == 2) 
				BackBrushes[0] = Brushes.Olive;
			
		}
	}
}

				
			

Lançamento da NinjaTrader para operações na B3

Reproduzir vídeo

Após um longo período de espera, finalmente, a Plataforma NinjaTrader foi homologada para operar na B3. Desde o dia 03/jan/2023 é possível contratar esta Plataforma pela Corretora Órama.

Conforme antecipado nos planos da Comunidade @neotraderbot, iremos gerar conteúdo informativo de diferentes plataformas de trading para que os membros da comunidade tenham informações do que é possível realizar em outros ambientes. Reforço que não estamos realizando nenhuma recomendação para mudança de Plataforma e que a decisão de migrar parte ou todo o processo de desenvolvimento e execução das estratégias automatizadas é muito pessoal e cabe apenas ao trader decidir sobre tal assunto.

Neste primeiro video sobre a Plataforma NinjaTrader vamos abordar as principais características do software: modelo de negócios, modularização do software, ecosistema de desenvolvimento, custos de contratação, detalhes gerais relacionados à automatização de estratégias.

Nas próximas semanas iremos gerar quase diariamente, seg a sexta, conteúdo sobre essa Plataforma antes de abordarmos em profunidade o desenvolvimento de estratégias em NinjaTrader Script!

EvoCode – Ambiente de desenvolvimento de estratégias da Trader Evolution

Reproduzir vídeo

Neste vídeo da séria “Conhecendo a Trader Evolution” vamos explorar o ambiente de desenvolvimento de estratégias: EvoCode.

Não se esqueça de indicar a Comunidade NeoTraderBot como parceiro na Plataforma TraderEvolution. Vá no menu superior em “Mais” – “Extensões” – “Indique parceiro” e digite o código “NEOTRADERBOT”.

Assim, você reforça sua participação na Comunidade e nos ajuda a pleitear novas funcionalidades e melhorias na plataforma visando o benefício de todos os membros em suas automatizações e desenvolvimento de estratégias.

Construtor de Capital – Liberação de acesso à Gamma Levels

Este tutorial visa apresentar o passo a passo para configuração e liberação de acesso aos alunos/assinantes das ferramentas desenvolvidas pela NeoTraderBot para Construtor de Capital na plataforma Meta Trader 5 (MT5). 

Uma vez enviadas as informações de e-mail da assinatura do indicador e número da conta da corretora Exness, a liberação de acesso está condicionada à confirmação de vinculo (aluno) junto à Construtor de Capital e será realizada em até 1 dia útil.

Em caso de dúvidas ou questões relacionadas às ferramentas Construtor de Capital, envie e-mail para contrutordecapital1@gmail.com.

Pré-configurações da MetaTrader

Passo 1: Abra o MetaTrader, vá no menu “Ferramentas” -> “Opções”.

Passo 2: Na tela que abrir, vá na aba “Expert Advisors” e em seguida marque a opção “Relacione no quadro abaixo as URL que deseja permitir a função WebRequest”. Insira na tabela a seguinte URL:

https://drive.usercontent.google.com/

Em seguida, clique em “OK”.

Instalação do Gamma Levels

Existem duas formas de instalar o Gamma Levels na MetaTrader. Recomenda-se que tente-se instalar pela forma 1 (mais simples). Caso o usuário tenha  conhecimento mais aprofundado sobre a plataforma MT5 e/ou tenha mais de uma instalação de MT5 na mesma máquina, pode-se instalar seguindo as instruções da Forma 2.

Forma 1: Ao receber o arquivo GammaLevelsCC_VXX.ex5 (onde XX é a versão da ferramenta), basta clicar duas vezes que o indicador será automaticamente instalado na MetaTrader.

Uma vez instalado, acesse a janela “Navegador” do MetaTrader e você verá dentro de “Consultor Expert” a ferramenta GammaLevels.

Forma 2: Abra o Windows Explorer e digite na barra de navegação %APPDATA%. A partir daí navegue até a pasta MetaQuotes -> Terminal -> Selecione a instalação desejada -> MQL5 -> Experts. 

Copie o arquivo GammaLevelsCC_VXX.ex5 (onde XX é a versão da ferramenta), para dentro dessa pasta e a ferramenta GammaLevels estará disponível nessa instalação específica do MT5.

Informações necessárias para ativação do Gamma Levels

Para realizar a ativação da ferramenta Gamma Levels para MT5, o usuário precisa enviar pelo formulário no final dessa página, o e-mail pelo qual realizou a assinatura do indicador e o número da conta da corretora. 

A informação de número da conta é obtida na janela “Navegador” -> Contas do MT5, conforme pode ser visto abaixo.

Inserindo o Gamma Levels em um gráfico

Uma vez, enviada a solicitação de ativação e confirmada a ativação pelo Construtor de Capital no e-mail informado, o usuário deve realizar os seguintes passos para incluir os níveis gamma em um gráfico.

Passo 1: Abra um gráfico no ativo desejado. Clique sobre o GammaLevels na aba Navegador, arraste e solte dentro do gráfico no qual deseja plotar os níveis Gamma.

Passo 2: Será aberta uma janela com informações do GammaLevels. Habilite a a opção “Permitir algotrading” e, em seguida, acesse a aba “Parâmetros de entrada”.

OBS: O GammaLevels não realiza nenhum tipo de operação automatizada.

Passo 3: Na aba de parâmetros, insira no campo apropriado o seu e-mail de assinatura da ferramenta GammaLevels. Nesta tela o usuário poderá configurar diversas propriedades de exibição de níveis, filtro de níveis por opções, agrupamento de níveis próximos e alarmes de cruzamento de níveis.

Recomenda-se que o usuário salve as configurações em um arquivo para reutilizar suas configurações. Assim, não é necessário configurar tudo novamente caso acrescente o indicador em outro gráfico. Para carregar uma pré-configuração de parâmetros do indicador, utilize a opção “Abrir”.

Clique em “OK”.

Passo 4: Uma vez configurado, o usuário poderá ver detalhes da execução da ferramenta na aba “Experts” em “Caixa de Ferramentas”, logo abaixo do gráfico. Caso a autenticação tenha sido efetuada corretamente, os níveis serão plotados no gráfico com o texto no lado direito. No canto superior direito do gráfico, o usuário verificará o texto “GammaLevelsCC” indicando que a ferramenta está aplicada naquele gráfico.

Liberação de Acesso - Ferramentas Construtor de Capital MT5
Este formulário visa recepcionar as chaves dos usuários para liberação de uso das ferramentas e códigos desenvolvidos pela NeoTraderBot para Construtor de Capital na plataforma Meta Trader 5 (MT5)

Como criar seu bot para Telegram

A ferramenta de Integração TraderEvolution / Telegram, desenvolvida pela NeoTraderBot, necessita que você crie um bot no Telegram.

Veja abaixo o passo-a-passo para criar o seu próprio bot no Telegram. O procedimento pode ser realizado tanto no Telegram Web quanto eu seu próprio aplicativo no celular.

Reproduzir vídeo

TUTORIAL - PASSO 1: Como criar seu bot para Telegram

1) Acesse o Telegram Web ou abra o app em seu celular
2) Pesquise por botFather

A pesquisa irá buscar os perfis públicos com este nome. Certifique de que irá selecionar o perfil correto conforme abaixo com a verificação do Telegram.

3) Inicie um chat com o perfil @BotFather
4) Digite o comando /newbot

Isto irá iniciar o processo de geração de um bot para Telegram.

5) Em seguida o @botFather irá lhe perguntar qual é o nome do seu bot. Escolha um nome conforme sua conveniência.

No exemplo abaixo, escolhemos o nome “TesteCriacaoBot”

6) No próximo passo, o @botFather irá lhe perguntar por um username que deve terminar com a palavra bot.

O username (nome de usuário) é uma chave única no Telegram e, portanto, alguns nomes podem estar ocupados.

No exemplo abaixo, tentamos “TesteCricaoBot” e fomos avisados de que esse username já havia sido escolhido. Na segunda tentativa, escolhemos o username testeCriacao1bot.

7) Salve em local seguro o token de acesso do seu bot e inicie um chat com o seu bot

Uma vez que o username seja aceito, o @botFather irá gerar um token de acesso ao bot. Esse token de acesso permite administrar o bot criado e, portanto, você deve guardar essa chave em um lugar seguro.

Em seguida, clique na URL indicada no início da mensagem e encaminhe um texto qualquer ao seu bot, para que o mesmo conste na sua lista de Grupos/Chats do Telegram.

 

Próximo passo...

Ok! Criamos com sucesso o nosso bot de Telegram o qual irá enviar mensagens dentro da estratégias e indicadores da TraderEvolution utilizando a ferramenta da NeoTraderBot.

No próximo passo iremos criar o grupo no qual o bot irá encaminhar mensagens (caso você ainda não tenha) e atribuir permissão de administrador ao seu bot recém-criado.

Como me registrar como Parceiro da NeoTraderBot?

Aqui na NeoTraderBot temos o objetivo de criar uma comunidade de traders interessados em utilizar a automação a seu favor no trading, seja 100% por meio de robôs, ou semi-automatizada, delegando a algoritmos e códigos automatizados a execução de algumas tarefas específicas.

Para que você tenha acesso a algumas condições especiais no uso de ferramentas, indicadores e estratégias, pedimos que nos ajude a fazer crescer a Comunidade NeoTraderBot, sinalizando como nosso parceiro dentro da plataforma Trader Evolution.

É muito simples fazer isso! Siga o passo-a-passo abaixo:

Passo 1: Na Plataforma Trader Evolution, clique no item “Ferramentas” no menu superior. Em seguida na opção “Extensões” -> “Indique parceiro”.

Passo 2: Vai abrir uma pequena janela, na qual você irá inserir o código “NEOTRADERBOT” para sinalizar para a plataforma Trader Evolution que você pertence a Comunidade NeoTraderBot.

Pronto! Ao sinalizar que você pertence à Comunidade NeoTraderBot, poderemos pleitear novas funcionalidades, ajustes ou melhorias de maneira centralizada e com mais relevância, uma vez que saberão quantas pessoas estão engajadas na Comunidade NeoTraderBot!

Programando Estratégias no Profit

O que precisa saber antes de começar...

Reproduzir vídeo

Neste documento vamos apresentar aspectos importantes antes que você comece a criar seu robô ou outro tipo de estratégia (indicador, coloração, screening).

Se fossemos classificar as dúvidas apresentadas por pessoas nas redes sociais sobre automatização de estratégias, dividiríamos em 3 grupos: Dúvidas de lógica de programação, Dúvidas sobre funções do Editor de Estratégias e Dúvidas sobre como implementar o operacional desejado.

Para as dúvidas de lógica de programação não há muito segredo, basta fazer um curso introdutório no assunto. Clique aqui e assista à primeira aula do Curso Básico de Lógica de Programação da NeoTraderBot (disponível em uma playlist no Youtube). Trata-se de um curso bem objetivo e que tem a meta de em 5 vídeos curtos te explicar os principais conceitos sobre lógica de programação, sendo o último vídeo uma aula prática de Pascal que é a linguagem de programação mãe da NTSL. Caso ainda não saiba, a NTSL é a sigla para Nelogica Trading System Language, que é a linguagem adaptada do Pascal para uso no Profit Chart.

Para as dúvidas relacionadas às funções do Editor de Estratégias…eu acho bastante compreensível a existência delas. Acredito até que haja mais dúvidas que o esperado devido ao fato da documentação da Nelógica ser muito ruim, além de ser difícil achar boas referências pela Internet (principalmente gratuitas). Pensando nisso, estamos estruturando uma área neste site, aberta para qualquer visitante, explicando melhor as funções embutidas no editor de estratégias, com exemplos e comentários das dúvidas mais frequentes. Além disso, haverá uma seção de Templates (modelos para montar suas estratégias) e Snipets (trechos de código fontes prontos para você utilizar como exemplo e acelerar o seu desenvolvimento).

Chegamos então a parte principal deste texto e que se relaciona com as dúvidas referentes à implementação de setups operacionais.

Algumas dessas dúvidas sobre implementação de operacionais podem recair sobre limitações já conhecidas do Profit. Assista este vídeo que é bem interessante e trata sobre as Limitações do Profit referentes à automatização de estratégias. No decorrer deste texto abordaremos tópicos diferentes, porém complementares.

Ok…Se tirarmos aquilo que o Profit não permite fazer, e que esperamos que sejam disponibilizadas melhorias para sanar, teremos as dúvidas que derivam do fato de as pessoas não entenderem como funciona o processamento das estratégias no Profit. Se os traders que estão buscando automatizar as estratégias entendessem sobre isso, talvez mais da metade dos problemas já seriam resolvidos.

Então vamos abordar a seguir dois pontos muito importantes que você deve saber antes de implementar estratégias no Profit Chart, incluindo robôs: Modelo de dados utilizado pelo Profit e Processamento das Estratégias.

Modelo de dados OHLCV

O modelo de dados utilizado pelo Profit é o OHLCV. Este é o modelo usado por quase 100% das plataformas de backtesting e a sigla OHLCV significa Open, High, Low, Close e Volume.

Trata-se dos dados de preço e volume disponibilizados para realização de backtesting. Quanto maior for a frequência demandada de dados, por exemplo, dados de 1 minuto, maior é o espaço demandado para armazenamento dessas informações.

Se fossemos salvar em nosso computador os dados de cada tick, ou seja, para cada alteração mínima de preço do ativo que estamos negociando, precisaríamos de muito espaço e banda de internet para requisitar os dados. Então torna-se impraticável disponibilizar por padrão dados tick a tick…É claro que isto poderia ser fornecido sob demanda, para não sobrecarregar sua plataforma e os servidores da Nelógica (se houvesse funcionalidade para tal no Profit!).

Então quando realizamos backtesting de uma estratégia, nós não temos os dados tick a tick, temos apenas dados por candle fechado, os já mencionados OHLCV. 

Grandes empresas do mercado financeiro operam algoritmos em alta frequencia, em inglês, High Frequency Trading. Mas eles tem muito dinheiro, os melhores recursos de TI e mentes brilhantes (vários PHDs) para programar e monitorar os algoritmos. Além disso, eles colocam os melhores servidores possíveis de se adquirir, que executam seus algoritmos dentro da B3, fisicamente ao lado dos servidores da B3, a poucos metros de cabo de distância, para reduzir ao máximo a latência, que é o tempo entre envio e a execução da ordem.

Para se ter uma ideia…se quando enviamos uma ordem para nossa corretora, o processo demora 100 milisegundos para a execução, a ordem dessas empresas leva 1 milisegundo para ser executada. Esses não são os valores exatos, é só para ilustrar que a diferença entre a sua latência e deles é muito significativa!

E se isso foi técnico demais, visualize essa cena…você está em uma pista de fórmula 1, dentro de um fusca e vai apostar uma corrida contra um trader de um grande fundo que opera HFT, só que ele está pilotando um Bugatti Veyron…

Acho melhor não compertirmos com esses caras….Nossa chance de sucesso é quase nula!

E por quê estamos  tanto tempo falando sobre isso? Para concluirmos que tentar implementar estratégias SCALP, que dependam de dados tick a tick, não é viável para nós pobres mortais. Nós até conseguimos rodar uma estratégia em tempo real utilizando dados tick a tick, mas não conseguimos fazer backtesting tick a tick, porque não temos os dados, e mesmo se tivéssemos precisaríamos ter um supercomputador para armazenar os dados e processar esse enorme volume de informação. E se não temos como fazer um backtesting adequado, colocar um robô para executar é como jogar na sorte…Não é o que queremos! Queremos rodar um robô que em backtesting tenha um histórico de desempenho favorável para nos dar confiabilidade para rodá-lo em conta real.

O dado OHLCV de maior frequência que conseguimos ter acesso no Profit Chart são dados de 1 minuto, e mesmo assim, atualmente, só conseguimos acessar os 3 últimos meses históricos. Este volume de dados é insuficiente para otimizar e realizar backtesting com confiabilidade adequada. Ou seja, se quiséssemos implementar uma estratégia para gráficos de 1 minuto, encontraríamos também bastante dificuldade.

Então uma dica importante é que as estratégias automatizadas começam a ser uma realidade factível com dados de 5 minutos em diante. A partir dessa frequência gráfica, você começa a ter mais chance de sucesso.

Processamento de Estratégias

Se entendermos bem o que está exposto abaixo, teremos a capacidade de resolver muito mais rapidamente eventuais problemas na hora de implementar nossas estratégias, ou talvez, até não tenhamos tantos problemas assim.

Toda estratégia no Profit Chart é processada sequencialmente, linha a linha, começando pelo begin do seu código fonte até o end.

Para cada novo dado, que em backtesting é sempre um novo candle ou renko fechado, a estratégia é processada novamente. Então se você tivermos, por exemplo, uma janela histórica de dados com 2000 elementos, a estratégia será processada 2000 vezes. Ou seja, uma vez para cada elemento de dado OHLCV, começando pelo mais antigo até o mais recente.

O pulo do gato está nas variáveis globais e a forma como elas são tratadas ao longo dos processamentos.

Por mais que declaremos variáveis globais com tipos básicos como integer ou float, no final das contas, as variáveis globais podem ser tratadas como arrays, ou no vocabulário da Nelogica, como séries. O que isto significa? Vamos a um exemplo.

Suponha que eu tenhamos uma variável global do tipo integer chamada iNum que é inicializada com o valor 1. E o código fonte da estratégia será apenas a atribuição iNum = iNum + 1. No primeiro processamento, antes de executar a linha de atribuição de iNum, iNum tem o valor 1, depois que executar a atribuição,  iNum terá o valor igual a 2., Na próxima execução, iNum começa como 2, mas depois de rodar a linha de atribuição iNum será igual a 3.

Perceba uma coisa interessante, os valores das variáveis globais são mantidos de um processamento para o próximo processamento. E, além disso, outro ponto importante é que cada execução do seu código empilha os valores das variáveis globais. 

Apesar de termos declarado iNum como um integer, esta variável pode ser acessada como se fosse um array. Se fizéssemos a referência de iNum[1], estaríamos acessando o valor de iNum da última execução (no caso, 6). Se nos referíssemos a iNum[2] estaríamos acessando o valor de iNum 2 barras antes do momento atual (no caso, 5), e assim por diante.

Compreender o empilhamento das variáveis globais é muito importante, pois fará diferença na hora de você implementar a sua estratégia/robô.

Um ponto importante a salientar é que, infelizmente, não temos como inicializar as variáveis globais antes de executar o robô ou da estratégia. É uma limitação da plataforma, mas nesse caso ainda tem como dar um jeitinho. Os templates disponibilizados aqui no site da NeoTraderBot já contemplam uma forma de inicializar as variáveis globais.

Seguindo….Como verificamos o impacto de executar o código da estratégia em backtesting apenas quando uma barra é encerrada? Se tivermos uma estratégia aplicada no backtesting a gráficos de 5 minutos, essa estratégia só vai atuar depois que fechar 5 minutos. Se a estratégia disparar uma ordem de compra ou venda a mercado, ela será executada apenas no preço de abertura da próxima barra de dados. Isso ocorre para manter premissas mais coerentes de simulação, uma vez que como não há informação sobre a dinâmica de movimento do preço dentro de uma barra fechada, o preço à mercado só pode ria ser o preço de abertura da próxima barra.

Veja o exemplo abaixo de um robô baseado em um setup de cruzamento de 3 médias, a ordem de compra/venda é realizada no candle no qual há o cruzamento da média, mas a execução sempre ocorre no preço de abertura da próxima barra.

É muito importante entender este aspecto do backtesting porque quando se roda um robô ou estratégia em tempo real, o novo dado OHLCV não é necessariamente de uma barra fechada. Para cada tick, antes de encerrar a barra de 5 minutos, o código da sua estratégia é processado. Então, se não forem tomados os devidos cuidados na programação, o comportamento em tempo real do robô será diferente do comportamento em backtesting…porque no backtesting não havia os dados tick a tick….e isso pode fazer uma grande diferença de desempenho….para melhor ou pior…não tem como saber.

Enquanto o Profit apenas permitia visualizar a estratégia de execução nos gráficos isso era um problema pequeno, porque não efetivava nenhuma ordem automaticamente…mas a partir do momento que os robôs puderem ser executados em conta real, e isto poderá ocorrer agora dia 29/setembro com o lançamento oficial do módulo de Automação de Estratégias, precisaremos ser ainda mais criterioso na escrita do código fonte das estratégias. Se quisermos manter o mesmo comportamento entre backtesting e conta real (e o ideal é isso mesmo), precisaremos garantir que as ações geradas pelo robô sejam feitas apenas no fechamento de uma barra.

É importante observar que na execução de uma estratégia em tempo real, a referência a uma variável global, mesmo que implícita (série de dados de preço do ativo), tal como High ou Máxima, um período antes será sempre o valor da variável global da barra fechada anterior (ex: HIgh[1] é sempre o preço máximo da barra fechada anterior e não o valor no tick anterior!). O valor atual da variável global não será empilhado, pois a barra está aberta, ele será apenas atualizado para cada processamento do código da estratégia, ocorrendo o empilhamento apenas quando a barra atual fechar.

Bônus: Dicas de Backtesting

Por fim, um ponto muito importante para realização adequada de backtesting de uma estratégia é SER CONSERVADOR!

É muito fácil fazer backtesting de estratégias com um desempenho tão incrível que nos faria milionários em pouco tempo de execução na conta real. Sempre desconfie desses bons resultados! Geralmente é sinal de que há algum problema no código fonte da estratégia. Ainda que não tenha gerado erro de compilação, pode ter gerado uma situação não factível no mundo real.

Uma situação muito frequente, seja por desconhecimento ou inexperiência, é programar as estratégias de execução (robôs) com ordens OCO, ou seja, com ordens de stoploss e take profit, enviando primeiramente a ordem de take profit.

Isto não é uma boa prática porque como no backtesting lidamos apenas com dados de barra fechada, o simulador não tem como saber dentro de uma barra OHLCV que engloba tanto o preço do stop quanto do take profit, qual preço foi atingido primeiro.

O simulador então utilizará a ordem que foi enviada primeiro. Assim, é uma boa prática sempre colocar o envio de ordens de stoploss antes das ordens de take profit. Fazendo isso, estaremos sendo conservadores. O desempenho da estratégia pode até ser pior do que seria se houvesse dados de tempo real, mas estremos gerenciando melhor nossa expectativa em relação ao desempenho provável em conta real.

Outra boa prática de backtesting é analisar a sensibilidade do robô a condições de Slippage.

Slippage é o escorregamento de preço de ordens enviadas para corretora. O que significa isso? É a diferença entre o preço da ordem enviada e o preço de execução. Por exemplo, se enviamos uma ordem de compra a mercado quando determinado ativo é  negociado a R$ 23,50, mas a ordem acaba sendo executada a R$ 23,53, tivemos um slippage de 3 centavos.

Felizmente, no Profit Chart é possível simular o desempenho de um robô com slippage de forma bem simples, bastando informar a quantidade de ticks. O slippage será aplicado para cada ordem a mercado enviada. Veja na figura abaixo onde configurar o slippage no backtesting.

Finalizando...

Se achou interessante o conteúdo deste documento e acha que existem outros pontos a serem conhecidos antes que um trader implemente sua primeira estratégia automatizada, deixe seu comentário abaixo!

Nos próximos documentos passaremos enfim para a parte prática: escrever as estratégias em código fonte!

Templates de Estratégias (Modelos pré-configurados)

Introdução

Os Templates de Estratégias da NeoTraderBot servem para padronizar e organizar a estrutura inicial dos códigos fontes das estratégias que iremos implementar.

Ao invés de abrir o Editor de Estratégias vazio e começar tudo de novo….podemos otimizar nosso tempo com as experiências acumuladas na Comunidade e reutilizar padrões que já contemplam algumas das melhores práticas de desenvolvimento de estratégias e robôs.

Todos os modelos estão salvos no repositório GitHub da NeoTraderBot e, para facilitar ainda mais a nossa vida, eles também estão copiados abaixo em suas últimas versões. Assim, ao invés de você ter que importar os modelos em arquivo .psf, você pode simplesmente copiar o modelo desejado e colar no seu Editor!

Comente as partes que não for utilizar em um primeiro momento pois elas podem vir a ser usadas a medida que o seu código-fonte evolui.

Utilize o menu direito dessa página para ir direto ao Template desejado.

Modelo de Estratégia de Execução (Robôs)

				
					// #######################################################################
// #######################################################################
// #######################################################################
// ######                            O                             #######
// ######                        ____|____                         #######
// ######                      _|         |_                       #######
// ######                     (_|  O   O  |_)                      #######
// ######                       |_________|                        #######
// ######                                                          #######
// ###### ____        __        ____________           ________    #######
// ###### | | \       | |       | |_________|         /  ____  \   #######
// ###### | |\ \      | |       | |                  /  /    \  \  #######
// ###### | | \ \     | |       | |____             |  |      |  | #######
// ###### | |  \ \    | |       | |____|            |  |      |  | #######
// ###### | |   \ \   | |       | |____|            |  |      |  | #######
// ###### | |    \ \  | |       | |                 |  |      |  | #######
// ###### | |     \ \ | |       | |_________         \  \____/  /  #######
// ###### |_|      \_\|_|       |_|_________|         \________/   #######
// ######                                                          #######
// ###### _______  __          __   ____  __   ___    __  _______  #######
// ######    |    |  \   /\   |  \ |     |  \ |   \  /  \    |     #######
// ######    |    |__/  /__\  |   ||__   |__/ |___/ |    |   |     #######
// ######    |    |\   /    \ |   ||     |\   |   \ |    |   |     #######
// ######    |    | \ /      \|__/ |____ | \  |___/  \__/    |     #######
// ######                                                          #######
// ######  Comunidade aberta de automatização de estratégias para  #######
// ######                    negociação de ativos                  #######
// ######                                                          #######
// ######                    www.NeoTraderBot.com                  #######
// #######################################################################
// #######################################################################
// #######################################################################
//
// -----------------------------------------------------------------------
// ---------------------- DADOS DA ESTRATÉGIA ----------------------------
// -----------------------------------------------------------------------
//
// NOME DA ESTRATÉGIA: 
//   DESENVOLVIDA POR: 
//    DATA DE CRIAÇÃO: 
//             VERSÃO: 
//      ATUALIZADA EM: 
// TIPO DE ESTRATÉGIA: ( ) Indicador  ( ) Coloração (X) Execução
//                     ( ) Screening  ( ) Texto     ( ) Alarme
//
// DESCRIÇÃO DA ESTRATÉGIA:
//
//
//
// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
//
// ######################### FIM DO CABEÇALHO ############################
//
//
// -----------------------------------------------------------------------
// -------------------------- Constantes ---------------------------------
// OBS: 
// -----------------------------------------------------------------------
const
  cPlotarIndicadores = true;  
  //
  // ---------------------------------------------------------------------
  // -------------------------- Parâmetros -------------------------------
  // OBS: Segue abaixo a descrição de cada parâmetro
  // 1) pXXXXXX -> 
  // 
  // 2) pYYYYYY -> 
  // 
  // 3) pZZZZZZ -> 
  // ---------------------------------------------------------------------
input
  pXXXXX(5);
  pYYYYY(True);
  pZZZZZ(2.3);

  // ---------------------------------------------------------------------
  // ---------------------- Variáveis globais ----------------------------
  // OBS:
  // ---------------------------------------------------------------------
var
//Estrutura padrão do modelo
bStarted: boolean;
bSinalCompra, bSinalVenda, bSinalLiquida, bSinalReversao : boolean;
bComprado, bVendido : boolean;

//Variáveis personalizadas
iXXXXX, iZZZZZZ: integer;
fXXXXX, fZZZZZZ: float;



begin

  // ---------------------------------------------------------------------
  // ----------------- Inicialização da estratégia -----------------------
  // OBS: Inicialização de variáveis a serem utilizadas na estratégia de 
  // execução
  // ---------------------------------------------------------------------
  if Not bStarted then
  begin
    bStarted := True;
    //Colocar aqui ações que serão executadas apenas no primeiro processamento
    //da estratégia. Por exemplo, inicialização de variáveis.
  end;

  // ---------------------------------------------------------------------
  // ------------ Atribuição de variáveis por processamento --------------
  // ---------------------------------------------------------------------
  //Estrutura padrão do modelo
  bSinalCompra := False;
  bSinalVenda := False;
  bSinalLiquida := False;
  bSinalReversao := False;
  bComprado := isBought();
  bVendido := isSold();

  // Atribuições das variáveis da estratégia




  // ---------------------------------------------------------------------
  // ----------------------- Cálculo dos sinais  -------------------------
  // OBS: Inserir lógica de cálculo dos sinais de compra/venda/liquidação
  // e reversão, se for o caso.
  // ---------------------------------------------------------------------
  if (...) then
      bSinalCompra := True;

  if (...) then
      bSinalVenda := True;

  if bComprado then
    if (...) then
      bSinalLiquida := True;

  if bVendido then
    if (...) then
      bSinalLiquida := True;

  if bComprado or bVendido then
      bSinalReversao := True;                  


  // ---------------------------------------------------------------------
  // -------------- Administração das posições abertas -------------------
  // OBS: Baseando-se na posição aberta, pode-se implementar lógicas para 
  // atualização de alvo ou stoploss
  // ---------------------------------------------------------------------    
  if bComprado then
  begin

  end;

  if bVendido then
  begin

  end;

  // ---------------------------------------------------------------------
  // ------------------- Envia ordens de compra/venda --------------------
  // OBS: Baseando-se nos sinais e na atual posição, cria as ordens de 
  // compra e venda de acordo com o setup desejado
  // --------------------------------------------------------------------- 

  




  // ---------------------------------------------------------------------
  // ------------------------ Plot de Indicadores ------------------------
  // OBS: É sempre interessante incluir indicadores usados pelo robô para
  // poder visualizar no gráfico do Módulo de Automação de Estratégias 
  // --------------------------------------------------------------------- 
  if cPlotarIndicadores then
  begin
    Plot(...);
    Plot2(...);
    Plot3(...);

  end;

end;









				
			

Modelo de Estratégia de Coloração

				
					// #######################################################################
// #######################################################################
// #######################################################################
// ######                            O                             #######
// ######                        ____|____                         #######
// ######                      _|         |_                       #######
// ######                     (_|  O   O  |_)                      #######
// ######                       |_________|                        #######
// ######                                                          #######
// ###### ____        __        ____________           ________    #######
// ###### | | \       | |       | |_________|         /  ____  \   #######
// ###### | |\ \      | |       | |                  /  /    \  \  #######
// ###### | | \ \     | |       | |____             |  |      |  | #######
// ###### | |  \ \    | |       | |____|            |  |      |  | #######
// ###### | |   \ \   | |       | |____|            |  |      |  | #######
// ###### | |    \ \  | |       | |                 |  |      |  | #######
// ###### | |     \ \ | |       | |_________         \  \____/  /  #######
// ###### |_|      \_\|_|       |_|_________|         \________/   #######
// ######                                                          #######
// ###### _______  __          __   ____  __   ___    __  _______  #######
// ######    |    |  \   /\   |  \ |     |  \ |   \  /  \    |     #######
// ######    |    |__/  /__\  |   ||__   |__/ |___/ |    |   |     #######
// ######    |    |\   /    \ |   ||     |\   |   \ |    |   |     #######
// ######    |    | \ /      \|__/ |____ | \  |___/  \__/    |     #######
// ######                                                          #######
// ######  Comunidade aberta de automatização de estratégias para  #######
// ######                    negociação de ativos                  #######
// ######                                                          #######
// ######                    www.NeoTraderBot.com                  #######
// #######################################################################
// #######################################################################
// #######################################################################
//
// -----------------------------------------------------------------------
// ---------------------- DADOS DA ESTRATÉGIA ----------------------------
// -----------------------------------------------------------------------
//
// NOME DA ESTRATÉGIA: 
//   DESENVOLVIDA POR: 
//    DATA DE CRIAÇÃO: 
//             VERSÃO: 
//      ATUALIZADA EM: 
// TIPO DE ESTRATÉGIA: ( ) Indicador  (X) Coloração ( ) Execução
//                     ( ) Screening  ( ) Texto     ( ) Alarme
//
// DESCRIÇÃO DA ESTRATÉGIA:
//     
// 
// 
// 
// 
// 
//
// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
//
// ######################### FIM DO CABEÇALHO ############################
//
//
// -----------------------------------------------------------------------
// -------------------------- Constantes ---------------------------------
// OBS: 
// -----------------------------------------------------------------------
const
  cXXXXXX = true;  
  //
  // ---------------------------------------------------------------------
  // -------------------------- Parâmetros -------------------------------
  // OBS: Segue abaixo a descrição de cada parâmetro
  // 1) pXXXXXX -> 
  // 
  // 2) pYYYYYY -> 
  // 
  // 3) pZZZZZZ -> 
  // ---------------------------------------------------------------------
input
  pXXXXX(5);
  pYYYYY(True);
  pZZZZZ(2.3);

  // ---------------------------------------------------------------------
  // ---------------------- Variáveis globais ----------------------------
  // OBS:
  // ---------------------------------------------------------------------
var
//Estrutura padrão do modelo
bStarted: boolean;


//Variáveis personalizadas
iXXXXX, iZZZZZZ: integer;
fXXXXX, fZZZZZZ: float;


begin
  // ---------------------------------------------------------------------
  // ----------------- Inicialização da estratégia -----------------------
  // OBS: Inicialização de variáveis a serem utilizadas na estratégia de 
  // coloração
  // ---------------------------------------------------------------------
  if Not bStarted then
  begin
    bStarted := True;
    //Colocar aqui ações que serão executadas apenas no primeiro processamento
    //da estratégia. Por exemplo, inicialização de variáveis.
  end;


  // ---------------------------------------------------------------------
  // ------------ Atribuição de variáveis por processamento --------------
  // ---------------------------------------------------------------------
  // Atribuições das variáveis da estratégia



  // ---------------------------------------------------------------------
  // ---------------------- Lógica de coloração  -------------------------
  // OBS: Inserir lógica de cálculo para coloração do gráfico 
  // ---------------------------------------------------------------------
  if (...) then
  begin
    PaintBar()
  end
  else
    if (...) then
    begin
      PaintBar()
    end;

    


end;
































				
			

Modelo de Estratégia de Indicador

				
					// #######################################################################
// #######################################################################
// #######################################################################
// ######                            O                             #######
// ######                        ____|____                         #######
// ######                      _|         |_                       #######
// ######                     (_|  O   O  |_)                      #######
// ######                       |_________|                        #######
// ######                                                          #######
// ###### ____        __        ____________           ________    #######
// ###### | | \       | |       | |_________|         /  ____  \   #######
// ###### | |\ \      | |       | |                  /  /    \  \  #######
// ###### | | \ \     | |       | |____             |  |      |  | #######
// ###### | |  \ \    | |       | |____|            |  |      |  | #######
// ###### | |   \ \   | |       | |____|            |  |      |  | #######
// ###### | |    \ \  | |       | |                 |  |      |  | #######
// ###### | |     \ \ | |       | |_________         \  \____/  /  #######
// ###### |_|      \_\|_|       |_|_________|         \________/   #######
// ######                                                          #######
// ###### _______  __          __   ____  __   ___    __  _______  #######
// ######    |    |  \   /\   |  \ |     |  \ |   \  /  \    |     #######
// ######    |    |__/  /__\  |   ||__   |__/ |___/ |    |   |     #######
// ######    |    |\   /    \ |   ||     |\   |   \ |    |   |     #######
// ######    |    | \ /      \|__/ |____ | \  |___/  \__/    |     #######
// ######                                                          #######
// ######  Comunidade aberta de automatização de estratégias para  #######
// ######                    negociação de ativos                  #######
// ######                                                          #######
// ######                    www.NeoTraderBot.com                  #######
// #######################################################################
// #######################################################################
// #######################################################################
//
// -----------------------------------------------------------------------
// ---------------------- DADOS DA ESTRATÉGIA ----------------------------
// -----------------------------------------------------------------------
//
// NOME DA ESTRATÉGIA: 
//   DESENVOLVIDA POR: 
//    DATA DE CRIAÇÃO: 
//             VERSÃO: 
//      ATUALIZADA EM: 
// TIPO DE ESTRATÉGIA: (X) Indicador  ( ) Coloração ( ) Execução
//                     ( ) Screening  ( ) Texto     ( ) Alarme
//
// DESCRIÇÃO DA ESTRATÉGIA:
// 
// 
// 
// 
// 
// 
//
// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
//
// ######################### FIM DO CABEÇALHO ############################
//
//
// -----------------------------------------------------------------------
// -------------------------- Constantes ---------------------------------
// OBS: 
// -----------------------------------------------------------------------
const
  cCONSTANTE = 1;
  //
  // ---------------------------------------------------------------------
  // -------------------------- Parâmetros -------------------------------
  // OBS: Segue abaixo a descriação de cada parâmetro
  // 1) parametro1 -> 
  // 2) parametro2 -> 
  // ---------------------------------------------------------------------
input
  pParametro(1);
  // ---------------------------------------------------------------------
  // ---------------------- Variáveis globais ----------------------------
  // OBS:
  // ---------------------------------------------------------------------
var
bStarted, 	bPlotIndicador: boolean;
begin
  // ---------------------------------------------------------------------
  // ----------------- Inicialização da estratégia -----------------------
  // OBS: Inicialização de variáveis a serem utilizadas na estratégia de 
  // execução
  // ---------------------------------------------------------------------
  if Not bStarted then
  begin
    bStarted := True;
    //Colocar aqui ações que serão executadas apenas no primeiro processamento
    //da estratégia. Por exemplo, inicialização de variáveis.
  end;


  // ---------------------------------------------------------------------
  // ------------ Atribuição de variáveis por processamento --------------
  // ---------------------------------------------------------------------



  // ---------------------------------------------------------------------
  // --------------------- Cálculo do indicador  -------------------------
  // OBS: Inserir lógica de cálculo do indicador e caso ele possa ser plo_
  // tado, atribuir em algum momento True para variável bPlotIndicador 
  // ---------------------------------------------------------------------
  bPlotIndicador := false;




  //
  // ---------------------------------------------------------------------
  // ------------------ Plota valores do indicador -----------------------
  // OBS: Atribuir na sessão anterior o valor para variavel bPlotIndicador
  // quando for possível plotar um valor para o indicador no instante atual
  // ---------------------------------------------------------------------
  if bPlotIndicador then
    begin
      Plot(cCONSTANTE);
    end;   

end;









				
			

Modelo de Estratégia de Screening

				
					// #######################################################################
// #######################################################################
// #######################################################################
// ######                            O                             #######
// ######                        ____|____                         #######
// ######                      _|         |_                       #######
// ######                     (_|  O   O  |_)                      #######
// ######                       |_________|                        #######
// ######                                                          #######
// ###### ____        __        ____________           ________    #######
// ###### | | \       | |       | |_________|         /  ____  \   #######
// ###### | |\ \      | |       | |                  /  /    \  \  #######
// ###### | | \ \     | |       | |____             |  |      |  | #######
// ###### | |  \ \    | |       | |____|            |  |      |  | #######
// ###### | |   \ \   | |       | |____|            |  |      |  | #######
// ###### | |    \ \  | |       | |                 |  |      |  | #######
// ###### | |     \ \ | |       | |_________         \  \____/  /  #######
// ###### |_|      \_\|_|       |_|_________|         \________/   #######
// ######                                                          #######
// ###### _______  __          __   ____  __   ___    __  _______  #######
// ######    |    |  \   /\   |  \ |     |  \ |   \  /  \    |     #######
// ######    |    |__/  /__\  |   ||__   |__/ |___/ |    |   |     #######
// ######    |    |\   /    \ |   ||     |\   |   \ |    |   |     #######
// ######    |    | \ /      \|__/ |____ | \  |___/  \__/    |     #######
// ######                                                          #######
// ######  Comunidade aberta de automatização de estratégias para  #######
// ######                    negociação de ativos                  #######
// ######                                                          #######
// ######                    www.NeoTraderBot.com                  #######
// #######################################################################
// #######################################################################
// #######################################################################
//
// -----------------------------------------------------------------------
// ---------------------- DADOS DA ESTRATÉGIA ----------------------------
// -----------------------------------------------------------------------
//
// NOME DA ESTRATÉGIA: 
//   DESENVOLVIDA POR: 
//    DATA DE CRIAÇÃO: 
//             VERSÃO: 
//      ATUALIZADA EM: 
// TIPO DE ESTRATÉGIA: ( ) Indicador  ( ) Coloração ( ) Execução
//                     (X) Screening  ( ) Texto     ( ) Alarme
//
// DESCRIÇÃO DA ESTRATÉGIA:
//     
// 
// 
// 
// 
// 
//
// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
//
// ######################### FIM DO CABEÇALHO ############################
//
//
// -----------------------------------------------------------------------
// -------------------------- Constantes ---------------------------------
// OBS: 
// -----------------------------------------------------------------------
const
  cXXXXXX = true;  
  //
  // ---------------------------------------------------------------------
  // -------------------------- Parâmetros -------------------------------
  // OBS: Segue abaixo a descrição de cada parâmetro
  // 1) pXXXXXX -> 
  // 
  // 2) pYYYYYY -> 
  // 
  // 3) pZZZZZZ -> 
  // ---------------------------------------------------------------------
input
  pXXXXX(5);
  pYYYYY(True);
  pZZZZZ(2.3);

  // ---------------------------------------------------------------------
  // ---------------------- Variáveis globais ----------------------------
  // OBS:
  // ---------------------------------------------------------------------
var
//Estrutura padrão do modelo
bStarted: boolean;


//Variáveis personalizadas
iXXXXX, iZZZZZZ: integer;
fXXXXX, fZZZZZZ: float;


begin
  // ---------------------------------------------------------------------
  // ----------------- Inicialização da estratégia -----------------------
  // OBS: Inicialização de variáveis a serem utilizadas na estratégia de 
  // coloração
  // ---------------------------------------------------------------------
  if Not bStarted then
  begin
    bStarted := True;
    //Colocar aqui ações que serão executadas apenas no primeiro processamento
    //da estratégia. Por exemplo, inicialização de variáveis.
  end;


  // ---------------------------------------------------------------------
  // ------------ Atribuição de variáveis por processamento --------------
  // ---------------------------------------------------------------------
  // Atribuições das variáveis da estratégia



  // ---------------------------------------------------------------------
  // ---------------------- Lógica de coloração  -------------------------
  // OBS: Inserir lógica de cálculo para coloração do gráfico 
  // ---------------------------------------------------------------------
  if (...) then
  begin
    Select()
  end
  else
    if (...) then
    begin
      Select();
    end;

    


end;
































				
			

Códigos de exemplo? Tome Snippets!

Aprender a programar envolve esforço, persistência e também colaboração com outros programadores (esse é um dos benefícios de participar de uma Comunidade como a NeoTraderBot!).

Pensando em acelerar a curva de aprendizado e reduzir o tempo que ficamos presos com problemas de programação, organizamos esta área de Snippets para elaboração de estratégias no Profit Chart.

Os Snippets são trechos de códigos independentes, autocontidos e funcionais. Ou seja, cada Snippet pode ser executado sem erros, é autocontido porque executa de início ao fim uma determinada tarefa, sendo assim funcional. Eles podem ser copiados e modificados de acordo com a necessidade do usuário

Navegue abaixo pelas categorias disponíveis e caso tenha alguma sugestão de nova categoria ou tarefa, comente nas áreas apropriadas. Caso tenha colegas que também possam fazer bom uso e contribuir com a Comunidade, compartilhe esta área do site pelos ícones abaixo.

 

Compartilhe essa página!

Share on facebook
Facebook
Share on telegram
Telegram
Share on whatsapp
WhatsApp
Share on email
Email

Snippets para Localização Temporal

Nesta área você terá acesso a pedaços de códigos fontes para localização da estratégia em relação ao tempo.

Tarefas disponibilizadas:

Snippets para Manipulação de Gráficos

Nesta área você terá acesso a pedaços de códigos fontes para manipular plot, cores de plotagem, espessura, tipo de gráfico, etc.

Tarefas disponibilizadas:

 

Snippets para Utilização de Indicadores da Plataforma

Nesta área você terá acesso a pedaços de códigos fontes para utilizar os indicadores disponibilizados por padrão na Plataforma.

Tarefas disponibilizadas:

 

Snippets para Localização Temporal

Introdução

Esta seção visa apresentar trechos de códigos com funcionalidades relativas à localização temporal da estratégia. Por exemplo, identificar se a atual barra é a primeira barra do dia para verificar gap diário.

Você pode acessar os Snippets diretamente pelo menu lateral direito, ou fazendo CTRL+F (CTRL+L) para localizar algum texto específico na página, uma vez que o conteúdo tende a crescer ao longo do tempo, dificultando a navegação pelo menu.

Caso tenham sugestões de código para acrescentar à lista, gentileza deixar o código nos comentários com o link para seu perfil em rede social (para devido crédito de autoria).

Snippets

Identificação do primeiro candle de cada dia

Reproduzir vídeo

Algumas estratégias necessitam da identificação da primeira barra do dia (candle) para executar determinada ação ou calcular o gap em relação ao fechamento do dia anterior.

				
					var
  bPrimeiraBarraDoDia : boolean;
  iDataAtual          : integer;
begin
  if (Date() <> iDataAtual) then
    begin
      iDataAtual := Date();
      bPrimeiraBarraDoDia := true;
    end;
  if bPrimeiraBarraDoDia then
    begin
      bPrimeiraBarraDoDia := false;
      //Faz alguma coisa na primeira barra do dia
      paintBar(clGreen);
    end;
end;
				
			

Identificação de barra por data e hora específicos

Este código localiza a barra (candle ou box) por uma data e hora desejados. Onde a hora é referente ao horário de abertura do candle desejado. Observa-se que existe uma parte do código comentada para utilização em backtesting de gráficos de renko.

OBS: As variáveis pDataDesejada e pHorarioDesejado não foram declaradas como parâmetros para facilitar o teste do Snippet, uma vez que não é possível alterar parâmetro dentro do Editor de Estratégias.

				
					var
  bBarraDesejada                 : boolean;
  pDataDesejada,pHorarioDesejado : integer;
begin
  pDataDesejada := 20220928;
  pHorarioDesejado := 1200;
  if (Date() = ELDate_Consol(pDataDesejada)) And (Time() = pHorarioDesejado) then
    begin
      bBarraDesejada := true;
      //Faz alguma coisa na barra identificada
      paintBar(clGreen);
    end
  else 
    bBarraDesejada := false;
end;
				
			

Identificação do primeiro tick de uma barra

Reproduzir vídeo

Este código identifica o primeiro tick de uma barra. Este Snippet tem aplicação apenas quando a estratégia é utlizada em tempo real.

OBS: É importante ressaltar que em backtesting com dados históricos não há dados tick a tick. Desta forma, este Snippet não possui aplicação em backtesting com dados de barra a barra.

				
					var
  bPrimeiroTickDaBarra : boolean;
  iBarraAtual          : integer;
begin
  if LastBarOnChart then
    if (CurrentBar <> iBarraAtual) then
      begin
        iBarraAtual := CurrentBar;
        bPrimeiroTickDaBarra := true;
      end
  else 
    bPrimeiroTickDaBarra := false;
  if bPrimeiroTickDaBarra then
    begin
      //Faz alguma coisa no primeiro tick da barra
      //Aplicável apenas em execução de tempo real
      paintBar(clGreen);
    end
  else 
    begin
      //Faz alguma coisa nos demais ticks da barra atual
      //Aplicável apenas em execução de tempo real
      paintBar(clYellow);
    end;
end;
				
			

Contador de Candles do dia

Este código realiza a contagem de barras dentro de um mesmo dia.

				
					var
  bPrimeiraBarraDoDia : boolean;
  iDataAtual          : integer;
  iCurrentBarIntraday, iFirstBarOfDay : integer;
begin
  if (Date() <> iDataAtual) then
    begin
      iDataAtual := Date();
      bPrimeiraBarraDoDia := true;
      iFirstBarOfDay := CurrentBar;
    end;
  if bPrimeiraBarraDoDia then
    begin
      bPrimeiraBarraDoDia := false;
      //Faz alguma coisa na primeira barra do dia
      paintBar(clGreen);
    end;

    iCurrentBarIntraday := CurrentBar - iFirstBarOfDay + 1;
    plotText(iCurrentBarIntraday, clWhite,0, 12);

end;
				
			

Manipulação de Gráficos

Introdução

Esta seção visa apresentar trechos de códigos com funcionalidades relativas à manipulação de gráficos e coloração.

Você pode acessar os Snippets diretamente pelo menu lateral direito, ou fazendo CRL+F (CTRL+L) para localizar algum texto específico na página, uma vez que o conteúdo tende a crescer ao longo do tempo, dificultando a navegação pelo menu.

Caso tenham sugestões de código para acrescentar à lista, gentileza deixar o código nos comentários com o link para seu perfil em rede social (para devido crédito de autoria).

Snippets

Como plotar mais de uma série de dados e Personalizar plot

Este código plota duas séries de valores constantes a fim de demonstrar como personalizar os atributos gráficos dos plots.

OBS: O preenchimento entre séries só pode ser configurado via interface gráfica. Verificar as constantes para tipos de gráficos e estilos de linhas.

				
					const
  cSerieA = 3;
  cSerieB = 2;
begin
  SetPlotColor(1,clGreen);
  SetPlotWidth(1,2);
  SetPlotStyle(1,psDashDot);
  SetPlotType(1,igLine);
  plotN(1,cSerieA);
  
  SetPlotColor(2,clRed);
  SetPlotStyle(2,psDashDot);
  SetPlotType(2,igHistogram);
  plotN(2,cSerieB);
end;
				
			

Utilização de Indicadores da Plataforma

Introdução

Esta seção visa apresentar trechos de códigos com exemplos de utilização dos indicadores disponibilizados na plataforma.

Você pode acessar os Snippets diretamente pelo menu lateral direito, ou fazendo CRL+F (CTRL+L) para localizar algum texto específico na página, uma vez que o conteúdo tende a crescer ao longo do tempo, dificultando a navegação pelo menu.

Caso tenham sugestões de código para acrescentar à lista, gentileza deixar o código nos comentários com o link para seu perfil em rede social (para devido crédito de autoria).

Snippets

Sugira um primeiro Snippet nos comentários!!!

				
					...
				
			

Ordens e Administração de Trade

Introdução

Esta seção visa apresentar trechos de códigos com exemplos de envio de ordens e administração de trade utilizando técnicas de stoploss (fixo, móvel, breakeven) e take profit.

Você pode acessar os Snippets diretamente pelo menu lateral direito, ou fazendo CRL+F (CTRL+L) para localizar algum texto específico na página, uma vez que o conteúdo tende a crescer ao longo do tempo, dificultando a navegação pelo menu.

Caso tenham sugestões de código para acrescentar à lista, gentileza deixar o código nos comentários com o link para seu perfil em rede social (para devido crédito de autoria).

Snippets

Como limitar a quantidade de trades por dia

Reproduzir vídeo

O código abaixo apresenta a funcionalidade em código fonte para limitar a quantidade de trades realizados pela sua estratégia/ robô (constante cQtdeMaxOperacoesNoDia).

Apesar do Módulo de Automação possui um limite de perda e ganho diário, ele não possui esta funcionalidade. Idealmente, a Nelogica deveria disponbilizar funções para verificação do resultado bruto alcançado até o momento para permitir outras forma de gestão de risco em código fonte.

				
					const
  // Mude aqui a qtde maxima de trades por dia 
  cQtdeMaxOperacoesNoDia = 5;

var 
  iQtdeOperacoesNoDia: integer;
  iDataAtual: integer;
  bJaContouOperacao: boolean;
  fMedia: float;

begin
  // Inicialização do contador de ordens do dia  
  if Date <> iDataAtual then
  begin
    iDataAtual := Date;
    iQtdeOperacoesNoDia := 0;
    bJaContouOperacao := false;
  end;
  
  // Setup de cruzamento de Media movel só para gerar operações
  fMedia := Media(3,Close);

  // Realiza abertura de posições apenas se número maximo de operação
  // não tiver sido atingido
  if iQtdeOperacoesNoDia < cQtdeMaxOperacoesNoDia then
  begin
    // COMPRA se fechamento cruzar media para cima e
    // VENDE se fechamento cruzar media pra baixo
    if (Close > fMedia) and (Close[1] <= fMedia[1]) and Not HasPosition then BuyAtMarket;       
    if (Close < fMedia) and (Close[1] >= fMedia[1]) and Not HasPosition then SellShortAtMarket;
  end;
  
  // Contabiliza a abertura da posição como mais uma operação no dia   
  if (isBought or isSold) and Not bJaContouOperacao then
  begin
    iQtdeOperacoesNoDia := iQtdeOperacoesNoDia + 1;
    bJaContouOperacao := true;  
  end;

  // Posiciona ordens para gestão do trade
  if isBought then
  begin
    SellShortStop(buyPrice - 5*MinPriceIncrement);
    SellShortLimit(buyPrice + 15*MinPriceIncrement);
  end;

  // Posiciona ordens para gestão do trade
  if isSold then
  begin
    BuyStop(sellPrice + 5*MinPriceIncrement);
    BuyLimit(sellPrice - 15*MinPriceIncrement);
  end;
  
  // Encerra posicao no mesmo dia
  if (Time >= 1645) and hasPosition then ClosePosition;

  // Se posição for encerrada ativa novamente o contador
  if Not IsBought and Not isSold and bJaContouOperacao then bJaContouOperacao := false;  

  // Apenas para inspeção gráfica do sinal
  Plot(fMedia);
  
end
				
			

Como limitar trades por objetivo de ganho ou limite de perda

Reproduzir vídeo

O código abaixo apresenta a funcionalidade em código fonte para limitar a realização de trades baseado no resultado do dia.

Caso o resultado das operações da estratégia atinja o objetivo de ganho ou o limite de perda, fornecidos em valores absolutos e unidade financeira pelos parâmetros pLimitePerdaDiaria e pObjetivoGanhoDiario, a estratégia não realiza mais operações e encerra posições abertas.

O parâmetro pPlotarResultado pode receber os valores “FECHADO”, “ABERTO” e “TOTAL”, para se referir ao resultado de trades fechados, resultado do trade em aberto e resultado total do dia (FECHADO + ABERTO), respectivamente.

				
					input
  pPlotarResultado("ABERTO");
  pLimitePerdaDiaria(200.00);
  pObjetivoGanhoDiario(600.00);

var
  fResultado: float;
  fResultadoDiario: float;
  iDataTeste: integer;
  iHora: integer;
begin
  //-----------------------------------------------------------
  //Plots podem ser excluídos...servem apenas para demonstração

  // Resultado fechado do dia
  If pPlotarResultado = "FECHADO" then
  begin
    fResultado := DailyResult(false);
    plot(fResultado);
    SetPlotStyle(1,psSolid);
    SetPlotColor(1,clWhite);
  end;

  // Resultado até o momento no dia (fechado + aberto)
  If pPlotarResultado = "TOTAL" then
  begin
    fResultado := DailyResult(true);
    plot2(fResultado);
    SetPlotStyle(2,psDash);
    SetPlotColor(2,clRed);
  end;

  // Resultado do trade aberto
  If pPlotarResultado = "ABERTO" then
  begin
    fResultado := DailyResult(true) - DailyResult(false); 
    if fResultado <> 0 then
      plot3(fResultado);
    SetPlotStyle(3,psDash);
    if fResultado >= 0  then SetPlotColor(3,clGreen)
    else SetPlotColor(3,clRed);
    SetPlotType(3, igHistogram);
  end;
  //-----------------------------------------------------------


  // Estratégias apenas opera se resultado do dia não 
  // tiver atingido objetivo de ganho ou limite de perda
  iDataTeste := ELDate(2023,2,10);
  fResultadoDiario := DailyResult(true);
  
  if (fResultadoDiario > -1*pLimitePerdaDiaria)
  and (fResultadoDiario < pObjetivoGanhoDiario) then
  begin
    // SIMULAÇÃO DE ORDENS PARA FINS DE EXEMPLO
    for iHora := 0 to 8 do
    begin
      if (Date = iDataTeste) and (Time = (0900 + iHora*100)) then
        if random(2) = 0 then BuyAtMarket else SellShortAtMarket;
  
      if (Date = iDataTeste) and (Time = (0930 + iHora*100)) then
        ClosePosition;
    end;

  end
  //Se resultado excedeu objetivo de ganho ou limite de perda
  //e houver posição aberta, então encerra a posição.
  else if hasPosition then ClosePosition;
                
            
end;
				
			

Limite de horário para encerramento de posição

Reproduzir vídeo

O código abaixo apresenta a funcionalidade em código fonte para encerramento de posição a partir de um determinado horário. É um exemplo útil para quem opera daytrade e não deseja/não pode correr o risco de carregar operação para o dia seguinte.

				
					var
  bBarraDesejada                 : boolean;
  pDataDesejada,pHorarioDesejado : integer;
  //Util apenas para Backtesting em Gráfico de Renko  
  pMargemMinutos: integer;  
begin
  pHorarioDesejado := 1645;
  pMargemMinutos := 15;
  //Para Gráficos de Candle/Renko executados em tempo real
  //if Time > pHorarioDesejado then

  //Para Gráficos de Renko, em backtesting, utiliza-se uma margem de tempo em torno do horário desejado
  if  (Time >= CalcTIme(pHorarioDesejado, -pMargemMinutos)) then
    begin
      bBarraDesejada := true;
      //Encerra posição caso esteja comprado/vendido
      if isBought or isSold then ClosePosition;
    end
  else
    bBarraDesejada := false;
end;
				
			

Stoploss simples (fixo)

Reproduzir vídeo

O código abaixo apresenta um exemplo de stoploss fixo e take profit (alvo de lucro da operação), para uma relação de risco/ganho de 3:1 em função de quantidade de ticks, aplicado a uma estratégia de posicionamento. O código tem um limite de horário para abertura e fechamento de posição, o qual pode ser alterado pelos parâmetros.

OBS 1: A versão é compatível com o Editor de Estratégias e Módulo de Automação de Estratégias. Devido a um bug do Profit, é necessário ter um comando ClosePosition, pois do contrário a ferramenta informa equivocadamente que não existem ordens para encerrar posição.

				
					const
 //Relação risco/ganho de 3:1
 cStopEmTicks = 10;
 cAlvoEmTicks = 30;
 cStopOffsetEmTicks = 50;

input
  bGestaoDeRiscoPelaEstrategia(true);
  iHorarioInicioAberturaPosicao(0905);
  iHorarioFimAberturaPosicao(1630);
  iHorarioEncerramentoDaytrade(1645);

var
  iCaraCoroa: integer;
  bSinalCompra, bSinalVenda, bPosicionado: boolean;
  fPrecoStop, fPrecoAlvo, fPrecoStopOffset: float;
  bConfigurouRisco: boolean;

begin

  bSinalCompra := false;
  bSinalVenda := false;
  bPosicionado := hasPosition;

  //ESTRATÉGIA CARA OU COROA!
  //Gera um numero aleatorio de 0 a 9. Se for menor igual a 4, gera
  //sinal de compra, se for maior que 4 geral sinal de venda
  if Not bPosicionado
  and (Time >= iHorarioInicioAberturaPosicao)
  and (Time <= iHorarioFimAberturaPosicao)
  then
  begin
    //Número aleatório foi substituido por minuto par ou impar para permitir depurar
    //melhor o robô quando a estratégia é inserida multiplas vezes: como indicador  e como execução
    //iCaraCoroa := Random(10);
    iCaraCoroa := mod(Time,2);
    if iCaraCoroa = 0 then bSinalCompra := true
    else bSinalVenda := true;
  end;


  //Gera ordem de compra a mercado quando há um Sinal de COMPRA
  //e define ordem stoploss e take profit
  if bSinalCompra then BuyAtMarket;

  //Gera ordem de venda a mercado quando há um Sinal de VENDA
  //e define ordem stoploss e take profit
  if bSinalVenda then SellShortAtMarket;

  if bGestaoDeRiscoPelaEstrategia then
  begin
    //POSIÇÃO COMPRADA
    //Código responsável pela manutenção das ordens de stoploss e take profit
    if isBought then
    begin
      if not bConfigurouRisco then
      begin
        fPrecoStop := BuyPrice - cStopEmTicks*MinPriceIncrement;
        fPrecoAlvo := BuyPrice + cAlvoEmTicks*MinPriceIncrement;
        fPrecoStopOffset := fPrecoStop - cStopOffsetEmTicks*MinPriceIncrement;
        bConfigurouRisco := true;
      end;

      SellToCoverStop(fPrecoStop,fPrecoStopOffset);
       SellToCoverLimit(fPrecoAlvo);
    end;

    //POSIÇÃO VENDIDA
    //Código responsável pela manutenção das ordens de stoploss e take profit
    if isSold then
    begin
      if not bConfigurouRisco then
      begin
        fPrecoStop := SellPrice + cStopEmTicks*MinPriceIncrement;
        fPrecoAlvo := SellPrice - cAlvoEmTicks*MinPriceIncrement;
        fPrecoStopOffset := fPrecoStop + cStopOffsetEmTicks*MinPriceIncrement;
        bConfigurouRisco := true;
      end;

      BuyToCoverStop(fPrecoStop,fPrecoStopOffset);
      BuyToCoverLimit(fPrecoAlvo);

    end;

    //Encerra posicao
    if (Time >= iHorarioEncerramentoDaytrade)
    and HasPosition
    then ClosePosition;

    if Not HasPosition then bConfigurouRisco := false;

  end;

  // Plot de Stop e Alvo para inspeção visual do código
  bPosicionado := hasPosition;
  if bPosicionado or bPosicionado[1] or bPosicionado[2] then
  begin
    PlotN(1,fPrecoStop);
    PlotN(2,fPrecoStopOffset);
    PlotN(3,fPrecoAlvo);
    SetPlotColor(1,clRed);
    SetPlotColor(2,clRed);
    SetPlotColor(3,clGreen);
    SetPlotStyle(1,psDash);
    SetPlotStyle(2,psDash);
    SetPlotStyle(3,psDash);
    SetPlotWidth(1,2);
    SetPlotWidth(2,2);
    SetPlotWidth(3,2);

end;


end;
				
			

Stoploss com Breakeven

Reproduzir vídeo

O código abaixo apresenta um exemplo de Stoploss fixo + Breakeven (alvo de lucro da operação), para uma relação de risco/ganho de 3:1 em função de quantidade de ticks, aplicado a uma estratégia de posicionamento aleatório com uma operação por dia.

OBS 1: A versão é compatível com o Editor de Estratégias e Módulo de Automação de Estratégias. Devido a um bug do Profit, é necessário ter um comando ClosePosition, pois do contrário a ferramenta informa equivocadamente que não existem ordens para encerrar posição.

				
					const
 //Relação risco/ganho de 3:1
 cStopEmTicks = 30;
 cStopOffsetEmTicks = 20;
 cBreakevenEmTicks = 30;
 cAlvoEmTIcks = 90;

input
  bGestaoDeRiscoPelaEstrategia(true);
  iHorarioInicioAberturaPosicao(0905);
  iHorarioFimAberturaPosicao(1630);
  iHorarioEncerramentoDaytrade(1645);

var
  iCaraCoroa: integer;
  bSinalCompra, bSinalVenda, bPosicionado: boolean;
  fPrecoStop, fPrecoAlvo, fPrecoStopOffset: float;
  bConfigurouRiscoInicial: boolean;
begin

  bSinalCompra := false;
  bSinalVenda := false;
  bPosicionado := hasPosition;

  //ESTRATÉGIA CARA OU COROA!
  //Gera um numero aleatorio de 0 a 9. Se for menor igual a 4, gera
  //sinal de compra, se for maior que 4 geral sinal de venda
  if Not bPosicionado
  and (Time >= iHorarioInicioAberturaPosicao)
  and (Time <= iHorarioFimAberturaPosicao)
  then
  begin
    //Número aleatório foi substituido por minuto par ou impar para permitir depurar
    //melhor o robô quando a estratégia é inserida multiplas vezes: como indicador  e como execução
    //iCaraCoroa := Random(10);
    iCaraCoroa := mod(Time,2);
    if iCaraCoroa = 0 then bSinalCompra := true
    else bSinalVenda := true;
  end;

  //Gera ordem de compra a mercado quando há um Sinal de COMPRA
  //e define ordem stoploss e take profit
  if bSinalCompra then BuyAtMarket;

  //Gera ordem de venda a mercado quando há um Sinal de VENDA
  //e define ordem stoploss e take profit
  if bSinalVenda then SellShortAtMarket;

  if bGestaoDeRiscoPelaEstrategia then
  begin
    //Código responsável pela manutenção das ordens de stoploss e take profit
    if isBought then
    begin
      if Not bConfigurouRiscoInicial then
      begin
        fPrecoStop := BuyPrice - cStopEmTicks*MinPriceIncrement;
        fPrecoAlvo := BuyPrice + cAlvoEmTicks*MinPriceIncrement;
        fPrecoStopOffset := fPrecoStop - cStopOffsetEmTicks*MinPriceIncrement;
        bConfigurouRiscoInicial := true;
      end;

      if Close >= (BuyPrice + cBreakevenEmTicks*MinPriceIncrement) then
      begin
        fPrecoStop := BuyPrice;
        fPrecoStopOffset := fPrecoStop-cStopOffsetEmTicks*MinPriceIncrement;
      end;

      SellToCoverStop(fPrecoStop,fPrecoStopOffset);
      SellToCoverLimit(fPrecoAlvo);
    end;

    //Código responsável pela manutenção das ordens de stoploss e take profit
    if isSold then
    begin
      if Not bConfigurouRiscoInicial then
      begin
        fPrecoStop := SellPrice + cStopEmTicks*MinPriceIncrement;
        fPrecoAlvo := SellPrice - cAlvoEmTicks*MinPriceIncrement;
        fPrecoStopOffset := fPrecoStop + cStopOffsetEmTicks*MinPriceIncrement;
        bConfigurouRiscoInicial := true;
      end;

      if Close <= (SellPrice - cBreakevenEmTicks*MinPriceIncrement) then
      begin
        fPrecoStop := SellPrice;
        fPrecoStopOffset := fPrecoStop+cStopOffsetEmTicks*MinPriceIncrement;
      end;

      BuyToCoverStop(fPrecoStop,fPrecoStopOffset);
      BuyToCoverLimit(fPrecoAlvo);

    end;


    //Encerra posicao
    if (Time >= iHorarioEncerramentoDaytrade)
    and HasPosition
    then ClosePosition;

    if Not hasPosition and bConfigurouRiscoInicial then bConfigurouRiscoInicial := false;


  end;

  bPosicionado := hasPosition;

  // Plot de Stop e Alvo para inspeção visual do código
  if bPosicionado or bPosicionado[1] or bPosicionado[2] then
  begin
    PlotN(1,fPrecoStop);
    PlotN(2,fPrecoStopOffset);
    PlotN(3,fPrecoAlvo);
    SetPlotColor(1,clRed);
    SetPlotColor(2,clRed);
    SetPlotColor(3,clGreen);
    SetPlotStyle(1,psDash);
    SetPlotStyle(2,psDash);
    SetPlotStyle(3,psDash);
    SetPlotWidth(1,2);
    SetPlotWidth(2,2);
    SetPlotWidth(3,2);
  end;

end;
				
			

Stoploss móvel (Versão contínua)

Reproduzir vídeo

O código abaixo apresenta um exemplo de stoploss móvel (Versão contínua), ou seja, valor de stop é atualizado a cada fechamento de candle. Só não é atualizado a cada tick por uma limitação do Profit.

O stop será alterado para cOffsetStopEmTicks em relação ao preço de fechamento do candle, não podendo o valor do stop retroceder. O código pode ser alterado para calcular o stop móvel em relação ao valor máximo do candle.

O exemplo também conta com ordem take profit (alvo de lucro da operação) para uma relação de risco/ganho de 3:1 em função de quantidade de ticks, aplicado a uma estratégia de posicionamento aleatório com uma operação por dia.

OBS 1: A versão é compatível com o Editor de Estratégias e Módulo de Automação de Estratégias. Devido a um bug do Profit, é necessário ter um comando ClosePosition, pois do contrário a ferramenta informa equivocadamente que não existem ordens para encerrar posição.

				
					const
 //Relação risco/ganho de 3:1
 cStopEmTicks = 15;
 cAlvoEmTicks = 45;
 cTraillingStopTrigger = 20;
 cTrailingStopOffset = 10;
 cStopOffsetEmTicks = 50;

input
  bGestaoDeRiscoPelaEstrategia(true);
  iHorarioInicioAberturaPosicao(0905);
  iHorarioFimAberturaPosicao(1630);
  iHorarioEncerramentoDaytrade(1645);

var
  iCaraCoroa: integer;
  bSinalCompra, bSinalVenda, bPosicionado: boolean;
  fPrecoStop, fPrecoAlvo, fPrecoStopOffset: float;
  bConfigurouRiscoInicial: boolean;
  bTrailingStopAtivado: boolean;
begin

  bSinalCompra := false;
  bSinalVenda := false;
  bPosicionado := hasPosition;

  //ESTRATÉGIA CARA OU COROA!
  //Gera um numero aleatorio de 0 a 9. Se for menor igual a 4, gera
  //sinal de compra, se for maior que 4 geral sinal de venda
  if Not bPosicionado
  and (Time >= iHorarioInicioAberturaPosicao)
  and (Time <= iHorarioFimAberturaPosicao)
  then
  begin
    //Número aleatório foi substituido por minuto par ou impar para permitir depurar
    //melhor o robô quando a estratégia é inserida multiplas vezes: como indicador  e como execução
    //iCaraCoroa := Random(10);
    iCaraCoroa := mod(Time,2);
    if iCaraCoroa = 0 then bSinalCompra := true
    else bSinalVenda := true;
  end;


  //Gera ordem de compra a mercado quando há um Sinal de COMPRA
  //e define ordem stoploss e take profit
  if bSinalCompra then BuyAtMarket;

  //Gera ordem de venda a mercado quando há um Sinal de VENDA
  //e define ordem stoploss e take profit
  if bSinalVenda then SellShortAtMarket;

  if bGestaoDeRiscoPelaEstrategia then
  begin

    //POSIÇÃO COMPRADA
    //Código responsável pela manutenção das ordens de stoploss e take profit
    if isBought then
    begin
      if Not bConfigurouRiscoInicial then
      begin
        fPrecoStop := BuyPrice - cStopEmTicks*MinPriceIncrement;
        fPrecoAlvo := BuyPrice + cAlvoEmTicks*MinPriceIncrement;
        fPrecoStopOffset := fPrecoStop - cStopOffsetEmTicks*MinPriceIncrement;
        bConfigurouRiscoInicial := true;
      end;

      if ((Close >= (BuyPrice + cTraillingStopTrigger*MinPriceIncrement))
          or (cTraillingStopTrigger = 0))
      and (not bTrailingStopAtivado) then bTrailingStopAtivado := true;

      if ((Close - cTrailingStopOffset*MinPriceIncrement) >= fPrecoStop)
      and (bTrailingStopAtivado) then
      begin
        fPrecoStop := Close - cTrailingStopOffset*MinPriceIncrement;
        fPrecoStopOffset := fPrecoStop - cStopOffsetEmTicks*MinPriceIncrement;
      end;

      SellToCoverStop(fPrecoStop,fPrecoStopOffset);
      SellToCoverLimit(fPrecoAlvo);

    end;


    //POSIÇÃO VENDIDA
    //Código responsável pela manutenção das ordens de stoploss e take profit
    if isSold then
    begin
      if Not bConfigurouRiscoInicial then
      begin
        fPrecoStop := SellPrice + cStopEmTicks*MinPriceIncrement;
        fPrecoAlvo := SellPrice - cAlvoEmTicks*MinPriceIncrement;
        fPrecoStopOffset := fPrecoStop + cStopOffsetEmTicks*MinPriceIncrement;
        bConfigurouRiscoInicial := true;
      end;

      if ((Close <= (SellPrice - cTraillingStopTrigger*MinPriceIncrement))
          or (cTraillingStopTrigger = 0))
      and (not bTrailingStopAtivado) then bTrailingStopAtivado := true;

      if ((Close + cTrailingStopOffset*MinPriceIncrement) <= fPrecoStop)
      and (bTrailingStopAtivado) then
      begin
        fPrecoStop := Close + cTrailingStopOffset*MinPriceIncrement;
        fPrecoStopOffset := fPrecoStop + cStopOffsetEmTicks*MinPriceIncrement;
      end;

      BuyToCoverStop(fPrecoStop,fPrecoStopOffset);
      BuyToCoverLimit(fPrecoAlvo);

    end;

    //Encerra posicao comprada no horario limite
    if (Time >= iHorarioEncerramentoDaytrade)
    and HasPosition
    then ClosePosition;

    if Not hasPosition and bConfigurouRiscoInicial then
    begin
      bConfigurouRiscoInicial := false;
      bTrailingStopAtivado := false;
    end;


  end;

  // Plot de Stop e Alvo para inspeção visual do código
  bPosicionado := hasPosition;
  if bPosicionado or bPosicionado[1] or bPosicionado[2] then
  begin
    PlotN(1,fPrecoStop);
    PlotN(2,fPrecoStopOffset);
    PlotN(3,fPrecoAlvo);
    SetPlotColor(1,clRed);
    SetPlotColor(2,clRed);
    SetPlotColor(3,clGreen);
    SetPlotStyle(1,psDash);
    SetPlotStyle(2,psDash);
    SetPlotStyle(3,psDash);
    SetPlotWidth(1,2);
    SetPlotWidth(2,2);
    SetPlotWidth(3,2);
  end;

end;
				
			

Stoploss móvel (Versão baseada em passos)

Reproduzir vídeo

O código abaixo apresenta um exemplo de stoploss móvel (Versão discreta, baseada em passos), ou seja, valor de stop é atualizado cada vez que o preço de fechamento do candle supera o passo definido em cTrailingStepEmTicks. Só não é atualizado a cada tick por uma limitação do Profit.

O stop será alterado para cOffsetStop em relação ao preço do último passo alcançado, não podendo o valor do stop retroceder. O código pode ser alterado para calcular o stop móvel em relação ao valor máximo do candle.

O exemplo também conta com ordem take profit (alvo de lucro da operação) em posições compradas, para uma relação de risco/ganho de 3:1. O raciocínio para posições vendidas é análogo.

OBS 1: A versão é compatível com o Editor de Estratégias e Módulo de Automação de Estratégias. Devido a um bug do Profit, é necessário ter um comando ClosePosition, pois do contrário a ferramenta informa equivocadamente que não existem ordens para encerrar posição.

				
					const
 //Relação risco/ganho de 3:1
 cStopEmTicks = 15;
 cAlvoEmTicks = 45;
 cTraillingStopTrigger = 0;
 cTrailingStopOffset = 8;
 cTrailingStepEmTicks = 10;
 cStopOffsetEmTicks = 10;

input
  bGestaoDeRiscoPelaEstrategia(true);
  iHorarioInicioAberturaPosicao(1000);
  iHorarioFimAberturaPosicao(1630);
  iHorarioEncerramentoDaytrade(1645);

var
  iCaraCoroa: integer;
  bSinalCompra, bSinalVenda, bPosicionado: boolean;
  fPrecoStop, fPrecoAlvo, fPrecoStopOffset: float;
  fFloorTraillingStop : float;
  bConfigurouRiscoInicial: boolean;
  bTrailingStopAtivado: boolean;

begin

  bSinalCompra := false;
  bSinalVenda := false;
  bPosicionado := hasPosition;

  //ESTRATÉGIA CARA OU COROA!
  //Gera um numero aleatorio de 0 a 9. Se for menor igual a 4, gera
  //sinal de compra, se for maior que 4 geral sinal de venda
  if Not bPosicionado
  and (Time >= iHorarioInicioAberturaPosicao)
  and (Time <= iHorarioFimAberturaPosicao)
  then
  begin
    //Número aleatório foi substituido por minuto par ou impar para permitir depurar
    //melhor o robô quando a estratégia é inserida multiplas vezes: como indicador  e como execução
    //iCaraCoroa := Random(10);
    iCaraCoroa := mod(Time,2);
    if iCaraCoroa = 0 then bSinalCompra := true
    else bSinalVenda := true;
  end;


  //Gera ordem de compra a mercado quando há um Sinal de COMPRA
  //e define ordem stoploss e take profit
  if bSinalCompra then BuyAtMarket;

  //Gera ordem de venda a mercado quando há um Sinal de VENDA
  //e define ordem stoploss e take profit
  if bSinalVenda then SellShortAtMarket;


  if bGestaoDeRiscoPelaEstrategia then
  begin
    //POSIÇÃO COMPRADA
    //Código responsável pela manutenção das ordens de stoploss e take profit
    if isBought then
    begin
      if Not bConfigurouRiscoInicial then
      begin
        fPrecoStop := BuyPrice - cStopEmTicks*MinPriceIncrement;
        fPrecoAlvo := BuyPrice + cAlvoEmTicks*MinPriceIncrement;
        fPrecoStopOffset := fPrecoStop - cStopOffsetEmTicks*MinPriceIncrement;
        bConfigurouRiscoInicial := true;
      end;

      if ((Close >= (BuyPrice + cTraillingStopTrigger*MinPriceIncrement))
         or (cTraillingStopTrigger = 0))
      and (not bTrailingStopAtivado) then bTrailingStopAtivado := true;

      fFloorTraillingStop := BuyPrice
          + floor((Close - BuyPrice)/(cTrailingStepEmTicks*MinPriceIncrement))
          *cTrailingStepEmTicks*MinPriceIncrement;

      if ((fFloorTraillingStop-cTrailingStopOffset*MinPriceIncrement) >= fPrecoStop)
      and bTrailingStopAtivado then
        fPrecoStop := fFloorTraillingStop - cTrailingStopOffset*MinPriceIncrement;


      SellToCoverStop(fPrecoStop,fPrecoStopOffset);
      SellToCoverLimit(fPrecoAlvo);
    end;

    //POSIÇÃO VENDIDA
    //Código responsável pela manutenção das ordens de stoploss e take profit
    if isSold Then
    begin
      if Not bConfigurouRiscoInicial then
      begin
        fPrecoStop := SellPrice + cStopEmTicks*MinPriceIncrement;
        fPrecoAlvo := SellPrice - cAlvoEmTicks*MinPriceIncrement;
        fPrecoStopOffset := fPrecoStop + cStopOffsetEmTicks*MinPriceIncrement;
        bConfigurouRiscoInicial := true;
      end;

      if ((Close <= (SellPrice - cTraillingStopTrigger*MinPriceIncrement))
          or (cTraillingStopTrigger = 0))
      and (not bTrailingStopAtivado) then bTrailingStopAtivado := true;

      if Close <= SellPrice then
        fFloorTraillingStop := SellPrice
            - floor((SellPrice - Close)/(cTrailingStepEmTicks*MinPriceIncrement))
            *cTrailingStepEmTicks*MinPriceIncrement;

      if ((fFloorTraillingStop+cTrailingStopOffset*MinPriceIncrement) <= fPrecoStop)
      and bTrailingStopAtivado then
        fPrecoStop := fFloorTraillingStop + cTrailingStopOffset*MinPriceIncrement;


      BuyToCoverStop(fPrecoStop,fPrecoStopOffset);
      BuyToCoverLimit(fPrecoAlvo);
    end;

    //Encerra posicao
    if (Time >= iHorarioEncerramentoDaytrade)
    and HasPosition
    then ClosePosition;

    if Not hasPosition and bConfigurouRiscoInicial then
    begin
      bConfigurouRiscoInicial := false;
      bTrailingStopAtivado := false;
    end;

  end;

  // Plot de Stop e Alvo para inspeção visual do código
  bPosicionado := hasPosition;
  if bPosicionado or bPosicionado[1] or bPosicionado[2] then
  begin
    PlotN(1,fPrecoStop);
    PlotN(2,fPrecoStopOffset);
    PlotN(3,fPrecoAlvo);
    SetPlotColor(1,clRed);
    SetPlotColor(2,clRed);
    SetPlotColor(3,clGreen);
    SetPlotStyle(1,psDash);
    SetPlotStyle(2,psDash);
    SetPlotStyle(3,psDash);
    SetPlotWidth(1,2);
    SetPlotWidth(2,2);
    SetPlotWidth(3,2);
  end;



end;
				
			

Stoploss móvel (Versão contínua) + Breakeven

Reproduzir vídeo

O código abaixo apresenta um exemplo avançado de stoploss móvel com Breakeven na versão contínua, ou seja, valor de stop é atualizado para cada valor de fechamento de candle encerrado. Só não é atualizado a cada tick por uma limitação do Profit.

O stop será alterado para cOffsetStop em relação ao maior preço de fechamento alcançado desde a abertura da posição. O código pode ser alterado para calcular o stop móvel em relação ao valor máximo do candle.

O exemplo também conta com ordem take profit (alvo de lucro da operação) em posições compradas, para uma relação de risco/ganho de 3:1. O raciocínio para posições vendidas é análogo.

OBS 1: A versão é compatível com o Editor de Estratégias e Módulo de Automação de Estratégias. Devido a um bug do Profit, é necessário ter um comando ClosePosition, pois do contrário a ferramenta informa equivocadamente que não existem ordens para encerrar posição.

				
					const
 //Relação risco/ganho de 3:1
 cStopEmTicks = 30;
 cStopOffsetEmTicks = 10;
 cTrailingStopOffset = 15;
 cBreakevenEmTicks = 10;
 cTraillingStopTrigger = 20;
 cAlvoEmTicks = 90;


input
  bGestaoDeRiscoPelaEstrategia(true);
  iHorarioInicioAberturaPosicao(0905);
  iHorarioFimAberturaPosicao(1630);
  iHorarioEncerramentoDaytrade(1645);

var
  iCaraCoroa: integer;
  bSinalCompra, bSinalVenda, bPosicionado: boolean;
  fPrecoStop, fPrecoAlvo, fPrecoStopOffset: float;
  bBreakevenAtivado: boolean;
  bConfigurouRiscoInicial: boolean;
  bTrailingStopAtivado: boolean;

begin

  bSinalCompra := false;
  bSinalVenda := false;
  bPosicionado := hasPosition;

  //ESTRATÉGIA CARA OU COROA!
  //Gera um numero aleatorio de 0 a 9. Se for menor igual a 4, gera
  //sinal de compra, se for maior que 4 geral sinal de venda
  if Not bPosicionado
  and (Time >= iHorarioInicioAberturaPosicao)
  and (Time <= iHorarioFimAberturaPosicao)
  then
  begin
    //Número aleatório foi substituido por minuto par ou impar para permitir depurar
    //melhor o robô quando a estratégia é inserida multiplas vezes: como indicador  e como execução
    //iCaraCoroa := Random(10);
    iCaraCoroa := mod(Time,2);
    if iCaraCoroa = 0 then bSinalCompra := true
    else bSinalVenda := true;
  end;

  //Gera ordem de compra a mercado quando há um Sinal de COMPRA
  //e define ordem stoploss e take profit
  if bSinalCompra then BuyAtMarket;

  //Gera ordem de venda a mercado quando há um Sinal de VENDA
  //e define ordem stoploss e take profit
  if bSinalVenda then SellShortAtMarket;

  if bGestaoDeRiscoPelaEstrategia then
  begin
    //Código responsável pela manutenção das ordens de stoploss e take profit
    if isBought then
    begin
      if Not bConfigurouRiscoInicial then
      begin
        fPrecoStop := BuyPrice - cStopEmTicks*MinPriceIncrement;
        fPrecoAlvo := BuyPrice + cAlvoEmTicks*MinPriceIncrement;
        fPrecoStopOffset := fPrecoStop - cStopOffsetEmTicks*MinPriceIncrement;
        bConfigurouRiscoInicial := true;
      end;

      if ((Close >= (BuyPrice + cTraillingStopTrigger*MinPriceIncrement))
          or (cTraillingStopTrigger = 0))
      and (not bTrailingStopAtivado) then bTrailingStopAtivado := true;

      if ((Close - cTrailingStopOffset*MinPriceIncrement) >= fPrecoStop)
      and bTrailingStopAtivado then
          fPrecoStop := Close - cTrailingStopOffset*MinPriceIncrement;

      if (Close >= (BuyPrice + cBreakevenEmTicks*MinPriceIncrement))
      and (not bBreakevenAtivado) then
      begin
        bBreakevenAtivado := true;
        if fPrecoStop < BuyPrice then fPrecoStop := BuyPrice;
      end;


      fPrecoStopOffset := fPrecoStop-cStopOffsetEmTicks*MinPriceIncrement;
      SellToCoverStop(fPrecoStop,fPrecoStopOffset);
      SellToCoverLimit(fPrecoAlvo);
    end;


    //Código responsável pela manutenção das ordens de stoploss e take profit
    if isSold then
    begin
      if Not bConfigurouRiscoInicial then
      begin
        fPrecoStop := SellPrice + cStopEmTicks*MinPriceIncrement;
        fPrecoAlvo := SellPrice - cAlvoEmTicks*MinPriceIncrement;
        fPrecoStopOffset := fPrecoStop + cStopOffsetEmTicks*MinPriceIncrement;
        bConfigurouRiscoInicial := true;
      end;

      if ((Close <= (SellPrice - cTraillingStopTrigger*MinPriceIncrement))
          or (cTraillingStopTrigger = 0))
      and (not bTrailingStopAtivado) then bTrailingStopAtivado := true;

      if ((Close + cTrailingStopOffset*MinPriceIncrement) <= fPrecoStop)
      and bTrailingStopAtivado then
          fPrecoStop := Close + cTrailingStopOffset*MinPriceIncrement;

      if (Close <= (SellPrice - cBreakevenEmTicks*MinPriceIncrement))
      and (not bBreakevenAtivado) then
      begin
        bBreakevenAtivado := true;
        if fPrecoStop > SellPrice then fPrecoStop := SellPrice;
      end;


      fPrecoStopOffset := fPrecoStop + cStopOffsetEmTicks*MinPriceIncrement;
      BuyToCoverStop(fPrecoStop,fPrecoStopOffset);
      BuyToCoverLimit(fPrecoAlvo);
    end;


    //Encerra posicao
    if (Time >= iHorarioEncerramentoDaytrade)
    and HasPosition
    then ClosePosition;

    if Not hasPosition and bConfigurouRiscoInicial then
    begin
      bConfigurouRiscoInicial := false;
      bBreakevenAtivado := false;
      bTrailingStopAtivado := false;
    end;

  end;

  // Plot de Stop e Alvo para inspeção visual do código
  bPosicionado := hasPosition;
  if bPosicionado or bPosicionado[1] or bPosicionado[2] then
  begin
    PlotN(1,fPrecoStop);
    PlotN(2,fPrecoStopOffset);
    PlotN(3,fPrecoAlvo);
    SetPlotColor(1,clRed);
    SetPlotColor(2,clRed);
    SetPlotColor(3,clGreen);
    SetPlotStyle(1,psDash);
    SetPlotStyle(2,psDash);
    SetPlotStyle(3,psDash);
    SetPlotWidth(1,2);
    SetPlotWidth(2,2);
    SetPlotWidth(3,2);
  end
  else
  begin
    NoPlot(1);
    NoPlot(2);
    NoPlot(3);
  end;


end;
				
			

Stoploss móvel (Versão baseada em passos) + Breakeven

O código abaixo apresenta um exemplo avançado de stoploss móvel com Breakeven na versão discreta (baseada em passos), ou seja, valor de stop é atualizado para cada valor de fechamento que supera o passo definido (cTrailingStepEmTicks). Só não é atualizado a cada tick por uma limitação do Profit.

O stop será alterado para cOffsetStop em relação ao último passo alcançado pelo maior preço de fechamento de candle desde a abertura da posição. O código pode ser alterado para calcular o stop móvel em relação ao valor máximo do candle.

O exemplo também conta com ordem take profit (alvo de lucro da operação) em posições compradas, para uma relação de risco/ganho de 3:1. O raciocínio para posições vendidas é análogo.

OBS 1: A versão é compatível com o Editor de Estratégias e Módulo de Automação de Estratégias. Devido a um bug do Profit, é necessário ter um comando ClosePosition, pois do contrário a ferramenta informa equivocadamente que não existem ordens para encerrar posição.

				
					const
 //Relação risco/ganho de 3:1
 cStopEmTicks = 30;
 cBreakevenEmTicks = 10;
 cTraillingStopTrigger = 20;
 cTrailingStepEmTicks = 20;
 cTrailingStopOffset = 10;
 cStopOffsetEmTicks = 10;
 cAlvoEmTIcks = 90;

input
  bGestaoDeRiscoPelaEstrategia(true);
  iHorarioInicioAberturaPosicao(0905);
  iHorarioFimAberturaPosicao(1630);
  iHorarioEncerramentoDaytrade(1645);

var
  iCaraCoroa: integer;
  bSinalCompra, bSinalVenda, bPosicionado: boolean;
  fPrecoStop, fPrecoAlvo, fPrecoStopOffset: float;
  fFloorTraillingStop: float;
  bBreakevenAtivado: boolean;
  bConfigurouRiscoInicial: boolean;
  bTrailingStopAtivado: boolean;

begin

  bSinalCompra := false;
  bSinalVenda := false;
  bPosicionado := hasPosition;

  //ESTRATÉGIA CARA OU COROA!
  //Gera um numero aleatorio de 0 a 9. Se for menor igual a 4, gera
  //sinal de compra, se for maior que 4 geral sinal de venda
  if Not bPosicionado
  and (Time >= iHorarioInicioAberturaPosicao)
  and (Time <= iHorarioFimAberturaPosicao)
  then
  begin
    //Número aleatório foi substituido por minuto par ou impar para permitir depurar
    //melhor o robô quando a estratégia é inserida multiplas vezes: como indicador  e como execução
    //iCaraCoroa := Random(10);
    iCaraCoroa := mod(Time,2);
    if iCaraCoroa = 0 then bSinalCompra := true
    else bSinalVenda := true;
  end;

  //Gera ordem de compra a mercado quando há um Sinal de COMPRA
  //e define ordem stoploss e take profit
  if bSinalCompra then BuyAtMarket;

  //Gera ordem de venda a mercado quando há um Sinal de VENDA
  //e define ordem stoploss e take profit
  if bSinalVenda then SellShortAtMarket;

  if bGestaoDeRiscoPelaEstrategia then
  begin
    //Código responsável pela manutenção das ordens de stoploss e take profit
    if isBought then
    begin
      if Not bConfigurouRiscoInicial then
      begin
        fPrecoStop := BuyPrice - cStopEmTicks*MinPriceIncrement;
        fPrecoAlvo := BuyPrice + cAlvoEmTicks*MinPriceIncrement;
        fPrecoStopOffset := fPrecoStop - cStopOffsetEmTicks*MinPriceIncrement;
        bConfigurouRiscoInicial := true;
      end;

      if ((Close >= (BuyPrice + cTraillingStopTrigger*MinPriceIncrement))
          or (cTraillingStopTrigger = 0))
      and (not bTrailingStopAtivado) then bTrailingStopAtivado := true;

      fFloorTraillingStop := BuyPrice
          + floor((Close - BuyPrice)/(cTrailingStepEmTicks*MinPriceIncrement))
          *cTrailingStepEmTicks*MinPriceIncrement;

      if ((fFloorTraillingStop-cTrailingStopOffset*MinPriceIncrement) >= fPrecoStop)
      and (Close >= BuyPrice+cTrailingStepEmTicks*MinPriceIncrement)
      and bTrailingStopAtivado then
        fPrecoStop := fFloorTraillingStop - cTrailingStopOffset*MinPriceIncrement;

      if (Close >= (BuyPrice + cBreakevenEmTicks*MinPriceIncrement))
      and (not bBreakevenAtivado) then
      begin
        bBreakevenAtivado := true;
        if fPrecoStop < BuyPrice then fPrecoStop := BuyPrice;
      end;

      fPrecoStopOffset := fPrecoStop-cStopOffsetEmTicks*MinPriceIncrement;

      SellToCoverStop(fPrecoStop,fPrecoStopOffset);
      SellToCoverLimit(fPrecoAlvo);
    end;


    //Código responsável pela manutenção das ordens de stoploss e take profit
    if isSold then
    begin
      if Not bConfigurouRiscoInicial then
      begin
        fPrecoStop := SellPrice + cStopEmTicks*MinPriceIncrement;
        fPrecoAlvo := SellPrice - cAlvoEmTicks*MinPriceIncrement;
        fPrecoStopOffset := fPrecoStop + cStopOffsetEmTicks*MinPriceIncrement;
        bConfigurouRiscoInicial := true;
      end;

      if ((Close <= (SellPrice - cTraillingStopTrigger*MinPriceIncrement))
          or (cTraillingStopTrigger = 0))
      and (not bTrailingStopAtivado) then bTrailingStopAtivado := true;

      if Close <= SellPrice then
        fFloorTraillingStop := SellPrice
            - floor((SellPrice - Close)/(cTrailingStepEmTicks*MinPriceIncrement))
            *cTrailingStepEmTicks*MinPriceIncrement;


      if ((fFloorTraillingStop+cTrailingStopOffset*MinPriceIncrement) <= fPrecoStop)
      and (Close <= SellPrice - cTrailingStepEmTicks*MinPriceIncrement)
      and bTrailingStopAtivado then
        fPrecoStop := fFloorTraillingStop + cTrailingStopOffset*MinPriceIncrement;


      if (Close <= (SellPrice - cBreakevenEmTicks*MinPriceIncrement))
      and (not bBreakevenAtivado) then
      begin
        bBreakevenAtivado := true;
        if fPrecoStop > SellPrice then fPrecoStop := SellPrice;
      end;


      fPrecoStopOffset := fPrecoStop + cStopOffsetEmTicks*MinPriceIncrement;

      BuyToCoverStop(fPrecoStop,fPrecoStopOffset);
      BuyToCoverLimit(fPrecoAlvo);

    end;


    //Encerra posicao
    if (Time >= iHorarioEncerramentoDaytrade)
    and HasPosition
    then ClosePosition;

    if Not hasPosition and bConfigurouRiscoInicial then
    begin
      bConfigurouRiscoInicial := false;
      bBreakevenAtivado := false;
      bTrailingStopAtivado := false;
    end;

  end;

  // Plot de Stop e Alvo para inspeção visual do código
  bPosicionado := hasPosition;
  if bPosicionado or bPosicionado[1] or bPosicionado[2] then
  begin
    PlotN(1,fPrecoStop);
    PlotN(2,fPrecoStopOffset);
    PlotN(3,fPrecoAlvo);
    SetPlotColor(1,clRed);
    SetPlotColor(2,clRed);
    SetPlotColor(3,clGreen);
    SetPlotStyle(1,psDash);
    SetPlotStyle(2,psDash);
    SetPlotStyle(3,psDash);
    SetPlotWidth(1,2);
    SetPlotWidth(2,2);
    SetPlotWidth(3,2);
  end
  else
  begin
    NoPlot(1);
    NoPlot(2);
    NoPlot(3);
  end;




end;
				
			

Confirmação de ordens por múltiplos sinais

O código abaixo apresenta um exemplo para o conceito de confirmação de compra por meio de dois sinais distintos: um sinal baseado em IFR e outro baseado em cruzamento de média.

Os sinais podem ser adaptados para quaisquer condições que se deseje. O importante deste exemplo é entender a lógica por trás de duplas confirmações ou múltiplas confirmações com janela de timeout para abertura de posição.

OBS 1: Como o foco do snippet é a confirmação de ordens com múltiplos sinais, a gestão de risco foi implementada da forma mais simples possível apenas para tornar o código funcional. Percebe-se que há um stop e alvo fixos na relação 3:1, onde o stop está 30 ticks atrás do preço de compra e o alvo a 90 ticks acima do preço de compra.

OBS 2: A parametrização dos indicadores, bem como a seleção dos indicadores deste exemplo não representam nenhuma recomendação de setup, sendo apenas um exemplo didático.

				
					const
  // Determina a qtde de candles a se aguardar a confirmação
  // de sinal de compra 
  iTimeoutConfirmacao = 12;
  // Limite para considerar sobrevenda no IFR
  iLimiteSobreVendaIFR = 35;

input
  iQtdePeriodosMedia(16);
  iQtdePeriodosIFR(16);
  //Compatibilidade com Módulo de Automação de Estratégias
  bModuloAutomacao(false);
var
  bSinalCompraIFR, bSinalCompraCruzMedia: boolean;
  fIFR, fMedia: float;

  iInteradorTimeout: integer;
  bSinalCompraConfirmada: boolean;
  bSinalCompraIFRativou, bSinalCompraCruzMediaAtivou: boolean;
  
  bComprado: boolean;
  bConfigurouRiscoOperacao: boolean;
  fPrecoAlvo, fPrecoStop, fStopOffset: float;
begin
  // Indicadores técnicos utilizados para sinais
  bComprado := isBought;
  fIFR := RSI(iQtdePeriodosIFR,0);
  fMedia := Media(iQtdePeriodosMedia,Close);
  bSinalCompraConfirmada := false;  

  //Sinais de compra individuais para indicadores
  bSinalCompraCruzMedia := (Close > fMedia) and (Close[1] <= fMedia[1]);
  bSinalCompraIFR := (fIFR > iLimiteSobreVendaIFR) and (fIFR[1] <= iLimiteSobreVendaIFR);

  // Auxilio visual de sinais individuais
  if bSinalCompraCruzMedia and Not bComprado then PlotText("S1", clBlue,-1,9);
  if bSinalCompraIFR and Not bComprado then PlotText("S2", clYellow,0,9);

  // Lógica para multiplas confirmações
  // Se Timeout for zero a dupla confirmação de compra deve ocorrer
  // no mesmo candle/box
  if Not bComprado then
  begin
    if (iTimeoutConfirmacao = 0) and bSinalCompraCruzMedia and bSinalCompraIFR then
      bSinalCompraConfirmada := true
    else
    if (iTimeoutConfirmacao > 0) then
    begin
      bSinalCompraConfirmada := false;
      bSinalCompraIFRativou := false;
      bSinalCompraCruzMediaAtivou := false;
  
      for iInteradorTimeout := 0 to iTimeoutConfirmacao do
      begin
        if bSinalCompraCruzMedia[iInteradorTimeout] = true then bSinalCompraCruzMediaAtivou := true;
        if bSinalCompraIFR[iInteradorTimeout] = true then bSinalCompraIFRativou := true;
        if bSinalCompraCruzMediaAtivou and bSinalCompraIFRativou then bSinalCompraConfirmada := true;
      end;
    end;
  end;

  // Se houver multipla confirmação, executa ordem a mercado
  if bSinalCompraConfirmada and Not bComprado then 
  begin
    BuyAtMarket;
    bConfigurouRiscoOperacao := false;
  end;
  bComprado := isBought;

  // Configura risco da operação no Módulo de Automação (Ordem OCO)
  // Para outras configurações de STOPLOSS, consulte os snippets no site
  if bModuloAutomacao then
  begin
    if bComprado and Not bConfigurouRiscoOperacao then
    begin
      fPrecoAlvo := buyPrice + 450*MinPriceIncrement;
      fPrecoStop := buyPrice - 150*MinPriceIncrement;
      fStopOffset := fPrecoStop - 100*MinPriceIncrement;

      SellShortStop(fPrecoStop, fStopOffset);
      SellShortLimit(fPrecoAlvo);
    end
    else
    //Proteção de pulo da ordem stop devido à gaps 
    if isBought and (Close < fStopOffset) then closePosition;

  end
  // Configura alvo e stoploss para Backtesting
  else
  begin
    if bComprado then
    begin
      fPrecoAlvo := buyPrice + 450*MinPriceIncrement;
      fPrecoStop := buyPrice - 150*MinPriceIncrement;
      fStopOffset := fPrecoStop - 60*MinPriceIncrement;

      SellToCoverStop(fPrecoStop, fStopOffset);
      //Proteção de pulo da ordem stop devido à gaps
      if isBought and (Close < fStopOffset) then closePosition;
      if isBought then SellToCoverLimit(fPrecoAlvo);
    end;
  end;


end.

				
			

Gestão de Risco diária e Proteção de Ganhos

Reproduzir vídeo

O código abaixo apresenta um exemplo de programação para fazer a gestão de risco do resultado diário de um robô.

Inicialmente, são estabelecidos para a estratégia o limite de perda (pLimitePerdaDiaria) e objetivo de ganho diário (pObjetivoGanhoDiario), bem como a proteção de ganho desejada (pProtecaoGanho), tudo em valor financeiro.

A medida que o robô faz as operações, caso o resultado atinja o limite de perda inicial, a estratégia para de operar durante o resto do dia.

Caso o objetivo de ganho seja atingido, a gestão de risco do código protege parte do ganho (pProtecaoGanho) e o robô continua a operar. Caso atinja novamente o objetivo de ganho, a partir do último patamar de ganho planejado, o lucro é novamente protegido.

				
					input
  pLimitePerdaDiaria(100.00);
  pObjetivoGanhoDiario(300.00);
  pProtecaoGanho(200.00);
  pTempoReal(false);
var
  fResultado: float;
  fResultadoDiario: float;
  iHora: integer;

  fObjetivoAtualGanho, fLimiteAtualPerda: float;
  fNovaReferencia: float;

  bPrimeiraBarraDoDia : boolean;
  iDataAtual          : integer;
  bPrimeiroTickDaBarra : boolean;
  iBarraAtual          : integer;
begin
  // Configura a gestão de risco no primeiro tick da primeira
  // barra do dia. Necessário agora que tem roteamento no tick
  // SNIPPET de "Identificação do primeiro candle de cada dia"
  // +
  // SNIPPET de "Identificação do primeiro tick de uma barra"
  if (Date() <> iDataAtual) then
    begin
      iDataAtual := Date();
      bPrimeiraBarraDoDia := true;
    end;
  if bPrimeiraBarraDoDia then
    begin
      bPrimeiraBarraDoDia := false;

      if (pTempoReal and LastBarOnChart) or not pTempoReal then
      if (CurrentBar <> iBarraAtual) then
        begin
          iBarraAtual := CurrentBar;
          bPrimeiroTickDaBarra := true;
        end
      else
        bPrimeiroTickDaBarra := false;

      if bPrimeiroTickDaBarra then
        begin
          //Faz alguma coisa no primeiro tick da barra
          //Aplicável apenas em execução de tempo real
          fObjetivoAtualGanho := pObjetivoGanhoDiario;
          fLimiteAtualPerda := pLimitePerdaDiaria;
          fNovaReferencia := 0;
        end;

    end;


  //-----------------------------------------------------------
  // SNIPPET de "Como limitar trades por objetivo de ganho ou limite de perda"
  // Resultado até o momento no dia (fechado + aberto)
    fResultado := DailyResult(true);
    plot(fResultado);
    SetPlotStyle(1,psDash);
    SetPlotColor(1,clGray);
    SetPlotType(1,igHistogram);

    plot2(fNovaReferencia - fLimiteAtualPerda);
    SetPlotStyle(2,psSolid);
    SetPlotColor(2,clRed);
    SetPlotWidth(2,3);

  // Estratégia qualquer de operação!!!
  // Estratégias apenas opera se resultado do dia não
  // tiver atingido objetivo de ganho ou limite de perda
  fResultadoDiario := DailyResult(true) - fNovaReferencia;

  if (fResultadoDiario > -1*fLimiteAtualPerda)
  and (fResultadoDiario < fObjetivoAtualGanho) then
  begin
    // SIMULAÇÃO DE ORDENS PARA FINS DE EXEMPLO
    for iHora := 0 to 8 do
    begin
      if (Time = (0900 + iHora*100)) or (Time = (0930 + iHora*100)) then
        if random(2) = 0 then BuyAtMarket else SellShortAtMarket;

      if (Time = (0920 + iHora*100)) Or (Time = (0950 + iHora*100)) then
        ClosePosition;
    end;

  end
  //Se resultado excedeu objetivo de ganho cria-se novos limites
  //Se atingiu limite de perda ou proteção de ganho então para de operar
  else 
  begin
    if fResultadoDiario <= -1*pLimitePerdaDiaria then
    begin
      if hasPosition then ClosePosition;
    end
    else
    if fResultadoDiario >= pObjetivoGanhoDiario then
    begin
       fNovaReferencia := fNovaReferencia + pObjetivoGanhoDiario;
       fLimiteAtualPerda := (pObjetivoGanhoDiario - pProtecaoGanho);
    end;

  end;

end;
				
			

Identificando resultado da última operação

Reproduzir vídeo

O código abaixo apresenta um exemplo de programação para identificar o resultado da última operação realizada. Assim, o trader pode realizar outras lógicas de limitação de sequência de trades com prejuízo, lucro e outras que desejar.

				
					var
  bHasPosition: boolean;
  iDia: integer;
  fResultadoFechadoDia, fResultadoTotalDia: float;
  fResultadoUltimoTrade, fResultadoAberto: float;
begin
  if (Date <> iDia) then
  begin
    iDia := Date;
    fResultadoUltimoTrade := 0;
  end;

  // ARMAZENAMENTO DE VARIÁVEIS (FACILITA A DEPURAÇÃO)
  bHasPosition := HasPosition;
  fResultadoTotalDia := DailyResult(true);
  fResultadoFechadoDia := DailyResult(false);

  // CALCULA O RESULTADO ABERTO
  if bHasPosition 
  then fResultadoAberto := fResultadoTotalDia - fResultadoFechadoDia
  else fResultadoAberto := 0;

  // CALCULA O RESULTADO DO ÚLTIMO TRADE
  if not bHasPosition and bHasPosition[1]
  then fResultadoUltimoTrade := fResultadoAberto[1];
 
  // PLOTA GRÁFICO PARA INSPEÇÃO VISUAL
  plot(fResultadoAberto);
  SetPlotType(1,igHistogram);
  if fResultadoAberto > 0 then SetPlotColor(1,clGreen)
  else if fResultadoAberto < 0 then SetPlotColor(1,clRed)
       else SetPlotColor(1,clGray);

  plot2(fResultadoUltimoTrade);
  SetPlotColor(2,clWhite);
  SetPlotStyle(2,psDash);
  SetPlotWidth(2,2);


  //ROTEAMENTO DE ORDENS
  if (Time = 0905) then BuyAtMarket;
  if (Time >= 0915) then ClosePosition;

end;
				
			

Como obter o preço médio executado durante montagem e realização parcial

É tarefa comum quando você está com um setup de montagem e realizações parciais querer estabelecer ordens de alvo e stop de acordo com o preço executado da última ordem e não do preço médio da posição.

É possível obter esse valor pelo código abaixo. No entanto, é importante ressaltar que devido às limitações da linguagem NTSL, caso haja várias execuções de ordens na mesma barra, o preço calculado de execução será o preço médio das ordens executadas na barra tendo em vista a diferença da posição.

				
					var
  iPosicao: integer;
  fPrecoMedio: float;
  fPrecoExecutado: float;

// ----------------------------------------------------------------------------------------
function getAvgFilledOrderPrice(previousPos: integer; previousPrice: Float; 
                                currentPos:integer; currentPrice: Float): float;
begin
  if  (currentPos <> 0) and (previousPos <> 0) 
  and (currentPos <> previousPos) then
  begin
    Result := (currentPos*currentPrice - previousPos*previousPrice)/(currentPos - previousPos);
  end
  else
    Result := 0;   
end;
// ----------------------------------------------------------------------------------------


begin
  // Como calcular preço médio de execução de ordens na barra
  iPosicao := Position;
  fPrecoMedio := Price;
  fPrecoExecutado := getAvgFilledOrderPrice(iPosicao[1], fPrecoMedio[1], iPosicao, fPrecoMedio);

  plot2(fPrecoExecutado);
  SetPlotType(2,igHistogram);
  // ---------------------------------------------------------

  if (Date = LastCalcDate) and (Time = 1500) then
      SellShortAtMarket(2);

  if (Date = LastCalcDate) and (Time = 1505) then
      BuyAtMarket(1);

  if (Date = LastCalcDate) and (Time = 1515) then
    SellShortAtMarket(2);

  if (Date = LastCalcDate) and (Time = 1530) then
    SellShortAtMarket(2);

  if (Time >= 1630) and hasPosition then ClosePosition;

  if hasPosition then Plot(Price);
  SetPlotColor(1, clWhite);
  SetPlotStyle(1, psDash);

end;
				
			

Implementação de estratégias

Introdução

Esta seção visa apresentar trechos de códigos com exemplos de tarefas comuns para implementação de estratégias.

Você pode acessar os Snippets diretamente pelo menu lateral direito, ou fazendo CRL+F (CTRL+L) para localizar algum texto específico na página, uma vez que o conteúdo tende a crescer ao longo do tempo, dificultando a navegação pelo menu.

Caso tenham sugestões de código para acrescentar à lista, gentileza deixar o código nos comentários com o link para seu perfil em rede social (para devido crédito de autoria).

Snippets

Cruzamento simples entre 2 séries

Reproduzir vídeo

O exemplo abaixo visa identificar quando há um cruzamento simples entre duas séries, considerando apenas o instante atual e anterior.

				
					var
  fMedia1, fMedia2: float;
  iCruzamento: integer;


function NTB_ArredondarFloat(Value: float; nCasas: integer):float;
var
    fValor: float;
    fParteInteira: float;
    fParteDecimal: float;
begin
  fValor := Value;
  fParteInteira := IntPortion(fValor);
  fParteDecimal := Round((fValor - fParteInteira)*Power(10,nCasas));

  Result := fParteInteira + fParteDecimal/Power(10,nCasas);
end;


begin
  iCruzamento := 0;
  fMedia1 := NTB_ArredondarFloat(Media(10,Close),2);
  fMedia2 := NTB_ArredondarFloat(Media(20,Close),2);

  if  (fMedia1 > fMedia2)
  and (fMedia1[1] <= fMedia2[1]) then
    iCruzamento := 1;

  if (fMedia1 < fMedia2)
  and (fMedia1[1] >= fMedia2[1]) then
    iCruzamento := -1;

  if iCruzamento = 1 then
  begin
    // O que fazer quando houver cruzamento para cima?
    PlotText("Cruzou acima", clGreen, -1,12);
  end;

  if iCruzamento = -1 then
  begin
    // O que fazer quando houver cruzamento para baixo?
    PlotText("Cruzou abaixo", clRed, -1,12);
  end;

  //Plot apenas para visualizar graficamente o funcionamento
  //do código
  Plot(fMedia1);
  Plot2(fMedia2);
  SetPlotColor(1,clRed);
  SetPlotWidth(1,2);  
  SetPlotColor(2,clWhite);
  SetPlotStyle(2,psDash);  
  SetPlotWidth(2,2);  

end;
				
			

Cruzamento simples entre 2 séries com percentual de cruzamento

O exemplo abaixo visa identificar quando há um cruzamento simples entre duas séries, considerando apenas o instante atual e anterior, e desde que o cruzamento seja superior a um determinado valor percentual.

				
					const
  //Constante fornecida em percentual. Ex: 0.1 significa 0.1%
  fPercCruzamento = 0.1;
var
  fMedia1, fMedia2: float;
  iCruzamento: integer;

begin
  iCruzamento := 0;
  fMedia1 := Media(10,Close);
  fMedia2 := Media(20,Close);    

  //Plot apenas para visualizar graficamente o funcionamento
  //do código
  Plot(fMedia1);
  Plot2(fMedia2); 

  if (fMedia1 <> 0) and (fMedia2 <> 0) then
  begin

    if  (fMedia1 > fMedia2)
    and (fMedia1[1] <= fMedia2[1])
    and (((fMedia1-fMedia2)/fMedia1*100) >= fPercCruzamento)
    then iCruzamento := 1;
  
    if  (fMedia1 < fMedia2)
    and (fMedia1[1] >= fMedia2[1]) 
    and ((Abs((fMedia2-fMedia1)/fMedia1*100)) >= fPercCruzamento)
    then iCruzamento := -1;
  
    if iCruzamento = 1 then 
    begin
      // O que fazer quando houver cruzamento para cima?
      PlotText("Cruzou pra cima", clGreen, -1,12);
    end;
  
    if iCruzamento = -1 then 
    begin
      // O que fazer quando houver cruzamento para baixo?
      PlotText("Cruzou pra baixo", clRed, -1,12);    
    end;
  end;

end;
				
			

Cruzamento entre 2 séries nos últimos N períodos

O exemplo abaixo visa identificar qual cruzamento houve entre duas séries nos últimos N períodos (constante cJanelaCruzamento).

				
					const
  cJanelaCruzamento = 5;
var
  fMedia1,fMedia2 : float;
  iCruzamento : integer;
  iUltimoCruzamentoJanela : integer;
  iPeriodo, iPeriodoJanela : integer;
begin
  iCruzamento := 0;
  fMedia1 := Media(10,Close);
  fMedia2 := Media(20,Close);

  //Plot apenas para visualizar graficamente o funcionamento
  //do código
  Plot(fMedia1);
  Plot2(fMedia2);

  if (fMedia1 > fMedia2) and (fMedia1[1] <= fMedia2[1]) then
    iCruzamento := 1;
  if (fMedia1 < fMedia2) and (fMedia1[1] >= fMedia2[1]) then
    iCruzamento := - 1;
  
  if iCruzamento = 1 then
    begin
      // O que fazer quando houver cruzamento para cima?
      PlotText("Cruzou pra cima",clGreen, - 1,12);
    end;
  
  if iCruzamento = - 1 then
    begin
      // O que fazer quando houver cruzamento para baixo?
      PlotText("Cruzou pra baixo",clRed, - 1,12);
    end;


  // Código para proteção do início da série em backtesting
  if MaxBarsBack < cJanelaCruzamento then
    iPeriodoJanela := MaxBarsBack
  else iPeriodoJanela := cJanelaCruzamento;
  
  // Identificação do último cruzamento
  if iPeriodoJanela >= 1 then
  begin  
    iUltimoCruzamentoJanela := iCruzamento;
    iPeriodo := 1;
    while iPeriodo <= iPeriodoJanela do
    begin
      if iCruzamento[iPeriodo] <> 0 then
      begin
         iUltimoCruzamentoJanela := iCruzamento[iPeriodo];
         iPeriodo := iPeriodoJanela + 1;
      end;
      iPeriodo := iPeriodo + 1;
    end;
  
    // Escreve no gráfico qual cruzamento houve nos últimos
    // cJanelaCruzamento periodos
    if (iCruzamento = 0) and (iUltimoCruzamentoJanela <> 0) then
      if iUltimoCruzamentoJanela = 1 then
        PlotText("Cruz p/ cima",clWhite, - 1,8)
      else
        PlotText("Cruz p/ baixo",clWhite, - 1,8);
  end;

end;
				
			

Toque na média utilizando percentual de proximidade

Reproduzir vídeo

O exemplo abaixo visa identificar quando ocorre o toque do preço em uma média, utilizando como parâmetro o percentual de proximidade.

OBS: Neste exemplo foi introduzido também uma função customizada para arredondar um valor float de acordo com a quantidade de casas decimais desejada (NTB_ArredondarFloat)). Este tipo de função não tem de forma nativa no Profit (o que é uma pena!);

				
					const
  // Define o percentual que caracteriza o toque
  // Se for igual a zero, a barra tem conter a média
  // Ex: se cPercProximidade = 0.5, define como toque se
  // preço chegar a 0.5% ou menos de distância da média
  cPercProximidade = 0.0;
var
  fMedia: float;
  bTocouMedia: boolean;


function NTB_ArredondarFloat(Value: float; nCasas: integer):float;
var
    fValor: float;
    fParteInteira: float;
    fParteDecimal: float;
begin
  fValor := Value;
  fParteInteira := IntPortion(fValor);
  fParteDecimal := Round((fValor - fParteInteira)*Power(10,nCasas));

  Result := fParteInteira + fParteDecimal/Power(10,nCasas);

end;

begin
  bTocouMedia := false;
  fMedia :=  NTB_ArredondarFloat(Media(20,Close),2);

  //Plot apenas para visualizar graficamente o funcionamento
  //do código
  Plot(fMedia);
  SetPlotColor(1,clRed);
  SetPlotWidth(1,2);
  if (cPercProximidade <> 0) then
  begin
    Plot2(NTB_ArredondarFloat(fMedia*(1 + cPercProximidade/100),2));
    Plot3(NTB_ArredondarFloat(fMedia*(1 - cPercProximidade/100),2));
    SetPlotColor(2, clGray);
    SetPlotColor(3, clGray);
  end;


  //Proteção para os primeiros períodos de backtesting
  //Quando pode ocorrer divisão por zero
  if fMedia <> 0 then
  begin

    // Situação em que a media está no meio da barra
    if (fMedia >= Low) and (fMedia <= High)
    then bTocouMedia := True;

    // Situação em que a media está abaixo do preço
    // negociado e este chegou a cPercProximidade da
    // média
    if (fMedia < Low)
    and (((Low - fMedia)/fMedia*100) <= cPercProximidade)
    then
    begin
      bTocouMedia := True;
    end;

    // Situação em que a media está abaixo do preço
    // negociado e este chegou a cPercProximidade da
    // média
    if (fMedia > High)
    and (((fMedia - High)/High*100) <= cPercProximidade)
    then
    begin
    bTocouMedia := True;
    end;

   if bTocouMedia then
     PlotText("Tocou",clWhite, - 1,8);

  end;

end;
				
			

Toque na média utilizando quantidade de ticks de proximidade

Reproduzir vídeo

O exemplo abaixo visa identificar quando ocorre o toque do preço em uma média, utilizando como parâmetro a quantidade de ticks do ativo.

OBS: Neste exemplo foi introduzido também uma função customizada para arredondar um valor float de acordo com a quantidade de casas decimais desejada (NTB_ArredondarFloat)). Este tipo de função não tem de forma nativa no Profit (o que é uma pena!);

				
					const
  // Define o percentual que caracteriza o toque
  // Se for igual a zero, a barra tem conter a média
  // Ex: se cPercProximidade = 0.5, define como toque se
  // preço chegar a 0.5% ou menos de distância da média
  cTicksProximidade = 0;
var
  fMedia: float;
  bTocouMedia: boolean;


function NTB_ArredondarFloat(Value: float; nCasas: integer):float;
var
    fValor: float;
    fParteInteira: float;
    fParteDecimal: float;
begin
  fValor := Value;
  fParteInteira := IntPortion(fValor);
  fParteDecimal := Round((fValor - fParteInteira)*Power(10,nCasas));

  Result := fParteInteira + fParteDecimal/Power(10,nCasas);

end;

begin
  bTocouMedia := false;
  fMedia :=  NTB_ArredondarFloat(Media(20,Close),2);

  //Plot apenas para visualizar graficamente o funcionamento
  //do código
  Plot(fMedia);
  SetPlotColor(1,clRed);
  SetPlotWidth(1,2);
  if (cTicksProximidade <> 0) then
  begin
    Plot2(fMedia + cTicksProximidade*MinPriceIncrement);
    Plot3(fMedia - cTicksProximidade*MinPriceIncrement);
    SetPlotColor(2,clGray);
    SetPlotColor(3,clGray);
  end;

  //Proteção para os primeiros períodos de backtesting
  //Quando pode ocorrer divisão por zero
  if fMedia <> 0 then
  begin

    // Situação em que a media está no meio da barra
    if (fMedia >= Low) and (fMedia <= High)
    then bTocouMedia := True;

    // Situação em que a media está abaixo do preço
    // negociado e este chegou a cPercProximidade da
    // média
    if (fMedia < Low)
    and (((Low - fMedia)/MinPriceIncrement) <= cTicksProximidade)
    then
    begin
      bTocouMedia := True;
    end;

    // Situação em que a media está abaixo do preço
    // negociado e este chegou a cPercProximidade da
    // média
    if (fMedia > High)
    and (((fMedia - High)/MinPriceIncrement) <= cTicksProximidade)
    then
    begin
    bTocouMedia := True;
    end;

   if bTocouMedia then
     PlotText("Tocou",clWhite, - 1,8);

  end;

end;
				
			

Como acessar o Book de Ofertas em NTSL por nível de preço

Reproduzir vídeo

O exemplo abaixo demonstra como armazenar em um array os próximos N níveis de preço do book e obter as quantidades apregoadas para estes níveis no lado da compra e da venda.

OBS: Este código funciona apenas quando o mercado está aberto, não sendo possível fazer backtesting de estratégias baseadas em leitura de book. Isso é algo comum às demais plataformas de trading.

				
					const
  cQtdeNiveis = 4;

input
  cAtivo("CASH3", feedBovespa);

var
  i: integer;
  fBookSell, fBookBuy: array[0..cQtdeNiveis] of float;
  fBookSellSum, fBookBuySum: float;

begin

  for i:= 0 to cQtdeNiveis do
  begin
    fBookSellSum := TotalSellQtd(cAtivo,i+1);
    fBookBuySum :=  TotalBuyQtd(cAtivo,i+1);
    
    if i <> 0 then
    begin
      fBookSell[i] := fBookSellSum - TotalSellQtd(cAtivo,i);    
      fBookBuy[i] := fBookBuySum - TotalBuyQtd(cAtivo,i);
    end
    else
    begin
      fBookSell[i] := fBookSellSum;
      fBookBuy[i] := fBookBuySum;  
    end; 
  end;

  
  {
  // Comparando retorno das funções (Ask/Bid)Size com Total(Sell/Buy)Qtd
  plot(fBookSell[0]);
  plot2(fBookBuy[0]);
  SetPlotColor(1,clRed);
  SetPlotColor(2,clRed);

  plot3(AskSize);
  plot4(BidSize);
  SetPlotColor(3,clYellow);   
  SetPlotColor(4,clYellow);
  }

  // Comparando os 5 primeiros níveis do lado da compra
  plot(fBookBuy[0]);
  plot2(fBookBuy[1]);
  plot3(fBookBuy[2]);
  plot4(fBookBuy[3]);
  plot5(fBookBuy[4]);

  SetPlotColor(1,clRed);
  SetPlotColor(2,clRed);
  SetPlotColor(3,clRed);   
  SetPlotColor(4,clRed);
  SetPlotColor(5,clRed);
  


end
				
			

Outros Snippets

Introdução

Esta seção visa apresentar outros exemplos de trechos de códigos que não se enquadram nas categorias anteriores.

Você pode acessar os Snippets diretamente pelo menu lateral direito, ou fazendo CRL+F (CTRL+L) para localizar algum texto específico na página, uma vez que o conteúdo tende a crescer ao longo do tempo, dificultando a navegação pelo menu.

Caso tenham sugestões de código para acrescentar à lista, gentileza deixar o código nos comentários com o link para seu perfil em rede social (para devido crédito de autoria).

Snippets

Escrevendo no Console com Timestamp para facilitar Debug

A partir da versão beta 215, tornou-se possível no Backtesting escrever texto no Console, o que facilita a depuração de estratégias.

Segue abaixo um snippet no qual há uma função que retorna o timestamp da barra. O corpo principal da estratégia apenas gera na aba “Compilação” o log com mensagem “Teste” precedido do timestamp no formato “DD/MM/AAAA HH:MM”.

				
					var
  horario: integer;
  timestamp : string;


//---------------------------------------------------
function getTimestamp: string;
var
  dia, mes_ano, hora: string;
begin

  if Month(Date) < 10 then 
    mes_ano := "0" + Month(Date) + "/" + Year(Date)
  else
    mes_ano := Month(Date) + "/" + Year(Date);    

  if DayofMonth(Date) < 10 then
    dia := "0" + DayofMonth(Date) + "/" + mes_ano
  else 
    dia := DayofMonth(Date) + "/" + mes_ano;

  if Floor(Time/100) < 10 then
    hora := "0" + Floor(Time/100)
  else
    hora := Floor(Time/100);

  if Mod(Time,100) < 10 then
    hora := hora + ":" + "0" + Mod(Time,100)
  else
    hora := hora + ":" + Mod(Time,100);    

  Result :=  dia + " " + hora + " - ";
end;
//---------------------------------------------------

begin
  if horario <> Time then
  begin
    timestamp := getTimestamp;
    ConsoleLog(getTimestamp() + "Teste", clBlue);
    horario := Time;
  end;
  
end;





				
			

Arrendondamento de valores para N casas decimais

Reproduzir vídeo

Como o Profit não tem nativamente uma função para arrendondar um float para uma determinada quantidade de casas decimais (N), a função abaixo foi implementada com esta finalidade.

				
					var
  fValorOriginal: float;
  fValorArred: float;

function NTB_ArredondarFloat(Value: float; nCasas: integer):float;
var
    fValor: float;
    fParteInteira: float;
    fParteDecimal: float;
begin
  fValor := Value;
  fParteInteira := IntPortion(fValor);
  fParteDecimal := Round((fValor - fParteInteira)*Power(10,nCasas));

  Result := fParteInteira + fParteDecimal/Power(10,nCasas);

end;

begin
  fValorOriginal := 12.345819;
  fValorArred :=  NTB_ArredondarFloat(fValorOriginal,2);

  if LastBarOnChart then
    PlotText(fValorArred,clWhite, - 1,8);
end;
				
			

Restrição de estratégia pelo código do ativo

O código abaixo visa identificar o código do ativo no qual a estratégia ou robô está sendo aplicado. A estratégia apenas é executada se o ticker do ativo for igual a constante “cAtivoEstrategia”.

Isto evita que as estratégias sejam rodadas de forma equivocada em ativos para os quais os parâmetros da estratégia não foram otimizados.

				
					const
  cAtivoEstrategia = "PETR4";
begin
  if GetAsset = cAtivoEstrategia then
  begin
    //TODO CÓDIGO FONTE DA SUA ESTRATÉGIA DEVE ESTAR AQUI DENTRO
    PaintBar(clGreen);
  end
  else
    if LastBarOnChart then
      plotText("Usar em " + cAtivoEstrategia,clWhite,-1,12);
end
				
			

Restrição de estratégia pelo tipo/frequência do gráfico

Reproduzir vídeo

O código abaixo visa identificar o tipo de gráfico no qual a estratégia ou robô está sendo aplicado. Caso não corresponda ao tipo de gráfico para o qual a estratégia foi otimizada, é exibida mensagem com informação sobre o tipo de gráfico adequado.

Isto evita que as estratégias sejam rodadas de forma equivocada para tipos de gráficos e frequências temporais diferentes daquelas para as quais foi validada.

				
					var
  bStarted, bGraficoOK: boolean;
  iTipoGrafico: integer;
  strMensagemErro: string;
begin
  if Not bStarted then
  begin
    bStarted := true;
    iTipoGrafico := GraphicInterval;

    //Verificação de Renko 3R
    if (iTipoGrafico = itRenko) and (GraphicOffset = 3) then bGraficoOK := true
    else strMensagemErro := "Estratégia para 3R"; 
    
    //Verificação de Gráfico de 5 minutos    
    //if (iTipoGrafico = itMinute) and (GraphicOffset = 5) then bGraficoOK := true
    //else strMensagemErro := "Estratégia para 5 Minutos";
         
  end;

  // Robô/Estratégia só irá ser executada se o gráfico estiver configurado
  // adequadamente
  if bGraficoOK then
  begin


  end
  // Se gráfico não estiver na configuração adequada, pinta todas as barras de vermelho
  // e exibe texto na última barra
  else
  begin
  paintBar(clRed);
  if LastBarOnChart then
    plotText(strMensagemErro,clWhite,-1,9);
  end;

end
				
			

Ignorar boxes de Gap em gráficos de Renko

Reproduzir vídeo

É bastante comum, principalmente na operação de contratos futuros, a ocorrência de gaps na abertura. Quando se está em um gráfico de Renko, o código da estratégia é processado para cada box incluído no gráfico devido ao gap.

Este código apresenta uma forma simples de não executar lógica sobre boxes referentes à gap. Os boxes de gap possuem duração igual a zero. Para realizar a verificação da duração temporal em minutos de um box, basta utilizar o comando BarDurationF.

				
					var
  bLocalizouBoxesGap : boolean;
  iDataUltimoBox, iUltimoBoxDiaAnterior, iBoxDeGAP: integer;
begin
  
  // Código é aplicável apenas à gráficos do tipo Renko
  if GraphicInterval = itRenko then
  begin  
    // Identificação de Box relacionados a GAP
    if Date <> iDataUltimoBox then
    begin
      iUltimoBoxDiaAnterior := CurrentBar - 1;
      iBoxDeGAP := CurrentBar;
      bLocalizouBoxesGap := false;
    end;
  
   iDataUltimoBox := Date;
   
   if Not bLocalizouBoxesGap then
    if BarDurationF = 0 then 
    begin
      iBoxDeGAP := CurrentBar;
      PaintBar(clRed);
    end
    else
    begin
      //Aqui foi identificado o primeiro box que não é de GAP
      bLocalizouBoxesGAP := true;
    end;


    //Aqui executa a estratégia em boxes que não são devido à
    //gap de abertura
    if bLocalizouBoxesGAP then
    begin
      PaintBar(clGreen);
    end;



  end
  // O Gráfico não é do tipo Renko!
  else
    if LastBarOnChart then PlotText("Aplicável apenas a Renko",clWhite,-1,10);

end
				
			

Cálculo de Gap em gráficos de Renko em termos de boxes

É bastante comum, principalmente na operação de contratos futuros, a ocorrência de gaps na abertura. Este código visa calcular o tamanho do gap nos gráficos de Renko em termos da quantidade de boxes.

OBS: É importante ressaltar que devido à própria natureza do gráfico de Renko, o cálculo de gap não é preciso quanto o cálculo de gap pelo gráfico de Candle.

OBS2: Os comandos OpenD(0) e CloseD(1) também podem ser utilizados em gráficos de renko, reduzindo o código abaixo a gap := (OpenD(0) – CloseD(1))/((GraphicOffset-1)*MinPriceIncrement). No entanto, os valores encontrados divergem em alguns dias de gap por 1 box. Pela minha apuração, o código abaixo apresenta os resultados corretos.

				
					var
  bLocalizouBoxesGap : boolean;
  fTamanhoBox : float;
  iDataUltimoBox, iUltimoBoxDiaAnterior, iBoxDeGAP: integer;
  fGAPdoDiaBox, fAberturaBox, fFechamentoDiaAnteriorBox: float;
begin
  
  // Código é aplicável apenas à gráficos do tipo Renko
  if GraphicInterval = itRenko then
  begin  
    fTamanhoBox := (GraphicOffset-1)*MinPriceIncrement;
    
    // Identificação de Box relacionados a GAP
    if Date <> iDataUltimoBox then
    begin
      iUltimoBoxDiaAnterior := CurrentBar - 1;
      iBoxDeGAP := CurrentBar;
      bLocalizouBoxesGap := false;
    end;
  
   iDataUltimoBox := Date;
   
   if Not bLocalizouBoxesGap then
    if BarDurationF = 0 then iBoxDeGAP := CurrentBar
    else
    begin
      //Aqui foi identificado o primeiro box que não é de GAP
      bLocalizouBoxesGAP := true;
  
      //Coloque abaixo o que deseja fazer no primero box do dia que não é GAP
      // --------------------------------------------------------------------
      if (Open < Close[1]) Or (Open > Close[1]) then fAberturaBox := Open[1]
      else fAberturaBox := Close[1];
      fFechamentoDiaAnteriorBox := Close[CurrentBar - iUltimoBoxDiaAnterior];
       
      fGAPdoDiaBox := (fAberturaBox -  fFechamentoDiaAnteriorBox)/fTamanhoBox;
  
      if fGAPdoDiaBox <> 0 then 
      begin
        if fGAPdoDiaBox > 0 then
          PlotText("GAP:" + Floor(fGAPdoDiaBox) + " Box",clGreen,-1,9)
        else
          PlotText("GAP:" + Floor(fGAPdoDiaBox) + " Box",clRed,-1,9);
        PaintBar(clRed);
      end;
      // --------------------------------------------------------------------
    end;
  end
  // O Gráfico não é do tipo Renko!
  else
    if LastBarOnChart then PlotText("Aplicável apenas a Renko",clWhite,-1,10);

end
				
			

Execução de estratégia em frequência superamostrada

Reproduzir vídeo

É de conhecimento de quem opera gráficos com tempo gráfico maior os impactos de se executar ordens apenas no fechamento dos candles/boxes.

Este Snippet visa tornar as ordens mais tempestivas, exemplificando uma forma de executar uma estratégia/robô em um tempo gráfico menor do que o original. Naturalmente que isso exige um código fonte mais complexo para tratar de forma adequada os cálculos de indicadores utilizados na estratégia.

O código de exemplo abaixo, demonstra como utilizar uma média móvel em um tempo gráfico superamostrado equivalente ao tempo gráfico original da estratégia (e com valor superior). Bem como também demonstra como seria o cálculo para obter a média de fechamento em tempos gráficos superiores ao gráfico supermostrado.

OBS: Embora não seja um requisito, sugere-se que o tempo gráfico original seja um múltiplo do tempo gráfico superamostrado.

				
					//LIMITAÇÃO IMPORTANTE: Não dá para fazer em escala de segundos
//devido a função time não retornar segundos
const
  // Estratégia originalmente rodava em gráfico de 15 min
  cTempoGraficoOriginal = 15;
  //Qtde de periodos no tempo gráfico original
  cQtdePeriodosMedia = 20;
  //Horario inicial de negociação do ativo
  //0900 para futuros, 1000 para mercado a vista
  cHoraInicioNegociacao = 0900;
var
  bStarted: boolean;

  iTempoGraficoAtual: integer;
  iQtdePeriodosEquivalente: integer;
  fMediaSuperAmostradaEquivalente: float;

  fInicializacaoMedia: float;
  fMediaTempoGraficoOriginal: float;
  iQtdePeriodosCalculados: integer;

  iHorarioEmMinutos: integer;
  iHorarioGrafSuperior: integer;
  bCalculouTempoGrafSuperior: boolean;

begin
  //1a opção: Dar preferencia sempre que possível
  // Identifica tempo gráfico utilizado e qtde de periodos equivalente para média superamostrada
  iTempoGraficoAtual := GraphicOffset;
  iQtdePeriodosEquivalente := Floor(cTempoGraficoOriginal/iTempoGraficoAtual)*cQtdePeriodosMedia;

  // Obtem média superamostrada equivalente
  fMediaSuperAmostradaEquivalente := Media(iQtdePeriodosEquivalente,Close);

  //Plot da série para inspeção
  PlotN(1,fMediaSuperAmostradaEquivalente);
  SetPlotColor(1, clWhite);
  SetPlotWidth(1,2);
  SetPlotStyle(1, psDash);



  //2a opção: Exige mais linhas de código para gerenciar execução
  //Amostrando apenas os valores de fechamento do Tempo gráfico original
  iHorarioEmMinutos := Floor(Time/100)*60+Mod(Time,100)
                     - (Floor(cHoraInicioNegociacao/100)*60+Mod(cHoraInicioNegociacao,100));
  
  if Not bStarted then
  begin
    iHorarioGrafSuperior := CalcTime(Time,-Mod(iHorarioEmMinutos, cTempoGraficoOriginal));
    bStarted := true;
  end;

  // Bloco para criar mecanismo de calcular apenas uma vez para o gráfico superior
  if (CalcTime(Time,-Mod(iHorarioEmMinutos, cTempoGraficoOriginal)) <> iHorarioGrafSuperior) then
  begin
    iHorarioGrafSuperior := CalcTime(Time,-Mod(iHorarioEmMinutos, cTempoGraficoOriginal));
    bCalculouTempoGrafSuperior := false;
  end;


  // Cálculo da média no tempo gráfico original
  if (Mod(iHorarioEmMinutos, cTempoGraficoOriginal) = 0) and Not bCalculouTempoGrafSuperior then
  begin
    bCalculouTempoGrafSuperior := true;
    if (iQtdePeriodosCalculados < cQtdePeriodosMedia) then 
    begin
      iQtdePeriodosCalculados := iQtdePeriodosCalculados + 1;
      fInicializacaoMedia := fInicializacaoMedia + Close[1];
    end
    else
      if (iQtdePeriodosCalculados = cQtdePeriodosMedia) then
      begin
        fMediaTempoGraficoOriginal := fInicializacaoMedia/iQtdePeriodosCalculados;
        iQtdePeriodosCalculados := iQtdePeriodosCalculados + 1;
      end
      else
        fMediaTempoGraficoOriginal := (fMediaTempoGraficoOriginal*cQtdePeriodosMedia
                                     - Close[1+cQtdePeriodosMedia*Floor(cTempoGraficoOriginal/iTempoGraficoAtual)]
                                     + Close[1])/cQtdePeriodosMedia;
  end;


  //Plot da série para inspeção
  PlotN(2,fMediaTempoGraficoOriginal);
  SetPlotColor(2, clRed);
  SetPlotWidth(2,2);
  SetPlotStyle(2, psSolid);

end
				
			

Como utilizar dados de preço de outros ativos

O código abaixo apenas exemplifica como obter os dados OHLCV de outras ativos em uma estratégia, o que pode ser feito via parâmetro ou constante. Caso o ativo desejado seja uma ação, deve-se atentar para modificar o feedBMF para feedBovespa.

				
					const
  cAtivo1 = Asset("INDFUT",feedBMF);
input
  pAtivo2("WINFUT",feedBMF);
  pQtdePeriodos(50);
var
  fMediaAtivo1, fMediaAtivo2: float;
begin
  fMediaAtivo1 := Media(pQtdePeriodos,cAtivo1.Close);
  fMediaAtivo2 := Media(Floor(pQtdePeriodos*1/3),pAtivo2.Close);
  plot(fMediaAtivo1);
  plot2(fMediaAtivo2);

end;
				
			

Criando o seu primeiro ROBÔ - V1

Reproduzir vídeo

Introdução

Neste documento vamos ver passo a passo de como criar o seu primeiro robô no Profit Chart DO ZERO…Você verá que com metodologia, organização e boas referências, programar um robô é uma tarefa relativamente fácil! Os verdadeiros desafios estão em outras partes do processo, e que abordaremos em outras oportunidades.

Eu já te prometo, desde já, que eu não vou te passar nenhum setup milagroso para te fazer rico. O objetivo deste documento não é te vender ilusões ou qualquer curso que seja. Eu quero te apresentar como eu vejo o processo de criação de um robô, que metodologia eu utilizo e você terá a real noção das dificuldades que enfrentará para desenvolver o seu próprio setup automatizado e, que se tudo der certo, um setup lucrativo!

Desde que o mundo é mundo, os vendedores sempre utilizaram a técnica de complicar as coisas para te vender facilidades, isso não é diferente nos dias de hoje…Então eu vou começar simplificando…Vou começar pelo começo! Eu criei o fluxograma abaixo para estabelecer uma linha guia de estrutura do nosso raciocínio.

Metodologia de Desenvolvimento de um Robô

A figura abaixo apresenta o fluxograma da metodologia aplicada no desenvolvimento de um robô. Vamos fazer uma passagem geral sobre a metodologia antes de aprofundar em cada etapa.

Tudo começa pela definição de um algoritmo. É daí que vem o termo algotrading….operações baseadas em algoritmos. No jargão popular, a gente chama de robô…e a Nelógica chama de “Estratégia de execução”…É tudo a mesma coisa!

E como é que achamos um algoritmo? Algoritmos, os bons algoritmos, não são achados por aí pela internet em vídeos de Youtube ou páginas sobre análise técnica. O máximo que você vai encontrar na internet são pessoas falando exatamente a mesma coisa, que são setups baseados em indicadores… quais são os sinais de entrada e sáida de cada setup. 

Apesar de haver muito chão a percorrer em termos de teste, validação, otimização e backtesting para pegar setups primários baseados em indicadores e transformá-los em algoritmos com alguma chance de sucesso, frequentemente você verá pessoas “vendendo” esses setups, ou até vendendo cursos, dizendo se tratar de estratégias infalíveis ou com alta taxa de acerto! Quem dera fosse fácil assim!

Quando o negócio é muito bom… Desconfie! Principalmente, se não puder ver o código fonte da estratégia que lhe está sendo recomendada! A verdade é que você pode até começar uma ideia por algum setup básico de análise técnica, mas terá que desenvolver por conta própria adaptações para chegar a um algoritmo capaz de rodar em conta real. E minha dica é: COMECE SIMPLES! 

Comece um algoritmo o mais simples possível. Rode as três etapas da metodologia e vá melhorando esse algoritmo em iterações sucessivas. Não tente abraçar o mundo logo na primeira implementação.

Uma vez que você tenha um algoritmo inicial, o próximo passo é escrever o código fonte. Esta etapa tem suas dificuldade técnicas de programação, mas você verá com o tempo que não se tratam das maiores dificuldades que encontrará no meio do caminho para desenvolver o seu robô!

Clique aqui para acessar os Modelos de estratégias, ou aqui para acessar a seção de Snippets!

Uma vez escrito o código fonte do algoritmo, sem erros de sintaxe. A gente vai rodar o robô com os dados disponíveis para verificar a aderência da execução do robô ao que havia sido planejado. Nesta terceira etapa, vamos procurar por erros e falhas no código e, se encontradas, vamos voltar à etapa anterior e ajustar a programação.

Agora que já tivemos uma visão geral das etapas, eu devo salientar que a metodologia de desenvolvimento de um robô não é tão linear como na figura apresentada anteriormente. Você verá que teremos muitas iterações entre as etapas, rodando vários ciclos de adaptações e  melhorias até chegar a uma versão de robô madura o suficiente para realizarmos a otimização de parâmetros e backtesting, visando verificar a sua viabilidade de execução em conta real. Mas isso é assunto para outra oportunidade. Por ora, vamos aprofundar em cada etapa nas seções abaixo.

Definindo o seu Algoritmo

Nesta primeira etapa precisamos definir com clareza (até onde podemos) como o robô deverá funcionar. Eu recomendo você abrir um bloco de anotações, físico ou virtual, e anotar suas respostas para as seguintes perguntas:

  1. Qual ativo pretendo operar?
  2. Meu robô vai operar comprado, vendido ou nos dois lados?
  3. Em que frequência gráfica ele vai operar? Ou vai operar de acordo com volatilidade em gráficos do tipo Renko?
  4. Quais indicadores técnicos vou utilizar?
  5. Quando ele deve abrir uma posição comprada? Em termos mais técnicos…qual é o sinal de compra? Faça a mesma pergunta para posição vendida! Desenvolva a resposta em termos de condições objetivas!
  6. Ele vai atuar apenas liquidando a posição ou vai permitir reversão de posição? Quais serão os sinais para cada situação?
  7. Meu robô vai segurar posição para swing trade ou só vai operar daytrade?
  8. Se não tiver sinal para liquidar ou reverter posição, como será definido o alvo da operação?
  9. Como será a administração das operações e a gestão de risco delas? Que técnicas de stoploss serão aplicadas? Vou utilizar stop com breakeven? Stop fixo? Stop móvel (Trailing stop)?

Eu sei que são muitas perguntas! Provavelmente você não tem resposta para todas as perguntas e algumas respostas poderão ser obtidas no processo de otimização da estratégia! O objetivo dessas perguntas é que você faça um brainstorming inicial!

Como a evolução natural nos ensina, a gente precisa se desenvolver de forma incremental! Primeiro a gente faz o simples funcionar e depois vamos aperfeiçoando e ajustando aos poucos…Aliás, essa é a filosofia de muitas diferentes metodologias de desenvolvimento de software… Então, não adianta começarmos pensando no mais complexo! Temos que simplificar ao máximo e escrever o código do nosso robô de forma iterativa, começando pela versão mais simples possível!

Escrevendo o Código-fonte

Esta é uma etapa bem “mão na massa”! Como já mencionei anteriormente, você poderá ganhar bastante tempo se aproveitar da experiência e informações compartilhadas pela Comunidade por meio dos Modelos de Estratégias e Snippets (exemplos de código fonte).

Minha recomendação é que comece o seu código fonte com organização desde o começo. Isso vai lhe ajudar a estruturar melhor, entender mais facilmente quando revisitar seu código ou até para que outra pessoa entenda seu código quando você o compartilhar.

Conte com a Comunidade e os fóruns disponíveis no site para te ajudar nessa etapa! 

Verificando a aderência do seu robô

Rodar um robô (estratégia de execução) em dados históricos, é bem fácil no Profit. Basta clicar no botão “Executar” e pronto! Mas fácil não quer dizerque seja  bom….tem muita coisa pra melhorar no editor de estratégias! Mas é o que temos por hoje temos que extrair o máximo que dá!

A primeira coisa que fazemos depois de rodar a primeira versão do robô (V1) é fazer uma inspeção visual para identificar erros grotescos de implementação! Por exemplo, você pode abrir o gráfico e não ter nenhuma sinalização de ordem. Ou ter apenas uma… Provavelmente, o seu código estaria com algum problema lógico.

Caso encontrasse algum problema, você teria que voltar ao código e tentar corrigir o problema, utilizando até o debug, que apesar de suas limitações é a ferramenta que dispomos para depurar o código fonte das estratégias.

O segundo filtro para identificar possíveis problemas é acessar a aba “Operações” ou “Gráfico de Operações” do modo “Estatísticas”, e inspecionar por problemas óbvios….Operações com lucros ou prejuízos muito grandes, ou operações com duração muito longa, características das operações que você não esperaria encontrar de acordo com os critérios do seu robô.

Caso encontrasse algum problema, você voltaria ao gráfico de simulação e verificaria a operação problemática, analisando o que pode ter ocorrido de diferente do previsto, inclusive depurando por meio de breakpoints.

Um ponto muito importante nessa etapa é tomar o cuidado para utilizar apenas os 70% dos dados históricos disponíveis e mais antigos. E por que disso? Porque os 30% restante dos dados, que são mais recentes serão utilizados para etapa de backtesting. 

É muito importante testar, validar e otimizar seu robô em uma janela de dados distinta da janela de dados de backtesting! A razão é meio óbvia, se você otimizar sua estratégia para todos os dados disponíveis, você pode estar ajustando o robô para as situações específicas daqueles dados e terá por consequência (ou ao menos se espera) que você encontre bons resultados! 

O que queremos no backtesting é verificar se o robô é capaz de generalizar bem com outros dados. Então não se esqueça de limitar sua análise nesta etapa de teste apenas aos dados que não serão usados no backtesting!

Colocando o Robô para rodar em conta real!

Executei as etapas 1, 2 e 3! Já posso colocar meu robô para rodar em conta real? Muito provavelmente a resposta é NÃO!

Lembra-se que eu disse que o processo de desenvolvimento de um robô é iterativo? Veja a figura abaixo para entender o que eu quis dizer com isso!

Dificilmente você conseguirá em uma única iteração do processo, chegar a um bom robô! Até pode…mas isso é altamente improvável.

Uma vez desenvolvido o código fonte da primeira versão do robô, vamos analisar o desempenho dele por meio de métricas objetivas, tais como taxa de acerto, relação risco ganho, lucro líquido, máximo drawdown.

Em seguida vamos postular ajustes que poderiam ser feitos para melhorar a métrica desejada. Geralmente, você irá buscar identificar aspectos relacionados à: ponto de abertura das operações, administração dos trades e gestão de risco, ponto de encerramento das operações.

Vamos fazer isso de forma iterativa até que cheguemos a uma situação de desempenho aceitável. É importante ter um diário do que está sendo alterado de uma versão para outra, guardar as principais métricas em uma planilha, bem como salvar o código fonte intermediário para não se perder no meio das iterações. Lembre-se, organização é muito importante para não perder o foco e gastar tempo desnecessário tentando entender o que você fez!

 

Exemplo de desenvolvimento de um robô

Para dar um exemplo prático e tornar mais tangível o processo de criação de um robô, eu utilizei um caso clássico de setup da literatura de indicadores técnicos para seguir tendência, em inglês, trend following system. Apesar de clássico, ou seja, existe há mais de 1 século, muita gente tira da cartola essa ideia todo ano, como se fosse inovadora.

A primeira versão do setup que iremos trabalhar ao longo deste documento e dos próximos, que vou chamar originalmente de Cruzamento triplo de médias móveis terá as seguintes definições:

  • Vai operar no mercado de ações permitindo swing trade;
  • Só vai operar comprado;
  • Vai utilizar 3 três médias móveis exponenciais de 10 (média rápida), 50 (média intermediária) e 200 (média lenta) períodos;
  • Vai operar em gráfico candle 15 minutos
  • Sinal de compra será o cruzamento da média intermediaria para cima da média lenta, estando a média rápida acima da média intermediária
  • Sinal de liquidação será média rápida cruzando para baixo a média intermediária;
  • Na primeira versão não será utilizado stoploss.

Pessoal, só para reforçar…este é um exemplo… não estou preocupado se é uma estratégia lucrativa ou não…Se funciona nos dias atuais ou não…Aliás já adianto que a taxa de acerto de setups básicos de cruzamento de médias é baixíssima…Isso é bom para fins didáticos. Vamos ter muito espaço para explorar!

Assista ao vídeo do Youtube que fizemos sobre a metodologia de criação de um robô e execução da primeira iteração do processo resultando na versão 1 (V1), conforme código fonte abaixo.

No próximo documento iremos realizar, na prática, sucessivas iterações a fim de melhorar o desempenho do algoritmo inicialmente proposto.

Nos vemos lá!

Robô de Cruzamento triplo de média móvel (V1)

Segue abaixo o código fonte gerado para primeira versão do robô de Cruzamento triplo de média móvel.

				
					// #######################################################################
// #######################################################################
// #######################################################################
// ######                            O                             #######
// ######                        ____|____                         #######
// ######                      _|         |_                       #######
// ######                     (_|  O   O  |_)                      #######
// ######                       |_________|                        #######
// ######                                                          #######
// ###### ____        __        ____________           ________    #######
// ###### | | \       | |       | |_________|         /  ____  \   #######
// ###### | |\ \      | |       | |                  /  /    \  \  #######
// ###### | | \ \     | |       | |____             |  |      |  | #######
// ###### | |  \ \    | |       | |____|            |  |      |  | #######
// ###### | |   \ \   | |       | |____|            |  |      |  | #######
// ###### | |    \ \  | |       | |                 |  |      |  | #######
// ###### | |     \ \ | |       | |_________         \  \____/  /  #######
// ###### |_|      \_\|_|       |_|_________|         \________/   #######
// ######                                                          #######
// ###### _______  __          __   ____  __   ___    __  _______  #######
// ######    |    |  \   /\   |  \ |     |  \ |   \  /  \    |     #######
// ######    |    |__/  /__\  |   ||__   |__/ |___/ |    |   |     #######
// ######    |    |\   /    \ |   ||     |\   |   \ |    |   |     #######
// ######    |    | \ /      \|__/ |____ | \  |___/  \__/    |     #######
// ######                                                          #######
// ######  Comunidade aberta de automatização de estratégias para  #######
// ######                    negociação de ativos                  #######
// ######                                                          #######
// ######                    www.NeoTraderBot.com                  #######
// #######################################################################
// #######################################################################
// #######################################################################
//
// -----------------------------------------------------------------------
// ---------------------- DADOS DA ESTRATÉGIA ----------------------------
// -----------------------------------------------------------------------
//
// NOME DA ESTRATÉGIA: _NBT_EXE_3CROSS
//   DESENVOLVIDA POR: Johnathas Carvalho
//    DATA DE CRIAÇÃO: 02/10/2022
//             VERSÃO: 1.0
//      ATUALIZADA EM: 02/10/2022
// TIPO DE ESTRATÉGIA: ( ) Indicador  ( ) Coloração (X) Execução
//                     ( ) Screening  ( ) Texto     ( ) Alarme
//
// DESCRIÇÃO DA ESTRATÉGIA:
// Estratégia baseada em cruzmaento triplo de média móvel
//
//
// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
//
// ######################### FIM DO CABEÇALHO ############################
//
//
// -----------------------------------------------------------------------
// -------------------------- Constantes ---------------------------------
// OBS:
// -----------------------------------------------------------------------
const
  cPlotarIndicadores = true;
  //
  // ---------------------------------------------------------------------
  // -------------------------- Parâmetros -------------------------------
  // OBS: Segue abaixo a descriação de cada parâmetro
  // 1) pLimiteSobreComprado -> Limite no qual considera-se que o cruzamento
  // para baixo gere uma operação de venda
  // 2) pLimiteSobreVendido -> Limite no qual considera-se que o cruzamento
  // para cima gere uma operação de compra
  // 3) pTamanhoPosicao -> Tamanho da exposição ao ativo
  // ---------------------------------------------------------------------
//input
//  pMediaRapida(10);
//  pMediaIntermediaria(50);
//  pMediaLenta(200);
//  pTamanhoPosicao(100);
  // ---------------------------------------------------------------------
  // ---------------------- Variáveis globais ----------------------------
  // OBS:
  // ---------------------------------------------------------------------
var
  bStarted                                     : boolean;
  bSinalCompra,bSinalVenda,bSinalLiquida       : boolean;
  bComprado,bVendido                           : boolean;
  fMediaRapida,fMediaIntermediaria,fMediaLenta : float;

  //Parametros
  pMediaRapida: integer;
  pMediaIntermediaria: integer;
  pMediaLenta: integer;
  pTamanhoPosicao: integer;

begin
  pMediaRapida := 10;
  pMediaIntermediaria := 50;
  pMediaLenta := 200;
  pTamanhoPosicao := 100;

  // ---------------------------------------------------------------------
  // ----------------- Inicialização da estratégia -----------------------
  // OBS: Inicialização de variáveis a serem utilizadas na estratégia de
  // execuçaõ
  // ---------------------------------------------------------------------
  if Not bStarted then
    begin
      bStarted := True;
    end;
  // ---------------------------------------------------------------------
  // ------------------ Inicialização de variáveis -----------------------
  // OBS: Inicialização de variáveis p/ cada tick/barra
  // Nem todas as variáveis são inicializadas aqui porque se não houver
  // dados suficientes não faz sentido inicializar algumas variáveis
  // ---------------------------------------------------------------------
  bSinalCompra := False;
  bSinalVenda := False;
  bSinalLiquida := False;
  bComprado := isBought();
  bVendido := isSold();

  fMediaRapida := Media(pMediaRapida,Close);
  fMediaIntermediaria := Media(pMediaIntermediaria,Close);
  fMediaLenta := Media(pMediaLenta,Close);


  //BUG: Se não tiver algum plot antes dos comandos de backtesting, não funciona!
  if cPlotarIndicadores then
    begin
      SetPlotColor(1,clRed);
      SetPlotWidth(1,2);
      SetPlotStyle(1,psDash);
      SetPlotColor(2,clOlive);
      SetPlotWidth(2,2);
      SetPlotColor(3,clWhite);
      SetPlotWidth(3,2);
      Plot(fMediaRapida);
      Plot2(fMediaIntermediaria);
      Plot3(fMediaLenta);
    end;

  // ---------------------------------------------------------------------
  // ----------------------- Cálculo dos sinais  -------------------------
  // OBS: Inserir lógica de cálculo dos sinais de compra/venda
  // ---------------------------------------------------------------------
  if (fMediaLenta <> 0) then
  begin
    if  (fMediaRapida >= fMediaIntermediaria)
    and (fMediaIntermediaria > fMediaLenta) 
    and (fMediaIntermediaria[1] <= fMediaLenta[1]) then
        bSinalCompra := True;
    
    if  bComprado 
    and (fMediaRapida < fMediaIntermediaria) 
    and (fMediaRapida[1] >= fMediaIntermediaria[1]) then
        bSinalLiquida := True;
  end;
  // ---------------------------------------------------------------------
  // ------------------- Envia ordens de compra/venda --------------------
  // OBS: Baseando-se nos sinais e na atual posição, cria as ordens de
  // compra e venda de acordo com o setup desejado
  // ---------------------------------------------------------------------
  // Abre posição comprada
  if Not (bComprado Or bVendido) and bSinalCompra then BuyAtMarket(pTamanhoPosicao);

  // Encerra posição comprada
  if (bComprado and bSinalLiquida) then SellToCoverAtMarket(pTamanhoPosicao);


end;
				
			

Melhorando o desempenho do seu robô

Reproduzir vídeo

No documento anterior, vimos o processo de criação de um robô, passo a passo, por meio de um exemplo de setup baseado no cruzamento de três média. Um setup clássico da análise técnica. Se você ainda não viu esse conteúdo, clique aqui antes de prosseguir com a leitura.

Nosso objetivo neste documento é ajustar e melhorar a implementação do nosso algoritmo. Pense nele como um diamante que precisamos lapidar. Iremos de forma iterativa, ou seja, em etapas graduais, trazer o brilho do nosso algoritmo bruto. Explorar o máximo possível da ideia originária e aumentar o seu potencial para as etapas subsequentes de otimização e backtesting.

Para isso, precisamos seguir uma linha de raciocínio, uma metodologia do que verificar na execução do código fonte da nossa estratégia, em que sequência e o que fazer.

Não existe uma fórmula fechada para isso, poderíamos começar por caminhos diferentes, trocar a ordem de alguns passos…isso vai depender dos resultados obtidos no teste e como você pretende priorizar os ajustes! O objetivo final é obter um algoritmo mais refinado do que a versão bruta original. Em outras palavras, um algoritmo com maior chance de ser lucrativo.

Isso quer dizer que o sucesso é garantido? Não! Haverá casos, e estes serão a maioria deles, em que por mais que trabalhemos em ajustes do código, o desempenho refinado do algoritmo não será bom! Isso faz parte do processo de elaboração de robôs…acostume-se! Nem todas ideias que a primeira vista parecem ser muito boas, vão se confirmar durante o processo. O que importa é o quanto você vai aprender cada vez que tentar criar um novo robô…pois isto permitirá acelerar o processo cada vez que executa-lo novamente.

Dito isso, vou apresentar a seguir um diagrama das etapas percorridas para melhorar o código fonte de uma estratégia/robô, representando uma metodologia para você seguir quando estiver trabalhando em suas próprias estratégias.

Metodologia

Antes de apresentarmos o diagrama das etapas metodológicas e explicar cada uma delas, precisamos esclarecer alguns pontos iniciais:

  • Ajustar código fonte não é otimizar estratégia;
  • Estabeleça uma configuração inicial de parâmetros para os indicadores da estratégia e mantenha esses valores fixos até o fim do processo;
  • A configuração dos parâmetros deve ser escolhida de forma a refletir uma condição razoável do setup, a qual permita que ajustes no código fonte tenham reflexos na métricas que iremos monitorar;
  • Recomenda-se incorporar a gestão de risco das operações no processo de otimização da estratégia;
  • Se sua estratégia não tiver uma regra para encerramento de posição, estabeleça uma relação de risco/retorno entre 2:1 e 3:1, apenas para proceder o processo de ajuste do código fonte. Utilize valores razoáveis de stop e alvo em função da volatilidade média do ativo;
  • Os ajustes do código fonte devem ser realizados em fluxos distintos para posições compradas e vendidas, visando aprimorar o código fonte para cada posição de forma independente. A decisão sobre quais posições a estratégia deve abrir dependerá do processo de otimização junto aos resultados obtidos em backtesting.

Feitas essas ressalvas, veja o diagrama abaixo das etapas sequências que iremos executar para ajustar o código fonte da nossa estratégia. As etapas de “Restrições primárias de operação” e “Definição de baseline” são fundamentais e serão executadas necessariamente nessa ordem. No entanto, as demais etapas são intercambiáveis e sua ordem de execução pode ser alterada/suprimida a depender do objetivo do programador.

Vamos ver nas próximas seções maiores detalhes sobre cada etapa.

1) Restrições primárias de operação

Neste primeiro passo, vamos identificar se a estratégia/ robô está operando conforme planejado em termos de duração e quantidade de papéis para cada posição.

Se for um robô de daytrading, temos que garantir que ele não está carregando posições de um dia para outro. E temos que verificar se as quantidades negociadas de papéis ou contratos estão conforme estabelecido pela nossa estratégia.

Se nossa estratégia operar em gráficos de Renko, temos que certificar que operações não estão sendo executadas em boxes de gaps (o que não é possível na prática!).

Enfim, nesta etapa iremos verificar e proceder ajustes a fim de garantir que as futuras alterações no código sejam avaliadas sob as mesmas bases e de forma correta.

2) Definição de baseline

Primeiramente, precisamos definir um intervalo fixo de datas para execução de testes e futuramente, otimização da estratégia. Precisamos fixar também a quantidade de papéis ou contratos que serão negociados, o ativo e o tempo gráfico a ser usado. Estas configurações devem se manter constante até o fim do processo, bem como os parâmetros dos indicadores utilizados.

Usualmente iremos separar da janela histórica de dados da seguinte forma, 50% dos dados mais antigos para ajustes da estratégia e otimização, os 30% dos próximos dados para realização de backtesting, e os últimos 20% para simular a operação do robô em uma execução em tempo real. Estes não são percentuais fixos, cabendo ao programador arbitrar uma divisão que seja melhor para cada caso.

O importante dessa segregação de dados é garantir que não haverá interseção da janela de dados utilizada para testes e otimização do código fonte, backtesting e avaliação com dados novos.

Para dar suporte a todo o processo de ajustes, recomendamos que o programador crie um diretório em seu computador para a estratégia ora em ajuste a armazene todos os artefatos do processo: versões do código fonte sempre que for feita uma alteração que gere uma versão intermediária (em formato txt) e relatório de trades realizados do Profit. Se você é membro da Comunidade, baixe a ferramenta ANALISADOR DE TRADES para realizar este processo de forma eficiente e estruturada..

Uma vez executado o código fonte original na janela de dados históricos definida, iremos monitorar e considerar os valores das métricas Taxa de acerto (%), Relação risco/ganho, quantidade de trades e resultado líquido como base de referência para o próximo ajuste no código fonte.

3) Refinamento dos sinais de entrada

Nesta etapa iremos analisar a relação de trades realizados pelo código original e verificar no gráfico os motivos que levaram as operações a dar prejuízo em termos dos sinais criados. Em outras palavras, queremos reduzir a probabilidade de falsos positivos. Queremos refinar nossos sinais de entrada das operações, para não incorrer em abertura de posição em situações com alta probabilidade de fracasso. Queremos, portanto, melhorar a nossa taxa de acerto e, possivelmente, a relação risco/ganho.

É importante ressaltar que não estamos otimizando o código ainda. Não vamos durante o ajuste do nosso código ficar alterando a quantidade de períodos de médias e parâmetros de indicadores. Esse não é o objetivo….isso ficará para outra etapa, que é a otimização do algoritmo, quando ele já estiver com a lógica refinada.

Nesta etapa, assim como nas subsequentes, as alterações serão incrementais. Ou seja, faremos um ajuste de cada vez, avaliaremos as métricas e, em seguida, iremos acrescentar outro ajuste ao código. Desta forma, cada versão do código fonte terá as alterações realizadas até o momento. Daí, a importância de manter um controle organizado das versões do código fonte e o adequado arquivamento dos trades realizados por cada versão para o cálculo das métricas de cada versão.

4) Filtro de operações de acordo com condição de mercado

Neste momento, vamos focar nossa atenção nas operações que ainda estão gerando prejuízo e vamos ver se existe um padrão entre as operações. Ou seja, se há uma situação de mercado comum que aumenta a chance de operações não serem bem sucedidas. Estaremos procurando coisas do tipo…todas operações com prejuízo tiveram abertura antes de X horas, ou ocorreram quando o mercado estava lateralizado, ou quando o plano de fundo do mercado era um movimento altista, baixista, etc…

Observe que não somos obrigados a fazer um ajuste em cada etapa só porque a etapa existe. Vamos fazer ajustes apenas se estes fizerem sentido e os manteremos no código apenas se o resultado melhorar. Caso alguma alteração retroceda um bom resultado de uma versão anterior, iremos sempre levar a frente nas próximas etapas a melhor versão até o momento.

5) Verificação de oportunidades perdidas

Analisar uma lista fechada de trades e buscar padrões é relativamente “fácil”…Mas nessa etapa teremos que  procurar pelo invisível…tentaremos identificar no gráfico aquilo que não vemos na lista de trades!

Teremos que voltar ao gráfico e realizar uma inspeção visual minuciosa do início do intervalo de teste até o fim, procurando não aquilo que foi feito…mas o que não foi feito e que se tivesse feito poderia ter gerado lucro. É claro, vamos olhar com as lentes do nosso algoritmo original….sem ficar criando novas regras. Podemos trabalhar no relaxamento do sinal de entrada, permitindo uma flexibilidade temporal em relação ao atendimento das condições para abertura de posição, por exemplo.

6) Refinamento do fechamento de posições

Neste passo vamos analisar se o encerramento de posição está ocorrendo em momento adequado, ou se há algum atraso neste encerramento que esteja  reduzindo o lucro das operações.

Podemos tentar utilizar de projeções para antecipar um encerramento de posição em momento mais vantajoso. Observe que não estamos tratando da gestão de risco das operações, como definição de alvo e stoploss…isto iremos fazer numa etapa posterior do processo de criação do robô, quando formos realizar a otimização da estratégia.

No entanto, caso a sua estratégia não tenha uma regra para liquidação de posição, você deve arbitrar um relação fixa de stop e alvo para que possamos avaliar o impacto das alterações do código fonte nas métricas de desempenho da estratégia. Esta relação deve ser razoável e deveria ter sido realizada no momento de geração do baseline. Caso isto não tenha sido feito, você precisará voltar na etapa de definição de baseline e rodar o código fonte de cada alteração com esta relação de encerramento de posição.

Caso neste momento, você identifique uma regra fixa para encerramento de posição no seu algoritmo, então o recomendável é atualizar o seu algoritmo e reiniciar o processo de ajustes do código fonte.

7) Melhorando a tempestividade das ordens

Esse passo se aplica às ordens à mercado utilizadas para abrir posições. É de conhecimento geral que, até o presente momento, o envio de ordens à mercado ocorre apenas no fechamento do Candle ou box, o que pode gerar um atraso muito grande na abertura da posição, dependendo do tempo gráfico utilizado pela estratégia.

Assim, uma possível solução para esta questão é executar o robô em uma frequência superamostrada realizando os ajustes necessários para manter o comportamento coerente a um tempo gráfico original. O nível de complexidade, bem como a viabilidade desses ajustes depende dos indicadores utilizados.

Aumentar a tempestividade das ordens não garante necessariamente resultados melhores. Assim, o programador deve avaliar se é justificável testar a estratégia em frequência superamostrada.

Um ponto importante é referente à disponibilidade de dados dados históricos. Quanto mais se aumentar a frequência, menor será a quantidade de dados disponíveis para teste, impedindo um comparação com as versões anteriores do código na mesma janela de dados. É importante verificar se a quantidade de trades realizados garante uma amostra com confiabilidade estatística adequada.

Conclusão

Apresentamos neste documento uma metodologia para guiar o processo de ajustes e refinamentos do código fonte de sua estratégia/robô.

A importância de seguir uma metodologia e organização do processo é aumentar a chance de obter ao fim do processo um resultado de desempenho do robô dentro dos critérios de aceitação do programador.

Nem sempre conseguiremos obter uma estratégia com desempenho aceitável, o que pode justificar não levar para a fase de otimização tal estratégia. No entanto, para cada insucesso, fica o acúmulo de experiência do programador, que terá cada vez mais facilidade e ferramentas para realizar o processo com estratégias futuras.

Observe que até o momento não falamos de Gestão de risco da estratégia. Pois eu defendo que a gestão de risco fará parte do processo de otimização, o qual será tema em outros documentos desta Base de Conhecimento!

Por fim, no melhor caso, o programador irá finalizar as etapas acima mencionadas com uma versão refinada do código fonte, que não necessariamente será última versão testada (pode ser uma intermediária), que irá avançar para a fase de otimização da estratégia.

Espero que este conteúdo seja útil para o leitor e contribua para o seu processo de desenvolvimento de estratégias.

Versão final do Código fonte para otimização

Para baixar todos os artefatos gerados pelo processo executado no vídeo (código fonte das versões, csv de trades e Analisador de trades), clique aqui.

OBS: A restrição de tipo de gráfico e tempo gráfico está comentada devido a um bug do Profit para execução da estratégia em backtesting.

				
					// #######################################################################
// #######################################################################
// #######################################################################
// ######                            O                             #######
// ######                        ____|____                         #######
// ######                      _|         |_                       #######
// ######                     (_|  O   O  |_)                      #######
// ######                       |_________|                        #######
// ######                                                          #######
// ###### ____        __        ____________           ________    #######
// ###### | | \       | |       | |_________|         /  ____  \   #######
// ###### | |\ \      | |       | |                  /  /    \  \  #######
// ###### | | \ \     | |       | |____             |  |      |  | #######
// ###### | |  \ \    | |       | |____|            |  |      |  | #######
// ###### | |   \ \   | |       | |____|            |  |      |  | #######
// ###### | |    \ \  | |       | |                 |  |      |  | #######
// ###### | |     \ \ | |       | |_________         \  \____/  /  #######
// ###### |_|      \_\|_|       |_|_________|         \________/   #######
// ######                                                          #######
// ###### _______  __          __   ____  __   ___    __  _______  #######
// ######    |    |  \   /\   |  \ |     |  \ |   \  /  \    |     #######
// ######    |    |__/  /__\  |   ||__   |__/ |___/ |    |   |     #######
// ######    |    |\   /    \ |   ||     |\   |   \ |    |   |     #######
// ######    |    | \ /      \|__/ |____ | \  |___/  \__/    |     #######
// ######                                                          #######
// ######  Comunidade aberta de automatização de estratégias para  #######
// ######                    negociação de ativos                  #######
// ######                                                          #######
// ######                    www.NeoTraderBot.com                  #######
// #######################################################################
// #######################################################################
// #######################################################################
//
// -----------------------------------------------------------------------
// ---------------------- DADOS DA ESTRATÉGIA ----------------------------
// -----------------------------------------------------------------------
//
// NOME DA ESTRATÉGIA: _NBT_EXE_3CROSS
//   DESENVOLVIDA POR: Johnathas Araujo de Carvalho
//    DATA DE CRIAÇÃO: 16/09/2022
//             VERSÃO: 3.0
//      ATUALIZADA EM: 12/11/2022
// TIPO DE ESTRATÉGIA: ( ) Indicador  ( ) Coloração (X) Execução
//                     ( ) Screening  ( ) Texto     ( ) Alarme
//
// DESCRIÇÃO DA ESTRATÉGIA:
//      Esta estratégia visa realizar compras mediante o cruzamento triplo
// de médias móveis exponenciais.
//
// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
//
// ######################### FIM DO CABEÇALHO ############################
//
//
// -----------------------------------------------------------------------
// -------------------------- Constantes ---------------------------------
// OBS:
// -----------------------------------------------------------------------
const
  cPlotarIndicadores = true;
  cProtecaoGap = 101.5;
    
  //
  // ---------------------------------------------------------------------
  // -------------------------- Parâmetros -------------------------------
  // OBS: Segue abaixo a descriação de cada parâmetro
  // 1) pLimiteSobreComprado -> Limite no qual considera-se que o cruzamento
  // para baixo gere uma operação de venda
  // 2) pLimiteSobreVendido -> Limite no qual considera-se que o cruzamento
  // para cima gere uma operação de compra
  // 3) pTamanhoPosicao -> Tamanho da exposição ao ativo
  // ---------------------------------------------------------------------
//input
//  pMediaRapida(10);
//  pMediaIntermediaria(50);
//  pMediaLenta(200);
//  pTamanhoPosicao(100);
  // ---------------------------------------------------------------------
  // ---------------------- Variáveis globais ----------------------------
  // OBS:
  // ---------------------------------------------------------------------
var
  bStarted                                     : boolean;
  bSinalCompra,bSinalVenda,bSinalLiquida       : boolean;
  bComprado,bVendido                           : boolean;
  fMediaRapida,fMediaIntermediaria,fMediaLenta : float;

  //Parametros
  pMediaRapida: integer;
  pMediaIntermediaria: integer;
  pMediaLenta: integer;
  pTamanhoPosicao: integer;
  fTBDetector, fUltimoTopo, fUltimoFundo: float;

begin
  pMediaRapida := 10;
  pMediaIntermediaria := 30;
  pMediaLenta := 50;
  pTamanhoPosicao := 100;

  // ---------------------------------------------------------------------
  // ----------------- Inicialização da estratégia -----------------------
  // OBS: Inicialização de variáveis a serem utilizadas na estratégia de
  // execuçaõ
  // ---------------------------------------------------------------------
  if Not bStarted then
    begin
      bStarted := True;
    end;

  //if (GraphicInterval <> itMinute) or (GraphicOffset <> 15) then
  //  if LastBarOnChart then plotText("Mudar para 15 min!", clWhite, -1, 12)
  //else
  //begin 
    // ---------------------------------------------------------------------
    // ------------------ Inicialização de variáveis -----------------------
    // OBS: Inicialização de variáveis p/ cada tick/barra
    // Nem todas as variáveis são inicializadas aqui porque se não houver
    // dados suficientes não faz sentido inicializar algumas variáveis
    // ---------------------------------------------------------------------
    bSinalCompra := False;
    bSinalVenda := False;
    bSinalLiquida := False;
    bComprado := isBought();
    bVendido := isSold();
  
    fMediaRapida := MediaExp(pMediaRapida,Close);
    fMediaIntermediaria := MediaExp(pMediaIntermediaria,Close);
    fMediaLenta := MediaExp(pMediaLenta,Close);
    fTBDetector := TopBottomDetector(4);

    if (fTBDetector <> 0) and (fTBDetector >= Close) then fUltimoTopo := fTBDetector;
    if (fTBDetector <> 0) and (fTBDetector <= Close) then fUltimoFundo := fTBDetector;


    if cPlotarIndicadores then
      begin
        SetPlotColor(1,clRed);
        SetPlotWidth(1,2);
        SetPlotStyle(1,psDash);
        SetPlotColor(2,clOlive);
        SetPlotWidth(2,2);
        SetPlotColor(3,clWhite);
        SetPlotWidth(3,2);
        Plot(fMediaRapida);
        Plot2(fMediaIntermediaria);
        Plot3(fMediaLenta);
      end;
  
    

    // ---------------------------------------------------------------------
    // ----------------------- Cálculo dos sinais  -------------------------
    // OBS: Inserir lógica de cálculo dos sinais de compra/venda
    // ---------------------------------------------------------------------
    if (fMediaLenta <> 0) then
    begin
      if  (fMediaRapida >= fMediaIntermediaria)
      and (fMediaIntermediaria > fMediaLenta) 
      and (fMediaIntermediaria[1] <= fMediaLenta[1])  then
      begin
        if (fMediaRapida/fMediaLenta*100 <= cProtecaoGap) then
        if  (fMediaLenta > fMediaLenta[1])
        and (fMediaLenta[1] > fMediaLenta[2]) then
        if  (fMediaRapida > fMediaRapida[1]) 
        and (fMediaRapida[1] > fMediaRapida[2]) then
        if Not ((Close <= fUltimoTopo) and (Close >= fUltimoFundo)) then
        if Not (Close <= fUltimoFundo) then
          bSinalCompra := True;
      end;
      
      if  bComprado 
      and (fMediaRapida < fMediaIntermediaria) 
      and (fMediaRapida[1] >= fMediaIntermediaria[1]) then
          bSinalLiquida := True;
    end;
    // ---------------------------------------------------------------------
    // ------------------- Envia ordens de compra/venda --------------------
    // OBS: Baseando-se nos sinais e na atual posição, cria as ordens de
    // compra e venda de acordo com o setup desejado
    // ---------------------------------------------------------------------
    // Abre posição comprada
    if Not (bComprado Or bVendido) and bSinalCompra then BuyAtMarket(pTamanhoPosicao);
  
    // Encerra posição comprada
    if (bComprado and bSinalLiquida) then SellToCoverAtMarket(pTamanhoPosicao);

  //end;

end;
				
			

Criando seu próprio Indicador

Reproduzir vídeo

Médias móveis, RSI, MACD, Bandas de Bollinger, Canal de Keltner, OBV, ATR, VWAP…Você já sabe do que eu estou falando: Dos indicadores de análise técnica! Nesse documento eu irei abordar o processo de criação de um indicador para que você entenda as etapas necessárias para criação do seu próprio indicador, desde a análise de dados e concepção do indicador até a implementação e verificação de consistência.

No vídeo acima, você poderá acompanhar o conteúdo deste documento de forma mais dinâmica, bem como acompanhar um exemplo do processo de criação do indicador Neo Volatility Band.

Introdução

Os indicadores nasceram com a análise técnica e se pudéssemos eleger o primeiro da espécie, seria a média móvel! Ela é usada há mais de um século…numa época e que não tinha computador, calculadoras digitais e os trades não ocorriam em alta frequencia como hoje. No entanto, já eram úteis para identificar tendências…Você sabe que elas podem ser aritméticas, exponenciais, ponderadas… E quando utilizadas em pares dão origem até a outros indicadores tal como o MACD.

Com o tempo surgiram vários outros indicadores, que passaram a ser agrupados entre indicadores de tendência, osciladores (que buscam identificar divergências que sinalizem reversões), indicadores de volatilidade, entre outros.

Criar um indicador qualquer não é tão difícil…o desafio é criar um que seja útil e consistente!

O que quero dizer com útil? Um indicador que possa ser usado como base para um setup operacional, afinal isso é o que se pretende fazer com indicadores! Além é claro de enfeitar o gráfico com toda a paleta de cores possíveis! (Só para deixar claro, isso foi uma ironia!)

E consistente…o que isso significa? Um indicador que responda objetivamente ao propósito pelo qual foi criado, ou seja, que tenha forte correlação com o que propõe sinalizar.

Então vamos direto ao ponto…Vamos abordar o fluxo para criação de um indicador e explicar em detalhes cada etapa.

Fluxo para criação de um indicador

A figura abaixo apresenta um diagrama das etapas necessárias para criação de um indicador. Observa-se que elas foram dispostas em um formato de ciclo onde, o fluxo se retroalimenta.

O mais natural é iniciar o fluxo pela “Análise de dados” passando pelas etapas de “Definição de Cálculo”, “Escrita de código fonte e “Verificação de consistência”.

Vamos abordar nas seções subsequentes o escopo de cada etapa.

1) Analisar dados

Esta é a primeira etapa do fluxo de criação de um indicador. Ao analisar os dados, temos que definir um enfoque: movimentação de preço, volume, agressão, volatilidade; bem como estudar a relação entre as variáveis analisadas.

O ideal é identificar um padrão que possa ser sinalizado com antecedência e confiança estatística. Os indicadores podem servir ao propósito de identificar tendências, reversões de preço, consolidações, exaustão de movimento, entre outros.

2) Definir Cálculo

Uma vez identificado um padrão nos dados, o desafio é conseguir converter números e ideias em fórmulas matemáticas. Afinal, teremos que programar o indicador, ainda que seja uma soma, divisão ou multiplicação, ou ponderação de algum valor, esta conta precisa fazer sentido!

Para definição do cálculo do indicador devemos sempre seguir a máxima de que “soluções devem ser tão simples quanto possível e tão complexas quanto for necessário”. Não tem como acertar sempre…portanto, o indicador será um modelo de aproximação da realidade, passível de erro e de falsas sinalizações. Outro cuidado que devemos ter nessa etapa é de não tornar as exceções regras do cálculo.

Ou seja, tente evitar criar muitas restrições no cálculo para mitigar o risco de estar no final das contas um ajuste de curva.

3) Escrever o código fonte

Dado o enorme desafio das etapas anteriores, talvez a codificação do indicador seja a parte mais fácil do processo!

Como sempre dizemos, comece seu código simples e vá complicando aos poucos, de forma iterativa. Não tente “abraçar o mundo”…um indicador é só um indicador…não comece a caracterizar seu indicador como um setup em si ou como uma regra de coloração. O indicador é parte de um processo de elaboração de setup! O indicador que está criando pode e deve permitir a elaboração de estratégias que se baseiem em seu valor, bem como regras de coloração…mas estes não são objetivos que devem ser incorporados no código do indicador!

4) Verificar a consistência

Esta é uma etapa de validação que pode representar o fim da elaboração do indicador, ou o início de um novo ciclo de desenvolvimento do indicador.

Nesta etapa temos que verificar se o indicador e os valores calculados fazem sentido e se os valores apresentados nos permitem construir hipóteses para analisar o mercado. Acima de tudo, os valores calculados pelo indicador cumprem o objetivo inicial? É factível a criação de um setup que se baseie no indicador?

Temos que verificar também as situações nas quais o indicador funciona bem e quando ele não funciona tão bem.

Por fim, precisamos definir quais são os parâmetros do indicador, que permitem ajustá-lo a diferentes ativos ou situações de mercado.

Conclusão

Espero que este conteúdo tenha agregado valor a você e que tenham percebido a semelhança com o processo de criação de um robô.

A diferença é que enquanto existe um trabalho de análise de dados, o qual você pode aprofundar-se ao nível desejado para criação do indicador, na criação de um robô o esforço maior concentra-se no backtesting e na otimização para administração de trades e gestão de risco.

Assim como os robôs, as estratégias de indicadores também podem ser otimizadas e avaliadas em backtesting. Iremos abordar estes temas em outros documentos da nossa Base de Conhecimento.

Código fonte do indicador: Neo Volatility Band

				
					// #######################################################################
// #######################################################################
// #######################################################################
// ######                            O                             #######
// ######                        ____|____                         #######
// ######                      _|         |_                       #######
// ######                     (_|  O   O  |_)                      #######
// ######                       |_________|                        #######
// ######                                                          #######
// ###### ____        __        ____________           ________    #######
// ###### | | \       | |       | |_________|         /  ____  \   #######
// ###### | |\ \      | |       | |                  /  /    \  \  #######
// ###### | | \ \     | |       | |____             |  |      |  | #######
// ###### | |  \ \    | |       | |____|            |  |      |  | #######
// ###### | |   \ \   | |       | |____|            |  |      |  | #######
// ###### | |    \ \  | |       | |                 |  |      |  | #######
// ###### | |     \ \ | |       | |_________         \  \____/  /  #######
// ###### |_|      \_\|_|       |_|_________|         \________/   #######
// ######                                                          #######
// ###### _______  __          __   ____  __   ___    __  _______  #######
// ######    |    |  \   /\   |  \ |     |  \ |   \  /  \    |     #######
// ######    |    |__/  /__\  |   ||__   |__/ |___/ |    |   |     #######
// ######    |    |\   /    \ |   ||     |\   |   \ |    |   |     #######
// ######    |    | \ /      \|__/ |____ | \  |___/  \__/    |     #######
// ######                                                          #######
// ######  Comunidade aberta de automatização de estratégias para  #######
// ######                    negociação de ativos                  #######
// ######                                                          #######
// ######                    www.NeoTraderBot.com                  #######
// #######################################################################
// #######################################################################
// #######################################################################
//
// -----------------------------------------------------------------------
// ---------------------- DADOS DA ESTRATÉGIA ----------------------------
// -----------------------------------------------------------------------
//
// NOME DA ESTRATÉGIA: NVI Neo Volatility Indicator
//   DESENVOLVIDA POR: NeoTraderBOt
//    DATA DE CRIAÇÃO: 12/10/2022
//             VERSÃO: 1.0
//      ATUALIZADA EM: 12/10/2022
// TIPO DE ESTRATÉGIA: (X) Indicador  ( ) Coloração ( ) Execução
//                     ( ) Screening  ( ) Texto     ( ) Alarme
//
// DESCRIÇÃO DA ESTRATÉGIA:
//    Indicador baseado em volatilidade utilizando função log-retorno e 
// desvio padrão em torno de uma média de curto prazo
//
//
//
//
//
// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
//
// ######################### FIM DO CABEÇALHO ############################
//
//
// -----------------------------------------------------------------------
// -------------------------- Constantes ---------------------------------
// OBS:
// -----------------------------------------------------------------------
//const
  //cCONSTANTE = 1;
  //
  // ---------------------------------------------------------------------
  // -------------------------- Parâmetros -------------------------------
  // OBS: Segue abaixo a descriação de cada parâmetro
  // 1) parametro1 ->
  // 2) parametro2 ->
  // ---------------------------------------------------------------------
input
  pQtdePeriodosVolatilidade(500);
  pQtdePeriodosMedia(36);
  pQtdeDesvioVol(2.0);
  // ---------------------------------------------------------------------
  // ---------------------- Variáveis globais ----------------------------
  // OBS:
  // ---------------------------------------------------------------------
var
bStarted, 	bPlotIndicador: boolean;
fLogRetorno: float;
fStdDev, fBandaSuperior, fBandaInferior: float;
fMedia: float;

begin
  // ---------------------------------------------------------------------
  // ----------------- Inicialização da estratégia -----------------------
  // OBS: Inicialização de variáveis a serem utilizadas na estratégia de
  // execução
  // ---------------------------------------------------------------------
  if Not bStarted then
  begin
    bStarted := True;
    //Colocar aqui ações que serão executadas apenas no primeiro processamento
    //da estratégia. Por exemplo, inicialização de variáveis.

  end;


  // ---------------------------------------------------------------------
  // ------------ Atribuição de variáveis por processamento --------------
  // ---------------------------------------------------------------------
  if Close[1] = 0 then fLogRetorno := 0 else fLogRetorno := Log(Close/close[1]);
  fMedia := Media(pQtdePeriodosMedia, Close);
  fStdDev := StdDevs(fLogRetorno, pQtdePeriodosVolatilidade);




  // ---------------------------------------------------------------------
  // --------------------- Cálculo do indicador  -------------------------
  // OBS: Inserir lógica de cálculo do indicador e caso ele possa ser plo_
  // tado, atribuir em algum momento True para variável bPlotIndicador
  // ---------------------------------------------------------------------
  bPlotIndicador := true;

  fBandaSuperior := fMedia*ExpValue(pQtdeDesvioVol*fStdDev);
  fBandaInferior := fMedia*ExpValue(-pQtdeDesvioVol*fStdDev);



  //
  // ---------------------------------------------------------------------
  // ------------------ Plota valores do indicador -----------------------
  // OBS: Atribuir na sessão anterior o valor para variavel bPlotIndicador
  // quando for possível plotar um valor para o indicador no instante atual
  // ---------------------------------------------------------------------
  if bPlotIndicador then
    begin
      PlotN(1, fMedia);
      PlotN(2, fBandaSuperior);
      PlotN(3, fBandaInferior);

      setPlotColor(1, clRed);
      setPlotColor(2, clWhite);
      setPlotColor(3, clWhite);
      SetPlotWidth(1,2);
      SetPlotWidth(2,2);
      SetPlotWidth(3,2);

    end;

end;
				
			

Criando uma Estratégia de Coloração

Reproduzir vídeo

As Estratégias de Coloração são o primeiro passo para a automatização de operações. No vídeo acima, explicamos o passo a passo para criar uma regra de coloração que se baseia em dois indicadores de Bandas de Bollinger. Assista ao vídeo para uma explicação dinâmica do processo de escrita do código fonte de uma estratégia de coloração!

Introdução

Se você já assistiu aos vídeos ou leu os documentos sobre como criar seu primeiro robô e como criar seu próprio indicador, então você já tem uma noção básica do processo de criar uma estratégia.

A criação de uma estratégia de coloração visa facilitar uma sinalização ao trader por uma cor no gráfico. Pode ser uma lógica simples ou um pouco mais complicada, englobando comparações de diferentes indicadores frente a valores de referência. Fato é que se espera que a coloração torne a ação do trader mais tempestiva, pois ele não terá que realizar as mesmas contas que a estratégia calculou para pintar o gráfico. Ao ver uma determinada cor no gráfico, o trader já saberá como agir ou se comportar.

Muitas soluções externas para automatização do roteamento de ordens do Profit utilizavam as regras de coloração para ativar envio de ordens. Embora tenha sido lançado o Módulo de Automação de Estratégias, acredito que o envio de ordens a mercado, baseado nas soluções visuais de automatização de ordens ainda representa uma vantagem em relação ao módulo (hoje!). A tendência é que essas soluções externas percam vantagem competitiva a medida que o Módulo de Automação de Estratégias seja aprimorado, tornando estas soluções obsoletas. Uma desvantagem dessas soluções é que os gráficos precisam estar abertos em tela, pois elas trabalham com o mapeamento da tela, limitando assim a quantidade de estratégias que podem rodar simultaneamente, além de não permitirem utilizar subcontas, pois a interface gráfica padrão do Profit não permite (em geral) essa opção fora do Módulo de Automação de Estratégias para clientes padrão.

Implementação de uma estratégia de coloração

A implementação de uma estratégias de coloração envolve três etapas: especificar regra de cor, implementar código e testar o funcionamento.

Acho que o próprio nome das etapas já torna bem intuitivo o que precisamos fazer para obter uma estratégia de coloração. É importante ressaltar, que muita gente gosta de colocar as lógicas de coloração dentro de estratégias de execução (robôs) ou indicadores, screenings. Assim, em um único código, você pode incluir no seu gráfico como indicador, como sinalização de ordens ou coloração.

No exemplo apresentado no vídeo, que não é uma recomendação de uso, realizamos a coloração de candles de acordo com sua posição em relação à 2 indicadores de bandas de Bollinger.

Se o preço estiver sendo negociado fora da primeira banda de bollinger, mas ainda dentro da segunda, entende-se que o preço pode estar em região de sobrevenda ou sobrecompra, mas ainda não engatou uma tendência forte. Se o preço estiver sendo negociado fora da segunda Banda de Bollinger, entende-se que o mercado está demonstrando uma tendência forte seja de alta ou de baixa.

Assim, foram estabelecidas cores para sinalizar essas situações e oferecer suporte para a operação manual do trader. O código fonte da referida estratégia encontra-se abaixo.

Código fonte: Estratégia de coloração baseada emduas Bandas de Bollinger

				
					// #######################################################################
// #######################################################################
// #######################################################################
// ######                            O                             #######
// ######                        ____|____                         #######
// ######                      _|         |_                       #######
// ######                     (_|  O   O  |_)                      #######
// ######                       |_________|                        #######
// ######                                                          #######
// ###### ____        __        ____________           ________    #######
// ###### | | \       | |       | |_________|         /  ____  \   #######
// ###### | |\ \      | |       | |                  /  /    \  \  #######
// ###### | | \ \     | |       | |____             |  |      |  | #######
// ###### | |  \ \    | |       | |____|            |  |      |  | #######
// ###### | |   \ \   | |       | |____|            |  |      |  | #######
// ###### | |    \ \  | |       | |                 |  |      |  | #######
// ###### | |     \ \ | |       | |_________         \  \____/  /  #######
// ###### |_|      \_\|_|       |_|_________|         \________/   #######
// ######                                                          #######
// ###### _______  __          __   ____  __   ___    __  _______  #######
// ######    |    |  \   /\   |  \ |     |  \ |   \  /  \    |     #######
// ######    |    |__/  /__\  |   ||__   |__/ |___/ |    |   |     #######
// ######    |    |\   /    \ |   ||     |\   |   \ |    |   |     #######
// ######    |    | \ /      \|__/ |____ | \  |___/  \__/    |     #######
// ######                                                          #######
// ######  Comunidade aberta de automatização de estratégias para  #######
// ######                    negociação de ativos                  #######
// ######                                                          #######
// ######                    www.NeoTraderBot.com                  #######
// #######################################################################
// #######################################################################
// #######################################################################
//
// -----------------------------------------------------------------------
// ---------------------- DADOS DA ESTRATÉGIA ----------------------------
// -----------------------------------------------------------------------
//
// NOME DA ESTRATÉGIA: _NTB_COL_2BandasBollinger
//   DESENVOLVIDA POR: NeoTraderBot
//    DATA DE CRIAÇÃO: 13/10/2022
//             VERSÃO: 1.0
//      ATUALIZADA EM: 13/10/2-22
// TIPO DE ESTRATÉGIA: (X) Indicador  (X) Coloração ( ) Execução
//                     ( ) Screening  ( ) Texto     ( ) Alarme
//
// DESCRIÇÃO DA ESTRATÉGIA:
//   Realiza a coloração de candles baseada na posição relativa do proço
// em função de dois indicadores de Bandas de Bollinger, um para histórico 
// recente e outro para histórico de médio prazo
//
//
//
//
// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
//
// ######################### FIM DO CABEÇALHO ############################
//
//
// -----------------------------------------------------------------------
// -------------------------- Constantes ---------------------------------
// OBS:
// -----------------------------------------------------------------------
//const
//  cXXXXXX = true;
  //
  // ---------------------------------------------------------------------
  // -------------------------- Parâmetros -------------------------------
  // OBS: Segue abaixo a descrição de cada parâmetro
  // 1) pXXXXXX ->
  //
  // 2) pYYYYYY ->
  //
  // 3) pZZZZZZ ->
  // ---------------------------------------------------------------------
input
  pQtdeDesvioBB1(1.5);
  pQtdePeriodoMediaBB1(36);
  pTipoMediaBB1(0);

  pQtdeDesvioBB2(2.0);
  pQtdePeriodoMediaBB2(100);
  pTipoMediaBB2(0);

  // ---------------------------------------------------------------------
  // ---------------------- Variáveis globais ----------------------------
  // OBS:
  // ---------------------------------------------------------------------
var
//Estrutura padrão do modelo
bStarted: boolean;


//Variáveis personalizadas
fBB1Sup, fBB1Inf: float;
fBB2Sup, fBB2Inf: float;


begin
  // ---------------------------------------------------------------------
  // ----------------- Inicialização da estratégia -----------------------
  // OBS: Inicialização de variáveis a serem utilizadas na estratégia de
  // coloração
  // ---------------------------------------------------------------------
  if Not bStarted then
  begin
    bStarted := True;
    //Colocar aqui ações que serão executadas apenas no primeiro processamento
    //da estratégia. Por exemplo, inicialização de variáveis.
  end;


  // ---------------------------------------------------------------------
  // ------------ Atribuição de variáveis por processamento --------------
  // ---------------------------------------------------------------------
  // Atribuições das variáveis da estratégia
  fBB1Sup := BollingerBands(pQtdeDesvioBB1, pQtdePeriodoMediaBB1, pTipoMediaBB1)|0|;
  fBB1Inf := BollingerBands(pQtdeDesvioBB1, pQtdePeriodoMediaBB1, pTipoMediaBB1)|1|;
  fBB2Sup := BollingerBands(pQtdeDesvioBB2, pQtdePeriodoMediaBB2, pTipoMediaBB2)|0|;
  fBB2Inf := BollingerBands(pQtdeDesvioBB2, pQtdePeriodoMediaBB2, pTipoMediaBB2)|1|;

  // ---------------------------------------------------------------------
  // ---------------------- Lógica de coloração  -------------------------
  // OBS: Inserir lógica de cálculo para coloração do gráfico
  // ---------------------------------------------------------------------

  //SITUAÇÃO 1: BB1 DENTRO de BB2
  if (fBB1Sup <= fBB2Sup) And (fBB1Inf >= fBB2Inf) then
  begin
    if (Close >= fBB2Sup) then PaintBar(clGreen)
    else
    if (Close <= fBB2Inf) then PaintBar(clRed)
    else
    if (Close >= fBB1Sup) And (Close < fBB2Sup) then PaintBar(clYellow)
    else
    if (Close <= fBB1Inf) And (Close > fBB2Inf) then PaintBar(clYellow);
  end
  else

  //SITUAÇÃO 2: Banda superior de BB1 ACIMA da banda superior de BB2
  //            Banda inferior de BB1 maior que banda inferior de BB2
  if (fBB1Sup > fBB2Sup) And (fBB1Inf >= fBB2Inf) then
  begin
    if (Close >= fBB2Sup) then PaintBar(clGreen)
    else
    if (Close <= fBB2Inf) then PaintBar(clRed)
    else
    if (Close <= fBB1Inf) And (Close > fBB2Inf) then PaintBar(clYellow);
  end
  else


  //SITUAÇÃO 3: Banda inferior de BB1 ABAIXO da banda inferior de BB2
  //            Banda superior de BB1 menor que banda superior de BB2
  if (fBB1Sup <= fBB2Sup) And (fBB1Inf < fBB2Inf) then
  begin
    if (Close >= fBB2Sup) then PaintBar(clGreen)
    else
    if (Close <= fBB2Inf) then PaintBar(clRed)
    else
    if (Close >= fBB1Sup) And (Close < fBB2Sup) then PaintBar(clYellow);
  end
  else

  //SITUAÇÃO 4: BB2 DENTRO de BB1
  if (fBB1Sup >= fBB2Sup) And (fBB1Inf <= fBB2Inf) then
  begin
    if (Close >= fBB1Sup) then PaintBar(clGreen)
    else
    if (Close <= fBB1Inf) then PaintBar(clRed);
  end;


  PlotN(1,fBB1Sup);
  PlotN(2,fBB1Inf);
  PlotN(3,fBB2Sup);
  PlotN(4,fBB2Inf);

  SetPlotStyle(1,psDash);
  SetPlotStyle(2,psDash);
  SetPlotStyle(3,psSolid);
  SetPlotStyle(4,psSolid);

  SetPlotColor(1,clWhite);
  SetPlotColor(2,clWhite);
  SetPlotColor(3,clYellow);
  SetPlotColor(4,clYellow);

  SetPlotWidth(1,1);
  SetPlotWidth(2,1);
  SetPlotWidth(3,2);
  SetPlotWidth(4,2);

end;
				
			

Programando em NinjaScript

Nesta seção iremos abordar os conceitos básicos necessários para implementar códigos em NinjaScript, tais como indicadores e robôs.

Introdução ao NinjaScript Editor

Reproduzir vídeo

Este vídeo visa apresentar o ambiente de programação NinjaScript Editor da NinjaTrader, bem como a integração com a IDE Visual Studio da Microsoft.

Todos os programas em NT8 são escritos na linguagem NinjaScript que é baseada em C#, possuindo orientação à objeto e permitindo tratamento de eventos.

Recomendamos a leitura da Documentação NinjaTrader no link a seguir, de preferência em inglês: https://ninjatrader.com/support/helpG…

Link para baixar a IDE Visual Studio: https://visualstudio.microsoft.com/pt…

Programação

Profit Chart - NTSL

Esta biblioteca contém material introdutório sobre lógica de programação, plataforma de operação Profit Chart e Backtesting, para que você inicie sua jornada de implementação de estratégias automatizadas de forma objetiva e gradual.

Conhecendo o Profit Chart

Nesta seção iremos abordar todos detalhes relativos à programação de estratégias dentro do Profit Chart.

Primeiro contato com o Profit

Reproduzir vídeo

Para ter sucesso em qualquer área de conhecimento é preciso saber utilizar bem as ferramentas do seu trabalho. Um marceneiro precisa saber usar muito bem o formão, a serra e o maquinário de madeira para fazer bons móveis. Um cirurgião não conseguiria conduzir uma cirurgia com sucesso em um paciente se não manipulasse muito bem o bisturi, o equipamento de microgravação, a medicação que precisa ser dosada, etc… Por que seria diferente para quem opera no mercado financeiro?

O objetivo desse texto é falar um pouco sobre a plataforma Profit Chart, comercializada pela empresa Nelogica no Brasil. As plataformas de negociação são imprescindíveis para quem deseja se especializar e aprofundar no assunto de operações e investimento no mercado financeiro. É a ferramenta do dia a dia do trader!

Existem outras plataformas profissionais disponíveis para se operar, mas certamente as duas com maior capilaridade para quem opera ativos da B3 é o Profit Chart e o MetaTrader da empresa MetaQuotes. Aqui na Comunidade decidimos começar a explorar o universo de automatização de estratégias para negociação de ativos na plataforma Profit Chart por algumas razões que detalhamos neste artigo do blog e nesse vídeo do nosso Canal no Youtube.

Quais são as funcionalidades que uma plataforma profissional de trading pode te oferecer? Antes de falar sobre as funcionalidades temos que definir muito bem o que se espera de uma plataforma profissional. Na minha opinião, parte dos requisitos esperados seriam:

  1. Funcionalidades que permitam análisar os movimentos do mercado e fluxo de negociação:
    • Multiplas janelas abertas de dados de ativos e outras informações;
    • Diferentes tipos de gráficos e plotagens;
    • Possibilidade de visualizar em qualquer tempo gráfico desejado (1 min, 5 min, 12 min, 60 min, etc…);
    • Informações detalhadas do Book de ofertas;
    • Informações detalhadas das negociações realizadas;
    • Possibilidade de personalizar a aparência dos gráficos;
    • entre outras…
  2. Facilidade para abrir posições, administrar e encerrar operações:
    • Operar diretamente no gráfico do ativo visando agir com maior tempestividade;
    • Funcionalidades de stoploss tanto para limitar prejuízos quanto para proteger ganhos;
    • Acompanhamento do desempenho das operações, quantidade, relação risco/ganho;
    • Evolução de patrimônio;
  3. Plataforma leve e que não trave e tampouco apresente falhas que execução que possam comprometer o desempenho das operações em andamento (Sem bugs);
  4. Possibilidade de operar múltiplas contas de corretoras;
  5. Possibilidade de configurar limites de gestão de risco a fim de proteger patrimônio contra atitudes com prudentes;
  6. Possibilidade de automatizar setups operacionais;
  7. Possibilidade de simular o mercado financeiro para determinada data e ativo.

Sabendo o que esperamos encontrar em uma plataforma profissional, gravamos o vídeo abaixo para quem está iniciando agora e ainda não viu uma plataforma ou apenas opera pelo home broker de sua corretora. Assista e deixe seu comentário!

Não estamos querendo pintar o quadro de que o software Profit Chart é perfeito. Pois o Profit Chart não é perfeito. É um software muito bom pelas ferramentas que oferece para analisar e ler o mercado, mas também possui algumas limitações importantes quanto à automatização de estratégias, principalmente por não permitir a e execução de robôs programados pelo próprio usuário em conta real. Ainda assim, o Profit pode ser considerado um bom ponto de partida para iniciarmos a jornada de conhecimento para automatização de estratégias na negociação de ativos! Com o tempo, naturalmente iremos abordar também a automatização em plataformas como MetaTrader, TradingView, e utilização de APIs em python para realizar estudos estatísticos e implementar algoritmos mais complexos para operar na bolsa!

Bom, por ora, no próximo documento vamos ensinar como utilizar o ambiente de edição de estratégias do Profit Chart. Esta será a principal ferramenta que iremos utilizar para criar códigos para automatizar diversas tarefas atinentes a operação na bolsa de valores, desde a criação de indicadores, regras de coloração, filtros de seleção de ativos até backtesting de estratégias de execução (robôs de investimento) e muito mais!

Editor de estratégias

Reproduzir vídeo

Este documento irá abordar todos os detalhes importantes sobre a ambiente de edição de estratégias do Profit Chart: Editor de Estratégias.

A linguagem utilizada pelo Profit Chart é a NTSL (Nelogica Trading System Language). É uma linguagem com uma sintaxe muito semelhante a Pascal, porém com uma restrição nos comandos. A linguagem NTSL também aceita comandos em português, embora não seja uma boa prática, dado que todas as linguagens com grande abrangência são em inglês. Logo, é melhor o usuário já se acostumar com os termos em inglês visando maior facilidade em uma transição futura para outra linguagem de programação.

Vamos às questões práticas…

Como acessar o Editor de Estratégias?

Após abrir o Profit, basta acessar o menu principal na parte superior, clicar em “Estratégias” e em seguida na opção “Editor de estratégias”.

O Editor de estratégias aparecerá conforme a figura abaixo.

Modos de exibição do Editor de Estratégias

Note que na parte superior temos 4 modos de exibição do editor de estratégias, que são:
  • Editor: apresenta apenas a tela de edição do código fonte e de debug (debug é uma funcionalidade para depurar seu código fonte, ou seja, executar passo a passo para verificar se tudo está rodando corretamente);
  • Gráfico: apresenta apenas o gráfico no qual está sendo testada a estratégia em edição;
  • Misto: apresenta tanto a tela de edição do código fonte e debug, quanto o gráfico no qual a estratégia em edição está sendo testada;
  • Estatísticas: este modo aplica-se apenas às estratégias de execução, ou seja, estratégias que realizam ordens de compra/venda para fins de backtest.

Vamos detalhar abaixo o modo de exibição mais utilizado, o modo “Editor”. O modo “Estatísticas” será bastante trabalhado nos documentos relacionados à backtesting.

Modo "Editor"

O modo editor possui três áreas principais: a barra de ferramentas, a área de edição de código e a área de compilação/debug.

Note que o editor pode ter múltiplas estratégias abertas em edição ao mesmo tempo. A barra inferior apresentará abas diferentes para cada estratégia. Uma estratégia que foi criada mas ainda não foi salva constará na aba “NoName”, conforme pode ser visto na figura abaixo.

Barra de ferramentas

Vamos detalhar a função de cada ícone da barra de ferramentas:

Ícone Função

Nova estratégia: abre janela para seleção de modelos do Profit para criar uma nova estratégia;

Abrir estratégia: abre uma janela para seleção de estratégias salvas no Profit;

Fechar estratégia: fecha a edição da estratégia atual. O usuário será perguntado se deseja salvar as alterações, caso haja alguma alteração não salva;

Salvar: salva as alterações existentes na estratégia. Caso haja algum erro de sintaxe, o sistema irá perguntar ao usuário se deseja salvar assim mesmo;

Salvar como: permite salvar a estratégia em edição como um novo arquivo de estratégia, podendo configurar um novo nome e descrição;

Verificar sintaxe: o sistema realiza uma verificação da sintaxe da estratégia e indica eventuais erros;

Step over (debug): uma vez em modo de depuração e a execução para em determinada linha de código, este botão executa a linha e para na próxima;

Trace into (debug): uma vez em modo de depuração e a execução para em uma determinada linha que realiza a chamada de uma função ou procedure criada pelo usuário, o depurador irá executar linha a linha o código fonte dentro da função/procedure chamada;

Executar estratégia: o editor de estratégia passa para o modo de exibição misto e apresenta o resultado da execução da estratégia no gráfico ao lado da área de edição do código-fonte. O depurador irá parar na primeira linha a ser executada que tenha breakpoint;

Parar estratégia: interrompe a execução da estratégia;

Propriedades da estratégia: permite , no caso de indicadores, configurar a aparência das séries plotadas (cor, espessura e tipo de tracejado, tipo de gráfico: linha/histograma), linhas guias e suas aparências (linhas horizontais com valor fixo) e configurar tipo de preenchimento entre as séries plotadas;

Formatação automática do código: realiza a identação (configuração de espaços) e quebras de linhas do código de forma automática e uniforme. (Nem sempre funciona direito!)

Lista de funções: apresenta listagem de funções disponíveis no editor de estratégias agrupadas por tema;

Lista de constantes: apresenta listagem de constantes definidas pelo Profit agrupadas por tema;

Linhas no Gráfico Principal: alterna a plotagem das séries entre um subgráfico ou dentro do gráfico principal do ativo;

Configurações do editor: abre janela para personalização do editor de estratégias, podendo alterar a fonte do editor, tamanho, cores e etc...

Área de edição de código

Na área de edição de código é apresentado o código fonte da estratégia. Note que há uma numeração das linhas a esquerda para facilitar a identificação do código quando houver sinalização de erro de sintaxe.

O usuário pode criar breakpoints para depuração do código (debug) clicando no vão entre a númeração da linha e a coluna em cinza. A criação do breakpoint será indicada por um ícone circular azul, bem como o preenchimento da linha de código na mesma cor.

Área de compilação/debug

Nesta área, é apresentado o resultado da verificação de sintaxe, bem como os erros existentes no código-fonte da estratégia.

Quando a estratégia é “debugada” (depurada), aparece nesta área também o valor das variáveis declaradas na estratégia.

Gerenciador de estratégias

O Gerenciador de estratégias apresenta todas as estratégias existentes no Profit, tanto aquelas criadas pelo usuário, quanto as estratégias importadas. O Gerenciador pode ser acessado pelo menu principal, clicando em “Estratégias” e em seguida, “Gerenciador de estratégias”, conforme figura abaixo.

O gerenciador deve se apresentar conforme figura a seguir. Será apresentado ao usuário uma relação de estratégias com a indicação do tipo a que pertence. É importante ressaltar que uma estratégia, pode estar associada a mais de um tipo. Por exemplo, pode haver uma estratégia que realiza tanto uma coloração de gráfico como também realiza o filtro do ativo (screening).

Para cada linha referente a cada estratégia, o usuário pode editar a estratégia (ícone de lápis), compartilhar a estratégia pelo Connect Chat com um outro usuário do Profit ou grupo (Ícone com 3 pontos) ou excluir a estratégia.

Pelo gerenciador de estratégias é possível também fazer a importação de estratégias criadas por outras pessoas e a exportação das estratégias existentes no Profit da máquina.

Como importar ou exportar estrategias?

A importação e exportação de estratégias é realizada por meio de arquivos com extensão psf (Profit strategies file). Esses arquivos podem conter uma ou mais estratégias, com ou sem o código fonte associado.

Quando o usuário não tem acesso ao código-fonte da estratégia, chamamos a estratégia de caixa-preta, uma vez que o usuário não tem informação sobre detalhes da programação, apenas pode informar parâmetros e ter acesso à saída da estratégia, seja ela um indicador ou uma coloração de gráfico. As estratégias caixa-branca são aquelas nas quais o usuário consegue visualizar todo o código fonte.

Para exportar uma estratégia, basta clicar no botão “Exportar” no canto inferior esquerdo do Gerenciador de estratégia. Será aberta uma janela conforme figura abaixo.

O usuário deverá selecionar o nome de um arquivo e uma pasta para realizar a exportação, bem como indicar por meio da caixa de seleção, quais estratégias serão exportadas para o arquivo psf. Note que a opção padrão do sistema é exportar sem código fonte. No entanto, caso o usuário deseje, poderá marcar a opção para exportar a estratégia e o código fonte associado.

O processo de importação de estratégia é análogo à exportação. O usuário deve selecionar um arquivo psf em seu computador e o Profit irá listar as estratégias contidas no arquivo para que o usuário selecione quais serão importadas.

Outra forma de compartilhar estratégias é pelo Connect Chat, sendo o processo mais natural para o usuário, pois ocorrerá dentro da interface do chat da plataforma Profit.

No próximo documento, iremos abordar quais são os tipos de estratégias que podem ser automatizadas na plataforma Profit Chart! 

Tipos de estratégias

Reproduzir vídeo

Neste documento vamos conhecer os tipos de estratégias que podem ser automatizadas no Profit Chart, para que serve cada estratégia, se é possível automatizá-las sem programação e serão apresentados exemplos para que fique bem clara a explicação. A ideia é que você tenha um panorama geral das possibilidades dentro do Profit Chart, pois em outros documentos iremos aprofundar em detalhes sobre como programar cada tipo de estratégia!

Caso tenha algum interesse por um tipo específico de estratégia, utilize o menu lateral direito para ir direto ao ponto desejado.

Então vamos começar tentando estruturar de uma forma mais simples o que seriam as estratégias principais e secundárias. Esta divisão foi criada por mim apenas para facilitar o entendimento. As estratégias principais são aquelas que estão diretamente relacionadas a setups operacionais, motivo que as tornam bastante difundidas e utilizadas. Já as estratégias secundárias, as quais são tão importantes quanto as principais, são relacionadas a outros aspectos de trading, tais como seleção de ativos,  gestão de risco, alarmes e tarefas mais simples como escrever texto em gráficos. Gostaria de ressaltar que as estratégias secundárias são tão importantes quanto às principais, sendo esta classificação adotada apenas para fins didáticos.

Estratégias Principais:

Estratégias Secundárias:

Vamos apresentar a seguir a definição e informações de cada tipo  de estratégia do Profit Chart.

Estratégia de Coloração

As estratégias de coloração são utilizadas para pintar os gráficos de acordo com a lógica que o trader desejar. Você pode pintar gráficos de preço, tais como candles, linhas, renko, ponto, o que quiser e também de volume! Você pode pintar o corpo dos candles, ou se preferir, o fundo do gráfico referente àquele candle!

Para que serve uma estratégia de coloração? Uma estratégia de coloração serve para automatizar uma análise que você faz manualmente. Serve para te liberar o tempo, atenção e foco que você dá para fazer esta análise…E o que você ganha com isso? Você ganha tempo e atenção para dedicar a algo mais importante…para entender o que de fato está acontecendo com o mercado e que se reflete nos movimentos de preço.

Exemplo 1: Colorindo InsideBar (Harami)

Este exemplo ilustra a coloração de candles classificados como InsideBar ou Harami (em japonês). E o que é um InsideBar? É um padrão gráfico no qual um candle possui o preço máximo menor que o preço máximo do candle anterior, bem como o preço mínimo maior que o preço mínimo do candle anterior.

A identificação de InsideBar é importante para alguns setup operacionais que utilizam esse padrão gráfico para iniciar posições. O gráfico abaixo exemplifica a aplicação de uma estratégia de coloração que pinta a barra de InsideBar na cor amarela.

Exempo 2: Double Crossover

Os setups de cruzamento de média (crossover) são amplamente utilizados em análise técnica e foram criados muito antes do uso intensivo de computadores no mercado financeiro.

Neste exemplo clássico de cruzamento de duas médias (double crossover), vamos colorir um gráfico de preço baseado no cruzamento de duas médias do preço de fechamento dos candles. Uma média rápida sobre os preços dos últimos 9 períodos e uma média lenta baseada no preços dos últimos 20 períodos. Obs: as quantidades de períodos das médias podem ser configuradas nos setup operacionais e  otimizadas de acordo com o ativo ou momento de mercado.

Quando a média rápida estiver acima da média lenta, isso sugere um movimento de alta e o gráfico será colorido de verde. Quando a média rápida estiver abaixo da média lenta, isso sugere um movimento de baixa e o gráfico será colorido de vermelho. Na figura abaixo, utilizamos a estratégia de coloração para pintar os candles do gráfico.

Na figura abaixo, utilizamos a mesma estratégia de coloração de cruzamento de média, mas dessa vez colorindo o fundo do gráfico.

Exemplo 3: Volume de agressão

Neste terceiro exemplo, vamos aplicar uma estratégia de coloração à um gráfico de saldo de agressão (que na verdade é um indicador!).

A estratégia de coloração consiste em identificar os momentos nos quais o saldo de agressão supera em duas unidades o desvio padrão da amostra dos últimos N períodos. Onde N para gráficos de 1 minuto poderia ser o valor de 2400 (5 dias x 8 horas x 60 minutos), o que abrange os últimos 5 dias de negociação.

Ou seja, se o saldo de agressão for comprador e for maior do que duas unidades de desvio padrão, a barra de saldo de agressão será pintada de verde. Se o saldo de agressão for vendedor e maior (em valor absoluto) que duas unidades de desvio padrão, a barra de saldo de agressão será pintada de vermelho.

A figura abaixo demonstra a aplicação da estratégia de coloração baseada em volume de agressão.

Estratégia de Indicador

As estratégias de indicadores plotam em um gráfico determinada série calculada com a lógica que o trader desejar. Pode ser tanto no gráfico de preço do próprio ativo, como em um subgráfico separado, geralmente abaixo do gráfico principal.

Criar um indicador que seja útil para tomar decisões não é uma tarefa muito fácil…Você precisa conhecer muito bem a lógica do mercado financeiro, as particularidades do tipo de ativo que está operando e transcrever em fórmulas matemáticas o cálculo de uma variável (o indicador) que lhe traga informação com valor agregado, informação útil para tomada de decisão. Geralmente, os indicadores estão muito vinculados a um determinado padrão de operação e são baseados em análise técnica. São exemplos de indicadores técnicos já consagrados pelo uso, as médias móveis, MACD, Índice de força relativa (IFR), entre outros.

Exemplo 1: Acumulação de Volume Agressor

Neste exemplo de indicador, vamos plotar um histograma em um subgráfico com a acumulação do saldo de agressão enquanto o saldo de agressão da barra permanecer do mesmo lado.

Por exemplo, uma vez que o saldo de agressão é comprador, a acumulação de saldo de agressão inicia. Para cada novo dado, se o saldo de agressão continuar sendo comprador, o indicador continuará acumulando o saldo. Caso haja um saldo vendedor de agressão, a acumulação é zerada e começa a acumular as agressões de venda, até que haja uma reversão de saldo de agressão para compra.

Veja a figura abaixo do indicador implementado de acumulação de Volume Agressor.

Exemplo 2: Administração de stoploss pela volatilidade média

Neste segundo exemplo de estratégia de indicador, vamos plotar no gráfico principal um limite de preço para administração manual de stoploss.

O usuário fornecerá como parâmetro o preço de entrada de uma operação de compra ou venda, bem como o horário de abertura da posição. O usuário também deve fornecer um múltiplo N da volatilidade média (a estratégia usa internamente o indicador ATR) para posicionar a linha área limite para posicionamento do stoploss.

Para cada candle fechado, o qual o preço tenha andado a favor da operação, o stoploss é atualizado para refletir o preço de fechamento deslocado de N ATRs.

Observe na figura abaixo, que o usuário sinalizou ao indicador uma compra às 13:58 no preço de R$ 31,11 no ativo PETR4. O stoploss foi configurado na estratégia para ficar 2 ATRs atrás do preço de fechamento dos candles. Observe que a operação deveria ser stopada manualmente no preço de R$ 31,13 conforme os parâmetros fornecidos.

Na próxima figura, é apresentado o caso de uma venda à R$ 31,28 às 15:47 no ativo PETR4. Nesse momento o usuário optou por um distanciamento de 3 ATRs do preço de fechamento para cálculo do stoploss.

Estratégia de Execução (Robôs)

Até semana passada eu diria que o nome estratégia de execução é uma nomenclatura ruim…porque no Profit a estratégia de execução não executa nada em conta real. Mas quem assistiu ao nosso vídeo falando sobre o novo módulo de Automação de Estratégias viu que tem novidades surgindo no Profit Chart! A estratégia de execução, ou os chamados robôs, já podem ser rodados em conta de simulador e em breve poderão rodar em conta real!

Então, além de poder fazer backtest em dados históricos, para verificar estatisticamente o desempenho de determinado setup operacional, em pouco tempo, vamos poder transformar essas estratégias de execução em robôs para rodar em conta real. Para os mais afoitos, isso não significa que você vai ficar rico pegando qualquer robô por aí na internet….Encontrar um robô lucrativo é uma tarefa muito exaustiva.

Os robôs talvez sejam o tipo de estratégia mais fácil de imaginar, pois todo mundo já visualiza ordens sendo colocadas no book de forma automática e toda administração das operações também sendo realizada de forma autônoma. E é exatamente para isso que se propõe os robôs, para automatizar um setup operacional e garantir consistência na execução do setup.

Vou apresentar a seguir um exemplo clássico e didático, que não representa nenhuma recomendação de uso, serve apenas para exemplificar as estratégias de execução ou robôs.

Exemplo: Cruzamento de 3 médias móveis (Triple crossover)

Nesse tipo de setup temos 3 médias móveis: uma média móvel rápida, uma intermediária e uma lenta. Cada média atuará sobre uma quantidade de períodos diferentes, sendo a rápida sobre menor quantidade de períodos, refletindo o movimento de preço mais recente suavizado e a média lenta englobando maio quantidade de períodos, representando a tendência principal do ativo em janelas gráficas maiores.

Assim, a quantidade de períodos são parâmetros que devem ser otimizados na estratégia. Por ora, vamos arbitrar a utilização dos seguintes valores 5, 10 e 20.

Observe que a estratégia foi implementada para que os sinais de compra sejam ativados quando a média rápida estiver acima da média intermediária e esta última cruzar para cima a média lenta. O sinal de liquidação da posição de compra ocorrerá quando a média rápida cruzar para baixo a média intermediária.

O sinal de venda é análogo e ocorre quando a média rápida estiver abaixo da média intermediária e houver o cruzamento para baixo desta última com a média lenta. O sinal de liquidação da posição vendida ocorre quando houver um cruzamento da média rápida acima da média intermediária.

Estratégia de Seleção (Screening)

Screening significa manter em tela, no seu campo de visão, alguma informação para monitoramento…Com as Estratégias de Seleção (screenings) podemos monitorar , em tempo real, todos os ativos da B3, ou um subconjunto que o trader escolher, por um padrão de movimentação ou situação também determinado pelo trader.

Ou seja, com os screenings poderemos automatizar a seleção das melhores oportunidades entre os ativos da B3 que se enquadrem em determinado operacional. Isto liberará o trader de tarefas manuais e repetitivas para poder se dedicar foco e atenção à analise dos movimentos do mercado e outras atividades que julgar importantes.

Os screenings podem ser aplicados em periodicidades de dados de 1 minuto, 15 minutos, dias, semanas….ou seja, pode usar dessa automação tanto para daytrading quanto para suas operações de swing trade.

Exemplo 1: Seleção de ativos em valorização nos últimos 3 dias

Nesse primeiro exemplo, ilustro a aplicação de um Screening para listar os ativos do índice IBOV que em periodicidade diária apresentaram valorização nos últimos 3 períodos, ou seja, 3 dias. É um caso de utilização das Estratégias de Seleção para filtrar oportunidades de swing trade.

As figuras abaixo ilustram a definição da regra de screening pela interface gráfica e a lista de ativos gerada a partir da regra definida.

Exemplo 2: Seleção de ativos em condição de InsideBar para operações de daytrading

Nesse segundo exemplo, verificamos a utilização de uma estratégia de seleção de InsideBar para aplicação de um Screening sobre uma lista de 6 ativos da B3 na periodicidade de dados de 1 minuto. É um exemplo de aplicação de screening para operações de daytrading.

As figuras abaixo demonstram a utilização de uma regra de alarme que também contém seleção no Screening e a lista de ativos gerada a partir da estratégia de seleção.

Estratégia de Alarme

Alarmes não tem a ver somente com tempo! Podemos até criar alarmes 10 minutos antes da liberação de dados importantes como Payroll…Mas o verdadeiro ganho das Estratégias de Alarme é exibir uma notificação em tela, geralmente acompanhado de um som, quando determinada situação ocorrer em um ativo específico!

As Estratégias de Alarme são configuradas no Profit por ativo dentro do Gerenciador de Alarmes. É necessário incluir as estratégias para cada ativo que desejar, e podem basear-se em periodicidades de 1 minuto, 15 minutos, 1 dia…a periodicidade de dados desejada! Assim, o trader não precisa ficar o tempo todo com as janelas dos ativos que está monitorando abertas, consumindo processamento do computador. O trader será notificado assim que ocorrer a condição programada por ele na estratégia de alarme, no ativo e na periodicidade de dado configurada.

As estratégias de alarme podem ser usadas de duas formas! Configurando no Gerenciador de Alarmes ou incluindo alarmes dentro de uma estratégia de coloração ou de execução. As estratégias podem estar associadas a mais de um tipo! Podemos ter uma estratégia de coloração que também gera alarmes! Porém, nesse caso, diferentemente do gerenciador de alarmes, é preciso deixar o gráfico aberto em tela para poder gerar o alarme.

Exemplo: Estratégia de alarme baseada em InsideBar (Gerenciador de Alarmes)

A figura abaixo demonstra a configuração no Gerenciador de Alarmes de um alarme baseado em uma Estratégia de Alarme de InsideBar para o ativo WINV22 na periodicidade de 1 minuto, quando o candle fechar. Em seguida, a próxima figura apresenta a notificação gerada pela estratégia de alarme.

Estratégia de Texto

As estratégias de texto são bastante simples e são utilizadas para apresentar determinado texto em uma barra (Candle ou Renko) quando a condição programada pelo trader ocorrer.

As estratégias de texto podem estar associadas às estratégias de indicadores ou estratégias de coloração. A figura abaixo apresenta um exemplo simples de apresentação do texto “IB” quando há identificação do padrão gráfico de InsideBar.

Estratégia de Negociação

Em resumo, as Estratégias de Negociação permitem definir ordens de stoploss e take profit, com saídas parciais ou não, para automatizar o posicionamento de ordens quando o trader abrir uma posição em um ativo.

As Estratégias de Negociação são configuradas poela interface gráfica, dentro do “Chart Trading” e é um excelente primeiro passo para automatização de setup operacional em conjunto com as Estratégias de Stoploss. Assista ao vídeo que explica o passo-a-passo de como configurar as estratégias de negociação publicado no Canal Youtube da Comunidade.

É importante ressaltar que quando se está implementando Robôs (Estratégias de Execução) no Profit, as Estratégias de Negociação ficam entrelaçadas no código-fonte. Dentro do código há muito mais liberdade para definir uma estratégia de negociação  porque depende apenas de como o código é estruturado. A administração de um trade aberto, pode ser feito usando breakeven, stop fixo ou stop móvel, basta  programar a gestão das posições da maneira que o trader desejar.

Reproduzir vídeo

Estratégia de Stoploss

Por fim, o último tipo de estratégia passível de automatização que iremos abordar são as Estratégias de Stoploss. Estas podem ser configuradas pela interface gráfica utilizando as técnicas de Autobreakeven e Stop móvel, sem necessidade de código fonte, e utilizadas em conjunto com as Estratégias de Negociação.

Assim como as estratégias de negociação, também é possível programar ordens de breakeven e stop móvel no código fonte das Estratégias de Execução (Robôs). Assista ao vídeo do Canal explicando como configurar uma estratégia de stoploss, pela interface gráfica, utilizando as técnicas de Autobreakeven e stop móvel em conjunto.

Reproduzir vídeo

Finalizando...

Este documento apresentou um panorama geral das estratégias que podem ser automatizadas no Profit Chart. 

Percebe-se que há muitas possibilidades de automação, desde pequenas tarefas pontuais como a possibilidade de automatizar todo o setup operacional.

O trader que deseja especializar-se no mercado financeiro precisa dominar as ferramentas de automatização para liberar seu tempo de tarefas rotineiras e manuais, permitindo ter atenção para analisar e estudar os movimentos de preço dos ativos, aprimorando assim seu conhecimento sobre o mercado financeiro.

Espero que tenha aproveitado o conteúdo!, pois nos próximos documentos iremos implementar  passo a passo cada tipo de estratégia!

Automatizando SEM programação

Espera aí! É possível automatizar sem programar? Então para que eu vou perder meu tempo aprendendo a programar!? Aposto que você deve ter pensado isso….rsrsrs…Ok! É um argumento bem válido…Mas vou te mostrar alguns pontos que talvez ajudem você a enxergar melhor a médio e longo prazo.

Para regras muito simples de coloração, estratégias de negociação e stoploss, ou um Screening (se não souber do que estou falando…leia o documento sobre Tipo de Estratégias), você pode recorrer a interface gráfica do Profit e criar a sua própria regra sem a necessidade de escrever código.

Se você não sabe programação (AINDA!!!) acho que vale a pena explorar essas funcionalidades! Fizemos vários vídeos explicando as estratégias e automatizações que você pode fazer no Profit Chart sem a necessidade de programar e criamos essa playlist no Youtube!

Mas em pouco tempo, você encontrará dificuldades para criar regras ou pouco mais sofisticadas pela interface gráfica. Além disso, perceberá que não acha lugar nenhum explicando o que gostaria de saber e tampouco conteúdos de qualidade na internet (exceto os materiais da NeoTraderBot…kkkk). Para ser muito sincero, a documentação da Nelogica, que é a empresa que desenvolve e mantém o Profit Chart,  é muito “minimalista” (estou tentando ser político para não falar um português mais claro!).

Além disso, a interface gráfica do Profit também te obriga a descrever suas regras de uma forma que pode dificultar a manutenção e ajustes futuros. E para fazer algumas coisas, você precisa saber exatamente o mesmo comando que precisaria saber se estivesse programando! Ou seja, não há vantagem nessa situação…é melhor programar mesmo!

Então para resumir, recomendamos fortemente que aprenda a programar o quanto antes! Aqui na NeoTraderBot você tem acesso a tudo que precisa para aprender a automatizar suas estratégias, desde o Curso Básico de Lógica de Programação e o passo-a-passo para fazer todas automatizações na plataforma Profit, até exemplos completos da implementação de estratégias de execução (robôs)!

Mas se ainda não sabe nada de programação e tem algumas ideias de coisas simples que pode fazer para te ajudar no seu operacional, então tente implementar pela interface gráfica, enquanto investe parte do seu tempo para também aprender programação. Se você não conseguir fazer pela interface gráfica é porque não é tão simples quanto imaginava!

E o que podemos automatizar no Profit sem escrever código? Segue a lista abaixo e a nossa playlist ensinando como automatizar cada etapa do seu operacional!

  1. Estratégias de negociação: automatização de ordens de ganho, saidas parciais e stoploss na abertura de posições;
  2. Estratégias de stoploss: Autobreakeven (desloca stoploss uma vez atingido um lucro mínimo, evitando assim que o trade resulte em prejuízo em um movimento contrário à posição) e Stop móvel (Trailing stop) que é uma técnica para proteger ganhos já alcançados a medida que o preço do ativo anda a favor da operação;
  3. Screening: filtro de ativos que estejam na condição adequada, de acordo com o seu operacional, para abrir posição, liquidar posição existente, etc…
  4. Regras de alarme: configuração de alarmes sonoros e visuais para alertar o trader sobre um condição específica em um ativo determinado.
  5. Regras de coloração: configuração de coloração de gráficos e barras de acordo com a preferência do trader para indicar situações específicas ou gatilhos para seu setup operacional;
  6. Regras de execução (robôs): em resumo são regras para criação de um robô. Apesar de poder criar robôs sem escrever código eu recomendo criá-los apenas por meio de código fonte.
 
 

No próximo documento vamos abordar as melhores práticas de programação, para que possa evoluir de forma assertiva, em um bom ritmo, escrevendo códigos-fonte organizados legíveis (fáceis de entender para você e para outros…no futuro você vai entender essa frase!) e mantendo uma curadoria adequada de suas estratégias.

Limitações da Plataforma

Não existe perfeição…e quando falamos de software é difícil acharmos um que não tenha bugs ou pontos de melhoria (que as vezes tem uma análise mais subjetiva…uma melhoria para um usuário pode não ser para outro).

Este documento visa abordar as limitações conhecidas da plataforma Profit Chart referentes a automatização de estratégias e backtesting. Trata-se de uma base de dados em constante evolução, que pode crescer ou diminuir (assim esperamos) a medida que os membros da comunidade apresentarem novos itens, ou se a Nelógica lançar atualizações da plataforma para tratar as questões apresentadas.

Primeiramente, antes de começarmos precisamos fazer justiça e ressaltar que em termos de disponibilização de ferramentas para análise de mercado, a Plataforma Profit Chart entrega muitas funcionalidades interessantes e é uma plataforma muito bem aceita pelos traders! Nosso papel é um pouco cruel, pois vamos ser bem críticos neste documento, mas sem desmerecer a qualidade do software Profit Chart!

Nossos olhares estarão direcionados ao módulo de Editor de Estratégias que vinha recebendo pouca atenção até meados de Agosto/2022, quando a Nelógica começou a lançar atualizações referentes à automação de estratégias.

A primeira atualização do Editor de estratégias que nos chamou a atenção foi a possibilidade de usar dados de preço de múltiplos ativos nas estratégias. Isso era algo desejado há muito tempo e apesar de ainda haver algumas limitações nessa funcionalidade, a atualização já abriu várias oportunidades para elaborar novas estratégias. Se quiser saber mais sobre isso, assista ao vídeo que fizemos sobre estratégia baseada em múltiplos ativos no Youtube da Comunidade.

Recentemente, ainda tivemos a disponibilização da versão 5.2.2.121 na qual foi lançado o módulo de Automação de Estratégias, permitindo rodar Estratégias de Execução (robôs) em conta simulada. Esta também era outra funcionalidade há muito tempo demandada à Nelógica (clique aqui para conhecer o módulo de automação de estratégias), que em breve permitirá rodar os robôs em conta real! Será uma revolução!

Estamos vendo com muito bons olhos o esforço da Nelógica em melhorar as funcionalidades relacionadas à automatização das estratégias! Assim, esperamos que este documento também alcance a equipe de desenvolvimento da Nelógica e que possamos contribuir para o aprimoramento da Plataforma por meio das sugestões apresentadas!

Sem mais delongas, veja abaixo as limitações da Plataforma Profit Chart listadas pela Comunidade NeoTraderBot, bem como observações sobre a evolução da situação de cada item.

Limitações conhecidas da Plataforma Profit Chart

Legenda:

O código fonte desenvolvido para backtesting não pode ser exatamente o mesmo que será executado como robô no Módulo de Automação.

Seria interessante se houvesse compatibilidade entre os dois contextos, evitando assim retrabalhos e erros de tradução de código para que este funcione em áreas distintas dentro do mesmo software.


Sugestões:

  1. Implementar um gestor de ordens em ambiente backtesting para que as ordens sejam tratadas da mesma forma em Backtesting e no Módulo de Automação;
  2. Tratamento das ordens de cobertura no Módulo de Automação, pois não são reconhecidas nesse contexto;
  3. Estratégias com multi-objetivos (coloração, indicador e execução) quando utilizadas no Módulo de Automação ou em gráficos em tempo real são incluídas como diferentes instâncias, que dependendo do objetivo também são processadas de formas diferentes, gerando descasamento de informações.
 

Embora haja dados tick a tick, as ordens são enviadas apenas no fechamento dos Candles e este comportamento não pode ser alterado.


Sugestões:

  1. Refatorar as funções de ordens para que permitam execução no tick ou no fechamento da barra, cabendo essa decisão ao programador.

USERVOICE: CRIAR parâmetro de funções de ROTEAMENTO DE ORDENS para serem executadas NO TICK ou fechamento da Barra [NeoTraderBot]

Para backtesting de estratégias baseadas em renko, não é possível garantir encerramento de posição de daytrade porque as ordens são executadas apenas no fechamento do box.


Sugestões:

  1. Reestruturar o modelo de simulação de renko para que o backtesting permita encerrar posição dentro do box que contiver o horário desejado.

USERVOICE: GARANTIR ENCERRAMENTO DE POSIÇÃO por horário para Gráficos não temporais em Backtesting (ex: Renko) [NeoTraderBot]

Seguem abaixo os pontos observados em relação ao recém lançado Módulo de Automação de Estratégias (lançamento oficial em 29/set/2022)

  1. Velocidade de replay impacta preço de abertura de posição. Se executa replay em 1x, o preço de abertura de uma posição é diferente se fosse executado em 10x, para todas as demais condições de código e simulação iguais. Por que acontece isso em replay?
  2. Estratégias que possuem indicadores são inseridos como uma instância separada da instância que realiza a execução de ordens. Isso gera problemas de consistência entre um plot baseado em preço de posição com o preço efetivamente realizado na instância de execução da estratégia;
  3. Processamento de replay é muito lento. Mesmo em 10x. Seria possível aprimorar isso? Executar o processamento dos dados em maior frequencia do que a renderização (amostrando renderização).
  4. Não há funções NTSL para retornar resultado bruto no momento.

USERVOICE: Velocidade de REPLAY NÃO DEVE IMPACTAR execução de ordens em estratégias/robôs no Módulo de Automação [NeoTraderBot]

O acesso a dados de 1 minutos (por exemplo) é muito limitado . A plataforma consegue recuperar apenas os últimos 3 (três) meses de dados de preço com frequência de 1 minuto. Para desenvolvimento de estratégias de alta frequência, otimização e backtesting, esse é um volume muito pequeno de dados.

Felizmente, à medida que utiliza-se dados com menor frequência (5, 15 60 minutos, 1 dia) é possível obter uma janela maior de dados históricos. Por exemplo, se o usuário demandar dados de 15 minutos, a plataforma recupera 6 anos. O que nesses casos demonstra-se adequado.


Sugestões:

  1. Permitir que o usuário puxe mais dados da base, quando for conveniente;
  2. Permitir carregar série de dados OHLCV (Open, High, Low, Close, Volume) para fins de backtesting.

USERVOICE: PERMITIR IMPORTAÇÃO DE DADOS OHLCV e Tick PARA FINS DE BACKTESTING [NeoTraderBot]

Para desenvolvimento de estratégia o trader/programador não possui acesso à dados de negociação (times & trades) com granularidade suficiente para implementar lógicas que se baseiem na forma como as negociações estão ocorrendo no mercado.

Tampouco, há acesso para a informações do Book de ofertas, quantidade de ordens por nível de preço, volume  das ordens, corretora, etc…Não ter esse tipo de dado disponível também cria limitação na implementação de estratégias que se baseiem em fundamentos diferentes da análise técnica.


Sugestões:

  1. Criar funções no editor de estratégia para obter acesso amplo à negociações realizadas no último tick;
  2. Criar funções no editor de estratégia para obter acesso às informações do book de ofertas.

A plataforma não apresenta funcionalidade para auxiliar a tarefa de otimização de parâmetros de estratégias.

Por exemplo, caso o usuário implemente um robô baseado em cruzamento de média, a plataforma poderia auxilia-lo na definição do número de períodos mais adequado para a média por meio da maximização ou minimização de alguma métrica, tal como maximização do percentual de operações vencedoras, ou minimização do drawdown médio das operações.


Sugestões:

  1. Criar funcionalidade para otimizar “parâmetros” das estratégias em função de uma métrica escolhida pelo usuário.

USERVOICE: CRIAR OTIMIZADOR de Estratégias no Profit [NeoTraderBot]

No Profit, toda estratégia de execução precisa estar vinculada a um gráfico de um ativo. Desta forma, não é possível criar ordens em um ativo baseado em sua posição em outros ativos. Ou seja, não há possibilidade de criar uma estratégia para operar uma correlação entre múltiplos ativos.

Esta limitação do Profit impede, por exemplo, de se criar uma estratégia para gestão de portfolio ou  estratégias de arbitragem, entre outras…


Sugestões:

  1. Alterar funções de Backtesting (IsBought, IsSold, SellPrice, BuyPrice, etc…) para que o usuário informe o código do ativo. Por default, o código seria o ativo no qual a estratégia de execução está rodando;
  2. Permitir executar em conta real estratégias que não estejam vinculadas a nenhum ativo específico;

USERVOICE: PERMITIR CRIAÇÃO DE ESTRATÉGIAS que envie ordens em DIFERENTES ATIVOS [NeoTraderBot]

Antes da versão beta 5.2.2.121 do Profit Chart, o debug do editor de estratégias não possuía opção de “continuar”. Ou seja, uma vez pausado o código em um breakpoint, o usuário tinha que percorrer linha a linha ou terminar de executar tudo de uma vez. Não era possível executar o código de uma vez até o próximo breakpoint.

Outra limitação era o fato de não haver a possibilidade de criação de breakpoint condicional. A atualização mencionada passou a permitir criar breakpoint baseados em timestamp (horário), o que já representou um avanço na ferramenta.


Sugestões:

  1. Permitir criação de breakpoints baseados em valor específico de uma variável;
  2. Permitir inspeção de expressões com base nos valores atuais das variáveis quando o código estiver pausado em um breakpoint;

USERVOICE:MELHORAR poder de Depuração da NTSL – MELHORAR DEBUG [NeoTraderBot]

Segue abaixo uma relação de ítens a serem melhorados no Editor de estratégias. A medida que forem sendo resolvidos pelas atualizações da plataforma, iremos sinalizar com a tag RESOLVIDO (Versão XXX).

    1. Não é possível alterar o valor dos parâmetros da estratégia no modo de exibição misto;
    2. Não é possível utilizar funções de indicadores passando como parâmetro o ativo no qual se deseja calcular o indicador;
    3. No desenvolvimento de indicadores, não é possível via código definir preenchimento e cor de preenchimento entre duas séries de dados. Isto invialibiliza preencher entre séries quando há mais do que 2 séries plotadas;
    4. Não há uma forma sistematizada de inicializar variáveis globais;
    5. Na linguagem NTSL, não há comando “break”   para os controles de repetição (for e while);
    6. Não há constantes definidas para valores máximos e mínimos de integer e float;
    7. Não há função built-in (já implementada) para manipulação básica de arrays, tais como obter valor máximo, valor mínimo, ordenar…etc)
    8. Ao utilizar o depurador estando o mercado aberto, a medida que chega novos dados, ainda que você esteja parado em um breakpoint, os plots se movimentam, dificultando a depuração

Sugestões:

  1. Criar função para preenchimento entre séries;
  2. Refatorar as funções de indicadores para que haja um parâmetro da série do ativo que se deseja calcular o indicador;
  3. Adicionar aba de “Parâmetros” às “Propriedades da Estratégia” para configurar valores dos parâmetros da estratégia no modo de exibição misto;
  4. Padronizar função OnInit para o usuário poder inicializar da forma que desejar as variáveis antes da estratégia começar a rodar;
  5. Incluir comando de break na linguagem NTSL para os controles de repetição;
  6. Definir constantes de valores máximos e mínimos dos tipos de dados Integer e Float;
  7. Criar algumas funções embutidas para manipulação de array, tais como: max, min e sort.

USERVOICE:MELHORIAS DIVERSAS em NTSL [NeoTraderBot]

USERVOICE:AUMENTAR PRECISÃO da função TIME, CURRENTTIME para segundos e CRIAR função de TempoRestante [NeoTraderBot]

USERVOICE:Refatoração de TODOS os indicadores da plataforma para aceitar como parâmetro a série de dados [NeoTraderBot]

USERVOICE:Criação de Bloco de INICIALIZAÇÃO na linguagem NTSL [NeoTraderBot]

USERVOICE: Criar nova ABA de ORDENS na seção de Estatística do Editor de Estratégias [NeoTraderBot]

USERVOICE:Criar função para retornar preço e quantidade de contratos/lotes negociados desde abertura da posição [NeoTraderBot]

USERVOICE: Criar  EXPORTAÇÃO /IMPORTAÇÃO DE ESTRATÉGIA AUTOMATIZADA configurada no MÓDULO DE AUTOMAÇÃO [NeoTraderBot]

Antes da versão beta 5.2.2.121 do Profit Chart, as estratégias de execução (robôs) só podiam ser usados para fins de backtesting, análise de desempenho em dados históricos e visualização nos gráficos de recomendação de operação, cabendo ao trader efetuar as operações sinalizadas pela estratégia.

O novo Módulo de Automação de Estratégias, lançado na versão beta mencionada, passou a permitir a execução de robôs em tempo real nas contas de simulação. Isto foi um grande avanço e que já prepara a plataforma para permitir rodar os robôs em conta real.

Acredito que essa atualização do Profit mais conservadora seja motivada para corrigir eventuais bugs do módulo antes de liberar para contas reais (acho isso bem responsável por parte da Nelógica!).

 


Sugestões:

  1. Permitir execução de robôs programados pelo próprio usuário em contas reais.

Caso tenham verificado outras limitações da plataforma Profit Chart, gentileza escrever nos comentários desse artigo, bem como sua sugestão de melhoria. Iremos, sempre que possível, complementar a lista com as observações dos membros da Comunidade.

Documentação NTSL (Nelogica)

A documentação apresentada abaixo é elaborada pela Nelogica e disponibilizada neste link. O documento abaixo foi baixado do link informado em 31/05/2023.

Curso Básico - Lógica de Programação

Este curso foi criado para fornecer o conhecimento básico para quem deseja começar a implementar suas próprias estratégias automatizadas de negociação de ativos, ou até mesmo compreender melhor o código de estratégias implementadas por outras pessoas.

Reproduzir vídeo

Aula 01 - Conceitos básicos

Nesta aula abordaremos as definições básicas de programação.

Se cheguei até aqui foi porque me apoiei no ombro dos gigantes.

Isaac Newton
Reproduzir vídeo

1. Introdução

Programação está se tornando (se já não for) um pré-requisito para qualquer pessoa do século 21. Cada dia que passa mais e mais de nossas atividades cotidianas e trabalhos são facilitados com a ajuda de softwares ou até inteiramente automatizadas por eles.

Ao contrário do que muita gente pensa, programação não é um bicho de sete cabeças! Se fosse fazer uma comparação, diria que é como aprender um idioma diferente, mas talvez seja até mais simples. Para os computadores não existe subjetividade…ou é ou não é… ou é zero ou é um!

Como tudo na vida (e Newton já sabia disso…), o conhecimento precisa ser construído de forma incremental para que com o tempo possamos compreender assuntos mais complexos. Assim, pretendo apresentar a você os conceitos básicos de programação sem os formalismos do meio acadêmico. Isto é um ponto de partida e o objetivo é que você entenda as ideias! Falarei sobre todos os conceitos básicos? Não, pois tem muito conceito! Contudo, falarei sobre o que você precisa saber neste momento para iniciar sua jornada de aprendizado. Conte comigo e com a comunidade para tirar suas dúvidas por meio do nosso fórum ou dos demais canais.

Então comecemos pelo começo, é claro! E ele inicia com o conceito de ALGORITMO 

2. O que são Algoritmos?

A noção de algoritmo foi identificada formalmente pela primeira vez na tradução de trabalhos de um matemático persa do século XII. Fique tranquilo porque não vamos aprofundar na história do desenvolvimento humano! Queria apenas ressaltar que o conceito de algoritmo surgiu quando não existia sequer a ideia de computadores e, no entanto, é amplamente empregado na área de computação.

Para ser objetivo, um ALGORITMO é uma sequência finita de ações que visam resolver um problema. Esta sequência de ações deve ser PRECISA (dizer exatamente o que precisa ser feito), não pode ser ambígua (não pode haver dúvidas sobre o que cada ação significa), CORRETA (deve resolver o problema) e, de preferência, EFICIENTE (quanto menos ações ou recursos forem exigidos para resolver o problema, melhor!).

Vamos a um exemplo clássico para você não esquecer: uma receita de bolo é um algoritmo! Veja bem…a receita começa dizendo o que você precisa (quais recursos são necessários) e, em seguida, te orienta passo a passo o que fazer com cada ingrediente para ao final obter um bolo.

Outro exemplo seria se alguem te parasse no meio da rua e te perguntasse onde fica determinada loja, você certamente responderia com um algoritmo: siga esta rua, vire à direita no 3º quarteirão, pega a esquerda na próxima rotatória, a loja está no lado direito da rua.

Acho que você já entendeu o que é um algoritmo e naturalmente está pensando que existem algoritmos simples, como os exemplos que dei, mas também existem algoritmos complexos, quando os problemas a serem resolvidos são mais dasafiadores. É verdade, mas a forma como são escritos os algoritmos é sempre a mesma.

Não existe um padrão único de como escrever um algoritmo e cada livro adota um padrão mais conveniente. No entanto, todos os padrões atendem a definição que vimos. Vamos ver um exemplo de algoritmo? Veja abaixo:

				
					Algoritmo calibrarPneusDoCarro:
para i := 1 até 4 passo 1:
início:
   enquanto Pneu_i.obterPressao() <= 30:
   inicio:
      Pneu_i.adicionarPressao(1 psi);
   fim;
fim;

				
			

O algoritmo calibrarPneusDoCarro é um exemplo muito simples. Ele começa pelo primeiro pneu do carro (linha 2, i =1) e enquanto a pressão do pneu for menor que 30 psi, é adicionado 1 psi ao pneu (linha 6) até que o presente pneu tenha pressão igual a 30 psi. Daí, o algoritmo passa para o próximo pneu e repete o processo até que os 4 pneus estejam com pressão igual a 30.

3. Estruturas de Dados

No Globo Repórter de hoje...

 

Se tem algo que não podemos deixar de falar quando falamos sobre algoritmos são as ESTRUTURA DE DADOS. As estruturas de dados são mecanismos para armazenar etapas e resultados intermediários ao longo da execução do algoritmo, ou até mesmo a solução final do problema.

Vamos deixar isso mais claro…Se eu te pedisse para me dizer o resultado da soma dos números de 1 a 10 e você não lembrasse da fórmula de somatório de PA (Progressão aritmética), você iria possivelmente começar somando 1 com 2 e memorizando o número 3. Em seguida, somaria 3 com 3, e memorizaria o número 6, seguiria esse processo iterativamente até o número 10 e chegaria ao resultado da soma que é 55.

Perceba neste exemplo que você precisou manter sempre em sua memória uma soma intermediária até chegar à última operação. Este resultado intermediário é uma estrutura de dados muito simples, é apenas um número inteiro. Mas as estruturas de dados podem ser tão complexas quanto sejam necessárias para resolver um problema. Em cursos de computação, todos os alunos aprendem estruturas de dados como vetores, matrizes, listas, filas, pilhas, árvores, grafos… Mas para começar a automatizar estratégias de negociação você não precisará saber sobre tudo isso. Com o tempo e necessidade, você irá acabar estudando mais a fundo as estruturas de dados. Por enquanto, vamos manter simples e complicar à medida que for preciso.

4. Linguagem de Programação

Como vimos até agora, os algoritmos e estrutura de dados existem independentemente da linguagem de programação e este é o conceito que abordaremos agora. O que é linguagem de programação? Senta que lá vem um pouco de história…mas espero que seja interessante para você!

Linguagem de programação é a forma pela qual você se comunicará com o seu computador. O computador é extremamente veloz, consegue guardar muita informação…mas tem um problema…ele só faz o que você ordena ele fazer!

No início da computação, as linguagens eram muito rudimentares, ou em termos mais técnicos, de baixo nível. Isso significa que o programador precisava transcrever seus algoritmos em uma sequência de 0 e 1, no que denominamos código de máquina. Tipo isso:

				
					0000101110101110111000011101100001101110101000110101101101101001010 
1011010101.....e por aí vaí milhares de zeros e uns.
				
			

Eram tempos difíceis para a comunicação homem-máquina…ainda bem que a tecnologia permitiu o incremento do poder de processamento dos computadores e a sua capacidade de memória. Com o tempo vieram os cartões perfurados, depois começaram a surgir linguagens que permitiam comandos em palavras de 3 letras, tipo: ADD (soma), MOV (move um número de uma posição de memória para outra), STO (grava isso na memória), etc. E de forma gradativa, a computação foi evoluindo para chegar nas linguagens de alto nível, que são as linguagens que temos contato hoje!

Intitulamos as linguagens de alto nível aquelas linguagens que nos permitem abstrair do que realmente acontece dentro do computador…ou seja não utilizamos comandos muito primitivos, como aqueles zeros e uns ou comandos com três letras…Em analogia, é como pedir para você escrever o seu nome numa folha…eu não precisaria te dizer letra a letra e como fazer cada letra para escrevê-lo. Eu simplesmente peço, escreva seu nome e você o fará de uma forma que eu não preciso saber como.

Tem muitas linguagens diferentes, elas podem ter propósito geral, tais como Pascal, Java, C, C++, Pyhton etc, com as quais você pode fazer qualquer tipo de programa, ou pode ser desenvolvida para um fim específico, por exemplo, renderizar as páginas que você acessa na internet (HTML).

5. Código fonte, Síntaxe e Compilador

O que os algoritmos têm a ver com as linguagens de programação? Ora, a gente como programador precisa transcrever os passos do algoritmo para uma linguagem que o seu computador entenda. E cada linguagem tem uma sintaxe (forma como escrevemos) bastante rígida! Não podemos escrever diferente da sintaxe esperada porque o computador não vai entender!

Assim, o texto transcrito a partir do nosso algoritmo para uma linguagem de programação é o que chamamos de CÓDIGO FONTE. Espero que esteja entendendo até aqui….já estamos finalizando os conceitos básicos que precisa saber sobre programação.

Depois que transcrevemos o nosso algoritmo de acordo com a sintaxe da linguagem de programação, geralmente existe um programa chamado COMPILADOR que irá traduzir os seus comandos de alto nível para uma sequencia de zeros e uns (código de máquina) para ser executado pelo computador!

Pense no compilador como um professor(a) que irá corrigir sua redação (seu código-fonte), mas muito rigoroso(a) ! Ele(a) só irá transformar seu código fonte em código de máquina se não houver nenhum erro de sintaxe!

Enfim, sua tarefa de programador termina quando tiver um código executável que resolva o problema que desejava. Ou não…talvez isso seja só o começo como programador!

6. Recapitulando...

Começamos com os conceitos de algoritmos e estrutura de dados. Em seguida, apresentamos o que são as linguagens de programação e como elas se relacionam com os algoritmos. Entendemos que o código fonte nada mais é do que seu algoritmo transcrito e precisa ter a sintaxe exigida pela linguagem de programação utilizada. Por fim, explicamos que o seu código fonte precisa ser compilado para um código de máquina que poderá ser executado pelo computador.

Aula 02 - Tipos de Dados e Operações

Aprenda os tipos básicos de dados e operações.

Reproduzir vídeo

1. Introdução

Programação é como brincar de lego…não é por acaso que até a empresa lego faz kits de programação para ensinar às crianças. A forma de pensar ao resolver um problema e programar a solução é sempre de encaixar blocos sequencialmente para obter o resultado desejado. Desta forma, temos que saber o que cada bloco faz para fazermos o melhor uso dele em nossos programas.

A seguir vamos aprender quais são os tipos básicos de dados e como podemos manipulá-los, ou seja, quais operações podemos realizar com eles. Por quanto ainda vamos tentar evitar ao máximo entrar em detalhes de linguagens de programação específicas e nos ater aos conceitos. Em breve, você poderá iniciar o estudo de uma linguagem de programação com os conceitos básicos já absorvidos.

2. Quais são os tipos básicos de dados?

Os primeiros blocos que precisamos conhecer são os tipos de dados. Em todas as linguagens de programação você irá encontrar três tipos basícos de dados, que podem ser números inteiros (que nas linguagens serão apresentados como integer ou int), números com casas decimais (ou ponto flutuante, que podem se apresentar como float, real, double) e dados booleanos (um tipo de dado que apresenta apenas dois valores possíveis: verdadeiro/falso, ou em inglês, true/false). Não se preocupe em decorar as nomenclaturas, pois cada linguagem pode chamar os tipos de dados de forma diferente e quando você obtiver fluência esse será um detalhe que não representará nenhuma dificuldade. Há ainda um tipo de dados conhecido como string, que são os dados de texto, mas que não iremos abordar nesse curso introdutório para restringir o conteúdo ao que é realmente essencial.

Um termo técnico muito comum em programação é a declaração de variáveis. O que siginifica isso? O seu código fonte certamente exigirá que você crie variáveis para armazenar informação. Para cada variável, o programador precisar atribuir um nome e o tipo de dados que aquela variável armazena. O processo de definir a variável é o que se chama “declarar variável”

3. Operações com dados numéricos

Vamos falar então sobre as operações que podemos fazer com os dados numéricos, sejam inteiros ou com casas decimais. Obviamente você já aprendeu isso na escola! É possível somar, subtrair, multiplicar, dividir, exponenciar, tirar a n-ésima raiz, obter resto de uma divisão, obter o valor absoluto do número, entre outras…

A diferença na programação quando usamos dados inteiros e dados com casas decimais ocorre quando tentamos armazenar o resultado de uma das operações acima mencionadas em uma variável com tipo de dado incompatível. 

Lembra que vimos na primeira aula que os computadores só fazem o que a gente pede!? Então, ao escrever seu programa você precisará declarar o tipo das variáveis que utilizará. Vamos supor que você tenha declarado uma variável inteira para armezar o número da sua residência em sua rua: num_residencia. Logo, se em algum momento você tentar atribuir um valor à variável num_residencia, este valor deverá ser um inteiro. Poderíamos atribuir valores por meio de vários tipos de operações:

				
					// Atribuição direta
num_residencia = 8;
				
			
				
					// Atribuição por divisão
num_residencia = 16/2;
				
			
				
					// Atribuição por multiplicação
num_residencia = 2*4;
				
			
				
					// Atribuição por exponenciação (2 elevado a 3)
num_residencia = 2**3;
				
			
				
					// Atribuição por n-ésima raiz (no caso, raiz quadrada)
num_residencia = 64**(1/2);
				
			

Para todas as atribuições acima não haveria problema, porque o resultado é sempre um número inteiro e a variável num_residencia é do tipo inteiro. Mas e se o resultado da operação fosse um número com casas decimais, ex: 10/3?

Nesse caso, dependeria de cada linguagem! Há linguagens que iriam fazer a conversão automática do resultado (técnicamente conhecida como conversão implícita), truncando as casas decimais e atribuiria o valor 3 à variável num_residencia. Outras poderiam gerar um erro durante a compilação do programa ou durante a execução. Assim, o mais adequado é você garantir que a variável receberá um valor do mesmo tipo que foi declarada.

Vamos supor agora que você declare uma variável chamada minha_altura como do tipo Real, ou seja, um número com casas decimais, para armazenar minha altura em metros. Observe que a variável minha_altura poderá receber tantos valores inteiros como valores com casas decimais.

Daí você pensa, quantas casas decimais o computador pode guardar? Se eu armazenasse em minha_altura o resultado da operação 5/3. A variável minha altura teria o valor 1,66 ou 1,66667, ou 1,666666….? Isto já começa a ficar um pouco técnico e você nem precisa se preocupar em profundidade com isso. Mas vou tentar lançar um pouco de luz para que entenda melhor. 

Cada tipo de dado numérico com casas decimais pode ter uma precisão diferente a depender da quantidade de bits que este tipo de dado ocupa na memória. Assim, quanto mais bits ele ocupar na memória, mais casas decimais ele pode armazenar. É correto você pensar que em casos de resultados com infinitas casas decimais o computador nunca terá o resultado exato e sim aproximado com maior ou menor precisão, dependendo do tipo de dado que esteja utilizando. Mas para efeitos práticos, a precisão numérica que temos hoje é tão grande que isso não representa problemas para a imensa maioria das aplicações!

4. Ordem de precedência das operações

Algo importante para se prestar atenção ao escrever uma fórmula para uma variável é a ordem de precedência das operações. Você já estudou isso em matemática, mas não custa nada lembrar:

  1. Parênteses;
  2. Expoentes;
  3. Multiplicações e divisões (da esquerda para direita);
  4. Somas e subtrações (da esquerda para direita).

Nada melhor do que eu exemplo para deixar as coisas mais claras! Vamos pensar na variável minha_altura, que é do tipo Real. Se eu atribuísse a fórmula abaixo à variável, qual seria o seu valor? Tente fazer antes de expandir a resposta!

  • minha_altura = (9 – 2*((2)*(5-4)))/3
  • minha_altura = (9 – 2*((2)*(1)))/3
  • minha_altura = (9 – 2*(2))/3
  • minha_altura = (9 – 4)/3
  • minha_altura = 5/3

Você deve estar pensando: para que alguém iria programar um código para fazer essa conta? Basta usar a calculadora! E você tem razão! Não teria sentido algum programar uma atribuição de variável dessa forma, foi apenas um exemplo didático!

Em programação, o que possivelmente você iria programar é uma fórmula que baseada em outras variáveis, possa calcular ou estimar sua altura. Assim, poderíamos reescrever a fórmula de minha_altura como:

 

				
					minha_altura = (A - 2*((B-2)*(C-D**2)))/3
				
			

Inserindo os valores de A, B, C e D, o programa iria calcular minha_altura. Note que você precisa programar apenas uma vez a fórmula, o resultado dependerá apenas das variáveis inseridas no programa.

Bom, por ora, acho que estamos satisfeitos sobre operações com dados numéricos. Vamos passar agora para o outro tipo de dado: dados booleanos.

5. Operações com dados booleanos

A denominação booleano foi realizada em homenagem ao matemático inglês George Boole, um dos país da lógica booleana. As operações booleanas ou lógica booleana estão presentes em todos os circuitos eletrônicos que puder imaginar, ou seja, é a base para todos os eletrônicos que conhecemos, desde o controle do portão eletrônico até o seu celular! Não vamos abordar a lógica booleana em profundidade explorando todas as suas propriedades, mas vamos falar do necessário para que possa aprender a programar.

Como já disse na introdução, uma variável booleana pode ter apenas um de dois valores possíveis: true ou false. Vou usar os termos em inglês daqui para frente, pois assim serão apresentados para você nas linguagens de programação que vier a estudar. Para as variáveis booleanas, podemos realizar três operações básicas booleanas:

  1. NOT;
  2. AND (E);
  3. OR (OU).

Vamos começar pela operação mais simples: NOT. Se A for uma variável do tipo booleana e seu valor for true. A operação (NOT A) resulta em false. Se B é uma variável booleana e seu valor é false. A operação (NOT B) resulta em true. Simples, não!? Vamos ver isso em um formato de tabela para estruturar o raciocínio (são as famosas tabelas da verdade que já vimos no ensino médio):

A NOT A
false
true
true
false

A operação AND (E) exige que todos os operandos sejam verdadeiros para que resulte em verdadeiro, senão o valor resultante será falso. Vejamos a tabela da verdade no caso de apenas dois operandos:

A B A AND B
false
false
false
false
true
false
true
false
false
true
true
true

Por fim, a operação OR (OU) exige que pelo menos um dos operandos seja verdadeiro para que o resultado seja verdadeiro. Se nenhum operando for verdadeiro, o resultado será falso. A tabela da verdade no caso de dois operandos é a seguinte:

A B A OR B
false
false
false
false
true
true
true
false
true
true
true
true

6. Praticando a lógica booleana

Agora que já vimos o básico da lógica booleana, vamos testar se realmente aprendemos. Veja abaixo a declaração de algumas variáveis e em seguida, calcule o resultado de cada expressão. Olhe as respostas só depois de ter tentado resolver!

 

				
					int A = 10
int B = 15
boolean C = false
real D = 35,5
int E = 2
				
			

R: true

R: false

R: false

R: true AND false

R: false

R: false OR false

R: false

R: false OR false OR true

R: true

R: true AND true

R: true

R: NOT(NOT(false))

R: NOT(true)

R: false

R: (100 – 106,5) < 0

R: true

R: (50 > 35,5) AND NOT(false)

R: true AND true

R: true

7. Tipo de dados especial: Arrays

Vamos agora falar de um tipo de dado muito útil em programação: os arrays (difícil encontrar uma tradução para essa palavra! Vamos usar em inglês mesmo!)

Os arrays não são um tipo de dado básico, tais como um número inteiro, real ou booleano, mas são extremamente relevantes. Os arrays são, na verdade, uma sequência de tamanho definido de algum tipo de dado básico. Por exemplo, suponhamos que precisássemos declarar 10 variáveis inteiras. Ao invés de criar 10 nomes diferentes, podemos declarar uma única variável (um array de números inteiros) com tamanho igual a 10, conforme figura abaixo. Vamos nomear o array abaixo de array_teste.

A variável array_teste teve seus valores inicializados de forma aleatória para fins didáticos. Podemos acessar cada valor do array por meio de um indexador/índice, um número inteiro que irá se referir à posição desejada do array.

Desta forma, se quisermos nos referir ao número 15, que ocupa a primeira posição da variável array_teste, iremos utilizar a seguinte convenção array_teste[1]. Da mesma forma, a última posição do array_teste possui o valor 10 e é referenciado como array_teste[10].

Um ponto importante de ressaltar é que a referencia para o primeiro elemento do array depende da linguagem. Algumas linguagens consideram os índices iniciando por 0. Se fosse este o caso, array_teste[0] retornaria o primeiro elemento da sequência, no caso 15, enquanto array_teste[1] iria se referir na verdade ao segundo elemento da lista, no caso 4, e o último elemento da lista seria array_teste[9], que teria o valor 10.

 

8. Recapitulando

Nesta aula começamos conhecendo os tipos básicos de dados comuns em todas as linguagens de programação. Em seguida, vimos as operações que podemos aplicar sobre os dados numéricos e a ordem de precedência no cálculo de fórmulas. Também vimos as operações básicas booleanas e realizamos alguns exercícios para fixar o conteúdo. Por fim, vimos que os arrays são uma sequência de dados de um mesmo tipo declarado como uma única variável indexada, e sua importância para programação.

Aula 03 - Controles de Fluxo

Controles de fluxo (Loops) são essenciais em programação. Nesta aula veremos:

Reproduzir vídeo

1. Introdução

Se na vida sempre chega uma hora que não dá para seguir o fluxo e temos que tomar decisões importantes, na programação isso acontece quase o tempo todo!

Lembra-se da parte da definição de algoritmo que diz ser uma sequência finita de ações!? Então…os programas são estruturados para serem executados de forma sequencial, eles seguem um fluxo que inicia na primeira linha de código e vai executando cada linha até chegar a última linha (a sequência precisa ser finita, ou seu computador vai ficar travado….rsrsrs)!

Se não pudéssemos alterar este fluxo, certamente a nossa capacidade de resolver problemas por meio de algoritmos seria muito reduzida. Assim, sistematizou-se a programação com estruturas básicas de controle de fluxo (ou Loops em inglês), as quais dividem-se em dois grandes grupos: CONTROLES DE SELEÇÃO e CONTROLES DE REPETIÇÃO. Vamos ver a seguir o que significa cada tipo de controle e como é sua estrutura.

2. Controles de seleção

Em nossas vidas, é muito comum condicionarmos as nossas ações à determinadas situações ou eventos. Você já deve ter pego a si mesmo dizendo algo do tipo: “Se eu ganhar na megasena eu compraria …”? Isso é um exemplo de controle de fluxo de seleção porque existe uma condição que é “ganhar na megasena”. SE essa condição for verdadeira, iremos SELECIONAR uma ação ou mais para serem executadas, no caso: “comprar alguma coisa”. Naturalmente que é muito improvável que este exemplo de condição seja verdadeira…mas não custa nada sonhar!

Sempre que dissermos condição podemos estar tratando na verdade de uma fórmula booleana tão complexa quanto fosse necessário…por exemplo: Se eu ganhar na megasena E (não tivesse filhos OU não fosse casado(a)), eu iria viajar 2 anos pelo mundo!

Dizem que para entendermos melhor basta desenhar…vamos tentar então! Veja a figura abaixo, ela é a estrutura básica de um controle de seleção. É a famosa estrutura if, em português: se!

A estrutura de fluxo do tipo if serve para realizar alguma ação dada que uma condição foi satisfeita, ou seja, é verdadeira. Se a condição for falsa, o programa continuará sua execução até o fim.

Podemos elaborar um pouco mais essa estrutura de seleção resultando na estrutura if..else (se…senão). Nessa estrutura além de um conjunto de ações ser executado se a condição for verdadeira, caso a condição seja falsa, é executado outro conjunto de ações, antes que o programa continue até o fim. Em diagrama, a estrutura if…else é representada da seguinte forma:

A partir dessa estrutura básica if…else, poderíamos colocar estruturas if…else dentro de uma estrutura if…else. Isso é o que chamamos em programação de aninhar (veja um exemplo na figura abaixo).

Ou seja, poderíamos aninhar uma estrutura if…else na parte else de outra estrutura, quantas vezes desejássemos (também poderia-se aninhar na parte if). Vamos a um exemplo abaixo em homenagem ao dia dos pais:

				
					definirPresenteDiaDosPais(Idade_pai: Integer:
  IF Idade_pai >= 20 AND Idade_pai <= 25:
     presente = comprar(“carteira”);
  ELSE
    IF Idade_pai > 25 AND Idade_pai <= 35:
      presente = comprar(“camiseta/calça”);
    ELSE
      IF Idade_pai > 35 AND Idade_pai <= 45:
        presente = comprar(“kit_ferramentas”);
      ELSE
        IF Idade_pai > 45 AND Idade_pai <= 55:
          presente = comprar(“conjunto_churrasco”);
        ELSE
          IF Idade_pai > 55 AND Idade_pai <= 65:
            presente = comprar(“sapato”);
          ELSE
            presente = comprar(“meias”);

  return presente;
				
			

Nada muito complicado, certo!? Mas o aninhamento descrito acima poderia ser escrito em uma sintaxe de melhor compreensão, que é a estrutura switch. É importante ressaltar que esse tipo de estrutura não está presente em todas as linguagens. Se fossemos reescrever o algoritmo acima utilizando a estututura switch, seria assim:

				
					definirPresenteDiaDosPais(Idade_pai: Integer:
  switch(Idade_pai):
    case Idade_pai >= 20 AND Idade_pai <= 25:
      presente = comprar(“carteira”);
    case Idade_pai > 25 AND Idade_pai <= 35:
      presente = comprar(“camiseta/calça”);
    case Idade_pai > 35 AND Idade_pai <= 45:
      presente = comprar(“kit_ferramentas”);
    case Idade_pai > 45 AND Idade_pai <= 55:
      presente = comprar(“conjunto_churrasco”);
    case Idade_pai > 55 AND Idade_pai <= 65:
      presente = comprar(“sapato”);
    default:
      presente = comprar(“meias”);
   end switch;

  return presente;
				
			

Com isso encerramos o que precisamos saber sobre estruturas de controle de fluxo de seleção. Espero que tenha entendido os conceitos até o momento!

3. Controles de repetição

Às vezes, para resolver determinado problema, precisamos repetir uma sequência de ações até que uma situação seja alcançada. Para estes casos, iremos utilizar os controles de repetição, cuja ideia geral está apresentada na figura abaixo:

Basicamente, enquanto uma condição for verdadeira, iremos executar algumas ações repetidamente. Após cada execução desse conjunto de ações, iremos verificar novamente se a condição é verdadeira, se for falsa o interromperá o loop de repetição e seguirá sua execução. Os tipos mais comuns de controles de repetição que encontramos nas linguagens de programação são: FOR e WHILE.

A estrutura FOR é geralmente utilizada quando queremos passar por uma sequência de dados e fazer algum tipo de operação para cada elemento. Em linguagem mais técnica, o processo de percorrer uma sequência de dados chama-se iterar.

No caso da estrutura FOR, geralmente temos uma variável inteira que inicia com determinado valor, e a cada execução do controle FOR esse valor é somado/subtraído de um passo (valor constante) até que chegue a um valor limite. Ou seja a quantidade de repetições é dada em função dessa variável que chamamos de iterador e seus limites inferior, superior e passo.

Por exemplo, vamos supor que tenhamos um array chamado NATURAIS, de números inteiros de 1 a 10, ou seja 10 elementos. Vamos supor ainda que tenhamos uma variável inteira chamada i, que é um índice para iterarmos sobre os valores do array. O primeiro elemento do array pode ser referenciado como NATURAIS[i] se i for igual a 1, e o valor de NATURAIS[1] é 1. Logicamente, o último elemento da lista será NATURAIS[10] e seu valor será 10.

Caso desejássemos obter o somatório de todos elementos do array, poderíamos utilizar o seguinte algoritmo:

				
					
soma = 0;
for i=1 until 10 step 1 do:
  soma = soma + NATURAIS[i];
				
			

Fácil, né!? Em linguagens de programação mais antigas, os iteradores eram apenas números inteiros. Algumas linguagens mais recentes permitem iterar de maneiras mais naturais e você certamente aprenderá esses detalhes mais específicos quando escolher uma linguagem para trabalhar.

A segunda estrutura de controle que utilizamos com frequência é WHILE. Nessa estrutura não temos um iterador explícito. Temos apenas a avaliação de uma condição que enquanto for verdadeira irá executar as ações previstas dentro do controle WHILE. Quando a condição se tornar falsa, o programa voltará ao seu fluxo de execução até o final.

Vamos a um exemplo simples…Suponha que queiramos “imprimir” na tela os números de 1 a 100. Você certamente pensou que podemos fazer isso facilmente com um controle FOR, mas vamos exercitar fazer isso com um controle WHILE:

				
					i = 1;
WHILE(i <= 100)
{
  Imprimir(i);
  i = i + 1;
}

				
			

Nas linguagens mais antigas havia variações da estrutura WHILE. Por exemplo, tem uma estrutura que se chama DO…WHILE, a qual executa primeiro as ações do controle WHILE antes de fazer a verificação da condição. Com isso, o controle de repetição é executado sempre ao menos uma vez. Novamente, não precisamos nos preocupar com essas peculiaridades, pois cada linguagem, embora haja muita semelhança entre elas, possuí sintaxes e características diferentes. E é mais oportuno aprofundar nisso quando você decidir por uma linguagem de programação para estudar.

4. Recapitulando

Tentamos ao longo dessa aula passar os conceitos gerais do que são os controles de fluxo sem entrar em detalhes específicos de linguagem de programação. É muito importante que tenhamos o entendimento do que são os controles de fluxo e como podemos utilizá-los para resolver problemas. Enquanto os controles de seleção nos permitem executar ações quando determinada condição (ou expressão booleana) for verdadeira, os controles de repetição nos permitirão repetir a execução de ações enquanto uma condição for verdadeira.

Ressaltei que neste momento, você não precisa se preocupar com peculiaridades de programação, pois você terá a oportunidade de aprender em maior profundidade quando escolher uma linguagem específica para trabalhar.

Aula 04 - Reutilizando código

Funções são essenciais na programação.

No mundo da programação há um constante esforço por tornar as linguagens cada vez mais naturais para nós seres humano (mais fáceis de programar), bem como mais eficientes (consumirem menos recursos computacionais).

Para o programador não é diferente, ele sempre está tentando programar cada vez melhor e mais rápido tendo em vista sua experiência acumulada, refletindo em códigos mais concisos (menos linhas de código) e mais eficientes.

A forma mais primitiva de ganhar velocidade em sua programação seria COPIAR e COLAR o que já fez no passado para resolver um problema e adaptá-lo para o problema que está tentando resolver. Acredite! Como programadores, fazemos muito isso! Mas uma forma mais estruturada de reutilizar código é por meio da criação de funções, o que veremos a seguir.

Reproduzir vídeo

O que são funções?

Antes de definirmos as funções vamos pensar melhor sobre o que é um programa! Um programa é a transcrição de um algoritmo em um código fonte que pode receber parâmetros, executar um conjunto de ações e retornar um resultado.

As funções também fazem exatamente isso, talvez pela única exceção de que elas estão contidas dentro dos programas. As funções são pedaços de código fonte que podem receber parâmetros, executam um conjunto de ações e podem retornar um resultado.

E quando é que criamos funções? Quando queremos fazer exatamente uma coisa que já fizemos em outro momento no nosso programa, ou seja, reutilizar código.

Qual a vantagem de usar funções? A gente economiza linhas de código e se precisar alterar as ações executadas, precisaremos mudar apenas em um lugar (dentro da função), ou seja, para facilitar a menutenção do código. Caso não tivesse uma função, o mesmo pedaço de código poderia estar replicado em vários lugares do seu programa! Tornando mais trabalhoso e susceptível a erros uma correção no código.

Assim, as funções servem também para generalizar em função dos parâmetros. Dentro delas podemos ter declaração de variáveis que serão conhecidas como variáveis locais, ou seja, são apenas utilizadas dentro da função.

Vamos a um exemplo para ilustrar isso melhor. Suponha que tenhamos um programa que calcule área de uma circunferência diversas vezes, o que você sabe que basta fazer a seguinte conta: pi*r**2 (onde r é o raio da circunferência). Assim, eu poderia criar uma função para realizar esse cálculo:

				
					
calculaAreaCircunferencia(raio: Real)
  real área;
  area = 3.1415*raio**2;
  
  return área;
				
			

Quando precisássemos calcular a área de uma circunferência com raio 10, apenas iríamos chamar a função calculaAreaCircunferencia(10) que ela retornaria o valor desejado.

É importante ressaltar que uma função pode receber mais de um parâmetro, mas geralmente retorna apenas uma estrutura de dados. Eu disse geralmente porque também há linguagens de programação que permitem às funções retornarem mais de uma estrutura.

Em algumas linguagens de programação são dados nomes diferentes para funções, a depender se retornam ou não valores. Por exemplo, tem linguagem que dá o nome procedure quando não há retorno de valor e function quando retorna…Novamente ressalto que estas especificidades de cada linguagem e é algo que será estudado quando você for se aprofundar em alguma delas. Para o momento, basta que tenha compreendido o diagrama abaixo que representa uma função.

Concluindo...

Ao longo das últimas quatro aulas, vimos de forma bem objetiva e prática os conceitos mais básicos da programação, passando por algoritmos, estrutura de dados, código fonte, compiladores, tipos básicos de dados, estruturas de controle e funções.

Com a informação apresentada até o momento, você já tem uma base inicial para implementarmos seus primeiros programas em uma linguagem específica. Isto é o que faremos na próxima aula! Nos vemos lá!

Aula 05 - Hands-on: Primeiros programas em Pascal

Nesta última aula iremos implementar dois programas de exemplo para consolidar o que vimos no curso básico e preparar o caminho para começarmos a implementação de estratégias automatizadas.

Reproduzir vídeo

1. Por onde "começar"?

Se você assistiu/leu as aulas do curso básico até aqui, deve estar se perguntando: por qual linguagem de programação devo “começar” a estudar e implementar meus primeiros programas/estratégias?

Eu penso que para aprender uma linguagem de programação, é necessário atender a um propósito, a uma finalidade prática, para não corrermos o risco de perder a motivação no meio do caminho. Como nesta comunidade nosso objetivo é compartilhar conhecimento e experiências sobre automatização de estratégias para negociação de ativos, iremos selecionar uma linguagem que facilite alcançar esse objetivo.

Neste contexto, existem duas plataformas com maior capilaridade no mercado: Profit Chart (Empresa Nelogica) e MetaTrader (Empresa MetaQuotes Software), quando se trata de negociação de ativos na B3. Ainda tem outras plataformas disponíveis por aí como TradingView e outras que também podem atuar na B3 quanto em criptoativos.

O Profit Chart baseia-se na linguagem Pascal, enquanto o MetaTrader baseia-se na linguagem C.

Iremos iniciar a construção das bases de conhecimento desta comunidade abordando inicialmente implementações de estratégias no Profit Chart. Por que? Porque eu acredito que seja uma plataforma mais amigável para quem está iniciando e com uma curva de aprendizado menor. Está certo que a plataforma é mais limitada em termos de implementação de estratégias do que o MetaTrader. Mas para quem está iniciando, ainda há muito espaço para aprender, testar seu conhecimento e implementar diversas estratégias.

O caminho natural em um segundo momento será abordarmos também a programação em C visando utilização do MetaTrader, software que apresenta uma interface gráfica menos amigável e uma curva de aprendizado maior, embora tenha uma comunidade mundial ativa desenvolvendo soluções.

Assim, visando reduzir nosso nível de preocupação com o que é essencial utilizaremos para esta aula um console virtual e compilador hospedado na web. Faremos isso para evitar passarmos pelo processo de baixar na internet um compilador de Pascal, instalarmos uma API para programar (nada mais é que um editor de texto específico para escrever código fonte). Pois este processo não será necessário para programar as estratégias no Profit Chart, não agregando informação relevante nesse momento.

Então clique em uma das opções de compiladores online abaixo para abrir em uma nova aba o console e compilador online de Pascal para prosseguirmos com esta aula!

      1. Onlinegdb.com;
      2. JDoodle;
      3. Rextester.com
      4. Tutorialspoint.com

Em todos os compiladores onlines haverá uma seção na página onde você poderá editar o código-fonte, e outra seção que será o terminal de comando no qual você irá visualizar o resultado da execução do seu programa. Cada compilador tem um botão para executar o código que pode estar sinalizado como “Run”, “Run code”, “Execute”, etc…

2. Entendendo a estrutura básica de um programa em Pascal

Ao abrir qualquer um dos links acima, você verá no editor de código fonte, possivelmente, o famoso programa “HelloWorld” que qualquer curso de programação irá ensinar como primeira lição! Vamos entender o que está escrito!?

				
					Program HelloWorld(output);
begin
  writeln('Hello, world!');
end.
				
			

Em Pascal todo programa começa com a declaração do nome do programa: Program HelloWorld. Em parentêses são fornecidos os parâmetros do programa. O parâmetro output é uma variável especial que se refere ao terminal de comando, e que especifica que neste programa os comandos de escrita (writeln, abreviação de write line) serão direcionados para o terminal (tela à direita do compilador virtual).

Entre as linhas 2 e 4 está o corpo do programa HelloWorld, que deve estar entre as palavras reservadas begin  e end. (não esqueça do ponto!).

Este é um programa muito simples! A única coisa que ele faz é escrever em tela a string (sequencia de caracteres) “Hello, world!”.

Clique no botão “Execute” no compilador virtual. Observe que o código do programa Hello World será compilado, e caso não haja nenhum erro de compilação, será executado! Nas últimas linhas do lado direito da tela, você deve visualizar o seguinte resultado, demonstrando que seu código foi compilado e o resultado da execução.

Parabéns! Você acabou de compilar e executar seu primeiro programa na linguagem Pascal! Agora vamos explorar um pouco mais os conceitos que você aprendeu até o momento, implementando alguns programas em Pascal. 

3. Hello, market! Uma versão um pouco mais elaborada...

Entre as linhas 1 e 2 do código fonte que vimos anteriormente, o Pascal nos permite realizar algumas coisas:

  • Declarar bibliotecas que serão utilizadas pelo programa (comando uses);
  • Declarar constantes (comando const);
  • Declarar variáveis globais (comando var);
  • Declarar functions/procedures.

As bibliotecas (library) são um repositório de funções e tipos de dados que permitem facilitar escrever um programa para determinada finalidade. Por exemplo, a biblioteca strings possui algumas funcionalidades para facilitar a manipulação de dados de texto. Toda biblioteca possui uma documentação com descrição de como utilizar os tipos de dados e funções.

As constantes são definições de dados que não podem ter seu valor alterado dentro do programa.

As variáveis globais são variáveis que podem ser utilizadas em qualquer lugar de seu programa principal e, naturalmente, podem ter seu valor modificado durante a execução do programa.

As funções (functions) são pedaços reutilizáveis de código fonte que retornam algum valor, enquanto os procedimentos (procedures) não retornam nenhum valor.

A seguir vamos complicar o código fonte de forma incremental para explorarmos a linguagem Pascal.

3.1 Declarando constantes

Vamos mudar o nome do programa para “HelloMarket” e declarar uma constante chamada “dizerHello” do tipo boolean e que tenha o valor verdadeiro. Vamos escrever “Hello, market” apenas se “dizerHello” for verdadeira. Veja abaixo como fica o código fonte:

				
					Program HelloMarket(output);
const
  dizerHello = true;
  
begin
  if dizerHello = true then
    writeln('Hello, market!');   
end.
				
			

Vamos nos atentar para alguns detalhes:

  • A atribuição de valor às constantes na seção const se dá utilizando o sinal “=”;
  • O operador de igualdade para condição do if também utiliza o sinal “=”, mas não trata de uma atribuição de valor e sim de uma expressão booleana;
  • Quando há apenas um comando a ser executado dentro de um controle de decisão/repetição, não há necessidade de utilizar os delimitadores begin…end;

Ao executar o código acima, você irá verificar que o resultado é o mesmo. Você pode tentar mudar a atribuição da constante “dizerHello” para false e verificar o resultado do programa.

3.2 Utilizando biblioteca sysutils

Vamos utilizar a biblioteca sysutils que possui várias funções interessantes para ajudar a escrever programas em Pascal. Como todo programador, você terá que se acostumar a ler a documentação das bibliotecas para aprender a utilizar as funções e até mesmo ver exemplos de uso. A documentação da biblioteca sysutils pode ser acessada aqui.

Agora vamos declarar uma variável do tipo string, chamada “frase”, contendo o texto que iremos imprimir na tela, na seção var do nosso programa. Também vamos usar a função Concat para concatenar (unir) duas strings: “Hello, ” e “market!”. Em seguida vamos usar a função UpperCase para transformar o resultado da concatenção em letras maiuscúlas e armazenar na variável “frase”. Vamos lá!?

				
					Program HelloMarket(output);
uses sysutils;
const
  dizerHello = true;
var 
  frase : string;
begin
  frase := UpperCase(Concat('Hello, ', 'market!'));
  if dizerHello = true then
    writeln(frase);   
end.
				
			

Você observará que o resultado do programa ainda será o mesmo, exceto que as letras estarão em maiúsculo.

3.3 Imprimindo "Hello, market!" n vezes

Bom, agora vamos utilizar um controle de repetição para imprimir o texto “Hello, market!” quantas vezes desejarmos.

Para isso vamos utilizar o controle for e também precisaremos declarar duas variáveis auxiliares do tipo inteiro, uma para fazer a contagem (variável i) e outra para dizer quantas vezes devemos repetir o texto (n_vezes). Veja como seria o código abaixo.

				
					Program HelloMarket(output);
uses sysutils;
const
  dizerHello = true;
var 
  frase : string;
  i, n_vezes : integer;
begin
  n_vezes := 5;
  frase := UpperCase(Concat('Hello, ', 'market!'));
  if dizerHello = true then
    for i := 1 to n_vezes do
        writeln(i, ') ', frase);   
end.
				
			

O resultado esperado da execução do programa segue abaixo:

3.4 Criando uma procedure

Vamos agora implementar uma procedure que recebe como parâmetro uma string e uma quantidade. Esses parâmetros servirão para dizer o texto que deve ser impresso e quantas vezes isso deve ocorrer.

Iremos implementar uma procedure porque em Pascal é esse nome que se dá a uma “função” que não retorna nenhum resultado para o programa principal. Veja abaixo como implementamos! O resultado esperado deve ser exatamente o mesmo da seção anterior.

				
					Program HelloMarket(output);
uses sysutils;
const
  dizerHello = true;
var 
  frase : string;
  i, n_vezes : integer;
  
procedure printHello(texto: string; t: integer);
begin
    for i:=1 to t do
        writeln(i, ') ', frase);
end;

begin
  n_vezes := 5;
  frase := UpperCase(Concat('Hello, ', 'market!'));
  if dizerHello = true then
    printHello(frase, n_vezes);  
end.
				
			

Note que no corpo principal do programa, existem duas variáveis chamadas n_vezes e frase, as quais são passadas como parâmetro para a procedure printHello. Dentro dessa procedure, os parâmetros podem possuir nomes diferentes, que é exatamente o caso. Dentro de printHello, a variável frase é chamada texto e a variável n_vezes é chamada de t. Qualquer alteração nos valores das variáveis texto e t não refletirão mudança no valor das variáveis frase e n_vezes. Isto deve-se ao fato dos parâmetros serem passados para as funções/procedures como valores.

Caso o programador deseja-se modificar os valores das variáveis fornecidas como parâmetros no escopo que chamou a função, ou seja, passando a referência das variáveis originais, bastaria definir os parâmetros precedidos com o comando var.

Esses mecanismos de passagem de parâmetros como valor ou como referência para funções ocorre em todas as linguagens de programação.

3.5 Obtendo dados do usuário

Obter dados externos é uma tarefa muito comum em programação. Ora o programa pode receber dados via terminal de comando, quando o dado a ser inserido é relativamente simples, ora o programa pode receber dados via arquivo de texto com um padrão definido, quando o volume e complexidade dos dados a serem recebidos justificar.

A última parte desse primeiro exercício de programação, será obtermos do usuário a quantidade de vezes que a frase “Hello, market!” deve ser impressa. Desta forma, vamos programar para que o programa peça esta informação e atue com este dado. Vamos lá!? Veja o código abaixo:

				
					Program HelloMarket(output);
uses strings;

const
  hello = 'Hello, market!';

var
  i, vezes: integer;
  
  dizerHello: boolean;

procedure printHello(print: boolean; t: integer);
begin
    for i:=1 to t do
        if (print = true) then
            writeln(i, ' - ', hello);
end;

begin
  dizerHello := true;
  
  writeln('Digite a quantidade de vezes que deseja dizer ''Hello, market!'':');
  readln(vezes);

  printHello(dizerHello, vezes);
    
end.
				
			

O resultado da execução do programa, inserindo o número 7 (seguido de ENTER) segue abaixo:

4. Implementando Bubble Sort

Este segundo exercício de programação consistirá em entendermos um algoritmo e implementarmos um programa que o execute.

Utilizaremos um algoritmo clássico de ordenação, chamado Bubble sort. Já aviso que não é o algoritmo mais eficiente para realizar tal tarefa, mas foi um dos primeiros desenvolvidos e tem o seu valor didático. Se você se interessar em conhecer algoritmos de ordenação, veja esse vídeo aqui (Bubble sort está no minuto 4:00)!

Veja abaixo o algoritmo Bubble sort (fonte: wikipedia). Tente entender o algoritmo antes de passarmos para implementação.

				
					procedure bubbleSort(A : list of sortable items)
    n := length(A)
    repeat
        newn := 0
        for i := 1 to n - 1 inclusive do
            if A[i - 1] > A[i] then
                swap(A[i - 1], A[i])
                newn := i
            end if
        end for
        n := newn
    until n ≤ 1
end procedure
				
			

Vou tentar lhe dar uma ideia de como funciona o algoritmo Bubble sort. Pense em uma lista “A” de números inteiros aleatórios. O algoritmo irá começar comparando os dois primeiros elementos da lista, A[0] e A[1]. Se A[0] for maior que A[1], esses elementos serão trocados na lista, de tal forma que A[1] ficará na segunda posição e A[0] na primeira posição da lista. Em seguida, o algoritmo compara A[1] com A[2], e troca de posição se A[1] for maior que A[2]. Esse processo irá se repetir até chegar na comparação de A[n-i] e A[n], sendo n a quantidade de elementos da lista.

Perceba que ao iterar de 1 até n, o maior elemento da lista estará ao final desse controle (linhas 5 a 10 do algoritmo) na posição n-1. Mas o restante da lista ainda não está ordenada!

Portanto, repete-se a iteração na lista de 1 até n-1 (linhas 5 a 10), fazendo com que o segundo maior elemento da lista agora ocupe a posição n-2. Essas iterações vão ocorrer sucessivamente, até que a última iteração será apenas para comparar o elemento da primeira posição com o elemento da segunda posição. Essas repetições são controlados pelo comando repeat (linha 3) e sua condição de parada na linha 12.

O nome Bubble sort vem da analogia de um copo com refrigerante, as bolhas vão subindo, asssim como os maiores elementos também vão subindo de posição dentro da lista.

Veja abaixo a implementação do algoritmo e tente entender um pouco cada parte antes de prosseguirmos.

				
					program programaOrdenacao;
uses SysUtils;

type
  IntegerArray = array of Integer;
var 
    listaNaoOrdenada: IntegerArray;
    listaOrdenada: IntegerArray;
    i, tamanhoLista: integer;

procedure swap( var a, b:integer);
var
  temp : integer;
begin
  temp := a;
  a := b;
  b := temp;
end;

function BubbleSort(a: IntegerArray): IntegerArray;
var
  n, newn, i:integer;
begin
  n := high( a );
  repeat
    newn := 0;
    for i := 1 to n   do
      begin
        if a[ i - 1 ] > a[ i ] then
          begin
            swap( a[ i - 1 ], a[ i ]);
            newn := i ;
          end;
      end ;
    n := newn;
  until n = 0;
  
BubbleSort := a;
end;

begin
  Write('Insira o tamanho da lista que deseja ordenar (pressione ENTER):');
  readln(tamanhoLista);

  SetLength(listaNaoOrdenada, tamanhoLista);
  SetLength(listaOrdenada, tamanhoLista);

  writeln('Digite ', tamanhoLista, ' números inteiros separados ENTER:');
  for i:= 0 to tamanhoLista-1 do
    readln(listaNaoOrdenada[i]);

  writeln();
  Write('Lista inserida: ');
  for i:= 0 to tamanhoLista-1 do
    Write(listaNaoOrdenada[i], '   ');
  Write(sLineBreak);
  
  listaOrdenada := BubbleSort(listaNaoOrdenada);
  
  Write('Lista ordenada: ');
  for i:= 0 to tamanhoLista-1 do
    Write(listaOrdenada[i], '   ');
  Write(sLineBreak);
end.


				
			

Perceba que a implementação de um algoritmo simples já começa a apresentar detalhes particulares de implementação. Vamos explorar um pouco o código fonte para explicá-lo.

As linhas 1 e 2 são bem objetivas, nomeia o programa como “programaOrdenacao” e informa que será utilizada a biblioteca SysUtils. A documentação do compilador FreePascal que é utilizado nos links dos compiladores online, bem como a documentação das bibliotecas está disponível no site freepascal.org.

Nas linhas 4 e 5, a gente irá declarar um tipo de dado chamado IntegerArray que será um array de Integer (vimos o que era array na segunda aula!). Essa declaração de tipo é uma exigência da linguagem para utilizarmos este tipo de dados como retorno da função BubbleSort.

Entre as linhas 6 e 9, vamos declarar as variáveis que o programa irá utilizar: uma lista não ordenada que será informada pelo usuário, uma lista ordenada que será o resultado da função BubbleSort, uma variável de iteração i e o tamanho da lista a ser informada pelo usuário.

A procedure swap (entre as linhas 11 e 18) realiza apenas a troca de valores entre dois elementos. Essa procedure foi criada devido à recorrência desse tipo de operação no algoritmo BubbleSort. Note que os parâmetros foram passados como referência, o que permite, portanto, a manipulação de seus valores e reflexo no escopo que chamou a procedure swap, no caso, a função BubbleSort.

Entre as linhas 20 e 39, você verá a função BubbleSort que implementa o algoritmo visto anteriormente A função recebe como parâmetro um array de inteiros por valor, e retorna outro array de inteiros ordenado.

Entre as linhas 41 e 64 está o corpo principal do programa. O programa começa solicitando ao usuário o tamanho da lista que será ordenada. Assim, o usuário deve fornecer um número inteiro positivo ao programa.

Com base nessa informação, as linhas 45 e 46 definem o tamanho dos arrays listaNaoOrdenada e listaOrdenada. Em seguida, nas linhas 48 a 50, o programa pede que o usuário insira cada um dos números da lista de tamanho que ele definiu. Ao tempo que os valores são informados, eles são gravados nas posições do array listaNaoOrdenada (linha 49 e 50).

Entre as linhas 52 e 56, o programa irá imprimir na tela qual foi a lista de valores inseridas pelo usuário.

Na linha 58, é executada a chamada da função BubbleSort e o resultado é armazenado na variável listaOrdenada.

Por fim, a lista ordenada é impressa em tela (linha 60 a 63).

Talvez você cometa o erro de inserir uma letra quando o programa solicitar o tamanho da lista. Você observará que ocorrerá um erro no programa, pois o valor inserido pelo usuário seria do tipo string e o programa está tentando armazenar em uma variável do tipo inteiro.

Esses erros em programação são conhecidos como erros de execução e ocorrem sempre que o usuário realiza uma ação diferente do esperado. Em programação, o programador sempre tenta prever estes casos de “exceção” parar que o programa trate de forma correta. Por exemplo, o programa poderia informar que o valor inserido não é um número inteiro e solicitar novamente a inserção da informação até que ela venha correta. Assim, não haveria erro de execução e o programa continuaria sua execução até o fim. Situação análoga poderia ocorrer no momento de informar os elementos da lista.

Próximos passos

Bom, chegamos ao fim do curso básico de lógica de programação e espero que tenham conseguido entender os principais conceitos e ideias por trás da programação.

Esta última aula, na qual entramos em detalhes específicos da linguagem Pascal demonstra um pouco como é a vida de um programador…Especializar-se em uma linguagem específica leva tempo, exige horas de leitura de documentação, inúmeras pesquisas no google sobre erros de compilação, exemplos de código fonte, etc. É um trabalho de pesquisa e estudo que exige proativdade para achar as soluções para os problemas. As dificuldades em programação sempre vão existir! No início você irá se deparar com dificuldade em tarefas simples que com o tempo se tornarão naturais de se programar, mas surgirão novas dificuldades em tarefas mais complexas.

O importante no final das contas, é manter-se motivado, sentir-se realizado pelas pequenas conquistas e buscar suporte e materiais de qualidade para consulta. A intenção do site Neo traderBot é justamente ter um ambiente colaborativo com materiais de relevância e pessoas interessadas em ajudar umas as outras na busca por soluções.

Espero que tenha gostado do curso, mas se há alguma sugestão ou critíca para que possamos melhorar o conteúdo, não hesite em comentar abaixo.

Muito obrigado e sucesso para você nessa jornada de conhecimento!

Programando Estratégias no Profit

O que precisa saber antes de começar...

Reproduzir vídeo

Neste documento vamos apresentar aspectos importantes antes que você comece a criar seu robô ou outro tipo de estratégia (indicador, coloração, screening).

Se fossemos classificar as dúvidas apresentadas por pessoas nas redes sociais sobre automatização de estratégias, dividiríamos em 3 grupos: Dúvidas de lógica de programação, Dúvidas sobre funções do Editor de Estratégias e Dúvidas sobre como implementar o operacional desejado.

Para as dúvidas de lógica de programação não há muito segredo, basta fazer um curso introdutório no assunto. Clique aqui e assista à primeira aula do Curso Básico de Lógica de Programação da NeoTraderBot (disponível em uma playlist no Youtube). Trata-se de um curso bem objetivo e que tem a meta de em 5 vídeos curtos te explicar os principais conceitos sobre lógica de programação, sendo o último vídeo uma aula prática de Pascal que é a linguagem de programação mãe da NTSL. Caso ainda não saiba, a NTSL é a sigla para Nelogica Trading System Language, que é a linguagem adaptada do Pascal para uso no Profit Chart.

Para as dúvidas relacionadas às funções do Editor de Estratégias…eu acho bastante compreensível a existência delas. Acredito até que haja mais dúvidas que o esperado devido ao fato da documentação da Nelógica ser muito ruim, além de ser difícil achar boas referências pela Internet (principalmente gratuitas). Pensando nisso, estamos estruturando uma área neste site, aberta para qualquer visitante, explicando melhor as funções embutidas no editor de estratégias, com exemplos e comentários das dúvidas mais frequentes. Além disso, haverá uma seção de Templates (modelos para montar suas estratégias) e Snipets (trechos de código fontes prontos para você utilizar como exemplo e acelerar o seu desenvolvimento).

Chegamos então a parte principal deste texto e que se relaciona com as dúvidas referentes à implementação de setups operacionais.

Algumas dessas dúvidas sobre implementação de operacionais podem recair sobre limitações já conhecidas do Profit. Assista este vídeo que é bem interessante e trata sobre as Limitações do Profit referentes à automatização de estratégias. No decorrer deste texto abordaremos tópicos diferentes, porém complementares.

Ok…Se tirarmos aquilo que o Profit não permite fazer, e que esperamos que sejam disponibilizadas melhorias para sanar, teremos as dúvidas que derivam do fato de as pessoas não entenderem como funciona o processamento das estratégias no Profit. Se os traders que estão buscando automatizar as estratégias entendessem sobre isso, talvez mais da metade dos problemas já seriam resolvidos.

Então vamos abordar a seguir dois pontos muito importantes que você deve saber antes de implementar estratégias no Profit Chart, incluindo robôs: Modelo de dados utilizado pelo Profit e Processamento das Estratégias.

Modelo de dados OHLCV

O modelo de dados utilizado pelo Profit é o OHLCV. Este é o modelo usado por quase 100% das plataformas de backtesting e a sigla OHLCV significa Open, High, Low, Close e Volume.

Trata-se dos dados de preço e volume disponibilizados para realização de backtesting. Quanto maior for a frequência demandada de dados, por exemplo, dados de 1 minuto, maior é o espaço demandado para armazenamento dessas informações.

Se fossemos salvar em nosso computador os dados de cada tick, ou seja, para cada alteração mínima de preço do ativo que estamos negociando, precisaríamos de muito espaço e banda de internet para requisitar os dados. Então torna-se impraticável disponibilizar por padrão dados tick a tick…É claro que isto poderia ser fornecido sob demanda, para não sobrecarregar sua plataforma e os servidores da Nelógica (se houvesse funcionalidade para tal no Profit!).

Então quando realizamos backtesting de uma estratégia, nós não temos os dados tick a tick, temos apenas dados por candle fechado, os já mencionados OHLCV. 

Grandes empresas do mercado financeiro operam algoritmos em alta frequencia, em inglês, High Frequency Trading. Mas eles tem muito dinheiro, os melhores recursos de TI e mentes brilhantes (vários PHDs) para programar e monitorar os algoritmos. Além disso, eles colocam os melhores servidores possíveis de se adquirir, que executam seus algoritmos dentro da B3, fisicamente ao lado dos servidores da B3, a poucos metros de cabo de distância, para reduzir ao máximo a latência, que é o tempo entre envio e a execução da ordem.

Para se ter uma ideia…se quando enviamos uma ordem para nossa corretora, o processo demora 100 milisegundos para a execução, a ordem dessas empresas leva 1 milisegundo para ser executada. Esses não são os valores exatos, é só para ilustrar que a diferença entre a sua latência e deles é muito significativa!

E se isso foi técnico demais, visualize essa cena…você está em uma pista de fórmula 1, dentro de um fusca e vai apostar uma corrida contra um trader de um grande fundo que opera HFT, só que ele está pilotando um Bugatti Veyron…

Acho melhor não compertirmos com esses caras….Nossa chance de sucesso é quase nula!

E por quê estamos  tanto tempo falando sobre isso? Para concluirmos que tentar implementar estratégias SCALP, que dependam de dados tick a tick, não é viável para nós pobres mortais. Nós até conseguimos rodar uma estratégia em tempo real utilizando dados tick a tick, mas não conseguimos fazer backtesting tick a tick, porque não temos os dados, e mesmo se tivéssemos precisaríamos ter um supercomputador para armazenar os dados e processar esse enorme volume de informação. E se não temos como fazer um backtesting adequado, colocar um robô para executar é como jogar na sorte…Não é o que queremos! Queremos rodar um robô que em backtesting tenha um histórico de desempenho favorável para nos dar confiabilidade para rodá-lo em conta real.

O dado OHLCV de maior frequência que conseguimos ter acesso no Profit Chart são dados de 1 minuto, e mesmo assim, atualmente, só conseguimos acessar os 3 últimos meses históricos. Este volume de dados é insuficiente para otimizar e realizar backtesting com confiabilidade adequada. Ou seja, se quiséssemos implementar uma estratégia para gráficos de 1 minuto, encontraríamos também bastante dificuldade.

Então uma dica importante é que as estratégias automatizadas começam a ser uma realidade factível com dados de 5 minutos em diante. A partir dessa frequência gráfica, você começa a ter mais chance de sucesso.

Processamento de Estratégias

Se entendermos bem o que está exposto abaixo, teremos a capacidade de resolver muito mais rapidamente eventuais problemas na hora de implementar nossas estratégias, ou talvez, até não tenhamos tantos problemas assim.

Toda estratégia no Profit Chart é processada sequencialmente, linha a linha, começando pelo begin do seu código fonte até o end.

Para cada novo dado, que em backtesting é sempre um novo candle ou renko fechado, a estratégia é processada novamente. Então se você tivermos, por exemplo, uma janela histórica de dados com 2000 elementos, a estratégia será processada 2000 vezes. Ou seja, uma vez para cada elemento de dado OHLCV, começando pelo mais antigo até o mais recente.

O pulo do gato está nas variáveis globais e a forma como elas são tratadas ao longo dos processamentos.

Por mais que declaremos variáveis globais com tipos básicos como integer ou float, no final das contas, as variáveis globais podem ser tratadas como arrays, ou no vocabulário da Nelogica, como séries. O que isto significa? Vamos a um exemplo.

Suponha que eu tenhamos uma variável global do tipo integer chamada iNum que é inicializada com o valor 1. E o código fonte da estratégia será apenas a atribuição iNum = iNum + 1. No primeiro processamento, antes de executar a linha de atribuição de iNum, iNum tem o valor 1, depois que executar a atribuição,  iNum terá o valor igual a 2., Na próxima execução, iNum começa como 2, mas depois de rodar a linha de atribuição iNum será igual a 3.

Perceba uma coisa interessante, os valores das variáveis globais são mantidos de um processamento para o próximo processamento. E, além disso, outro ponto importante é que cada execução do seu código empilha os valores das variáveis globais. 

Apesar de termos declarado iNum como um integer, esta variável pode ser acessada como se fosse um array. Se fizéssemos a referência de iNum[1], estaríamos acessando o valor de iNum da última execução (no caso, 6). Se nos referíssemos a iNum[2] estaríamos acessando o valor de iNum 2 barras antes do momento atual (no caso, 5), e assim por diante.

Compreender o empilhamento das variáveis globais é muito importante, pois fará diferença na hora de você implementar a sua estratégia/robô.

Um ponto importante a salientar é que, infelizmente, não temos como inicializar as variáveis globais antes de executar o robô ou da estratégia. É uma limitação da plataforma, mas nesse caso ainda tem como dar um jeitinho. Os templates disponibilizados aqui no site da NeoTraderBot já contemplam uma forma de inicializar as variáveis globais.

Seguindo….Como verificamos o impacto de executar o código da estratégia em backtesting apenas quando uma barra é encerrada? Se tivermos uma estratégia aplicada no backtesting a gráficos de 5 minutos, essa estratégia só vai atuar depois que fechar 5 minutos. Se a estratégia disparar uma ordem de compra ou venda a mercado, ela será executada apenas no preço de abertura da próxima barra de dados. Isso ocorre para manter premissas mais coerentes de simulação, uma vez que como não há informação sobre a dinâmica de movimento do preço dentro de uma barra fechada, o preço à mercado só pode ria ser o preço de abertura da próxima barra.

Veja o exemplo abaixo de um robô baseado em um setup de cruzamento de 3 médias, a ordem de compra/venda é realizada no candle no qual há o cruzamento da média, mas a execução sempre ocorre no preço de abertura da próxima barra.

É muito importante entender este aspecto do backtesting porque quando se roda um robô ou estratégia em tempo real, o novo dado OHLCV não é necessariamente de uma barra fechada. Para cada tick, antes de encerrar a barra de 5 minutos, o código da sua estratégia é processado. Então, se não forem tomados os devidos cuidados na programação, o comportamento em tempo real do robô será diferente do comportamento em backtesting…porque no backtesting não havia os dados tick a tick….e isso pode fazer uma grande diferença de desempenho….para melhor ou pior…não tem como saber.

Enquanto o Profit apenas permitia visualizar a estratégia de execução nos gráficos isso era um problema pequeno, porque não efetivava nenhuma ordem automaticamente…mas a partir do momento que os robôs puderem ser executados em conta real, e isto poderá ocorrer agora dia 29/setembro com o lançamento oficial do módulo de Automação de Estratégias, precisaremos ser ainda mais criterioso na escrita do código fonte das estratégias. Se quisermos manter o mesmo comportamento entre backtesting e conta real (e o ideal é isso mesmo), precisaremos garantir que as ações geradas pelo robô sejam feitas apenas no fechamento de uma barra.

É importante observar que na execução de uma estratégia em tempo real, a referência a uma variável global, mesmo que implícita (série de dados de preço do ativo), tal como High ou Máxima, um período antes será sempre o valor da variável global da barra fechada anterior (ex: HIgh[1] é sempre o preço máximo da barra fechada anterior e não o valor no tick anterior!). O valor atual da variável global não será empilhado, pois a barra está aberta, ele será apenas atualizado para cada processamento do código da estratégia, ocorrendo o empilhamento apenas quando a barra atual fechar.

Bônus: Dicas de Backtesting

Por fim, um ponto muito importante para realização adequada de backtesting de uma estratégia é SER CONSERVADOR!

É muito fácil fazer backtesting de estratégias com um desempenho tão incrível que nos faria milionários em pouco tempo de execução na conta real. Sempre desconfie desses bons resultados! Geralmente é sinal de que há algum problema no código fonte da estratégia. Ainda que não tenha gerado erro de compilação, pode ter gerado uma situação não factível no mundo real.

Uma situação muito frequente, seja por desconhecimento ou inexperiência, é programar as estratégias de execução (robôs) com ordens OCO, ou seja, com ordens de stoploss e take profit, enviando primeiramente a ordem de take profit.

Isto não é uma boa prática porque como no backtesting lidamos apenas com dados de barra fechada, o simulador não tem como saber dentro de uma barra OHLCV que engloba tanto o preço do stop quanto do take profit, qual preço foi atingido primeiro.

O simulador então utilizará a ordem que foi enviada primeiro. Assim, é uma boa prática sempre colocar o envio de ordens de stoploss antes das ordens de take profit. Fazendo isso, estaremos sendo conservadores. O desempenho da estratégia pode até ser pior do que seria se houvesse dados de tempo real, mas estremos gerenciando melhor nossa expectativa em relação ao desempenho provável em conta real.

Outra boa prática de backtesting é analisar a sensibilidade do robô a condições de Slippage.

Slippage é o escorregamento de preço de ordens enviadas para corretora. O que significa isso? É a diferença entre o preço da ordem enviada e o preço de execução. Por exemplo, se enviamos uma ordem de compra a mercado quando determinado ativo é  negociado a R$ 23,50, mas a ordem acaba sendo executada a R$ 23,53, tivemos um slippage de 3 centavos.

Felizmente, no Profit Chart é possível simular o desempenho de um robô com slippage de forma bem simples, bastando informar a quantidade de ticks. O slippage será aplicado para cada ordem a mercado enviada. Veja na figura abaixo onde configurar o slippage no backtesting.

Finalizando...

Se achou interessante o conteúdo deste documento e acha que existem outros pontos a serem conhecidos antes que um trader implemente sua primeira estratégia automatizada, deixe seu comentário abaixo!

Nos próximos documentos passaremos enfim para a parte prática: escrever as estratégias em código fonte!

Templates de Estratégias (Modelos pré-configurados)

Introdução

Os Templates de Estratégias da NeoTraderBot servem para padronizar e organizar a estrutura inicial dos códigos fontes das estratégias que iremos implementar.

Ao invés de abrir o Editor de Estratégias vazio e começar tudo de novo….podemos otimizar nosso tempo com as experiências acumuladas na Comunidade e reutilizar padrões que já contemplam algumas das melhores práticas de desenvolvimento de estratégias e robôs.

Todos os modelos estão salvos no repositório GitHub da NeoTraderBot e, para facilitar ainda mais a nossa vida, eles também estão copiados abaixo em suas últimas versões. Assim, ao invés de você ter que importar os modelos em arquivo .psf, você pode simplesmente copiar o modelo desejado e colar no seu Editor!

Comente as partes que não for utilizar em um primeiro momento pois elas podem vir a ser usadas a medida que o seu código-fonte evolui.

Utilize o menu direito dessa página para ir direto ao Template desejado.

Modelo de Estratégia de Execução (Robôs)

				
					// #######################################################################
// #######################################################################
// #######################################################################
// ######                            O                             #######
// ######                        ____|____                         #######
// ######                      _|         |_                       #######
// ######                     (_|  O   O  |_)                      #######
// ######                       |_________|                        #######
// ######                                                          #######
// ###### ____        __        ____________           ________    #######
// ###### | | \       | |       | |_________|         /  ____  \   #######
// ###### | |\ \      | |       | |                  /  /    \  \  #######
// ###### | | \ \     | |       | |____             |  |      |  | #######
// ###### | |  \ \    | |       | |____|            |  |      |  | #######
// ###### | |   \ \   | |       | |____|            |  |      |  | #######
// ###### | |    \ \  | |       | |                 |  |      |  | #######
// ###### | |     \ \ | |       | |_________         \  \____/  /  #######
// ###### |_|      \_\|_|       |_|_________|         \________/   #######
// ######                                                          #######
// ###### _______  __          __   ____  __   ___    __  _______  #######
// ######    |    |  \   /\   |  \ |     |  \ |   \  /  \    |     #######
// ######    |    |__/  /__\  |   ||__   |__/ |___/ |    |   |     #######
// ######    |    |\   /    \ |   ||     |\   |   \ |    |   |     #######
// ######    |    | \ /      \|__/ |____ | \  |___/  \__/    |     #######
// ######                                                          #######
// ######  Comunidade aberta de automatização de estratégias para  #######
// ######                    negociação de ativos                  #######
// ######                                                          #######
// ######                    www.NeoTraderBot.com                  #######
// #######################################################################
// #######################################################################
// #######################################################################
//
// -----------------------------------------------------------------------
// ---------------------- DADOS DA ESTRATÉGIA ----------------------------
// -----------------------------------------------------------------------
//
// NOME DA ESTRATÉGIA: 
//   DESENVOLVIDA POR: 
//    DATA DE CRIAÇÃO: 
//             VERSÃO: 
//      ATUALIZADA EM: 
// TIPO DE ESTRATÉGIA: ( ) Indicador  ( ) Coloração (X) Execução
//                     ( ) Screening  ( ) Texto     ( ) Alarme
//
// DESCRIÇÃO DA ESTRATÉGIA:
//
//
//
// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
//
// ######################### FIM DO CABEÇALHO ############################
//
//
// -----------------------------------------------------------------------
// -------------------------- Constantes ---------------------------------
// OBS: 
// -----------------------------------------------------------------------
const
  cPlotarIndicadores = true;  
  //
  // ---------------------------------------------------------------------
  // -------------------------- Parâmetros -------------------------------
  // OBS: Segue abaixo a descrição de cada parâmetro
  // 1) pXXXXXX -> 
  // 
  // 2) pYYYYYY -> 
  // 
  // 3) pZZZZZZ -> 
  // ---------------------------------------------------------------------
input
  pXXXXX(5);
  pYYYYY(True);
  pZZZZZ(2.3);

  // ---------------------------------------------------------------------
  // ---------------------- Variáveis globais ----------------------------
  // OBS:
  // ---------------------------------------------------------------------
var
//Estrutura padrão do modelo
bStarted: boolean;
bSinalCompra, bSinalVenda, bSinalLiquida, bSinalReversao : boolean;
bComprado, bVendido : boolean;

//Variáveis personalizadas
iXXXXX, iZZZZZZ: integer;
fXXXXX, fZZZZZZ: float;



begin

  // ---------------------------------------------------------------------
  // ----------------- Inicialização da estratégia -----------------------
  // OBS: Inicialização de variáveis a serem utilizadas na estratégia de 
  // execução
  // ---------------------------------------------------------------------
  if Not bStarted then
  begin
    bStarted := True;
    //Colocar aqui ações que serão executadas apenas no primeiro processamento
    //da estratégia. Por exemplo, inicialização de variáveis.
  end;

  // ---------------------------------------------------------------------
  // ------------ Atribuição de variáveis por processamento --------------
  // ---------------------------------------------------------------------
  //Estrutura padrão do modelo
  bSinalCompra := False;
  bSinalVenda := False;
  bSinalLiquida := False;
  bSinalReversao := False;
  bComprado := isBought();
  bVendido := isSold();

  // Atribuições das variáveis da estratégia




  // ---------------------------------------------------------------------
  // ----------------------- Cálculo dos sinais  -------------------------
  // OBS: Inserir lógica de cálculo dos sinais de compra/venda/liquidação
  // e reversão, se for o caso.
  // ---------------------------------------------------------------------
  if (...) then
      bSinalCompra := True;

  if (...) then
      bSinalVenda := True;

  if bComprado then
    if (...) then
      bSinalLiquida := True;

  if bVendido then
    if (...) then
      bSinalLiquida := True;

  if bComprado or bVendido then
      bSinalReversao := True;                  


  // ---------------------------------------------------------------------
  // -------------- Administração das posições abertas -------------------
  // OBS: Baseando-se na posição aberta, pode-se implementar lógicas para 
  // atualização de alvo ou stoploss
  // ---------------------------------------------------------------------    
  if bComprado then
  begin

  end;

  if bVendido then
  begin

  end;

  // ---------------------------------------------------------------------
  // ------------------- Envia ordens de compra/venda --------------------
  // OBS: Baseando-se nos sinais e na atual posição, cria as ordens de 
  // compra e venda de acordo com o setup desejado
  // --------------------------------------------------------------------- 

  




  // ---------------------------------------------------------------------
  // ------------------------ Plot de Indicadores ------------------------
  // OBS: É sempre interessante incluir indicadores usados pelo robô para
  // poder visualizar no gráfico do Módulo de Automação de Estratégias 
  // --------------------------------------------------------------------- 
  if cPlotarIndicadores then
  begin
    Plot(...);
    Plot2(...);
    Plot3(...);

  end;

end;









				
			

Modelo de Estratégia de Coloração

				
					// #######################################################################
// #######################################################################
// #######################################################################
// ######                            O                             #######
// ######                        ____|____                         #######
// ######                      _|         |_                       #######
// ######                     (_|  O   O  |_)                      #######
// ######                       |_________|                        #######
// ######                                                          #######
// ###### ____        __        ____________           ________    #######
// ###### | | \       | |       | |_________|         /  ____  \   #######
// ###### | |\ \      | |       | |                  /  /    \  \  #######
// ###### | | \ \     | |       | |____             |  |      |  | #######
// ###### | |  \ \    | |       | |____|            |  |      |  | #######
// ###### | |   \ \   | |       | |____|            |  |      |  | #######
// ###### | |    \ \  | |       | |                 |  |      |  | #######
// ###### | |     \ \ | |       | |_________         \  \____/  /  #######
// ###### |_|      \_\|_|       |_|_________|         \________/   #######
// ######                                                          #######
// ###### _______  __          __   ____  __   ___    __  _______  #######
// ######    |    |  \   /\   |  \ |     |  \ |   \  /  \    |     #######
// ######    |    |__/  /__\  |   ||__   |__/ |___/ |    |   |     #######
// ######    |    |\   /    \ |   ||     |\   |   \ |    |   |     #######
// ######    |    | \ /      \|__/ |____ | \  |___/  \__/    |     #######
// ######                                                          #######
// ######  Comunidade aberta de automatização de estratégias para  #######
// ######                    negociação de ativos                  #######
// ######                                                          #######
// ######                    www.NeoTraderBot.com                  #######
// #######################################################################
// #######################################################################
// #######################################################################
//
// -----------------------------------------------------------------------
// ---------------------- DADOS DA ESTRATÉGIA ----------------------------
// -----------------------------------------------------------------------
//
// NOME DA ESTRATÉGIA: 
//   DESENVOLVIDA POR: 
//    DATA DE CRIAÇÃO: 
//             VERSÃO: 
//      ATUALIZADA EM: 
// TIPO DE ESTRATÉGIA: ( ) Indicador  (X) Coloração ( ) Execução
//                     ( ) Screening  ( ) Texto     ( ) Alarme
//
// DESCRIÇÃO DA ESTRATÉGIA:
//     
// 
// 
// 
// 
// 
//
// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
//
// ######################### FIM DO CABEÇALHO ############################
//
//
// -----------------------------------------------------------------------
// -------------------------- Constantes ---------------------------------
// OBS: 
// -----------------------------------------------------------------------
const
  cXXXXXX = true;  
  //
  // ---------------------------------------------------------------------
  // -------------------------- Parâmetros -------------------------------
  // OBS: Segue abaixo a descrição de cada parâmetro
  // 1) pXXXXXX -> 
  // 
  // 2) pYYYYYY -> 
  // 
  // 3) pZZZZZZ -> 
  // ---------------------------------------------------------------------
input
  pXXXXX(5);
  pYYYYY(True);
  pZZZZZ(2.3);

  // ---------------------------------------------------------------------
  // ---------------------- Variáveis globais ----------------------------
  // OBS:
  // ---------------------------------------------------------------------
var
//Estrutura padrão do modelo
bStarted: boolean;


//Variáveis personalizadas
iXXXXX, iZZZZZZ: integer;
fXXXXX, fZZZZZZ: float;


begin
  // ---------------------------------------------------------------------
  // ----------------- Inicialização da estratégia -----------------------
  // OBS: Inicialização de variáveis a serem utilizadas na estratégia de 
  // coloração
  // ---------------------------------------------------------------------
  if Not bStarted then
  begin
    bStarted := True;
    //Colocar aqui ações que serão executadas apenas no primeiro processamento
    //da estratégia. Por exemplo, inicialização de variáveis.
  end;


  // ---------------------------------------------------------------------
  // ------------ Atribuição de variáveis por processamento --------------
  // ---------------------------------------------------------------------
  // Atribuições das variáveis da estratégia



  // ---------------------------------------------------------------------
  // ---------------------- Lógica de coloração  -------------------------
  // OBS: Inserir lógica de cálculo para coloração do gráfico 
  // ---------------------------------------------------------------------
  if (...) then
  begin
    PaintBar()
  end
  else
    if (...) then
    begin
      PaintBar()
    end;

    


end;
































				
			

Modelo de Estratégia de Indicador

				
					// #######################################################################
// #######################################################################
// #######################################################################
// ######                            O                             #######
// ######                        ____|____                         #######
// ######                      _|         |_                       #######
// ######                     (_|  O   O  |_)                      #######
// ######                       |_________|                        #######
// ######                                                          #######
// ###### ____        __        ____________           ________    #######
// ###### | | \       | |       | |_________|         /  ____  \   #######
// ###### | |\ \      | |       | |                  /  /    \  \  #######
// ###### | | \ \     | |       | |____             |  |      |  | #######
// ###### | |  \ \    | |       | |____|            |  |      |  | #######
// ###### | |   \ \   | |       | |____|            |  |      |  | #######
// ###### | |    \ \  | |       | |                 |  |      |  | #######
// ###### | |     \ \ | |       | |_________         \  \____/  /  #######
// ###### |_|      \_\|_|       |_|_________|         \________/   #######
// ######                                                          #######
// ###### _______  __          __   ____  __   ___    __  _______  #######
// ######    |    |  \   /\   |  \ |     |  \ |   \  /  \    |     #######
// ######    |    |__/  /__\  |   ||__   |__/ |___/ |    |   |     #######
// ######    |    |\   /    \ |   ||     |\   |   \ |    |   |     #######
// ######    |    | \ /      \|__/ |____ | \  |___/  \__/    |     #######
// ######                                                          #######
// ######  Comunidade aberta de automatização de estratégias para  #######
// ######                    negociação de ativos                  #######
// ######                                                          #######
// ######                    www.NeoTraderBot.com                  #######
// #######################################################################
// #######################################################################
// #######################################################################
//
// -----------------------------------------------------------------------
// ---------------------- DADOS DA ESTRATÉGIA ----------------------------
// -----------------------------------------------------------------------
//
// NOME DA ESTRATÉGIA: 
//   DESENVOLVIDA POR: 
//    DATA DE CRIAÇÃO: 
//             VERSÃO: 
//      ATUALIZADA EM: 
// TIPO DE ESTRATÉGIA: (X) Indicador  ( ) Coloração ( ) Execução
//                     ( ) Screening  ( ) Texto     ( ) Alarme
//
// DESCRIÇÃO DA ESTRATÉGIA:
// 
// 
// 
// 
// 
// 
//
// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
//
// ######################### FIM DO CABEÇALHO ############################
//
//
// -----------------------------------------------------------------------
// -------------------------- Constantes ---------------------------------
// OBS: 
// -----------------------------------------------------------------------
const
  cCONSTANTE = 1;
  //
  // ---------------------------------------------------------------------
  // -------------------------- Parâmetros -------------------------------
  // OBS: Segue abaixo a descriação de cada parâmetro
  // 1) parametro1 -> 
  // 2) parametro2 -> 
  // ---------------------------------------------------------------------
input
  pParametro(1);
  // ---------------------------------------------------------------------
  // ---------------------- Variáveis globais ----------------------------
  // OBS:
  // ---------------------------------------------------------------------
var
bStarted, 	bPlotIndicador: boolean;
begin
  // ---------------------------------------------------------------------
  // ----------------- Inicialização da estratégia -----------------------
  // OBS: Inicialização de variáveis a serem utilizadas na estratégia de 
  // execução
  // ---------------------------------------------------------------------
  if Not bStarted then
  begin
    bStarted := True;
    //Colocar aqui ações que serão executadas apenas no primeiro processamento
    //da estratégia. Por exemplo, inicialização de variáveis.
  end;


  // ---------------------------------------------------------------------
  // ------------ Atribuição de variáveis por processamento --------------
  // ---------------------------------------------------------------------



  // ---------------------------------------------------------------------
  // --------------------- Cálculo do indicador  -------------------------
  // OBS: Inserir lógica de cálculo do indicador e caso ele possa ser plo_
  // tado, atribuir em algum momento True para variável bPlotIndicador 
  // ---------------------------------------------------------------------
  bPlotIndicador := false;




  //
  // ---------------------------------------------------------------------
  // ------------------ Plota valores do indicador -----------------------
  // OBS: Atribuir na sessão anterior o valor para variavel bPlotIndicador
  // quando for possível plotar um valor para o indicador no instante atual
  // ---------------------------------------------------------------------
  if bPlotIndicador then
    begin
      Plot(cCONSTANTE);
    end;   

end;









				
			

Modelo de Estratégia de Screening

				
					// #######################################################################
// #######################################################################
// #######################################################################
// ######                            O                             #######
// ######                        ____|____                         #######
// ######                      _|         |_                       #######
// ######                     (_|  O   O  |_)                      #######
// ######                       |_________|                        #######
// ######                                                          #######
// ###### ____        __        ____________           ________    #######
// ###### | | \       | |       | |_________|         /  ____  \   #######
// ###### | |\ \      | |       | |                  /  /    \  \  #######
// ###### | | \ \     | |       | |____             |  |      |  | #######
// ###### | |  \ \    | |       | |____|            |  |      |  | #######
// ###### | |   \ \   | |       | |____|            |  |      |  | #######
// ###### | |    \ \  | |       | |                 |  |      |  | #######
// ###### | |     \ \ | |       | |_________         \  \____/  /  #######
// ###### |_|      \_\|_|       |_|_________|         \________/   #######
// ######                                                          #######
// ###### _______  __          __   ____  __   ___    __  _______  #######
// ######    |    |  \   /\   |  \ |     |  \ |   \  /  \    |     #######
// ######    |    |__/  /__\  |   ||__   |__/ |___/ |    |   |     #######
// ######    |    |\   /    \ |   ||     |\   |   \ |    |   |     #######
// ######    |    | \ /      \|__/ |____ | \  |___/  \__/    |     #######
// ######                                                          #######
// ######  Comunidade aberta de automatização de estratégias para  #######
// ######                    negociação de ativos                  #######
// ######                                                          #######
// ######                    www.NeoTraderBot.com                  #######
// #######################################################################
// #######################################################################
// #######################################################################
//
// -----------------------------------------------------------------------
// ---------------------- DADOS DA ESTRATÉGIA ----------------------------
// -----------------------------------------------------------------------
//
// NOME DA ESTRATÉGIA: 
//   DESENVOLVIDA POR: 
//    DATA DE CRIAÇÃO: 
//             VERSÃO: 
//      ATUALIZADA EM: 
// TIPO DE ESTRATÉGIA: ( ) Indicador  ( ) Coloração ( ) Execução
//                     (X) Screening  ( ) Texto     ( ) Alarme
//
// DESCRIÇÃO DA ESTRATÉGIA:
//     
// 
// 
// 
// 
// 
//
// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
//
// ######################### FIM DO CABEÇALHO ############################
//
//
// -----------------------------------------------------------------------
// -------------------------- Constantes ---------------------------------
// OBS: 
// -----------------------------------------------------------------------
const
  cXXXXXX = true;  
  //
  // ---------------------------------------------------------------------
  // -------------------------- Parâmetros -------------------------------
  // OBS: Segue abaixo a descrição de cada parâmetro
  // 1) pXXXXXX -> 
  // 
  // 2) pYYYYYY -> 
  // 
  // 3) pZZZZZZ -> 
  // ---------------------------------------------------------------------
input
  pXXXXX(5);
  pYYYYY(True);
  pZZZZZ(2.3);

  // ---------------------------------------------------------------------
  // ---------------------- Variáveis globais ----------------------------
  // OBS:
  // ---------------------------------------------------------------------
var
//Estrutura padrão do modelo
bStarted: boolean;


//Variáveis personalizadas
iXXXXX, iZZZZZZ: integer;
fXXXXX, fZZZZZZ: float;


begin
  // ---------------------------------------------------------------------
  // ----------------- Inicialização da estratégia -----------------------
  // OBS: Inicialização de variáveis a serem utilizadas na estratégia de 
  // coloração
  // ---------------------------------------------------------------------
  if Not bStarted then
  begin
    bStarted := True;
    //Colocar aqui ações que serão executadas apenas no primeiro processamento
    //da estratégia. Por exemplo, inicialização de variáveis.
  end;


  // ---------------------------------------------------------------------
  // ------------ Atribuição de variáveis por processamento --------------
  // ---------------------------------------------------------------------
  // Atribuições das variáveis da estratégia



  // ---------------------------------------------------------------------
  // ---------------------- Lógica de coloração  -------------------------
  // OBS: Inserir lógica de cálculo para coloração do gráfico 
  // ---------------------------------------------------------------------
  if (...) then
  begin
    Select()
  end
  else
    if (...) then
    begin
      Select();
    end;

    


end;
































				
			

Códigos de exemplo? Tome Snippets!

Aprender a programar envolve esforço, persistência e também colaboração com outros programadores (esse é um dos benefícios de participar de uma Comunidade como a NeoTraderBot!).

Pensando em acelerar a curva de aprendizado e reduzir o tempo que ficamos presos com problemas de programação, organizamos esta área de Snippets para elaboração de estratégias no Profit Chart.

Os Snippets são trechos de códigos independentes, autocontidos e funcionais. Ou seja, cada Snippet pode ser executado sem erros, é autocontido porque executa de início ao fim uma determinada tarefa, sendo assim funcional. Eles podem ser copiados e modificados de acordo com a necessidade do usuário

Navegue abaixo pelas categorias disponíveis e caso tenha alguma sugestão de nova categoria ou tarefa, comente nas áreas apropriadas. Caso tenha colegas que também possam fazer bom uso e contribuir com a Comunidade, compartilhe esta área do site pelos ícones abaixo.

 

Compartilhe essa página!

Share on facebook
Facebook
Share on telegram
Telegram
Share on whatsapp
WhatsApp
Share on email
Email

Snippets para Localização Temporal

Nesta área você terá acesso a pedaços de códigos fontes para localização da estratégia em relação ao tempo.

Tarefas disponibilizadas:

Snippets para Manipulação de Gráficos

Nesta área você terá acesso a pedaços de códigos fontes para manipular plot, cores de plotagem, espessura, tipo de gráfico, etc.

Tarefas disponibilizadas:

 

Snippets para Utilização de Indicadores da Plataforma

Nesta área você terá acesso a pedaços de códigos fontes para utilizar os indicadores disponibilizados por padrão na Plataforma.

Tarefas disponibilizadas:

 

Criando o seu primeiro ROBÔ - V1

Reproduzir vídeo

Introdução

Neste documento vamos ver passo a passo de como criar o seu primeiro robô no Profit Chart DO ZERO…Você verá que com metodologia, organização e boas referências, programar um robô é uma tarefa relativamente fácil! Os verdadeiros desafios estão em outras partes do processo, e que abordaremos em outras oportunidades.

Eu já te prometo, desde já, que eu não vou te passar nenhum setup milagroso para te fazer rico. O objetivo deste documento não é te vender ilusões ou qualquer curso que seja. Eu quero te apresentar como eu vejo o processo de criação de um robô, que metodologia eu utilizo e você terá a real noção das dificuldades que enfrentará para desenvolver o seu próprio setup automatizado e, que se tudo der certo, um setup lucrativo!

Desde que o mundo é mundo, os vendedores sempre utilizaram a técnica de complicar as coisas para te vender facilidades, isso não é diferente nos dias de hoje…Então eu vou começar simplificando…Vou começar pelo começo! Eu criei o fluxograma abaixo para estabelecer uma linha guia de estrutura do nosso raciocínio.

Metodologia de Desenvolvimento de um Robô

A figura abaixo apresenta o fluxograma da metodologia aplicada no desenvolvimento de um robô. Vamos fazer uma passagem geral sobre a metodologia antes de aprofundar em cada etapa.

Tudo começa pela definição de um algoritmo. É daí que vem o termo algotrading….operações baseadas em algoritmos. No jargão popular, a gente chama de robô…e a Nelógica chama de “Estratégia de execução”…É tudo a mesma coisa!

E como é que achamos um algoritmo? Algoritmos, os bons algoritmos, não são achados por aí pela internet em vídeos de Youtube ou páginas sobre análise técnica. O máximo que você vai encontrar na internet são pessoas falando exatamente a mesma coisa, que são setups baseados em indicadores… quais são os sinais de entrada e sáida de cada setup. 

Apesar de haver muito chão a percorrer em termos de teste, validação, otimização e backtesting para pegar setups primários baseados em indicadores e transformá-los em algoritmos com alguma chance de sucesso, frequentemente você verá pessoas “vendendo” esses setups, ou até vendendo cursos, dizendo se tratar de estratégias infalíveis ou com alta taxa de acerto! Quem dera fosse fácil assim!

Quando o negócio é muito bom… Desconfie! Principalmente, se não puder ver o código fonte da estratégia que lhe está sendo recomendada! A verdade é que você pode até começar uma ideia por algum setup básico de análise técnica, mas terá que desenvolver por conta própria adaptações para chegar a um algoritmo capaz de rodar em conta real. E minha dica é: COMECE SIMPLES! 

Comece um algoritmo o mais simples possível. Rode as três etapas da metodologia e vá melhorando esse algoritmo em iterações sucessivas. Não tente abraçar o mundo logo na primeira implementação.

Uma vez que você tenha um algoritmo inicial, o próximo passo é escrever o código fonte. Esta etapa tem suas dificuldade técnicas de programação, mas você verá com o tempo que não se tratam das maiores dificuldades que encontrará no meio do caminho para desenvolver o seu robô!

Clique aqui para acessar os Modelos de estratégias, ou aqui para acessar a seção de Snippets!

Uma vez escrito o código fonte do algoritmo, sem erros de sintaxe. A gente vai rodar o robô com os dados disponíveis para verificar a aderência da execução do robô ao que havia sido planejado. Nesta terceira etapa, vamos procurar por erros e falhas no código e, se encontradas, vamos voltar à etapa anterior e ajustar a programação.

Agora que já tivemos uma visão geral das etapas, eu devo salientar que a metodologia de desenvolvimento de um robô não é tão linear como na figura apresentada anteriormente. Você verá que teremos muitas iterações entre as etapas, rodando vários ciclos de adaptações e  melhorias até chegar a uma versão de robô madura o suficiente para realizarmos a otimização de parâmetros e backtesting, visando verificar a sua viabilidade de execução em conta real. Mas isso é assunto para outra oportunidade. Por ora, vamos aprofundar em cada etapa nas seções abaixo.

Definindo o seu Algoritmo

Nesta primeira etapa precisamos definir com clareza (até onde podemos) como o robô deverá funcionar. Eu recomendo você abrir um bloco de anotações, físico ou virtual, e anotar suas respostas para as seguintes perguntas:

  1. Qual ativo pretendo operar?
  2. Meu robô vai operar comprado, vendido ou nos dois lados?
  3. Em que frequência gráfica ele vai operar? Ou vai operar de acordo com volatilidade em gráficos do tipo Renko?
  4. Quais indicadores técnicos vou utilizar?
  5. Quando ele deve abrir uma posição comprada? Em termos mais técnicos…qual é o sinal de compra? Faça a mesma pergunta para posição vendida! Desenvolva a resposta em termos de condições objetivas!
  6. Ele vai atuar apenas liquidando a posição ou vai permitir reversão de posição? Quais serão os sinais para cada situação?
  7. Meu robô vai segurar posição para swing trade ou só vai operar daytrade?
  8. Se não tiver sinal para liquidar ou reverter posição, como será definido o alvo da operação?
  9. Como será a administração das operações e a gestão de risco delas? Que técnicas de stoploss serão aplicadas? Vou utilizar stop com breakeven? Stop fixo? Stop móvel (Trailing stop)?

Eu sei que são muitas perguntas! Provavelmente você não tem resposta para todas as perguntas e algumas respostas poderão ser obtidas no processo de otimização da estratégia! O objetivo dessas perguntas é que você faça um brainstorming inicial!

Como a evolução natural nos ensina, a gente precisa se desenvolver de forma incremental! Primeiro a gente faz o simples funcionar e depois vamos aperfeiçoando e ajustando aos poucos…Aliás, essa é a filosofia de muitas diferentes metodologias de desenvolvimento de software… Então, não adianta começarmos pensando no mais complexo! Temos que simplificar ao máximo e escrever o código do nosso robô de forma iterativa, começando pela versão mais simples possível!

Escrevendo o Código-fonte

Esta é uma etapa bem “mão na massa”! Como já mencionei anteriormente, você poderá ganhar bastante tempo se aproveitar da experiência e informações compartilhadas pela Comunidade por meio dos Modelos de Estratégias e Snippets (exemplos de código fonte).

Minha recomendação é que comece o seu código fonte com organização desde o começo. Isso vai lhe ajudar a estruturar melhor, entender mais facilmente quando revisitar seu código ou até para que outra pessoa entenda seu código quando você o compartilhar.

Conte com a Comunidade e os fóruns disponíveis no site para te ajudar nessa etapa! 

Verificando a aderência do seu robô

Rodar um robô (estratégia de execução) em dados históricos, é bem fácil no Profit. Basta clicar no botão “Executar” e pronto! Mas fácil não quer dizerque seja  bom….tem muita coisa pra melhorar no editor de estratégias! Mas é o que temos por hoje temos que extrair o máximo que dá!

A primeira coisa que fazemos depois de rodar a primeira versão do robô (V1) é fazer uma inspeção visual para identificar erros grotescos de implementação! Por exemplo, você pode abrir o gráfico e não ter nenhuma sinalização de ordem. Ou ter apenas uma… Provavelmente, o seu código estaria com algum problema lógico.

Caso encontrasse algum problema, você teria que voltar ao código e tentar corrigir o problema, utilizando até o debug, que apesar de suas limitações é a ferramenta que dispomos para depurar o código fonte das estratégias.

O segundo filtro para identificar possíveis problemas é acessar a aba “Operações” ou “Gráfico de Operações” do modo “Estatísticas”, e inspecionar por problemas óbvios….Operações com lucros ou prejuízos muito grandes, ou operações com duração muito longa, características das operações que você não esperaria encontrar de acordo com os critérios do seu robô.

Caso encontrasse algum problema, você voltaria ao gráfico de simulação e verificaria a operação problemática, analisando o que pode ter ocorrido de diferente do previsto, inclusive depurando por meio de breakpoints.

Um ponto muito importante nessa etapa é tomar o cuidado para utilizar apenas os 70% dos dados históricos disponíveis e mais antigos. E por que disso? Porque os 30% restante dos dados, que são mais recentes serão utilizados para etapa de backtesting. 

É muito importante testar, validar e otimizar seu robô em uma janela de dados distinta da janela de dados de backtesting! A razão é meio óbvia, se você otimizar sua estratégia para todos os dados disponíveis, você pode estar ajustando o robô para as situações específicas daqueles dados e terá por consequência (ou ao menos se espera) que você encontre bons resultados! 

O que queremos no backtesting é verificar se o robô é capaz de generalizar bem com outros dados. Então não se esqueça de limitar sua análise nesta etapa de teste apenas aos dados que não serão usados no backtesting!

Colocando o Robô para rodar em conta real!

Executei as etapas 1, 2 e 3! Já posso colocar meu robô para rodar em conta real? Muito provavelmente a resposta é NÃO!

Lembra-se que eu disse que o processo de desenvolvimento de um robô é iterativo? Veja a figura abaixo para entender o que eu quis dizer com isso!

Dificilmente você conseguirá em uma única iteração do processo, chegar a um bom robô! Até pode…mas isso é altamente improvável.

Uma vez desenvolvido o código fonte da primeira versão do robô, vamos analisar o desempenho dele por meio de métricas objetivas, tais como taxa de acerto, relação risco ganho, lucro líquido, máximo drawdown.

Em seguida vamos postular ajustes que poderiam ser feitos para melhorar a métrica desejada. Geralmente, você irá buscar identificar aspectos relacionados à: ponto de abertura das operações, administração dos trades e gestão de risco, ponto de encerramento das operações.

Vamos fazer isso de forma iterativa até que cheguemos a uma situação de desempenho aceitável. É importante ter um diário do que está sendo alterado de uma versão para outra, guardar as principais métricas em uma planilha, bem como salvar o código fonte intermediário para não se perder no meio das iterações. Lembre-se, organização é muito importante para não perder o foco e gastar tempo desnecessário tentando entender o que você fez!

 

Exemplo de desenvolvimento de um robô

Para dar um exemplo prático e tornar mais tangível o processo de criação de um robô, eu utilizei um caso clássico de setup da literatura de indicadores técnicos para seguir tendência, em inglês, trend following system. Apesar de clássico, ou seja, existe há mais de 1 século, muita gente tira da cartola essa ideia todo ano, como se fosse inovadora.

A primeira versão do setup que iremos trabalhar ao longo deste documento e dos próximos, que vou chamar originalmente de Cruzamento triplo de médias móveis terá as seguintes definições:

  • Vai operar no mercado de ações permitindo swing trade;
  • Só vai operar comprado;
  • Vai utilizar 3 três médias móveis exponenciais de 10 (média rápida), 50 (média intermediária) e 200 (média lenta) períodos;
  • Vai operar em gráfico candle 15 minutos
  • Sinal de compra será o cruzamento da média intermediaria para cima da média lenta, estando a média rápida acima da média intermediária
  • Sinal de liquidação será média rápida cruzando para baixo a média intermediária;
  • Na primeira versão não será utilizado stoploss.

Pessoal, só para reforçar…este é um exemplo… não estou preocupado se é uma estratégia lucrativa ou não…Se funciona nos dias atuais ou não…Aliás já adianto que a taxa de acerto de setups básicos de cruzamento de médias é baixíssima…Isso é bom para fins didáticos. Vamos ter muito espaço para explorar!

Assista ao vídeo do Youtube que fizemos sobre a metodologia de criação de um robô e execução da primeira iteração do processo resultando na versão 1 (V1), conforme código fonte abaixo.

No próximo documento iremos realizar, na prática, sucessivas iterações a fim de melhorar o desempenho do algoritmo inicialmente proposto.

Nos vemos lá!

Robô de Cruzamento triplo de média móvel (V1)

Segue abaixo o código fonte gerado para primeira versão do robô de Cruzamento triplo de média móvel.

				
					// #######################################################################
// #######################################################################
// #######################################################################
// ######                            O                             #######
// ######                        ____|____                         #######
// ######                      _|         |_                       #######
// ######                     (_|  O   O  |_)                      #######
// ######                       |_________|                        #######
// ######                                                          #######
// ###### ____        __        ____________           ________    #######
// ###### | | \       | |       | |_________|         /  ____  \   #######
// ###### | |\ \      | |       | |                  /  /    \  \  #######
// ###### | | \ \     | |       | |____             |  |      |  | #######
// ###### | |  \ \    | |       | |____|            |  |      |  | #######
// ###### | |   \ \   | |       | |____|            |  |      |  | #######
// ###### | |    \ \  | |       | |                 |  |      |  | #######
// ###### | |     \ \ | |       | |_________         \  \____/  /  #######
// ###### |_|      \_\|_|       |_|_________|         \________/   #######
// ######                                                          #######
// ###### _______  __          __   ____  __   ___    __  _______  #######
// ######    |    |  \   /\   |  \ |     |  \ |   \  /  \    |     #######
// ######    |    |__/  /__\  |   ||__   |__/ |___/ |    |   |     #######
// ######    |    |\   /    \ |   ||     |\   |   \ |    |   |     #######
// ######    |    | \ /      \|__/ |____ | \  |___/  \__/    |     #######
// ######                                                          #######
// ######  Comunidade aberta de automatização de estratégias para  #######
// ######                    negociação de ativos                  #######
// ######                                                          #######
// ######                    www.NeoTraderBot.com                  #######
// #######################################################################
// #######################################################################
// #######################################################################
//
// -----------------------------------------------------------------------
// ---------------------- DADOS DA ESTRATÉGIA ----------------------------
// -----------------------------------------------------------------------
//
// NOME DA ESTRATÉGIA: _NBT_EXE_3CROSS
//   DESENVOLVIDA POR: Johnathas Carvalho
//    DATA DE CRIAÇÃO: 02/10/2022
//             VERSÃO: 1.0
//      ATUALIZADA EM: 02/10/2022
// TIPO DE ESTRATÉGIA: ( ) Indicador  ( ) Coloração (X) Execução
//                     ( ) Screening  ( ) Texto     ( ) Alarme
//
// DESCRIÇÃO DA ESTRATÉGIA:
// Estratégia baseada em cruzmaento triplo de média móvel
//
//
// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
//
// ######################### FIM DO CABEÇALHO ############################
//
//
// -----------------------------------------------------------------------
// -------------------------- Constantes ---------------------------------
// OBS:
// -----------------------------------------------------------------------
const
  cPlotarIndicadores = true;
  //
  // ---------------------------------------------------------------------
  // -------------------------- Parâmetros -------------------------------
  // OBS: Segue abaixo a descriação de cada parâmetro
  // 1) pLimiteSobreComprado -> Limite no qual considera-se que o cruzamento
  // para baixo gere uma operação de venda
  // 2) pLimiteSobreVendido -> Limite no qual considera-se que o cruzamento
  // para cima gere uma operação de compra
  // 3) pTamanhoPosicao -> Tamanho da exposição ao ativo
  // ---------------------------------------------------------------------
//input
//  pMediaRapida(10);
//  pMediaIntermediaria(50);
//  pMediaLenta(200);
//  pTamanhoPosicao(100);
  // ---------------------------------------------------------------------
  // ---------------------- Variáveis globais ----------------------------
  // OBS:
  // ---------------------------------------------------------------------
var
  bStarted                                     : boolean;
  bSinalCompra,bSinalVenda,bSinalLiquida       : boolean;
  bComprado,bVendido                           : boolean;
  fMediaRapida,fMediaIntermediaria,fMediaLenta : float;

  //Parametros
  pMediaRapida: integer;
  pMediaIntermediaria: integer;
  pMediaLenta: integer;
  pTamanhoPosicao: integer;

begin
  pMediaRapida := 10;
  pMediaIntermediaria := 50;
  pMediaLenta := 200;
  pTamanhoPosicao := 100;

  // ---------------------------------------------------------------------
  // ----------------- Inicialização da estratégia -----------------------
  // OBS: Inicialização de variáveis a serem utilizadas na estratégia de
  // execuçaõ
  // ---------------------------------------------------------------------
  if Not bStarted then
    begin
      bStarted := True;
    end;
  // ---------------------------------------------------------------------
  // ------------------ Inicialização de variáveis -----------------------
  // OBS: Inicialização de variáveis p/ cada tick/barra
  // Nem todas as variáveis são inicializadas aqui porque se não houver
  // dados suficientes não faz sentido inicializar algumas variáveis
  // ---------------------------------------------------------------------
  bSinalCompra := False;
  bSinalVenda := False;
  bSinalLiquida := False;
  bComprado := isBought();
  bVendido := isSold();

  fMediaRapida := Media(pMediaRapida,Close);
  fMediaIntermediaria := Media(pMediaIntermediaria,Close);
  fMediaLenta := Media(pMediaLenta,Close);


  //BUG: Se não tiver algum plot antes dos comandos de backtesting, não funciona!
  if cPlotarIndicadores then
    begin
      SetPlotColor(1,clRed);
      SetPlotWidth(1,2);
      SetPlotStyle(1,psDash);
      SetPlotColor(2,clOlive);
      SetPlotWidth(2,2);
      SetPlotColor(3,clWhite);
      SetPlotWidth(3,2);
      Plot(fMediaRapida);
      Plot2(fMediaIntermediaria);
      Plot3(fMediaLenta);
    end;

  // ---------------------------------------------------------------------
  // ----------------------- Cálculo dos sinais  -------------------------
  // OBS: Inserir lógica de cálculo dos sinais de compra/venda
  // ---------------------------------------------------------------------
  if (fMediaLenta <> 0) then
  begin
    if  (fMediaRapida >= fMediaIntermediaria)
    and (fMediaIntermediaria > fMediaLenta) 
    and (fMediaIntermediaria[1] <= fMediaLenta[1]) then
        bSinalCompra := True;
    
    if  bComprado 
    and (fMediaRapida < fMediaIntermediaria) 
    and (fMediaRapida[1] >= fMediaIntermediaria[1]) then
        bSinalLiquida := True;
  end;
  // ---------------------------------------------------------------------
  // ------------------- Envia ordens de compra/venda --------------------
  // OBS: Baseando-se nos sinais e na atual posição, cria as ordens de
  // compra e venda de acordo com o setup desejado
  // ---------------------------------------------------------------------
  // Abre posição comprada
  if Not (bComprado Or bVendido) and bSinalCompra then BuyAtMarket(pTamanhoPosicao);

  // Encerra posição comprada
  if (bComprado and bSinalLiquida) then SellToCoverAtMarket(pTamanhoPosicao);


end;
				
			

Melhorando o desempenho do seu robô

Reproduzir vídeo

No documento anterior, vimos o processo de criação de um robô, passo a passo, por meio de um exemplo de setup baseado no cruzamento de três média. Um setup clássico da análise técnica. Se você ainda não viu esse conteúdo, clique aqui antes de prosseguir com a leitura.

Nosso objetivo neste documento é ajustar e melhorar a implementação do nosso algoritmo. Pense nele como um diamante que precisamos lapidar. Iremos de forma iterativa, ou seja, em etapas graduais, trazer o brilho do nosso algoritmo bruto. Explorar o máximo possível da ideia originária e aumentar o seu potencial para as etapas subsequentes de otimização e backtesting.

Para isso, precisamos seguir uma linha de raciocínio, uma metodologia do que verificar na execução do código fonte da nossa estratégia, em que sequência e o que fazer.

Não existe uma fórmula fechada para isso, poderíamos começar por caminhos diferentes, trocar a ordem de alguns passos…isso vai depender dos resultados obtidos no teste e como você pretende priorizar os ajustes! O objetivo final é obter um algoritmo mais refinado do que a versão bruta original. Em outras palavras, um algoritmo com maior chance de ser lucrativo.

Isso quer dizer que o sucesso é garantido? Não! Haverá casos, e estes serão a maioria deles, em que por mais que trabalhemos em ajustes do código, o desempenho refinado do algoritmo não será bom! Isso faz parte do processo de elaboração de robôs…acostume-se! Nem todas ideias que a primeira vista parecem ser muito boas, vão se confirmar durante o processo. O que importa é o quanto você vai aprender cada vez que tentar criar um novo robô…pois isto permitirá acelerar o processo cada vez que executa-lo novamente.

Dito isso, vou apresentar a seguir um diagrama das etapas percorridas para melhorar o código fonte de uma estratégia/robô, representando uma metodologia para você seguir quando estiver trabalhando em suas próprias estratégias.

Metodologia

Antes de apresentarmos o diagrama das etapas metodológicas e explicar cada uma delas, precisamos esclarecer alguns pontos iniciais:

  • Ajustar código fonte não é otimizar estratégia;
  • Estabeleça uma configuração inicial de parâmetros para os indicadores da estratégia e mantenha esses valores fixos até o fim do processo;
  • A configuração dos parâmetros deve ser escolhida de forma a refletir uma condição razoável do setup, a qual permita que ajustes no código fonte tenham reflexos na métricas que iremos monitorar;
  • Recomenda-se incorporar a gestão de risco das operações no processo de otimização da estratégia;
  • Se sua estratégia não tiver uma regra para encerramento de posição, estabeleça uma relação de risco/retorno entre 2:1 e 3:1, apenas para proceder o processo de ajuste do código fonte. Utilize valores razoáveis de stop e alvo em função da volatilidade média do ativo;
  • Os ajustes do código fonte devem ser realizados em fluxos distintos para posições compradas e vendidas, visando aprimorar o código fonte para cada posição de forma independente. A decisão sobre quais posições a estratégia deve abrir dependerá do processo de otimização junto aos resultados obtidos em backtesting.

Feitas essas ressalvas, veja o diagrama abaixo das etapas sequências que iremos executar para ajustar o código fonte da nossa estratégia. As etapas de “Restrições primárias de operação” e “Definição de baseline” são fundamentais e serão executadas necessariamente nessa ordem. No entanto, as demais etapas são intercambiáveis e sua ordem de execução pode ser alterada/suprimida a depender do objetivo do programador.

Vamos ver nas próximas seções maiores detalhes sobre cada etapa.

1) Restrições primárias de operação

Neste primeiro passo, vamos identificar se a estratégia/ robô está operando conforme planejado em termos de duração e quantidade de papéis para cada posição.

Se for um robô de daytrading, temos que garantir que ele não está carregando posições de um dia para outro. E temos que verificar se as quantidades negociadas de papéis ou contratos estão conforme estabelecido pela nossa estratégia.

Se nossa estratégia operar em gráficos de Renko, temos que certificar que operações não estão sendo executadas em boxes de gaps (o que não é possível na prática!).

Enfim, nesta etapa iremos verificar e proceder ajustes a fim de garantir que as futuras alterações no código sejam avaliadas sob as mesmas bases e de forma correta.

2) Definição de baseline

Primeiramente, precisamos definir um intervalo fixo de datas para execução de testes e futuramente, otimização da estratégia. Precisamos fixar também a quantidade de papéis ou contratos que serão negociados, o ativo e o tempo gráfico a ser usado. Estas configurações devem se manter constante até o fim do processo, bem como os parâmetros dos indicadores utilizados.

Usualmente iremos separar da janela histórica de dados da seguinte forma, 50% dos dados mais antigos para ajustes da estratégia e otimização, os 30% dos próximos dados para realização de backtesting, e os últimos 20% para simular a operação do robô em uma execução em tempo real. Estes não são percentuais fixos, cabendo ao programador arbitrar uma divisão que seja melhor para cada caso.

O importante dessa segregação de dados é garantir que não haverá interseção da janela de dados utilizada para testes e otimização do código fonte, backtesting e avaliação com dados novos.

Para dar suporte a todo o processo de ajustes, recomendamos que o programador crie um diretório em seu computador para a estratégia ora em ajuste a armazene todos os artefatos do processo: versões do código fonte sempre que for feita uma alteração que gere uma versão intermediária (em formato txt) e relatório de trades realizados do Profit. Se você é membro da Comunidade, baixe a ferramenta ANALISADOR DE TRADES para realizar este processo de forma eficiente e estruturada..

Uma vez executado o código fonte original na janela de dados históricos definida, iremos monitorar e considerar os valores das métricas Taxa de acerto (%), Relação risco/ganho, quantidade de trades e resultado líquido como base de referência para o próximo ajuste no código fonte.

3) Refinamento dos sinais de entrada

Nesta etapa iremos analisar a relação de trades realizados pelo código original e verificar no gráfico os motivos que levaram as operações a dar prejuízo em termos dos sinais criados. Em outras palavras, queremos reduzir a probabilidade de falsos positivos. Queremos refinar nossos sinais de entrada das operações, para não incorrer em abertura de posição em situações com alta probabilidade de fracasso. Queremos, portanto, melhorar a nossa taxa de acerto e, possivelmente, a relação risco/ganho.

É importante ressaltar que não estamos otimizando o código ainda. Não vamos durante o ajuste do nosso código ficar alterando a quantidade de períodos de médias e parâmetros de indicadores. Esse não é o objetivo….isso ficará para outra etapa, que é a otimização do algoritmo, quando ele já estiver com a lógica refinada.

Nesta etapa, assim como nas subsequentes, as alterações serão incrementais. Ou seja, faremos um ajuste de cada vez, avaliaremos as métricas e, em seguida, iremos acrescentar outro ajuste ao código. Desta forma, cada versão do código fonte terá as alterações realizadas até o momento. Daí, a importância de manter um controle organizado das versões do código fonte e o adequado arquivamento dos trades realizados por cada versão para o cálculo das métricas de cada versão.

4) Filtro de operações de acordo com condição de mercado

Neste momento, vamos focar nossa atenção nas operações que ainda estão gerando prejuízo e vamos ver se existe um padrão entre as operações. Ou seja, se há uma situação de mercado comum que aumenta a chance de operações não serem bem sucedidas. Estaremos procurando coisas do tipo…todas operações com prejuízo tiveram abertura antes de X horas, ou ocorreram quando o mercado estava lateralizado, ou quando o plano de fundo do mercado era um movimento altista, baixista, etc…

Observe que não somos obrigados a fazer um ajuste em cada etapa só porque a etapa existe. Vamos fazer ajustes apenas se estes fizerem sentido e os manteremos no código apenas se o resultado melhorar. Caso alguma alteração retroceda um bom resultado de uma versão anterior, iremos sempre levar a frente nas próximas etapas a melhor versão até o momento.

5) Verificação de oportunidades perdidas

Analisar uma lista fechada de trades e buscar padrões é relativamente “fácil”…Mas nessa etapa teremos que  procurar pelo invisível…tentaremos identificar no gráfico aquilo que não vemos na lista de trades!

Teremos que voltar ao gráfico e realizar uma inspeção visual minuciosa do início do intervalo de teste até o fim, procurando não aquilo que foi feito…mas o que não foi feito e que se tivesse feito poderia ter gerado lucro. É claro, vamos olhar com as lentes do nosso algoritmo original….sem ficar criando novas regras. Podemos trabalhar no relaxamento do sinal de entrada, permitindo uma flexibilidade temporal em relação ao atendimento das condições para abertura de posição, por exemplo.

6) Refinamento do fechamento de posições

Neste passo vamos analisar se o encerramento de posição está ocorrendo em momento adequado, ou se há algum atraso neste encerramento que esteja  reduzindo o lucro das operações.

Podemos tentar utilizar de projeções para antecipar um encerramento de posição em momento mais vantajoso. Observe que não estamos tratando da gestão de risco das operações, como definição de alvo e stoploss…isto iremos fazer numa etapa posterior do processo de criação do robô, quando formos realizar a otimização da estratégia.

No entanto, caso a sua estratégia não tenha uma regra para liquidação de posição, você deve arbitrar um relação fixa de stop e alvo para que possamos avaliar o impacto das alterações do código fonte nas métricas de desempenho da estratégia. Esta relação deve ser razoável e deveria ter sido realizada no momento de geração do baseline. Caso isto não tenha sido feito, você precisará voltar na etapa de definição de baseline e rodar o código fonte de cada alteração com esta relação de encerramento de posição.

Caso neste momento, você identifique uma regra fixa para encerramento de posição no seu algoritmo, então o recomendável é atualizar o seu algoritmo e reiniciar o processo de ajustes do código fonte.

7) Melhorando a tempestividade das ordens

Esse passo se aplica às ordens à mercado utilizadas para abrir posições. É de conhecimento geral que, até o presente momento, o envio de ordens à mercado ocorre apenas no fechamento do Candle ou box, o que pode gerar um atraso muito grande na abertura da posição, dependendo do tempo gráfico utilizado pela estratégia.

Assim, uma possível solução para esta questão é executar o robô em uma frequência superamostrada realizando os ajustes necessários para manter o comportamento coerente a um tempo gráfico original. O nível de complexidade, bem como a viabilidade desses ajustes depende dos indicadores utilizados.

Aumentar a tempestividade das ordens não garante necessariamente resultados melhores. Assim, o programador deve avaliar se é justificável testar a estratégia em frequência superamostrada.

Um ponto importante é referente à disponibilidade de dados dados históricos. Quanto mais se aumentar a frequência, menor será a quantidade de dados disponíveis para teste, impedindo um comparação com as versões anteriores do código na mesma janela de dados. É importante verificar se a quantidade de trades realizados garante uma amostra com confiabilidade estatística adequada.

Conclusão

Apresentamos neste documento uma metodologia para guiar o processo de ajustes e refinamentos do código fonte de sua estratégia/robô.

A importância de seguir uma metodologia e organização do processo é aumentar a chance de obter ao fim do processo um resultado de desempenho do robô dentro dos critérios de aceitação do programador.

Nem sempre conseguiremos obter uma estratégia com desempenho aceitável, o que pode justificar não levar para a fase de otimização tal estratégia. No entanto, para cada insucesso, fica o acúmulo de experiência do programador, que terá cada vez mais facilidade e ferramentas para realizar o processo com estratégias futuras.

Observe que até o momento não falamos de Gestão de risco da estratégia. Pois eu defendo que a gestão de risco fará parte do processo de otimização, o qual será tema em outros documentos desta Base de Conhecimento!

Por fim, no melhor caso, o programador irá finalizar as etapas acima mencionadas com uma versão refinada do código fonte, que não necessariamente será última versão testada (pode ser uma intermediária), que irá avançar para a fase de otimização da estratégia.

Espero que este conteúdo seja útil para o leitor e contribua para o seu processo de desenvolvimento de estratégias.

Versão final do Código fonte para otimização

Para baixar todos os artefatos gerados pelo processo executado no vídeo (código fonte das versões, csv de trades e Analisador de trades), clique aqui.

OBS: A restrição de tipo de gráfico e tempo gráfico está comentada devido a um bug do Profit para execução da estratégia em backtesting.

				
					// #######################################################################
// #######################################################################
// #######################################################################
// ######                            O                             #######
// ######                        ____|____                         #######
// ######                      _|         |_                       #######
// ######                     (_|  O   O  |_)                      #######
// ######                       |_________|                        #######
// ######                                                          #######
// ###### ____        __        ____________           ________    #######
// ###### | | \       | |       | |_________|         /  ____  \   #######
// ###### | |\ \      | |       | |                  /  /    \  \  #######
// ###### | | \ \     | |       | |____             |  |      |  | #######
// ###### | |  \ \    | |       | |____|            |  |      |  | #######
// ###### | |   \ \   | |       | |____|            |  |      |  | #######
// ###### | |    \ \  | |       | |                 |  |      |  | #######
// ###### | |     \ \ | |       | |_________         \  \____/  /  #######
// ###### |_|      \_\|_|       |_|_________|         \________/   #######
// ######                                                          #######
// ###### _______  __          __   ____  __   ___    __  _______  #######
// ######    |    |  \   /\   |  \ |     |  \ |   \  /  \    |     #######
// ######    |    |__/  /__\  |   ||__   |__/ |___/ |    |   |     #######
// ######    |    |\   /    \ |   ||     |\   |   \ |    |   |     #######
// ######    |    | \ /      \|__/ |____ | \  |___/  \__/    |     #######
// ######                                                          #######
// ######  Comunidade aberta de automatização de estratégias para  #######
// ######                    negociação de ativos                  #######
// ######                                                          #######
// ######                    www.NeoTraderBot.com                  #######
// #######################################################################
// #######################################################################
// #######################################################################
//
// -----------------------------------------------------------------------
// ---------------------- DADOS DA ESTRATÉGIA ----------------------------
// -----------------------------------------------------------------------
//
// NOME DA ESTRATÉGIA: _NBT_EXE_3CROSS
//   DESENVOLVIDA POR: Johnathas Araujo de Carvalho
//    DATA DE CRIAÇÃO: 16/09/2022
//             VERSÃO: 3.0
//      ATUALIZADA EM: 12/11/2022
// TIPO DE ESTRATÉGIA: ( ) Indicador  ( ) Coloração (X) Execução
//                     ( ) Screening  ( ) Texto     ( ) Alarme
//
// DESCRIÇÃO DA ESTRATÉGIA:
//      Esta estratégia visa realizar compras mediante o cruzamento triplo
// de médias móveis exponenciais.
//
// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
//
// ######################### FIM DO CABEÇALHO ############################
//
//
// -----------------------------------------------------------------------
// -------------------------- Constantes ---------------------------------
// OBS:
// -----------------------------------------------------------------------
const
  cPlotarIndicadores = true;
  cProtecaoGap = 101.5;
    
  //
  // ---------------------------------------------------------------------
  // -------------------------- Parâmetros -------------------------------
  // OBS: Segue abaixo a descriação de cada parâmetro
  // 1) pLimiteSobreComprado -> Limite no qual considera-se que o cruzamento
  // para baixo gere uma operação de venda
  // 2) pLimiteSobreVendido -> Limite no qual considera-se que o cruzamento
  // para cima gere uma operação de compra
  // 3) pTamanhoPosicao -> Tamanho da exposição ao ativo
  // ---------------------------------------------------------------------
//input
//  pMediaRapida(10);
//  pMediaIntermediaria(50);
//  pMediaLenta(200);
//  pTamanhoPosicao(100);
  // ---------------------------------------------------------------------
  // ---------------------- Variáveis globais ----------------------------
  // OBS:
  // ---------------------------------------------------------------------
var
  bStarted                                     : boolean;
  bSinalCompra,bSinalVenda,bSinalLiquida       : boolean;
  bComprado,bVendido                           : boolean;
  fMediaRapida,fMediaIntermediaria,fMediaLenta : float;

  //Parametros
  pMediaRapida: integer;
  pMediaIntermediaria: integer;
  pMediaLenta: integer;
  pTamanhoPosicao: integer;
  fTBDetector, fUltimoTopo, fUltimoFundo: float;

begin
  pMediaRapida := 10;
  pMediaIntermediaria := 30;
  pMediaLenta := 50;
  pTamanhoPosicao := 100;

  // ---------------------------------------------------------------------
  // ----------------- Inicialização da estratégia -----------------------
  // OBS: Inicialização de variáveis a serem utilizadas na estratégia de
  // execuçaõ
  // ---------------------------------------------------------------------
  if Not bStarted then
    begin
      bStarted := True;
    end;

  //if (GraphicInterval <> itMinute) or (GraphicOffset <> 15) then
  //  if LastBarOnChart then plotText("Mudar para 15 min!", clWhite, -1, 12)
  //else
  //begin 
    // ---------------------------------------------------------------------
    // ------------------ Inicialização de variáveis -----------------------
    // OBS: Inicialização de variáveis p/ cada tick/barra
    // Nem todas as variáveis são inicializadas aqui porque se não houver
    // dados suficientes não faz sentido inicializar algumas variáveis
    // ---------------------------------------------------------------------
    bSinalCompra := False;
    bSinalVenda := False;
    bSinalLiquida := False;
    bComprado := isBought();
    bVendido := isSold();
  
    fMediaRapida := MediaExp(pMediaRapida,Close);
    fMediaIntermediaria := MediaExp(pMediaIntermediaria,Close);
    fMediaLenta := MediaExp(pMediaLenta,Close);
    fTBDetector := TopBottomDetector(4);

    if (fTBDetector <> 0) and (fTBDetector >= Close) then fUltimoTopo := fTBDetector;
    if (fTBDetector <> 0) and (fTBDetector <= Close) then fUltimoFundo := fTBDetector;


    if cPlotarIndicadores then
      begin
        SetPlotColor(1,clRed);
        SetPlotWidth(1,2);
        SetPlotStyle(1,psDash);
        SetPlotColor(2,clOlive);
        SetPlotWidth(2,2);
        SetPlotColor(3,clWhite);
        SetPlotWidth(3,2);
        Plot(fMediaRapida);
        Plot2(fMediaIntermediaria);
        Plot3(fMediaLenta);
      end;
  
    

    // ---------------------------------------------------------------------
    // ----------------------- Cálculo dos sinais  -------------------------
    // OBS: Inserir lógica de cálculo dos sinais de compra/venda
    // ---------------------------------------------------------------------
    if (fMediaLenta <> 0) then
    begin
      if  (fMediaRapida >= fMediaIntermediaria)
      and (fMediaIntermediaria > fMediaLenta) 
      and (fMediaIntermediaria[1] <= fMediaLenta[1])  then
      begin
        if (fMediaRapida/fMediaLenta*100 <= cProtecaoGap) then
        if  (fMediaLenta > fMediaLenta[1])
        and (fMediaLenta[1] > fMediaLenta[2]) then
        if  (fMediaRapida > fMediaRapida[1]) 
        and (fMediaRapida[1] > fMediaRapida[2]) then
        if Not ((Close <= fUltimoTopo) and (Close >= fUltimoFundo)) then
        if Not (Close <= fUltimoFundo) then
          bSinalCompra := True;
      end;
      
      if  bComprado 
      and (fMediaRapida < fMediaIntermediaria) 
      and (fMediaRapida[1] >= fMediaIntermediaria[1]) then
          bSinalLiquida := True;
    end;
    // ---------------------------------------------------------------------
    // ------------------- Envia ordens de compra/venda --------------------
    // OBS: Baseando-se nos sinais e na atual posição, cria as ordens de
    // compra e venda de acordo com o setup desejado
    // ---------------------------------------------------------------------
    // Abre posição comprada
    if Not (bComprado Or bVendido) and bSinalCompra then BuyAtMarket(pTamanhoPosicao);
  
    // Encerra posição comprada
    if (bComprado and bSinalLiquida) then SellToCoverAtMarket(pTamanhoPosicao);

  //end;

end;
				
			

Criando seu próprio Indicador

Reproduzir vídeo

Médias móveis, RSI, MACD, Bandas de Bollinger, Canal de Keltner, OBV, ATR, VWAP…Você já sabe do que eu estou falando: Dos indicadores de análise técnica! Nesse documento eu irei abordar o processo de criação de um indicador para que você entenda as etapas necessárias para criação do seu próprio indicador, desde a análise de dados e concepção do indicador até a implementação e verificação de consistência.

No vídeo acima, você poderá acompanhar o conteúdo deste documento de forma mais dinâmica, bem como acompanhar um exemplo do processo de criação do indicador Neo Volatility Band.

Introdução

Os indicadores nasceram com a análise técnica e se pudéssemos eleger o primeiro da espécie, seria a média móvel! Ela é usada há mais de um século…numa época e que não tinha computador, calculadoras digitais e os trades não ocorriam em alta frequencia como hoje. No entanto, já eram úteis para identificar tendências…Você sabe que elas podem ser aritméticas, exponenciais, ponderadas… E quando utilizadas em pares dão origem até a outros indicadores tal como o MACD.

Com o tempo surgiram vários outros indicadores, que passaram a ser agrupados entre indicadores de tendência, osciladores (que buscam identificar divergências que sinalizem reversões), indicadores de volatilidade, entre outros.

Criar um indicador qualquer não é tão difícil…o desafio é criar um que seja útil e consistente!

O que quero dizer com útil? Um indicador que possa ser usado como base para um setup operacional, afinal isso é o que se pretende fazer com indicadores! Além é claro de enfeitar o gráfico com toda a paleta de cores possíveis! (Só para deixar claro, isso foi uma ironia!)

E consistente…o que isso significa? Um indicador que responda objetivamente ao propósito pelo qual foi criado, ou seja, que tenha forte correlação com o que propõe sinalizar.

Então vamos direto ao ponto…Vamos abordar o fluxo para criação de um indicador e explicar em detalhes cada etapa.

Fluxo para criação de um indicador

A figura abaixo apresenta um diagrama das etapas necessárias para criação de um indicador. Observa-se que elas foram dispostas em um formato de ciclo onde, o fluxo se retroalimenta.

O mais natural é iniciar o fluxo pela “Análise de dados” passando pelas etapas de “Definição de Cálculo”, “Escrita de código fonte e “Verificação de consistência”.

Vamos abordar nas seções subsequentes o escopo de cada etapa.

1) Analisar dados

Esta é a primeira etapa do fluxo de criação de um indicador. Ao analisar os dados, temos que definir um enfoque: movimentação de preço, volume, agressão, volatilidade; bem como estudar a relação entre as variáveis analisadas.

O ideal é identificar um padrão que possa ser sinalizado com antecedência e confiança estatística. Os indicadores podem servir ao propósito de identificar tendências, reversões de preço, consolidações, exaustão de movimento, entre outros.

2) Definir Cálculo

Uma vez identificado um padrão nos dados, o desafio é conseguir converter números e ideias em fórmulas matemáticas. Afinal, teremos que programar o indicador, ainda que seja uma soma, divisão ou multiplicação, ou ponderação de algum valor, esta conta precisa fazer sentido!

Para definição do cálculo do indicador devemos sempre seguir a máxima de que “soluções devem ser tão simples quanto possível e tão complexas quanto for necessário”. Não tem como acertar sempre…portanto, o indicador será um modelo de aproximação da realidade, passível de erro e de falsas sinalizações. Outro cuidado que devemos ter nessa etapa é de não tornar as exceções regras do cálculo.

Ou seja, tente evitar criar muitas restrições no cálculo para mitigar o risco de estar no final das contas um ajuste de curva.

3) Escrever o código fonte

Dado o enorme desafio das etapas anteriores, talvez a codificação do indicador seja a parte mais fácil do processo!

Como sempre dizemos, comece seu código simples e vá complicando aos poucos, de forma iterativa. Não tente “abraçar o mundo”…um indicador é só um indicador…não comece a caracterizar seu indicador como um setup em si ou como uma regra de coloração. O indicador é parte de um processo de elaboração de setup! O indicador que está criando pode e deve permitir a elaboração de estratégias que se baseiem em seu valor, bem como regras de coloração…mas estes não são objetivos que devem ser incorporados no código do indicador!

4) Verificar a consistência

Esta é uma etapa de validação que pode representar o fim da elaboração do indicador, ou o início de um novo ciclo de desenvolvimento do indicador.

Nesta etapa temos que verificar se o indicador e os valores calculados fazem sentido e se os valores apresentados nos permitem construir hipóteses para analisar o mercado. Acima de tudo, os valores calculados pelo indicador cumprem o objetivo inicial? É factível a criação de um setup que se baseie no indicador?

Temos que verificar também as situações nas quais o indicador funciona bem e quando ele não funciona tão bem.

Por fim, precisamos definir quais são os parâmetros do indicador, que permitem ajustá-lo a diferentes ativos ou situações de mercado.

Conclusão

Espero que este conteúdo tenha agregado valor a você e que tenham percebido a semelhança com o processo de criação de um robô.

A diferença é que enquanto existe um trabalho de análise de dados, o qual você pode aprofundar-se ao nível desejado para criação do indicador, na criação de um robô o esforço maior concentra-se no backtesting e na otimização para administração de trades e gestão de risco.

Assim como os robôs, as estratégias de indicadores também podem ser otimizadas e avaliadas em backtesting. Iremos abordar estes temas em outros documentos da nossa Base de Conhecimento.

Código fonte do indicador: Neo Volatility Band

				
					// #######################################################################
// #######################################################################
// #######################################################################
// ######                            O                             #######
// ######                        ____|____                         #######
// ######                      _|         |_                       #######
// ######                     (_|  O   O  |_)                      #######
// ######                       |_________|                        #######
// ######                                                          #######
// ###### ____        __        ____________           ________    #######
// ###### | | \       | |       | |_________|         /  ____  \   #######
// ###### | |\ \      | |       | |                  /  /    \  \  #######
// ###### | | \ \     | |       | |____             |  |      |  | #######
// ###### | |  \ \    | |       | |____|            |  |      |  | #######
// ###### | |   \ \   | |       | |____|            |  |      |  | #######
// ###### | |    \ \  | |       | |                 |  |      |  | #######
// ###### | |     \ \ | |       | |_________         \  \____/  /  #######
// ###### |_|      \_\|_|       |_|_________|         \________/   #######
// ######                                                          #######
// ###### _______  __          __   ____  __   ___    __  _______  #######
// ######    |    |  \   /\   |  \ |     |  \ |   \  /  \    |     #######
// ######    |    |__/  /__\  |   ||__   |__/ |___/ |    |   |     #######
// ######    |    |\   /    \ |   ||     |\   |   \ |    |   |     #######
// ######    |    | \ /      \|__/ |____ | \  |___/  \__/    |     #######
// ######                                                          #######
// ######  Comunidade aberta de automatização de estratégias para  #######
// ######                    negociação de ativos                  #######
// ######                                                          #######
// ######                    www.NeoTraderBot.com                  #######
// #######################################################################
// #######################################################################
// #######################################################################
//
// -----------------------------------------------------------------------
// ---------------------- DADOS DA ESTRATÉGIA ----------------------------
// -----------------------------------------------------------------------
//
// NOME DA ESTRATÉGIA: NVI Neo Volatility Indicator
//   DESENVOLVIDA POR: NeoTraderBOt
//    DATA DE CRIAÇÃO: 12/10/2022
//             VERSÃO: 1.0
//      ATUALIZADA EM: 12/10/2022
// TIPO DE ESTRATÉGIA: (X) Indicador  ( ) Coloração ( ) Execução
//                     ( ) Screening  ( ) Texto     ( ) Alarme
//
// DESCRIÇÃO DA ESTRATÉGIA:
//    Indicador baseado em volatilidade utilizando função log-retorno e 
// desvio padrão em torno de uma média de curto prazo
//
//
//
//
//
// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
//
// ######################### FIM DO CABEÇALHO ############################
//
//
// -----------------------------------------------------------------------
// -------------------------- Constantes ---------------------------------
// OBS:
// -----------------------------------------------------------------------
//const
  //cCONSTANTE = 1;
  //
  // ---------------------------------------------------------------------
  // -------------------------- Parâmetros -------------------------------
  // OBS: Segue abaixo a descriação de cada parâmetro
  // 1) parametro1 ->
  // 2) parametro2 ->
  // ---------------------------------------------------------------------
input
  pQtdePeriodosVolatilidade(500);
  pQtdePeriodosMedia(36);
  pQtdeDesvioVol(2.0);
  // ---------------------------------------------------------------------
  // ---------------------- Variáveis globais ----------------------------
  // OBS:
  // ---------------------------------------------------------------------
var
bStarted, 	bPlotIndicador: boolean;
fLogRetorno: float;
fStdDev, fBandaSuperior, fBandaInferior: float;
fMedia: float;

begin
  // ---------------------------------------------------------------------
  // ----------------- Inicialização da estratégia -----------------------
  // OBS: Inicialização de variáveis a serem utilizadas na estratégia de
  // execução
  // ---------------------------------------------------------------------
  if Not bStarted then
  begin
    bStarted := True;
    //Colocar aqui ações que serão executadas apenas no primeiro processamento
    //da estratégia. Por exemplo, inicialização de variáveis.

  end;


  // ---------------------------------------------------------------------
  // ------------ Atribuição de variáveis por processamento --------------
  // ---------------------------------------------------------------------
  if Close[1] = 0 then fLogRetorno := 0 else fLogRetorno := Log(Close/close[1]);
  fMedia := Media(pQtdePeriodosMedia, Close);
  fStdDev := StdDevs(fLogRetorno, pQtdePeriodosVolatilidade);




  // ---------------------------------------------------------------------
  // --------------------- Cálculo do indicador  -------------------------
  // OBS: Inserir lógica de cálculo do indicador e caso ele possa ser plo_
  // tado, atribuir em algum momento True para variável bPlotIndicador
  // ---------------------------------------------------------------------
  bPlotIndicador := true;

  fBandaSuperior := fMedia*ExpValue(pQtdeDesvioVol*fStdDev);
  fBandaInferior := fMedia*ExpValue(-pQtdeDesvioVol*fStdDev);



  //
  // ---------------------------------------------------------------------
  // ------------------ Plota valores do indicador -----------------------
  // OBS: Atribuir na sessão anterior o valor para variavel bPlotIndicador
  // quando for possível plotar um valor para o indicador no instante atual
  // ---------------------------------------------------------------------
  if bPlotIndicador then
    begin
      PlotN(1, fMedia);
      PlotN(2, fBandaSuperior);
      PlotN(3, fBandaInferior);

      setPlotColor(1, clRed);
      setPlotColor(2, clWhite);
      setPlotColor(3, clWhite);
      SetPlotWidth(1,2);
      SetPlotWidth(2,2);
      SetPlotWidth(3,2);

    end;

end;
				
			

Criando uma Estratégia de Coloração

Reproduzir vídeo

As Estratégias de Coloração são o primeiro passo para a automatização de operações. No vídeo acima, explicamos o passo a passo para criar uma regra de coloração que se baseia em dois indicadores de Bandas de Bollinger. Assista ao vídeo para uma explicação dinâmica do processo de escrita do código fonte de uma estratégia de coloração!

Introdução

Se você já assistiu aos vídeos ou leu os documentos sobre como criar seu primeiro robô e como criar seu próprio indicador, então você já tem uma noção básica do processo de criar uma estratégia.

A criação de uma estratégia de coloração visa facilitar uma sinalização ao trader por uma cor no gráfico. Pode ser uma lógica simples ou um pouco mais complicada, englobando comparações de diferentes indicadores frente a valores de referência. Fato é que se espera que a coloração torne a ação do trader mais tempestiva, pois ele não terá que realizar as mesmas contas que a estratégia calculou para pintar o gráfico. Ao ver uma determinada cor no gráfico, o trader já saberá como agir ou se comportar.

Muitas soluções externas para automatização do roteamento de ordens do Profit utilizavam as regras de coloração para ativar envio de ordens. Embora tenha sido lançado o Módulo de Automação de Estratégias, acredito que o envio de ordens a mercado, baseado nas soluções visuais de automatização de ordens ainda representa uma vantagem em relação ao módulo (hoje!). A tendência é que essas soluções externas percam vantagem competitiva a medida que o Módulo de Automação de Estratégias seja aprimorado, tornando estas soluções obsoletas. Uma desvantagem dessas soluções é que os gráficos precisam estar abertos em tela, pois elas trabalham com o mapeamento da tela, limitando assim a quantidade de estratégias que podem rodar simultaneamente, além de não permitirem utilizar subcontas, pois a interface gráfica padrão do Profit não permite (em geral) essa opção fora do Módulo de Automação de Estratégias para clientes padrão.

Implementação de uma estratégia de coloração

A implementação de uma estratégias de coloração envolve três etapas: especificar regra de cor, implementar código e testar o funcionamento.

Acho que o próprio nome das etapas já torna bem intuitivo o que precisamos fazer para obter uma estratégia de coloração. É importante ressaltar, que muita gente gosta de colocar as lógicas de coloração dentro de estratégias de execução (robôs) ou indicadores, screenings. Assim, em um único código, você pode incluir no seu gráfico como indicador, como sinalização de ordens ou coloração.

No exemplo apresentado no vídeo, que não é uma recomendação de uso, realizamos a coloração de candles de acordo com sua posição em relação à 2 indicadores de bandas de Bollinger.

Se o preço estiver sendo negociado fora da primeira banda de bollinger, mas ainda dentro da segunda, entende-se que o preço pode estar em região de sobrevenda ou sobrecompra, mas ainda não engatou uma tendência forte. Se o preço estiver sendo negociado fora da segunda Banda de Bollinger, entende-se que o mercado está demonstrando uma tendência forte seja de alta ou de baixa.

Assim, foram estabelecidas cores para sinalizar essas situações e oferecer suporte para a operação manual do trader. O código fonte da referida estratégia encontra-se abaixo.

Código fonte: Estratégia de coloração baseada emduas Bandas de Bollinger

				
					// #######################################################################
// #######################################################################
// #######################################################################
// ######                            O                             #######
// ######                        ____|____                         #######
// ######                      _|         |_                       #######
// ######                     (_|  O   O  |_)                      #######
// ######                       |_________|                        #######
// ######                                                          #######
// ###### ____        __        ____________           ________    #######
// ###### | | \       | |       | |_________|         /  ____  \   #######
// ###### | |\ \      | |       | |                  /  /    \  \  #######
// ###### | | \ \     | |       | |____             |  |      |  | #######
// ###### | |  \ \    | |       | |____|            |  |      |  | #######
// ###### | |   \ \   | |       | |____|            |  |      |  | #######
// ###### | |    \ \  | |       | |                 |  |      |  | #######
// ###### | |     \ \ | |       | |_________         \  \____/  /  #######
// ###### |_|      \_\|_|       |_|_________|         \________/   #######
// ######                                                          #######
// ###### _______  __          __   ____  __   ___    __  _______  #######
// ######    |    |  \   /\   |  \ |     |  \ |   \  /  \    |     #######
// ######    |    |__/  /__\  |   ||__   |__/ |___/ |    |   |     #######
// ######    |    |\   /    \ |   ||     |\   |   \ |    |   |     #######
// ######    |    | \ /      \|__/ |____ | \  |___/  \__/    |     #######
// ######                                                          #######
// ######  Comunidade aberta de automatização de estratégias para  #######
// ######                    negociação de ativos                  #######
// ######                                                          #######
// ######                    www.NeoTraderBot.com                  #######
// #######################################################################
// #######################################################################
// #######################################################################
//
// -----------------------------------------------------------------------
// ---------------------- DADOS DA ESTRATÉGIA ----------------------------
// -----------------------------------------------------------------------
//
// NOME DA ESTRATÉGIA: _NTB_COL_2BandasBollinger
//   DESENVOLVIDA POR: NeoTraderBot
//    DATA DE CRIAÇÃO: 13/10/2022
//             VERSÃO: 1.0
//      ATUALIZADA EM: 13/10/2-22
// TIPO DE ESTRATÉGIA: (X) Indicador  (X) Coloração ( ) Execução
//                     ( ) Screening  ( ) Texto     ( ) Alarme
//
// DESCRIÇÃO DA ESTRATÉGIA:
//   Realiza a coloração de candles baseada na posição relativa do proço
// em função de dois indicadores de Bandas de Bollinger, um para histórico 
// recente e outro para histórico de médio prazo
//
//
//
//
// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
//
// ######################### FIM DO CABEÇALHO ############################
//
//
// -----------------------------------------------------------------------
// -------------------------- Constantes ---------------------------------
// OBS:
// -----------------------------------------------------------------------
//const
//  cXXXXXX = true;
  //
  // ---------------------------------------------------------------------
  // -------------------------- Parâmetros -------------------------------
  // OBS: Segue abaixo a descrição de cada parâmetro
  // 1) pXXXXXX ->
  //
  // 2) pYYYYYY ->
  //
  // 3) pZZZZZZ ->
  // ---------------------------------------------------------------------
input
  pQtdeDesvioBB1(1.5);
  pQtdePeriodoMediaBB1(36);
  pTipoMediaBB1(0);

  pQtdeDesvioBB2(2.0);
  pQtdePeriodoMediaBB2(100);
  pTipoMediaBB2(0);

  // ---------------------------------------------------------------------
  // ---------------------- Variáveis globais ----------------------------
  // OBS:
  // ---------------------------------------------------------------------
var
//Estrutura padrão do modelo
bStarted: boolean;


//Variáveis personalizadas
fBB1Sup, fBB1Inf: float;
fBB2Sup, fBB2Inf: float;


begin
  // ---------------------------------------------------------------------
  // ----------------- Inicialização da estratégia -----------------------
  // OBS: Inicialização de variáveis a serem utilizadas na estratégia de
  // coloração
  // ---------------------------------------------------------------------
  if Not bStarted then
  begin
    bStarted := True;
    //Colocar aqui ações que serão executadas apenas no primeiro processamento
    //da estratégia. Por exemplo, inicialização de variáveis.
  end;


  // ---------------------------------------------------------------------
  // ------------ Atribuição de variáveis por processamento --------------
  // ---------------------------------------------------------------------
  // Atribuições das variáveis da estratégia
  fBB1Sup := BollingerBands(pQtdeDesvioBB1, pQtdePeriodoMediaBB1, pTipoMediaBB1)|0|;
  fBB1Inf := BollingerBands(pQtdeDesvioBB1, pQtdePeriodoMediaBB1, pTipoMediaBB1)|1|;
  fBB2Sup := BollingerBands(pQtdeDesvioBB2, pQtdePeriodoMediaBB2, pTipoMediaBB2)|0|;
  fBB2Inf := BollingerBands(pQtdeDesvioBB2, pQtdePeriodoMediaBB2, pTipoMediaBB2)|1|;

  // ---------------------------------------------------------------------
  // ---------------------- Lógica de coloração  -------------------------
  // OBS: Inserir lógica de cálculo para coloração do gráfico
  // ---------------------------------------------------------------------

  //SITUAÇÃO 1: BB1 DENTRO de BB2
  if (fBB1Sup <= fBB2Sup) And (fBB1Inf >= fBB2Inf) then
  begin
    if (Close >= fBB2Sup) then PaintBar(clGreen)
    else
    if (Close <= fBB2Inf) then PaintBar(clRed)
    else
    if (Close >= fBB1Sup) And (Close < fBB2Sup) then PaintBar(clYellow)
    else
    if (Close <= fBB1Inf) And (Close > fBB2Inf) then PaintBar(clYellow);
  end
  else

  //SITUAÇÃO 2: Banda superior de BB1 ACIMA da banda superior de BB2
  //            Banda inferior de BB1 maior que banda inferior de BB2
  if (fBB1Sup > fBB2Sup) And (fBB1Inf >= fBB2Inf) then
  begin
    if (Close >= fBB2Sup) then PaintBar(clGreen)
    else
    if (Close <= fBB2Inf) then PaintBar(clRed)
    else
    if (Close <= fBB1Inf) And (Close > fBB2Inf) then PaintBar(clYellow);
  end
  else


  //SITUAÇÃO 3: Banda inferior de BB1 ABAIXO da banda inferior de BB2
  //            Banda superior de BB1 menor que banda superior de BB2
  if (fBB1Sup <= fBB2Sup) And (fBB1Inf < fBB2Inf) then
  begin
    if (Close >= fBB2Sup) then PaintBar(clGreen)
    else
    if (Close <= fBB2Inf) then PaintBar(clRed)
    else
    if (Close >= fBB1Sup) And (Close < fBB2Sup) then PaintBar(clYellow);
  end
  else

  //SITUAÇÃO 4: BB2 DENTRO de BB1
  if (fBB1Sup >= fBB2Sup) And (fBB1Inf <= fBB2Inf) then
  begin
    if (Close >= fBB1Sup) then PaintBar(clGreen)
    else
    if (Close <= fBB1Inf) then PaintBar(clRed);
  end;


  PlotN(1,fBB1Sup);
  PlotN(2,fBB1Inf);
  PlotN(3,fBB2Sup);
  PlotN(4,fBB2Inf);

  SetPlotStyle(1,psDash);
  SetPlotStyle(2,psDash);
  SetPlotStyle(3,psSolid);
  SetPlotStyle(4,psSolid);

  SetPlotColor(1,clWhite);
  SetPlotColor(2,clWhite);
  SetPlotColor(3,clYellow);
  SetPlotColor(4,clYellow);

  SetPlotWidth(1,1);
  SetPlotWidth(2,1);
  SetPlotWidth(3,2);
  SetPlotWidth(4,2);

end;
				
			

Frameworks de Programação

Um framework de programação é uma estrutura de código padronizada que possui diversas funcionalidades típicas já implementadas, sendo necessário apenas a parametrização. Com isso você ganha tempo, pois pode parametrizar em curto espaço de tempo diferentes ideias de trading, testar diferentes combinações de técnicas sem precisar ter um conhecimento profundo de programação (embora ainda seja necessário uma pequena noção de código para parametrizar estratégias). A economia de tempo de programação é da ordem de 80 a 95%.

Não existe um código que funciona para tudo. Se prezamos pela simplicidade e casos mais comuns, quem tem necessidades mais complexas não é atendido. Se fazemos algo já complexo e altamente parametrizável, isso pode causar um custo de processamento muito grande para a maioria dos casos que são simples.

Assim, a Comunidade NeoTraderBot disponibiliza diferentes versões de framework, compondo um portfolio em nível incremental de funcionalidades e complexidade. Veja abaixo um quadro comparativo de funcionalidades das versões:

FUNCIONALIDADES

MODO

Modo Daytrade e Swing Trade

ORDENS

Ordens de abertura de posição
Somente à mercado
Mercado/Limitada/Stop
Tamanho de posições
Fixo (Parametrizável)
Variável (via código)
Sinal de reversão ou encerramento
Filtro de Compra Venda

ADM TRADE

Ordens OCO para Stop/Alvo
Risco/Ganho definido em parâmetro
Definição de Preço de Stop/Alvo via código

-

TÉCNICA DE STOPLOSS

Stop Breakeven
Stop Móvel (Trailing Stop)
-

Versão contínua

Stop temporizado
-

GESTÃO OPERACIONAL

E FINANCEIRA

Limitação de qtde de trades por dia
Interrupção diária da estratégia por limite de trades com prejuízo
-
Interrupção diária da estratégia por trades com prejuízo consecutivos
-
Restrição de Perdas/Objetivo de Ganho diário
-
Contador de Trades com prejuízo/lucro
-
Contador de Trades consecutivos com prejuízo/lucro
-
Janelas de negociação para abertura de posição
1
até 4
Encerramento de posição em horário limite

Recursos Visuais

Plot das linhas de Alvo/Stoploss/Gatilho BreakEven

SUPORTE TÉCNICO

Resolução de Dúvidas pelo Discord (Tópico Exclusivo)

-

VALOR DO FRAMEWORK

Gratuito

R$ 649

(pagamento único)

O usuário que adquirir o framework THUNDER tem direito às atualizações do framework e também desconto no valor de futuras versões de framework com mais funcionalidades (referente ao valor já pago).

Desejamos sucesso no desenvolvimento de suas estratégias e robôs traders!

Versão LIGHT

FRAMEWORK-ntsl-light

Esta é a primeira versão de framework lançada pela Comunidade NeoTraderBot. É uma versão gratuita e simples, mas que possui algumas funcionalidades básicas de gestão de robô e de operações.

A ideia principal do Framework NTSL LIGHT é que o usuário entenda como se utiliza um framework e como ele pode se beneficiar de funcionalidades já implementadas, bastando programar os sinais desejados de abertura de posição, reversão e encerramento.

FRAMEWORK NTSL LIGHT é uma versão de demonstração, sem custo e com o código fonte aberto. Ele foi concebido para ser executado em gráficos temporais e os sinais fornecidos pelo usuário serão executados com ordens a mercado.

FRAMEWORK NTSL LIGHT

Coded by NeoTraderBot
R$ 0 Sem custo
  • Modo Daytrade e Swing Trade
  • Gerenciamento de abertura de posição de tamanho fixo
  • Administração de trade via sinal de reversão ou encerramento
  • Administração de trade com Risco/Ganho pré-definido
  • Ordens OCO de Stoploss e TakeProfit
  • Plot das linhas de Alvo/Stoploss/Gatilho Breakeven
  • Limitação de quantidade de trades por dia
  • Janela de negociação para abertura de posição
  • Encerramento de posição em horário limite
CÓD ABERTO

Versão THUNDER

FRAMEWORK ntsl THUNDER

O FRAMEWORK NTSL THUNDER é uma versão com mais funcionalidades que a versão gratuita e direito a suporte técnico. Com a versão THUNDER o trader terá ainda mais possibilidades para realizar seus backtests! 

Esta versão também foi concebida para ser executada em gráficos temporais e, além das funcionalidades da versão LIGHT, ela também possui os seguintes diferenciais:

      • Possibilidade de configuração do tamanho das posições;
      • Possibilidade de roteamento de ordens stop e limitadas;
      • Filtro de posição comprada/vendida;
      • Interrupção diária da estratégia em função da qtde de trades com prejuízo (total e/ou consecutivos);
      • Stoploss temporizado em função da qtde de barras transcorridas após abertura da posição;
      • Gestão de risco financeiro com limite de perda e objetivo de ganho;
      • Possibilidade de aplicação de técnica de Stop móvel (individualmente ou em conjunção com RG Fixo e Breakeven);
      • Configuração de até 4 janelas de negociação;

Um quadro comparativo completo das funcionalidades das versões de framework pode ser visto nesta página.

FRAMEWORK NTSL THUNDER

Coded by NeoTraderBot
R$ 649 pagamento único
  • Direito a suporte técnico
  • Direito a atualizações da versão
  • Desconto do valor pago em caso de upgrade de versão
* Após a compra, você receberá um e-mail com o link para download do Framework.

Documentação

Esta é a documentação dos Frameworks NTSL criados pela NeoTraderBot. Um primeiro ponto a ressaltar é que todos os frameworks disponibilizados pela Comunidade NeoTraderBot possuem a FINALIDADE EXCLUSIVAMENTE EDUCACIONAL. Não obstante serem compatíveis com o Módulo de Automação, eles devem ser utilizados apenas em backtesting e Conta de Simulação.

A razão pela qual a NeoTraderBot não disponibiliza frameworks destinados para execução no Módulo de Automação é porque entendemos que para colocar uma estratégia ou setup para operar em conta real são necessárias otimizações de código, proteções contra falhas e situações atípicas, entre outras particularidades que dependem da estratégia a ser executada. Assim, ou o trader realiza esses ajustes sobre o código utilizado no backtesting (caso tenha conhecimento para tal) ou pode realizar a contratação de algum profissional que faça a programação adequada, tendo em vista que a estratégia foi validada em backtesting.

Este manual está organizado de acordo com as sessões de parâmetros do framework e o seu conteúdo será atualizado a medida que surgirem demandas por maiores esclarecimentos acerca de suas funcionalidades.

O suporte técnico de dúvidas sobre os Frameworks (para quem adquiriu alguma versão paga) é realizado pelo Servidor Discord (acessível por este link). Pedimos a gentileza de manifestar que realizaram a compra do código ao entrar no grupo para que receba a permisssão para o tópico exclusivo dos frameworks.

Caso deseje alguma funcionalidade ainda não contemplada nas versões de framework disponíveis, você pode sugerir ou recomendar novas funcionalidades/melhorias no formulário abaixo.

Sugestão de Funcionalidades para Frameworks NTSL

Tipos de Programas, Fluxo de execução e Eventos Pré-definidos

Reproduzir vídeo

Este vídeo visa apresentar os tipos de programas possíveis da plataforma MetaTrader e como eles são executados.

Os tipos de programas possíveis de codificar em MQL5 são: serviço, script, expert advisor (EA) e indicador. Iremos abordar detalhes relacionados a forma de execução, single thread ou multi-thread, bem como explicar como é o fluxo de execução desses programas.

Explicaremos o conceito de fila de eventos, o seu funcionamento e quais são os eventos pré-definidos na linguagem para o utilização pelos programas.

Saber como um código é processado, suas características e como é o fluxo de execução é fundamental para que um programador e trader possa desenvolver um código fonte de qualidade e alcançar seus objetivos de maneira eficiente na criação de robôs e indicadores.

Sempre recomendamos a leitura da Documentação MQL5, no link abaixo, pois há muita informação relevante sobre a plataforma MetaTrader. https://www.mql5.com/en/docs.

Programando em EvoCode

Como criar robôs e indicadores utilizando EvoCode

EvoCode – Ambiente de desenvolvimento de estratégias da Trader Evolution

Reproduzir vídeo

Neste vídeo da séria “Conhecendo a Trader Evolution” vamos explorar o ambiente de desenvolvimento de estratégias: EvoCode.

Não se esqueça de indicar a Comunidade NeoTraderBot como parceiro na Plataforma TraderEvolution. Vá no menu superior em “Mais” – “Extensões” – “Indique parceiro” e digite o código “NEOTRADERBOT”.

Assim, você reforça sua participação na Comunidade e nos ajuda a pleitear novas funcionalidades e melhorias na plataforma visando o benefício de todos os membros em suas automatizações e desenvolvimento de estratégias.

Como configurar o Visual Studio para Trader Evolution [Desenvolvimento e depuração]

Reproduzir vídeo

Neste vídeo, irei demonstrar o passo-a-passo para configurar o Visual Studio para desenvolver e depurar estratégias e indicadores da TraderEvolution.

Não se esqueça de indicar a Comunidade NeoTraderBot como parceiro na Plataforma TraderEvolution. Vá no menu superior em “Mais” – “Extensões” – “Indique parceiro” e digite o código “NEOTRADERBOT”.

Assim, você reforça sua participação na Comunidade e nos ajuda a pleitear novas funcionalidades e melhorias na plataforma visando o benefício de todos os membros em suas automatizações e desenvolvimento de estratégias.

Como CRIAR DO ZERO um INDICADOR NA TRADER EVOLUTION

Reproduzir vídeo

Neste vídeo, irei demonstrar o passo-a-passo como criar a partir do zero um indicador na plataforma TraderEvolution, escrevendo o código em EVOCODE. Para isso, iremos criar um indicador de volatilidade média.

Você pode fazer o download do indicador com CÓDIGO FONTE ABERTO pelo link abaixo:

        🤖 https://neotraderbot.com/indicador-de…

Não se esqueça de indicar a Comunidade NeoTraderBot como parceiro na Plataforma TraderEvolution. Vá no menu superior em “Mais” – “Extensões” – “Indique parceiro” e digite o código “NEOTRADERBOT”.

Assim, você reforça sua participação na Comunidade e nos ajuda a pleitear novas funcionalidades e melhorias na plataforma visando o benefício de todos os membros em suas automatizações e desenvolvimento de estratégias.

Documentação

Esta é a documentação dos Frameworks NTSL criados pela NeoTraderBot. Um primeiro ponto a ressaltar é que todos os frameworks disponibilizados pela Comunidade NeoTraderBot possuem a FINALIDADE EXCLUSIVAMENTE EDUCACIONAL. Não obstante serem compatíveis com o Módulo de Automação, eles devem ser utilizados apenas em backtesting e Conta de Simulação.

A razão pela qual a NeoTraderBot não disponibiliza frameworks destinados para execução no Módulo de Automação é porque entendemos que para colocar uma estratégia ou setup para operar em conta real são necessárias otimizações de código, proteções contra falhas e situações atípicas, entre outras particularidades que dependem da estratégia a ser executada. Assim, ou o trader realiza esses ajustes sobre o código utilizado no backtesting (caso tenha conhecimento para tal) ou pode realizar a contratação de algum profissional que faça a programação adequada, tendo em vista que a estratégia foi validada em backtesting.

Este manual está organizado de acordo com as sessões de parâmetros do framework e o seu conteúdo será atualizado a medida que surgirem demandas por maiores esclarecimentos acerca de suas funcionalidades.

O suporte técnico de dúvidas sobre os Frameworks (para quem adquiriu alguma versão paga) é realizado pelo Servidor Discord (acessível por este link). Pedimos a gentileza de manifestar que realizaram a compra do código ao entrar no grupo para que receba a permisssão para o tópico exclusivo dos frameworks.

Caso deseje alguma funcionalidade ainda não contemplada nas versões de framework disponíveis, você pode sugerir ou recomendar novas funcionalidades/melhorias no formulário abaixo.

Sugestão de Funcionalidades para Frameworks NTSL

Configurações gerais

Os parâmetros de configurações gerais definem o modo de funcionamento do robô-trader e como este irá funcionar em backtesting.

Todos os frameworks da NeoTraderBot realizam uma verificação básica de consistência dos parâmetros fornecidos e, em caso de erro, o robô trader não é executado e uma mensagem constará na aba “Compilação” do Editor de Estratégias. Devido à dificuldades do ambiente de log da Nelogica, os erros são pontuados um de cada vez, não sendo exibidos todos em uma única mensagem.

Os parâmetros do framework relacionados a gestão de risco das operações são tratados em termos de unidades de ticks (menor variação do ativo) devida a maior generalização do código fonte.

Devido a ausência de funcionalidade para modificação dos parâmetros em ambiente de backtesting, recomenda-se alterar o valor padrão de cada parâmetro para fins de simulação no Editor de Estratégias.

 
pModoDayTrade (boolean)

Este parâmetro deve ser true quando o setup implementado contemplar apenas operações intradiárias. Caso o parâmetro seja false, o robô-trader será assumido como um setup de swing trade atuando em tempos gráfico acima da periodicidade diária.

O modo DayTrade (valor true) pressupõe que o tempo gráfico deve ser na escala de segundos ou minutos. Uma vez habilitado este modo, serão habilitadas as funcionalidades de limitação de quantidade diária de trades, horário de encerramento automático de posição e janelas temporais para abertura de posição.

No caso do modo DayTrade não estar ativado, os parâmetros pHorarioEncerramentoPosicao, pJanelaNegocIni0X e pJanelaNegocFim0X perdem sua utilidade uma vez que o tempo gráfico será maior que a periodicidade diária.

pHorarioEncerramentoPosicao (integer)

Este parâmetro é aplicável apenas quando o modo DayTrade está ativado e refere-se ao horário no formato HHMM no qual as posições abertas devem ser encerradas a fim de evitar o carregamento da posição para o dia seguinte.

Por exemplo, caso o trader deseje encerrar suas operações às 17:00, o valor desse parâmetro deve ser 1700.

É importante observar que em backtesting o encerramento de posição se dará com uma ordem à mercado e será executado no preço de abertura da próxima barra.

pQtdeLotesMinimosNegociados (integer)

Este parâmetro irá definir a quantidade de lotes a serem negociados e, portanto, deverá ser um número inteiro.

Por exemplo, se o trader deseja negociar 5 mini-contratos de índice, o valor do parâmetro deve ser 5.

pQtdeLotesConfiguravel (boolean)

Este parâmetro permite que o trader defina pelo código fonte, no momento da abertura das posições o temanho da exposição, ou seja, a quantidade de papeis a serem negociados. Esta quantidade pode variar de posição para posição conforme programação do trader.

A configuração do tamanho da posição a ser aberta é realizada pela variável fQtdeLotesAberturaPosicao.

pStopOffsetEmTicks (integer)

Este parâmetro bem poderia ser definido como constante. Trata-se do offset fornecido nas ordens stop, que é o caso da ordem de stoploss.

Recomenda-se utilizar um valor bem generoso a fim de evitar o pulo de ordem no ambiente de backtesting devido à gaps, embora o framework já preveja o encerramento a mercado em caso de pulo da ordem stop.

Em simulações de estratégias que operam intraday não é tão comum a ocorrência de grandes gaps entre as barras. Assim, um valor de 10 ticks para este parâmetro costuma ser adequado na maior parte das situações.

pOperarComprado (boolean)
  THUNDER  

Este parâmetro, se true, irá permitir apenas que posições compradas sejam abertas pela estratégia no backtest.

pOperarVendido (boolean)

Este parâmetro, se true, irá permitir apenas que posições vendidas sejam abertas pela estratégia no backtest.

pAbrirPosicaoSomenteAMercado (boolean)

Se este parâmetro for true, todas as operações realizadas pela estratégia serão realizadas a mercado, ou seja, as ordens serão sempre executadas após fechamento da barra e no preço de abertura da próxima barra.

Caso o parâmetro seja false, o trader deve definir via código o preço desejado de abertura das posições (variável fPrecoAberturaPosicao). O framework irá definir se a ordem a ser roteada será uma ordem do tipo stop ou limitada, dependendo do preço negociado no backtest.

Gestão de risco do robô

Nesse grupo de parâmetros, pode-se configurar alguns aspectos da gestão de risco do robô, tais a interrupção do robô após uma quantidade máxima de trades no dia, ou de trades com prejuízo (consecutivos ou não). Também é possível configurar um stoploss temporizado em função da quantidade de barras após a abertura da posição.

pHabilitaLimiteQtdeTrades (boolean)

Quando true, e estando o robô-trader no modo DayTrade, não serão permitidas mais operações do que a quantidade informada no parâmetro pQtdeMaxOperacoesDiarias. Desta forma, a estratégia será interrompida uma vez que tenham sido realizadas a quantidade de operações definada no parâmetro pQtdeMaxOperacoesDiarias. 

Caso este parâmetro seja false, ou o robô-trader não esteja no modo DayTrade, a quantidade informada em pQtdeMaxOperacoesDiarias será desconsiderada.

pQtdeMaxOperacoesDiarias (integer)

Este parâmetro refere-se a quantidade limite de operações diárias quando o robô-trader estiver no modo DayTrade e pHabilitaLImiteQtdeTrades receber o valor true.

pHabilitaLimiteTradesPrejuizo (boolean)

Quando true, e estando o robô-trader no modo DayTrade, a estratégia não irá mais abrir posições no dia, caso tenha sido atingido o limite total de posições encerradas com prejuízo (definido no parâmetro pQtdeMaxTradesPrejuizoPorDia) ou o limite de posições encerradas consecutivamente com prejuízo (definido no parâmetro pQtdeMaxTradesPrejuizo ConsecutivosPorDia). 

Caso este parâmetro seja false, ou o robô-trader não esteja no modo DayTrade, as quantidades informadas nos parâmetros pQtdeMaxTradesPrejuizoPorDia epQtdeMaxTradesPrejuizoConsecutivosPorDia serão desconsideradas.

pQtdeMaxTradesPrejuizoPorDia (integer)

Este parâmetro refere-se a quantidade total limite de operações diárias com prejuízo quando o robô-trader estiver no modo DayTrade e pHabilitaLimiteTradesPrejuizo receber o valor true.

pQtdeMaxTradesPrejuizoConsecutivosPorDia (integer)

Este parâmetro refere-se a quantidade limite de operações consecutivas e diárias com prejuízo quando o robô-trader estiver no modo DayTrade e pHabilitaLimiteTradesPrejuizo receber o valor true.

pHabilitaStopTemporizado (boolean)

Quando true, as operações serão encerradas após a quantidade de barras definida no parâmetro pQtdeBarrasStopTemporizado. 

Esta funcionalidade aplica-se tanto ao modo daytrade ou swing trade.

pQtdeBarrasStopTemporizado (integer)

Este parâmetro refere-se a quantidade limite de barras para uma posição aberta. A contagem inclui a barra de abertura da posição.

Por exemplo, se o valor desse parâmetro for 3, a posição será encerrada na 2 barra após a barra de abertura da posição, caso a posição não tenha sido encerrada anteriormente por atingir o stop ou alvo.

Ordens OCO - RG Fixo

A administração das posições pode ser realizada por meio de ordens OCO (One-Cancel-Others) de stoploss e alvo, conforme demonstrado na figura abaixo (a qual aplicou-se também o stoploss Breakeven concomitantemente).

A vantagem de utilizar as ordens OCO é o gerenciamento automático da plataforma em relação ao cancelamento da ordem na ponta contrária à ordem executada. Por exemplo, se sua operação atingir o alvo, a ordem de stoploss é automaticamente cancelada.

Caso o usuário não utilize esta fucionalidade, as operações pode ser revertidas por meio do sinal de reversão (bSinalReversao) ou encerradas por meio do sinal bSinalEncerramento, a serem definidos pelo usuário.

Diferentemente da execução dos sinais que ocorrerá por ordens a mercado no fechamento da barra, as ordens OCO são apregoadas e, portanto, executadas quando o preço é atingido. A ordem de stoploss será sempre uma ordem do tipo stop (passível de slippage devido à sua natureza), enquanto as ordens de alvo será do tipo limitadas (compondo o book de ofertas).

pOCO_RGFixo (boolean)

Quando true, este parâmetro irá habilitar a funcionalidade de ordens OCO de stoploss e alvo. Uma vez aberta uma posição, o usuário irá observar na linha branca o preço médio de sua posição, na linha vermelha a posição do stoploss e na linha azul a posição do alvo.

Obs: as linhas no gráfico serão plotadas apenas se o usuário configurar o parâmetro pPlotarLinhasOCO para true.

pStopFixoEmTicks (integer)

Este parâmetro é utilizado para definir o stoploss inicial da operação em relação ao preço médio na unidade de ticks. Por exemplo, no caso do mini-contrato de índice, um tick possui 5 pontos. Assim, caso o stop desejado seja de 50 pontos, isto representa 10 ticks.

Se o usuário habilitar a funcionalidade de Stop Breakeven, o stop inicialmente configurado será deslocado caso o gatilho de breakeven seja atingido.

pAlvoFixoEmTicks (integer)

Este parâmetro é utilizado para definir o alvo das operações em função do preço médio da posição na unidade de ticks. 

Por exemplo, no caso de um operação no mini-contrato de dólar, onde cada tick equivale a 0,5 pontos. Caso o usuário deseje um alvo de 10 pontos, isto será representado por 20 ticks.

Gestão de risco financeiro

Nesse grupo de parâmetros é possível configurar limites diários para perda ou objetivos de ganho para a estratégia.

pHabilitaLimitePerdaDiaria (boolean)

Quando true, e estando o robô-trader no modo DayTrade, a estratégia não irá mais abrir posições no dia, caso tenha sido atingido o limite de perda financeira definido no parâmetro pLimitePerdaDiaria.

Por exemplo, se o usuário não deseja perder mais do que R$ 100 no dia, ele deve colocar este valor no parâmetro pLimitePerdaDiaria.

É importante observar que a estratégia será interrompida após o limite ter sido atingido. Como as operações são encerradas geralmente no fechamento das barras por ordens a mercado, a perda diária ficará próxima do valor de referência informado mas não coincidirá com o limite estabelecido. Ou seja, as posições abertas não serão estopadas exatamente no limite da perda diária definida.

Caso este parâmetro seja false, ou o robô-trader não esteja no modo DayTrade, o valor informado no parâmetro pLimitePerdaDiaria será desconsiderado.

pLimitePerdaDiaria (integer)

Este parâmetro refere-se ao valor financeiro de referência a ser utilizado como limite de perdas diárias. Uma vez ultrapassado esse limite, a estratégia será interrompida após o encerramento da posição.

pHabilitaObjetivoGanhoDiario (boolean)

Quando true, e estando o robô-trader no modo DayTrade, a estratégia não irá mais abrir posições no dia, caso tenha sido atingido o objetivo de ganho definido no parâmetro pObjetivoGanhoDiario.

Por exemplo, se o usuário tiver como objetivo  R$ 300 no dia, ele deve colocar este valor no parâmetro pObjetivoGanhoDiario.

É importante observar que a estratégia será interrompida após o objetivo ter sido atingido. Como as operações são encerradas geralmente no fechamento das barras por ordens a mercado, o ganho diário ficará próximo do valor de referência informado mas não coincidirá com o objetivo estabelecido. Ou seja, as posições abertas não serão encerradas exatamente no objetivo de ganho diário definido.

Caso este parâmetro seja false, ou o robô-trader não esteja no modo DayTrade, o valor informado no parâmetro pObjetivoGanhoDiario será desconsiderado.

pObjetivoGanhoDiario (integer)

Este parâmetro refere-se ao valor financeiro de referência a ser utilizado como objetivo de ganho diário. Uma vez ultrapassado esse objetivo, a estratégia será interrompida após o encerramento da posição.

Stop Breakeven

O Stop Breakeven consiste em uma gestão de risco da operação na qual uma vez atingido determinado lucro, o stoploss é deslocado para uma posição na qual a operação não renderá mais prejuízo, podendo ser o preço de abertura da posição ou uma proteção parcial de ganhos.

Veja a figura abaixo a qual apresenta um exemplo de Stop Breakeven e será usada como referência para explicar a função de cada parâmetro de configuração.

pStopBreakEven (boolean)
  LIGHT       THUNDER  

Quando true, este parâmetro irá habilitar a funcionalidade de stop Breakeven. Observe que o uso do StopBreakEven não é vinculado ao uso de ordens OCO de stoploss e alvo, e também pode ser usado junto com o Stop móvel (trailling stop) presente na versão THUNDER. Em outras palavras, o usuário pode utilizar apenas a gestão de risco da operação pelo StopBreakEven, o que deixará a operação desprotegida até que o gatilho do breakeven seja acionado.,

pGatilhoNoPrecoFechamento (boolean)
  LIGHT       THUNDER  

Este parâmetro quando true, irá realizar o deslocamento ou posicionamento de stop na posição configurada apenas quando uma barra fechar acima do gatilho de breakeven no caso de uma posição comprada ou abaixo do gatilho quando a operação for de venda.

Caso o parâmetro seja false, o deslocamento ou posicionamento de stop na posição será realizado se em algum momento a máxima de uma barra fechar acima do gatilho de breakeven no caso de uma posição comprada ou a mínima de uma barra fechar abaixo do gatilho quando a operação for de venda.

É importante ressaltar que devido ao funcionamento do modelo de execução da Nelogica, a atualização ou posicionamento do stopBreakeven, independente da configuração de pGatilhonoPrecoFechamento, será realizada apenas após o fechamento da barra na qual a condição de gatilho foi satisfeita.

Observe pela figura acima que apenas após o preço superar a linha de breakeven (linha tracejada amarela), o stop foi deslocado para a posição configurada, o que ocorreu no fechamento da barra.

pGatilhoBreakEvenEmTicks (integer)
  LIGHT       THUNDER  

Este parâmetro é utilizado para definir quantos ticks uma operação deve andar a favor até que seja aplicado o Stoploss Breakeven.

pLucroPreservadoEmTicks (integer)
  LIGHT       THUNDER  

Este parâmetro é utilizado para configurar a posição do stop Breakeven. Caso seu valor seja zero, uma vez acionado o gatilho, o stop será colocado no mesmo preço da posição.

O usuário também pode colocar um valor positivo. Assim, o stop será posicionado ou deslocado para uma posição na qual se a operação for stopada haverá a garantia de realização de lucro parcial.

Stop Móvel (Trailling stop)

O Stop Móvel (Trailling Stop) consiste em uma gestão de risco da operação na qual uma vez atingido determinado gatilho, o stoploss passa a ser atualizado para ficar sempre uma determinada distância atrás do preço de fechamento da barra, reduzindo assim o prejuízo de um eventual loss ou garantindo uma proteção parcial de ganhos, a depender da posição definida para o gatilho.

Veja a figura abaixo a qual apresenta um exemplo da aplicação individual do Stop Móvel e que será usada como referência para explicar a função de cada parâmetro de configuração.

pStopMovel (boolean)
  THUNDER  

Quando true, este parâmetro irá habilitar a funcionalidade de stop móvel. Observe que o stop móvel pode ser usado individualmente ou em concomitância com o Stop BreakEven e as configuração de RG FIXO.

Assim, o usuário pode utilizar apenas a gestão de risco da operação pelo Stop móvel, o que deixará a operação desprotegida até que o gatilho do stop móvel seja acionado. Ou de maneira mais prudente, com a aplicação de ordens OCO RG Fixo. Ainda pode fazer uma combinação com o Stop BreakEven, gerando assim uma administração completa de risco da operação.

pGatilhoStopMovelNoPrecoFechamento (boolean)
  THUNDER  

Este parâmetro quando true, irá realizar o deslocamento ou posicionamento de stop na posição configurada apenas quando uma barra fechar acima do gatilho de stop móvel no caso de uma posição comprada ou abaixo do gatilho quando a operação for de venda.

Caso o parâmetro seja false, o deslocamento ou posicionamento de stop na posição será realizado se em algum momento a máxima de uma barra fechar acima do gatilho de breakeven no caso de uma posição comprada ou a mínima de uma barra fechar abaixo do gatilho quando a operação for de venda.

É importante ressaltar que devido ao funcionamento do modelo de execução da Nelogica, a atualização ou posicionamento do stop, independente da configuração de pGatilhoNoPrecoFechamento, será realizada apenas após o fechamento da barra na qual a condição de gatilho foi satisfeita.

Observe pela figura acima que apenas após o preço superar a linha de gatilho do stop móvel (linha tracejada em vermelho escuro), o stop foi deslocado para a posição configurada, o que ocorreu no fechamento da barra.

pGatilhoStopMovelEmTicks (integer)
  THUNDER  

Este parâmetro é utilizado para definir quantos ticks uma operação deve andar a favor até que seja ativado o Stoploss móvel.

Se o trader definir o valor zero, isso significa que o stop móvel será habilitado já na abertura da posição.

pAncorarStopMovelXTicksAtras (integer)
  THUNDER  

Este parâmetro é utilizado para, uma vez ativado o stop móvel, definir quantos ticks o stoploss deve ficar atrás do preço de fechamento da barra.

É importante ressaltar que o stop móvel não retrocede o valor do stoploss. Ou seja, uma vez deslocado o stoploss para mais próximo do preço negociado, o stoploss não retroage para uma posição mais distante do preço negociado.

Janelas de negociação

Nos frameworks é possível configurar uma janela temporal para aplicação das ordens advindas dos sinais do robô-trader. Assim, o usuário pode controlar o período do dia em que as posições podem ser abertas.

Na versão LIGHT o usuário pode configurar apenas 1 janela de negociação, ao passo que na versão THUNDER, o usuário pode configurar até 4 janelas de negociação.

Caso o robô-trader esteja configurado para executar em um tempo gráfico com periodicidade acima da diária, as configurações de janela de negociação não serão aplicáveis, dada a impossibilidade de gerir o funcionamento da estratégia dentro de uma barra em ambiente de backtesting com dados históricos OHLCV de maneira confiável (condições de funcionamento do Editor de Estratégia da Nelogica).

pJanelaNegocIni0X (integer)
  LIGHT       THUNDER  

Este parâmetro recebe um horário no formato HHMM para definir a partir de qual horário uma posição pode ser aberta. O horário utilizado para esta funcionalidade é o retorno da função nativa da ntsl “Time”, a qual retorna o horário de abertura da barra.

pJanelaNegocFim0X (integer)
  LIGHT       THUNDER  

Este parâmetro recebe um horário no formato HHMM para definir até qual horário  uma posição pode ser aberta. O horário utilizado para esta funcionalidade é o retorno da função nativa da ntsl “Time”, a qual retorna o horário de abertura da barra.

Recursos gráficos

Os frameworks possuem a funcionalidade de plotar as linhas de stoploss, alvo, gatilho de breakeven, gatilho de stop móvel e preço médio da posição, bem como aplicar coloração quando os sinais definidos pelo usuário forem satisfeitos e estiverem em condição adequada para que ordens sejam roteada, conforme pode ser observado na figura abaixo.

pPlotarLinhasOCO (boolean)
  LIGHT       THUNDER  

Quando true, este parâmetro irá habilitar o plot das linhas de stoploss (sólida na cor vermelho), alvo da operação (sólida na cor azul), preço médio da posição (sólido na cor branca) e os níveis de preço dos gatilhos de breakeven (tracejada na cor amarelo) e stop móvel (tracejada na cor vermelho escuro), enquanto os mesmos não forem acionados.

pPintarBarrasDeSinal (boolean)
  LIGHT       THUNDER  

Quando true, este parâmetro irá habilitar a funcionalidade de colorir as barras de sinal configuradas pelo usuário e que esteja em condições adequadas para execução:

        • Sinal de compra pintará a barra de verde caso não haja posição aberta;
        • Sinal de venda pintará a barra de vermelho caso não haja posição aberta;
        • Sinal de reversão pintará a barra de amarelo caso haja posição aberta;
        • Sinal de fechamento pintará a barra de azul caso haja posição aberta.

Configurações gerais

Os parâmetros de configurações gerais definem o modo de funcionamento do robô-trader e como este irá funcionar em backtesting.

Todos os frameworks da NeoTraderBot realizam uma verificação básica de consistência dos parâmetros fornecidos e, em caso de erro, o robô trader não é executado e uma mensagem constará na aba “Compilação” do Editor de Estratégias. Devido à dificuldades do ambiente de log da Nelogica, os erros são pontuados um de cada vez, não sendo exibidos todos em uma única mensagem.

Os parâmetros do framework relacionados a gestão de risco das operações são tratados em termos de unidades de ticks (menor variação do ativo) devida a maior generalização do código fonte.

Devido a ausência de funcionalidade para modificação dos parâmetros em ambiente de backtesting, recomenda-se alterar o valor padrão de cada parâmetro para fins de simulação no Editor de Estratégias.

 
pModoDayTrade (boolean)

Este parâmetro deve ser true quando o setup implementado contemplar apenas operações intradiárias. Caso o parâmetro seja false, o robô-trader será assumido como um setup de swing trade atuando em tempos gráfico acima da periodicidade diária.

O modo DayTrade (valor true) pressupõe que o tempo gráfico deve ser na escala de segundos ou minutos. Uma vez habilitado este modo, serão habilitadas as funcionalidades de limitação de quantidade diária de trades, horário de encerramento automático de posição e janelas temporais para abertura de posição.

No caso do modo DayTrade não estar ativado, os parâmetros pHorarioEncerramentoPosicao, pJanelaNegocIni0X e pJanelaNegocFim0X perdem sua utilidade uma vez que o tempo gráfico será maior que a periodicidade diária.

pHorarioEncerramentoPosicao (integer)

Este parâmetro é aplicável apenas quando o modo DayTrade está ativado e refere-se ao horário no formato HHMM no qual as posições abertas devem ser encerradas a fim de evitar o carregamento da posição para o dia seguinte.

Por exemplo, caso o trader deseje encerrar suas operações às 17:00, o valor desse parâmetro deve ser 1700.

É importante observar que em backtesting o encerramento de posição se dará com uma ordem à mercado e será executado no preço de abertura da próxima barra.

pQtdeLotesMinimosNegociados (integer)

Este parâmetro irá definir a quantidade de lotes a serem negociados e, portanto, deverá ser um número inteiro.

Por exemplo, se o trader deseja negociar 5 mini-contratos de índice, o valor do parâmetro deve ser 5.

pQtdeLotesConfiguravel (boolean)

Este parâmetro permite que o trader defina pelo código fonte, no momento da abertura das posições o temanho da exposição, ou seja, a quantidade de papeis a serem negociados. Esta quantidade pode variar de posição para posição conforme programação do trader.

A configuração do tamanho da posição a ser aberta é realizada pela variável fQtdeLotesAberturaPosicao.

pStopOffsetEmTicks (integer)

Este parâmetro bem poderia ser definido como constante. Trata-se do offset fornecido nas ordens stop, que é o caso da ordem de stoploss.

Recomenda-se utilizar um valor bem generoso a fim de evitar o pulo de ordem no ambiente de backtesting devido à gaps, embora o framework já preveja o encerramento a mercado em caso de pulo da ordem stop.

Em simulações de estratégias que operam intraday não é tão comum a ocorrência de grandes gaps entre as barras. Assim, um valor de 10 ticks para este parâmetro costuma ser adequado na maior parte das situações.

pOperarComprado (boolean)
  THUNDER  

Este parâmetro, se true, irá permitir apenas que posições compradas sejam abertas pela estratégia no backtest.

pOperarVendido (boolean)

Este parâmetro, se true, irá permitir apenas que posições vendidas sejam abertas pela estratégia no backtest.

pAbrirPosicaoSomenteAMercado (boolean)

Se este parâmetro for true, todas as operações realizadas pela estratégia serão realizadas a mercado, ou seja, as ordens serão sempre executadas após fechamento da barra e no preço de abertura da próxima barra.

Caso o parâmetro seja false, o trader deve definir via código o preço desejado de abertura das posições (variável fPrecoAberturaPosicao). O framework irá definir se a ordem a ser roteada será uma ordem do tipo stop ou limitada, dependendo do preço negociado no backtest.

Aula 02 - Tipos de Dados e Operações

Aprenda os tipos básicos de dados e operações.

Reproduzir vídeo

1. Introdução

Programação é como brincar de lego…não é por acaso que até a empresa lego faz kits de programação para ensinar às crianças. A forma de pensar ao resolver um problema e programar a solução é sempre de encaixar blocos sequencialmente para obter o resultado desejado. Desta forma, temos que saber o que cada bloco faz para fazermos o melhor uso dele em nossos programas.

A seguir vamos aprender quais são os tipos básicos de dados e como podemos manipulá-los, ou seja, quais operações podemos realizar com eles. Por quanto ainda vamos tentar evitar ao máximo entrar em detalhes de linguagens de programação específicas e nos ater aos conceitos. Em breve, você poderá iniciar o estudo de uma linguagem de programação com os conceitos básicos já absorvidos.

2. Quais são os tipos básicos de dados?

Os primeiros blocos que precisamos conhecer são os tipos de dados. Em todas as linguagens de programação você irá encontrar três tipos basícos de dados, que podem ser números inteiros (que nas linguagens serão apresentados como integer ou int), números com casas decimais (ou ponto flutuante, que podem se apresentar como float, real, double) e dados booleanos (um tipo de dado que apresenta apenas dois valores possíveis: verdadeiro/falso, ou em inglês, true/false). Não se preocupe em decorar as nomenclaturas, pois cada linguagem pode chamar os tipos de dados de forma diferente e quando você obtiver fluência esse será um detalhe que não representará nenhuma dificuldade. Há ainda um tipo de dados conhecido como string, que são os dados de texto, mas que não iremos abordar nesse curso introdutório para restringir o conteúdo ao que é realmente essencial.

Um termo técnico muito comum em programação é a declaração de variáveis. O que siginifica isso? O seu código fonte certamente exigirá que você crie variáveis para armazenar informação. Para cada variável, o programador precisar atribuir um nome e o tipo de dados que aquela variável armazena. O processo de definir a variável é o que se chama “declarar variável”

3. Operações com dados numéricos

Vamos falar então sobre as operações que podemos fazer com os dados numéricos, sejam inteiros ou com casas decimais. Obviamente você já aprendeu isso na escola! É possível somar, subtrair, multiplicar, dividir, exponenciar, tirar a n-ésima raiz, obter resto de uma divisão, obter o valor absoluto do número, entre outras…

A diferença na programação quando usamos dados inteiros e dados com casas decimais ocorre quando tentamos armazenar o resultado de uma das operações acima mencionadas em uma variável com tipo de dado incompatível. 

Lembra que vimos na primeira aula que os computadores só fazem o que a gente pede!? Então, ao escrever seu programa você precisará declarar o tipo das variáveis que utilizará. Vamos supor que você tenha declarado uma variável inteira para armezar o número da sua residência em sua rua: num_residencia. Logo, se em algum momento você tentar atribuir um valor à variável num_residencia, este valor deverá ser um inteiro. Poderíamos atribuir valores por meio de vários tipos de operações:

				
					// Atribuição direta
num_residencia = 8;
				
			
				
					// Atribuição por divisão
num_residencia = 16/2;
				
			
				
					// Atribuição por multiplicação
num_residencia = 2*4;
				
			
				
					// Atribuição por exponenciação (2 elevado a 3)
num_residencia = 2**3;
				
			
				
					// Atribuição por n-ésima raiz (no caso, raiz quadrada)
num_residencia = 64**(1/2);
				
			

Para todas as atribuições acima não haveria problema, porque o resultado é sempre um número inteiro e a variável num_residencia é do tipo inteiro. Mas e se o resultado da operação fosse um número com casas decimais, ex: 10/3?

Nesse caso, dependeria de cada linguagem! Há linguagens que iriam fazer a conversão automática do resultado (técnicamente conhecida como conversão implícita), truncando as casas decimais e atribuiria o valor 3 à variável num_residencia. Outras poderiam gerar um erro durante a compilação do programa ou durante a execução. Assim, o mais adequado é você garantir que a variável receberá um valor do mesmo tipo que foi declarada.

Vamos supor agora que você declare uma variável chamada minha_altura como do tipo Real, ou seja, um número com casas decimais, para armazenar minha altura em metros. Observe que a variável minha_altura poderá receber tantos valores inteiros como valores com casas decimais.

Daí você pensa, quantas casas decimais o computador pode guardar? Se eu armazenasse em minha_altura o resultado da operação 5/3. A variável minha altura teria o valor 1,66 ou 1,66667, ou 1,666666….? Isto já começa a ficar um pouco técnico e você nem precisa se preocupar em profundidade com isso. Mas vou tentar lançar um pouco de luz para que entenda melhor. 

Cada tipo de dado numérico com casas decimais pode ter uma precisão diferente a depender da quantidade de bits que este tipo de dado ocupa na memória. Assim, quanto mais bits ele ocupar na memória, mais casas decimais ele pode armazenar. É correto você pensar que em casos de resultados com infinitas casas decimais o computador nunca terá o resultado exato e sim aproximado com maior ou menor precisão, dependendo do tipo de dado que esteja utilizando. Mas para efeitos práticos, a precisão numérica que temos hoje é tão grande que isso não representa problemas para a imensa maioria das aplicações!

4. Ordem de precedência das operações

Algo importante para se prestar atenção ao escrever uma fórmula para uma variável é a ordem de precedência das operações. Você já estudou isso em matemática, mas não custa nada lembrar:

  1. Parênteses;
  2. Expoentes;
  3. Multiplicações e divisões (da esquerda para direita);
  4. Somas e subtrações (da esquerda para direita).

Nada melhor do que eu exemplo para deixar as coisas mais claras! Vamos pensar na variável minha_altura, que é do tipo Real. Se eu atribuísse a fórmula abaixo à variável, qual seria o seu valor? Tente fazer antes de expandir a resposta!

  • minha_altura = (9 – 2*((2)*(5-4)))/3
  • minha_altura = (9 – 2*((2)*(1)))/3
  • minha_altura = (9 – 2*(2))/3
  • minha_altura = (9 – 4)/3
  • minha_altura = 5/3

Você deve estar pensando: para que alguém iria programar um código para fazer essa conta? Basta usar a calculadora! E você tem razão! Não teria sentido algum programar uma atribuição de variável dessa forma, foi apenas um exemplo didático!

Em programação, o que possivelmente você iria programar é uma fórmula que baseada em outras variáveis, possa calcular ou estimar sua altura. Assim, poderíamos reescrever a fórmula de minha_altura como:

 

				
					minha_altura = (A - 2*((B-2)*(C-D**2)))/3
				
			

Inserindo os valores de A, B, C e D, o programa iria calcular minha_altura. Note que você precisa programar apenas uma vez a fórmula, o resultado dependerá apenas das variáveis inseridas no programa.

Bom, por ora, acho que estamos satisfeitos sobre operações com dados numéricos. Vamos passar agora para o outro tipo de dado: dados booleanos.

5. Operações com dados booleanos

A denominação booleano foi realizada em homenagem ao matemático inglês George Boole, um dos país da lógica booleana. As operações booleanas ou lógica booleana estão presentes em todos os circuitos eletrônicos que puder imaginar, ou seja, é a base para todos os eletrônicos que conhecemos, desde o controle do portão eletrônico até o seu celular! Não vamos abordar a lógica booleana em profundidade explorando todas as suas propriedades, mas vamos falar do necessário para que possa aprender a programar.

Como já disse na introdução, uma variável booleana pode ter apenas um de dois valores possíveis: true ou false. Vou usar os termos em inglês daqui para frente, pois assim serão apresentados para você nas linguagens de programação que vier a estudar. Para as variáveis booleanas, podemos realizar três operações básicas booleanas:

  1. NOT;
  2. AND (E);
  3. OR (OU).

Vamos começar pela operação mais simples: NOT. Se A for uma variável do tipo booleana e seu valor for true. A operação (NOT A) resulta em false. Se B é uma variável booleana e seu valor é false. A operação (NOT B) resulta em true. Simples, não!? Vamos ver isso em um formato de tabela para estruturar o raciocínio (são as famosas tabelas da verdade que já vimos no ensino médio):

A NOT A
false
true
true
false

A operação AND (E) exige que todos os operandos sejam verdadeiros para que resulte em verdadeiro, senão o valor resultante será falso. Vejamos a tabela da verdade no caso de apenas dois operandos:

A B A AND B
false
false
false
false
true
false
true
false
false
true
true
true

Por fim, a operação OR (OU) exige que pelo menos um dos operandos seja verdadeiro para que o resultado seja verdadeiro. Se nenhum operando for verdadeiro, o resultado será falso. A tabela da verdade no caso de dois operandos é a seguinte:

A B A OR B
false
false
false
false
true
true
true
false
true
true
true
true

6. Praticando a lógica booleana

Agora que já vimos o básico da lógica booleana, vamos testar se realmente aprendemos. Veja abaixo a declaração de algumas variáveis e em seguida, calcule o resultado de cada expressão. Olhe as respostas só depois de ter tentado resolver!

 

				
					int A = 10
int B = 15
boolean C = false
real D = 35,5
int E = 2
				
			

R: true

R: false

R: false

R: true AND false

R: false

R: false OR false

R: false

R: false OR false OR true

R: true

R: true AND true

R: true

R: NOT(NOT(false))

R: NOT(true)

R: false

R: (100 – 106,5) < 0

R: true

R: (50 > 35,5) AND NOT(false)

R: true AND true

R: true

7. Tipo de dados especial: Arrays

Vamos agora falar de um tipo de dado muito útil em programação: os arrays (difícil encontrar uma tradução para essa palavra! Vamos usar em inglês mesmo!)

Os arrays não são um tipo de dado básico, tais como um número inteiro, real ou booleano, mas são extremamente relevantes. Os arrays são, na verdade, uma sequência de tamanho definido de algum tipo de dado básico. Por exemplo, suponhamos que precisássemos declarar 10 variáveis inteiras. Ao invés de criar 10 nomes diferentes, podemos declarar uma única variável (um array de números inteiros) com tamanho igual a 10, conforme figura abaixo. Vamos nomear o array abaixo de array_teste.

A variável array_teste teve seus valores inicializados de forma aleatória para fins didáticos. Podemos acessar cada valor do array por meio de um indexador/índice, um número inteiro que irá se referir à posição desejada do array.

Desta forma, se quisermos nos referir ao número 15, que ocupa a primeira posição da variável array_teste, iremos utilizar a seguinte convenção array_teste[1]. Da mesma forma, a última posição do array_teste possui o valor 10 e é referenciado como array_teste[10].

Um ponto importante de ressaltar é que a referencia para o primeiro elemento do array depende da linguagem. Algumas linguagens consideram os índices iniciando por 0. Se fosse este o caso, array_teste[0] retornaria o primeiro elemento da sequência, no caso 15, enquanto array_teste[1] iria se referir na verdade ao segundo elemento da lista, no caso 4, e o último elemento da lista seria array_teste[9], que teria o valor 10.

 

8. Recapitulando

Nesta aula começamos conhecendo os tipos básicos de dados comuns em todas as linguagens de programação. Em seguida, vimos as operações que podemos aplicar sobre os dados numéricos e a ordem de precedência no cálculo de fórmulas. Também vimos as operações básicas booleanas e realizamos alguns exercícios para fixar o conteúdo. Por fim, vimos que os arrays são uma sequência de dados de um mesmo tipo declarado como uma única variável indexada, e sua importância para programação.

Atribuindo permissões para o bot

Uma vez criado um bot dentro do Telegram, ou já tendo um bot para finalidade de integração com a TraderEvolution. o próximo passo é atribuir permissão de administrador ao bot nos grupos que receberão mensagens pelas suas estratégias, robôs e indicadores da TraderEvolution.

O procedimento pode ser realizado tanto no Telegram Web quanto eu seu próprio aplicativo no celular.

Reproduzir vídeo

TUTORIAL - PASSO 2: Atribuindo ao bot permissão de Administrador

1) Acesse o Telegram Web ou abra o app em seu celular
2) Crie um novo Grupo

Caso já possua um grupo para o qual suas estratégias encaminharão mensagens, vá para o Passo 3.

Neste primeiro momento, não iremos adicionar nenhum membro ao grupo. Clique no botão avançar no canto inferior direito.

Escolha um nome para o grupo que está criando. Nesse exemplo, utilizamos o nome “Grupo Teste”.

3) Inclusão do bot como membro do grupo

Selecione o grupo na listagem lateral esquerda. Em seguida, clique no cabeçalho superior onde há a informação do nome do grupo e quantidade de membros.

Será exibido um painel no lado direito da tela. Clique sobre o ícone de lápis no canto superior direito para abrir o painel de administração.

Em seguida clique no item “Members”, conforme demonstrado abaixo.

Uma vez exibida a listagem de membros atuais, clique no botão de adicionar novos membros no canto inferior direito.

Busque pelo nome do bot desejado. Como há muitos bots públicos, certifique-se de que está selecionando corretamente o bot que criou.

4) Atribua permissão de administrador ao bot

Agora que o bot já é membro do grupo, volte ao painel de administração e clique em “Administrators”.

Será exibida uma listagem com os atuais membros do grupo. Selecione o bot que acabou de adicionar como membro do grupo.

Em geral, não há necessidade de alterar as permissões já configuradas por padrão. Assim, clique na seta de voltar.

5) Certifique que seu bot é administrador do grupo

Ao voltar, você verá novamente a relação de administradores do grupo, onde deve constar o nome do bot e a observação de que você concedeu a permissão de administrador ao bot.

Próximo passo...

Já temos um bot do Telegram e um grupo para receber as mensagens das nossas estratégias da TraderEvolution.

O próximo passo, será identificar o ID do grupo que criamos, pois precisaremos desse ID para encaminhar as mensagens pela ferramenta de integração da NeoTraderBot.

Explorando a Interface Gráfica e PRINCIPAIS FUNCIONALIDADES da Trader Evolution

Reproduzir vídeo

Neste segundo vídeo da séria “Conhecendo a Trader Evolution” vamos explorar de maneira geral a interface gráfica da Plataforma, para que tenhamos uma noção de onde encontrar as ferramentas principais.

Sinalize na plataforma o código “NEOTRADERBOT” para indicar que faz parte da Comunidade e podermos verificar benefícios especiais aos membros! (No menu principal, vá em “Mais”, em seguida “Indique parceiro”)

Algoritmos, Segregação de dados e Overfitting

Reproduzir vídeo

Antes de falarmos sobre algoritmos de otimização, precisamos abordar o tema de segregação de dados dados históricos disponíveis para permitir a adequada realização de otimização e de backtesting.

A separação de dados é fundamental e precisa ser realizada antes de iniciar a otimização. Normalmente, deixamos os dados mais recentes reservados para o backtesting e um intervalo de tempo que permita uma quantidade suficiente de operações para analisar o resultado do backtesting com significância estatística. Ainda abordaremos aspectos a backtesting em outros materiais…por enquanto, é preciso entender que backtesting é um processo de validação executado após a otimização.

Não existe uma fórmula mágica ou um percentual específico dos dados para separar para backtesting. Na literatura, vemos sugestão de percentuais entre 15% a 30%…isso geralmente depende de vários fatores e também da quantidade de dados históricos que se tem disponível. Por exemplo, se uma estratégia opera daytrade, seria recomendável ter, no mínimo, 100 dias de operação no backtesting. Para que haja uma significância estatística na validação, ou seja para que a estratégia tenha a oportunidade de  experimentar situações distintas de alta, baixa, correção, lateralização… Se o intervalo médio entre as operações de uma estratégia é de 2 dias…então é preciso, no mínimo, 200 dias. Observe que no primeiro caso, haverá possivelmente mais operações do que no segundo caso. Quanto maior a amostra de operações no backtesting melhor, o problema é que há uma limitação de tamanho dos dados de backtesting e, geralmente,  precisamos de mais dados para a otimização do que para backtesting.

O conjunto de dados que separamos para backtesting nós vamos esquecer que existe enquanto estivermos fazendo a otimização e vamos chamar de OUT OF SAMPLE… a razão disso vai ficar mais clara no decorrer da explicação sobre otimização. Os dados que iremos utilizar para otimizar vamos chamar de IN SAMPLE.

Vamos agora falar sobre dois algoritmos muito empregados na otimização de estratégias.

Grid Search

O primeiro algoritmo que vamos tratar se chama Grid Search. Isto é só um nome bonito para um processo de exploração do espaço de busca por força bruta! Ou seja, este algoritmo simula todas as possibilidades de combinação dos parâmetros da estratégia. Você viu no exemplo do vídeo anterior que uma estratégia de cruzamento triplo de média, com 7 graus de liberdade gerou aproximadamente 7 milhões de possibilidades.

É coisa pra caramba! Não dá pra simular isso tudo…fica muito caro! Imagina a quantidade de tempo, o custo de máquinas ou de aluguel de cloud computing para se obter os parâmetros otimizados de uma estratégia que pode no final resultar em uma estratégia não lucrativa.

A primeira lição é ponderar sobre os recursos que se tem a disposição para realizar a otimização. Você vai fazer a simulação e tabelamento dos resultados de forma automática, sem intervenção humana….tudo bem…você pode simular mais possibilidades. Se você vai fazer na mão o processo de otimização com Grid Search, você vai ter que reduzir o espaço de busca.

Vou te dar um exemplo básico de Grid Search. Suponha que iremos otimizar apenas 2 variáveis da nossa estratégia, sendo 5 possibilidades para a primeira variável X e 5 para a segunda variável Y. Têm-se então 25 pontos que representam as combinações dos valores das variáveis X e Y. O Grid Search consiste em rodar a estratégia para cada um desses 25 pontos. Mas em qual ordem? Como iremos testar tudo de qualquer  forma, achar a solução na força bruta, então tanto faz! Mas nada impede também de rodar e coletar o resultado em uma planilha ou aplicativo web em uma ordem que julgar mais interessante.

O Profit Chart, na versão de hoje (12/12/2022), não oferece nenhum funcionalidade de suporte ao processo de otimização. Ou seja, se você só usar o Profit, só poderá fazer uma otimização bem limitada com um espaço de busca pequeno. Para ampliar o espaço de busca e automatizar o processo você precisará utilizar outra plataforma ou framework.

A próxima pergunta que você deve estar fazendo é se existem formas mais elaboradas de se otimizar uma estratégia do que simular na força bruta cada possibilidade? Sim! E uma resposta é algoritmo genético!

Algoritmo Genético

Os algoritmos genéticos baseiam-se nos processos de evolução genética e seleção natural que observamos na natureza e consistem em uma forma de percorrer o espaço de busca.

Em uma explicação com termos bem simples….o algoritmo inicia com uma população de indivíduos gerados aleatoriamente que é a primeira geração. Cada individuo possui em seu DNA uma codificação de alguma possibilidade das variáveis de entrada. Cada individuo terá um resultado associado na simulação. Essa população irá reproduzir, escolhendo aleatoriamente casais, que devido à combinação genética dos pais, irão gerar filhos que terão em seu DNA uma codificação que é uma mistura do DNA de seus pais, consistindo em uma outra possibilidade de variáveis de entrada. Os filhos também terão um resultado associado na simulação, sendo a segunda geração do algoritmo. Daí, como acontece na vida, podem haver mutações nos indivíduos que nascerem, consistindo em pequenas alterações aleatórias e alguns indivíduos irão “morrer”, não passando para futuras gerações seu código genético, que são os indivíduos com pior resultado.

Ou seja, parte da população da geração atual vai permanecer, parte não irá prosseguir para futuras gerações, novos indivíduos serão gerados por combinação dos pais, alguns dos novos indivíduos sofrerão mutações permitindo maior variabilidade genética. Na próxima etapa, os filhos já irão reproduzir, e esse processo irá ocorrer de forma iterativa, regido pela seleção natural daqueles que apresentarem melhores resultados, até que uma condição de parada seja atingida, por exemplo, não tenha surgido nenhum individuo nas últimas 5 gerações com resultado melhor do que o melhor resultado já encontrado.

Qual é o benefício almejado pelos algoritmos genéticos? Reduzir o esforço computacional exigido na força bruta, reduzindo a probabilidade de ter que calcular todas as possibilidades do espaço de busca, pois o algoritmo genético irá percorrer o espaço de forma mais eficiente! Uma vez encontrado a solução ótima, é improvável que haja uma solução melhor do que aquela, no espaço de busca não explorado.

Explicados os dois algoritmos mais utilizados para otimização de estratégias, vamos falar enfim do principal risco da otimização: Overfitting.

Overfitting

Como o nome diz overfitting é um ajuste excessivo ou sobre-ajuste. No caso da otimização é a obtenção de variáveis de entrada da estratégia que funcionam muito bem para os dados IN SAMPLE, mas quando executado o backtesting a estratégia apresenta uma deterioração muito significativa do resultado. Ou seja, o ajuste do modelo encontrado possui baixa capacidade de generalização.

Este é o maior risco da otimização: deterioração de desempenho com dados novos. E quais são as possíveis causas de overfitting? Excesso de graus de liberdade e dados com viés. Vamos entender isso melhor:

Quanto mais variáveis de entrada a otimização estiver calculando, mais graus de liberdade você estamos dando para que a otimização ajuste a estratégia aos dados apresentados. Isto significa que podemos estar otimizando um modelo muito específico que utilize mais indicadores do que precisa ou colocando na otimização muitas variáveis. As configurações que apresentarem os melhores resultados em otimização podem ter chance grande de estarem com overfitting. Algumas pessoas recomendam descartar os melhores resultados, mas é recomendável rodar todas eles em backtesting para certificar se realmente houve ou não overfitting.

Outra forma de incorrer em overfitting é fazer a otimização em um conjunto de dados muito específico, ou seja, dados que tenham, por exemplo, apenas uma tendência de alta no plano mais macro e baixa volatilidade. A otimização vai gerar a melhor configuração para esta situação. Se o backtesting tiver dados, por exemplo, de uma tendência de baixa ou maior volatilidade, é bem provável que o modelo não terá bom desempenho porque a otimização não presenciou esse tipo de situação no ajuste das variáveis.

É bom ressaltar a diferença entre overfitting e otimização focada em situação de mercado. Haverá situações em que desejamos que uma estratégia tenha desempenho equilibrado tanto em mercado de alta como de baixa ou lateralizado. E pra isso precisamos garantir que os dados in sample contenham essa diversidade de cenários.

Mas também podem haver situações, em que queremos fazer a otimização apenas com dados de mercado em alta, por exemplo. Porque iremos colocar para rodar o robô apenas nesta situação. Então é interessante fazer a otimização focada neste cenário, mas sem incorrer em overfitting. O overfitting nesse caso seria ter um desempenho ruim, mesmo quando o backtesting é aplicado em cenário semelhante aos dados de otimização. Isto significa que a otimização fez um sobreajuste para a situação de mercado de alta dos dados de treino, apresentando pouca capacidade de generalização.

É importante observar que a identificação de overfitting é feita no backtesting com dados OUT OF SAMPLE, ou seja, não utilizados na otimização. E por isto a importância de separarmos os dados no início do processo!

O problema do overfitting é que quando ele não é percebido, o elaborador da estratégia cria a falsa expectativa de desempenho da estratégia baseado em resultados de otimização que não vão se repetir com dados novos, o que pode representar prejuízos financeiros que apenas cessarão quando decidir-se parar de rodar a estratégia. E talvez a causa desse prejuízo nem seja corretamente identificada pelo elaborador da estratégia.

Conclusão

Muito bem! Vimos assuntos importantes tais como algoritmos de otimização, cuidados devidos a segregação de dados e o problema mais temido da otimização: overfitting.

Vamos lançar uma pergunta para motivar o próximo texto sobre otimização. Uma vez que tenhamos econtrado uma configuração ótima para a estratégia sem overfitting. Até quando esta configuração deve ser utilizada De quanto em quanto tempo devemos reavaliar a configuração dos parâmetros da estratégia?

Veja o próximo material de otimização para aprender mais sobre robustez no processo de otimização por meio de técnicas de validação cruzada.

Editor de estratégias

Reproduzir vídeo

Este documento irá abordar todos os detalhes importantes sobre a ambiente de edição de estratégias do Profit Chart: Editor de Estratégias.

A linguagem utilizada pelo Profit Chart é a NTSL (Nelogica Trading System Language). É uma linguagem com uma sintaxe muito semelhante a Pascal, porém com uma restrição nos comandos. A linguagem NTSL também aceita comandos em português, embora não seja uma boa prática, dado que todas as linguagens com grande abrangência são em inglês. Logo, é melhor o usuário já se acostumar com os termos em inglês visando maior facilidade em uma transição futura para outra linguagem de programação.

Vamos às questões práticas…

Como acessar o Editor de Estratégias?

Após abrir o Profit, basta acessar o menu principal na parte superior, clicar em “Estratégias” e em seguida na opção “Editor de estratégias”.

O Editor de estratégias aparecerá conforme a figura abaixo.

Modos de exibição do Editor de Estratégias

Note que na parte superior temos 4 modos de exibição do editor de estratégias, que são:
  • Editor: apresenta apenas a tela de edição do código fonte e de debug (debug é uma funcionalidade para depurar seu código fonte, ou seja, executar passo a passo para verificar se tudo está rodando corretamente);
  • Gráfico: apresenta apenas o gráfico no qual está sendo testada a estratégia em edição;
  • Misto: apresenta tanto a tela de edição do código fonte e debug, quanto o gráfico no qual a estratégia em edição está sendo testada;
  • Estatísticas: este modo aplica-se apenas às estratégias de execução, ou seja, estratégias que realizam ordens de compra/venda para fins de backtest.

Vamos detalhar abaixo o modo de exibição mais utilizado, o modo “Editor”. O modo “Estatísticas” será bastante trabalhado nos documentos relacionados à backtesting.

Modo "Editor"

O modo editor possui três áreas principais: a barra de ferramentas, a área de edição de código e a área de compilação/debug.

Note que o editor pode ter múltiplas estratégias abertas em edição ao mesmo tempo. A barra inferior apresentará abas diferentes para cada estratégia. Uma estratégia que foi criada mas ainda não foi salva constará na aba “NoName”, conforme pode ser visto na figura abaixo.

Barra de ferramentas

Vamos detalhar a função de cada ícone da barra de ferramentas:

Ícone Função

Nova estratégia: abre janela para seleção de modelos do Profit para criar uma nova estratégia;

Abrir estratégia: abre uma janela para seleção de estratégias salvas no Profit;

Fechar estratégia: fecha a edição da estratégia atual. O usuário será perguntado se deseja salvar as alterações, caso haja alguma alteração não salva;

Salvar: salva as alterações existentes na estratégia. Caso haja algum erro de sintaxe, o sistema irá perguntar ao usuário se deseja salvar assim mesmo;

Salvar como: permite salvar a estratégia em edição como um novo arquivo de estratégia, podendo configurar um novo nome e descrição;

Verificar sintaxe: o sistema realiza uma verificação da sintaxe da estratégia e indica eventuais erros;

Step over (debug): uma vez em modo de depuração e a execução para em determinada linha de código, este botão executa a linha e para na próxima;

Trace into (debug): uma vez em modo de depuração e a execução para em uma determinada linha que realiza a chamada de uma função ou procedure criada pelo usuário, o depurador irá executar linha a linha o código fonte dentro da função/procedure chamada;

Executar estratégia: o editor de estratégia passa para o modo de exibição misto e apresenta o resultado da execução da estratégia no gráfico ao lado da área de edição do código-fonte. O depurador irá parar na primeira linha a ser executada que tenha breakpoint;

Parar estratégia: interrompe a execução da estratégia;

Propriedades da estratégia: permite , no caso de indicadores, configurar a aparência das séries plotadas (cor, espessura e tipo de tracejado, tipo de gráfico: linha/histograma), linhas guias e suas aparências (linhas horizontais com valor fixo) e configurar tipo de preenchimento entre as séries plotadas;

Formatação automática do código: realiza a identação (configuração de espaços) e quebras de linhas do código de forma automática e uniforme. (Nem sempre funciona direito!)

Lista de funções: apresenta listagem de funções disponíveis no editor de estratégias agrupadas por tema;

Lista de constantes: apresenta listagem de constantes definidas pelo Profit agrupadas por tema;

Linhas no Gráfico Principal: alterna a plotagem das séries entre um subgráfico ou dentro do gráfico principal do ativo;

Configurações do editor: abre janela para personalização do editor de estratégias, podendo alterar a fonte do editor, tamanho, cores e etc...

Área de edição de código

Na área de edição de código é apresentado o código fonte da estratégia. Note que há uma numeração das linhas a esquerda para facilitar a identificação do código quando houver sinalização de erro de sintaxe.

O usuário pode criar breakpoints para depuração do código (debug) clicando no vão entre a númeração da linha e a coluna em cinza. A criação do breakpoint será indicada por um ícone circular azul, bem como o preenchimento da linha de código na mesma cor.

Área de compilação/debug

Nesta área, é apresentado o resultado da verificação de sintaxe, bem como os erros existentes no código-fonte da estratégia.

Quando a estratégia é “debugada” (depurada), aparece nesta área também o valor das variáveis declaradas na estratégia.

Gerenciador de estratégias

O Gerenciador de estratégias apresenta todas as estratégias existentes no Profit, tanto aquelas criadas pelo usuário, quanto as estratégias importadas. O Gerenciador pode ser acessado pelo menu principal, clicando em “Estratégias” e em seguida, “Gerenciador de estratégias”, conforme figura abaixo.

O gerenciador deve se apresentar conforme figura a seguir. Será apresentado ao usuário uma relação de estratégias com a indicação do tipo a que pertence. É importante ressaltar que uma estratégia, pode estar associada a mais de um tipo. Por exemplo, pode haver uma estratégia que realiza tanto uma coloração de gráfico como também realiza o filtro do ativo (screening).

Para cada linha referente a cada estratégia, o usuário pode editar a estratégia (ícone de lápis), compartilhar a estratégia pelo Connect Chat com um outro usuário do Profit ou grupo (Ícone com 3 pontos) ou excluir a estratégia.

Pelo gerenciador de estratégias é possível também fazer a importação de estratégias criadas por outras pessoas e a exportação das estratégias existentes no Profit da máquina.

Como importar ou exportar estrategias?

A importação e exportação de estratégias é realizada por meio de arquivos com extensão psf (Profit strategies file). Esses arquivos podem conter uma ou mais estratégias, com ou sem o código fonte associado.

Quando o usuário não tem acesso ao código-fonte da estratégia, chamamos a estratégia de caixa-preta, uma vez que o usuário não tem informação sobre detalhes da programação, apenas pode informar parâmetros e ter acesso à saída da estratégia, seja ela um indicador ou uma coloração de gráfico. As estratégias caixa-branca são aquelas nas quais o usuário consegue visualizar todo o código fonte.

Para exportar uma estratégia, basta clicar no botão “Exportar” no canto inferior esquerdo do Gerenciador de estratégia. Será aberta uma janela conforme figura abaixo.

O usuário deverá selecionar o nome de um arquivo e uma pasta para realizar a exportação, bem como indicar por meio da caixa de seleção, quais estratégias serão exportadas para o arquivo psf. Note que a opção padrão do sistema é exportar sem código fonte. No entanto, caso o usuário deseje, poderá marcar a opção para exportar a estratégia e o código fonte associado.

O processo de importação de estratégia é análogo à exportação. O usuário deve selecionar um arquivo psf em seu computador e o Profit irá listar as estratégias contidas no arquivo para que o usuário selecione quais serão importadas.

Outra forma de compartilhar estratégias é pelo Connect Chat, sendo o processo mais natural para o usuário, pois ocorrerá dentro da interface do chat da plataforma Profit.

No próximo documento, iremos abordar quais são os tipos de estratégias que podem ser automatizadas na plataforma Profit Chart! 

Snippets para Manipulação de Gráficos

Esta seção visa apresentar trechos de códigos com funcionalidades relativas à manipulação de gráficos.

Você pode acessar os Snippets diretamente pelo menu lateral direito, ou fazendo CRL+F (CTRL+L) para localizar algum texto específico na página, uma vez que o conteúdo tende a crescer ao longo do tempo, dificultando a navegação pelo menu.

Caso tenham sugestões de código para acrescentar à lista, gentileza deixar o código nos comentários com o link para seu perfil em rede social (para devido crédito de autoria).

Snippets

Como configurar as propriedades de Plots nos Indicadores?

Reproduzir vídeo

Praticamente todas as propriedades de um plot no NinjaScript podem ser definidas no método AddPlot. Este método possui duas sobrecargas.

A primeira versão cria apenas uma linha sólida com cor específica. Na segunda versão de AddPlot, os parâmetros permitem maior flexibilidade na configuração, conforme pode ser visto no exemplo abaixo.

				
					AddPlot(new Stroke(Brushes.LimeGreen, DashStyleHelper.Solid, 1, 10), PlotStyle.Bar, "Plot1");
Plots[0].Autowidth = true;
				
			

No exemplo acima, criamos um plot chamado “Plot1” que é uma barra na cor verde limão, sólida, com opacidade em 10%. Também configuramos a largura da barra para ser a mesma da série de dados do gráfico.

O objeto Stroke permite definir a cor do plot pelo parâmetro da classe Brush, o tipo de traçado pelo parâmetro da classe DashStyleHelper, a espessura e transparência do plot. A transparência é o único parâmetro que não pode ser configurado na interface gráfica.

Existem diversos tipos de plots na NinjaTrader, tais como linhas, barras, gráfico em degrau, linha horizontal, marcações em bloco, cruz, triangulos, pontos. E também é possível não exibir o plot no gráfico, mas apenas no DataBox, passando como parâmetro o tipo PlotStyle.PriceBox.

Como alterar a cor da barra e do fundo do gráfico?

Reproduzir vídeo

Em NinjaScript é possível pintar a barra e o fundo do gráfico utilizando a lógica que desejar. Além disso, você pode em qualquer momento do tempo refazer a pintura de qualquer barra ou fundo de barra no gráfico, o que dá uma grande flexibilidade ao trader programador.

Veja abaixo exemplo de como pintar para o momento atual uma barra de azul e o fundo de oliva. Caso deseje pintar uma barra do passado, basta usar o indexador da série com o valor desejado. Por exemplo, BarBrushes[1] refere-se a cor da penúltima barra do gráfico em relação a barra processada no momento.

				
					BarBrushes[0] = Brushes.Blue;
BackBrushes[0] = Brushes.Olive;

				
			

OBS: Caso você deseje retirar a cor atribuído a um desses elementos basta atribuir o valor null a série desejada.

Como plotar indicadores em estratégias em painel separado?

Reproduzir vídeo

Essa é uma tarefa que pode ser realizada em uma única linha de comando no NinjaScript. Basta no método OnStateChange, quando o estado do ninjascript for DataLoaded, ou seja, quando já tiver carregado todos os dados do gráfico, você chamar o método AddChartIndicator, conforme demonstrado abaixo.

				
					if (State == State.DataLoaded)
{
    AddChartIndicator(MACD(12,26,9));
}

				
			

Pintando uma região entre duas médias ou séries

Seguem abaixo dois exemplos de pintura de região entre as médias exponencias de 9 e 90 períodos utilizando diferentes sobrecargas do método Draw.Region. Na primeira sobrecarga, vamos pintar essa região desde o início do gráfico utilizando os índices de barras e na segunda sobrecarga, vamos pintar apenas um intervalo de datahora específico.

				
					protected override void OnBarUpdate()
{
    //Pinta a região entre as duas médias em todo o gráfico
    Draw.Region(this, "pinturaRegiao", CurrentBar, 0, EMA(9), EMA(90), Brushes.White, Brushes.Blue, 30);
    
    //Pinta a região entre as médias apenas no intervalo de data informado
    Draw.Region(this, "pinturaTempo", new DateTime(2023,8,30), new DateTime(2023,8,31,9,5,30), EMA(9), EMA(90), Brushes.Blue, Brushes.Yellow, 80);
}
				
			

Como escrever texto nas barras e em região fixa do gráfico?

Reproduzir vídeo

Seguem abaixo dois exemplos de pintura de região entre as médias exponencias de 9 e 90 períodos utilizando diferentes sobrecargas do método Draw.Region. Na primeira sobrecarga, vamos pintar essa região desde o início do gráfico utilizando os índices de barras e na segunda sobrecarga, vamos pintar apenas um intervalo de datahora específico.

				
					protected override void OnBarUpdate()
{
    //Cria texto nas barras que fecharam acima da barra anterior
    if (isRising(Close))
        Draw.Text(this, "Barra" + CurrentBar.ToString(), true, Close[0].ToString(), Close[0], 0, Brushes.White, new SimpleFont(), TextAlignment.Left, Brushes.Yellow, Brushes.Blue, 20);
        
    //Cria um texto em região específica do gráfico
    Draw.TextFixed(this, "TextoFixo", "Coded by NeoTraderBot\n", TextPosition.BottomRight);
}
				
			

Snippets para Manipulação de Gráficos

Esta seção visa apresentar trechos de códigos com funcionalidades relativas à manipulação de gráficos.

Você pode acessar os Snippets diretamente pelo menu lateral direito, ou fazendo CRL+F (CTRL+L) para localizar algum texto específico na página, uma vez que o conteúdo tende a crescer ao longo do tempo, dificultando a navegação pelo menu.

Caso tenham sugestões de código para acrescentar à lista, gentileza deixar o código nos comentários com o link para seu perfil em rede social (para devido crédito de autoria).

Snippets

Como criar e configurar os atributos gerais de um plot?

Os plots, ou Lines como é definida a Classe dentro do EvoCode devem ser instanciados no construtor do indicador. Cada Line recebe um nome por meio do método Set e assim pode ser indexado.

O programador pode configurar a visbilidade o estilo de linha (histograma, linha, escada, etc…), a cor padrão, a espessura, entre outras propriedades. Veja abaixo um exemplo de como criar 2 plots, um histograma e uma linha pontilhada.

				
					public IndicadorXYZ(): base()
{
    //Linha pontilhada
    Lines.Set("Média rápida");
    Lines["Média rápida"].Color = Color.Red;
	Lines["Média rápida"].Style = LineStyle.DotLine;
	Lines["Média rápida"].Width = 1;
	
	//Histograma
	Lines.Set("Histograma");
    Lines["Histograma"].Color = Color.Gray;
	Lines["Histograma"].Style = LineStyle.Histogram;
}
				
			

Eu posso plotar indicadores em uma estratégia?

Sim! Apesar da classe StrategyBuilder não possuir interface com classe Lines, é possível instanciarmos indicadores dentro das estratégias. Assim, os plots e elementos gráficos dos indicadores também serão exibidos no gráfico ao rodar a estratégia. 

Os indicadores devem ser instanciados no método Init e naturalmente também devem ser declarados como atributos da classe.

Veja abaixo alguns exemplos de instanciação de indicadores:

Instanciando uma média móvel (Indicador nativo)
				
					private BuiltInIndicator fastAvg;

public override void Init()
{
	fastAvg = IndicatorsManager.BuildIn.MA(HistoryDataSeries, fastPeriod, fastAvgType, 0, PriceType.Close);
} 
				
			
Instanciando Average True Range (ATR)
				
					private BuiltInIndicator avgTrueRange;

public override void Init()
{
    avgTrueRange = IndicatorsManager.BuildIn.ATR(HistoryDataSeries, 200);
} 
				
			
Instanciando Indicador Próprio chamado "NTB_TripleCrossoverIndicator"

Observe que ao instanciar um indicador próprio com o método custom, fornecemos 3 parâmetros: o nome do indicador (nome da classe), a série de dados, e um array com os valores dos parâmetros.

				
					private BuiltInIndicator NTB_3Cross;

public override void Init()
{
	NTB_3Cross = IndicatorsManager.BuildIn.Custom("NTB_TripleCrossoverIndicator" 
	                                              ,	HistoryDataSeries
	                                              , new Object[]{fastestPeriod,
  			                                              	   fastestAvgType,
  			                                              	   fastPeriod,
  			                                              	   fastAvgType,
  			                                              	   slowPeriod,
  			                                              	   slowAvgType})
} 
				
			

Como mudar a cor do plot em determinada condição?

As cores de um plot podem ser alteradas para qualquer posição a qualquer instante. Basta atribuir a cor desejada ao marcador da Line. Veja no exemplo abaixo um código que atribui cores a um histograma de maneira condicional: se a barra for de alta usa corAlta, senão usa corBaixa.

				
					public override void Update(TickStatus args)
{
	if (args == TickStatus.IsQuote)
	{
		Color corAlta = Color.FromArgb(0, 51, 0);;
		Color corBaixa = Color.FromArgb(153, 0, 0);;
		
		Lines["Volat."].SetValue(rangeAtual);
    	Lines["Volat."].Markers.Set((barData.GetOpen() < barData.GetClose()) ? corAlta : corBaixa, 0);
	}
}
				
			

Como inserir um texto no cabeçalho do gráfico?

Caso esteja trabalhando com indicadores, é possível inserir um texto no cabeçalho do gráfico (Veja na figura abaixo). Com esta funcionalidade, você pode inserir informações que julgue ser úteis de serem exibidas no gráfico.

				
					Notification.Comment("Aqui é onde ficam os comentários!");
				
			

Como garantir que indicador será aplicado apenas ao gráfico principal?

Em alguns casos, é desejável garantir que o indicador esteja sendo aplicado no gráfico principal ou em um gráfico separado. Caso o usuário tenha aplicado o indicador na janela diferente da esperada, pode-se alertar isso por meio de um texto, conforme figura abaixo.

Para se implementar esta funcionalidade, deve-se incluir a biblioteca Runtime.Scripts.Charts no cabeçalho do código fonte, e dentro da classe do indicador sobrescrever o método onPaintChart, conforme código exemplo abaixo.

				
					using Runtime.Script.Charts;

public override void OnPaintChart(object sender, PaintChartEventArgs args)
{
    var graphic = args.Graphics;
    int windowNumber = ChartSource.FindWindow(this);
	Font fonte = new Font("Arial", 24);
	Brush boxBrush = new SolidBrush(Color.LightGray);
	
	//É o número da janela que define se o indicador está no gráfico principal (= 0)
    if (windowNumber != 0)
    {
        using (StringFormat format = new StringFormat())
        {
            format.LineAlignment = StringAlignment.Center;
            format.Alignment = StringAlignment.Center;

            graphic.DrawString("O indicador deve ser aplicado ao gráfico principal", fonte, boxBrush, args.Rectangle, format);
        }

        return;
    }
}		
				
			

Instalando NT8 e Configurando Market Data

Reproduzir vídeo

Neste video iremos apresentar passo a passo para instalar a Plataforma NinjaTrader e realizar a configuração o Market Data, tanto para acesso a dados das Bolsas Americanas (NYSE, NASDAQ, CME, etc…) e B3.

Após um longo período de espera, finalmente, a Plataforma NinjaTrader foi homologada para operar na B3. Desde o dia 03/jan/2023 é possível contratar esta Plataforma pela Corretora Órama.

Conforme antecipado nos planos da Comunidade @neotraderbot, iremos gerar conteúdo informativo de diferentes plataformas de trading para que os membros da comunidade tenham informações do que é possível realizar em outros ambientes.

Reforço que não estamos realizando nenhuma recomendação para mudança de Plataforma e que a decisão de migrar parte ou todo o processo de desenvolvimento e execução das estratégias automatizadas é muito pessoal e cabe apenas ao trader decidir sobre tal assunto.

Como configurar o Visual Studio para Trader Evolution [Desenvolvimento e depuração]

Reproduzir vídeo

Neste vídeo, irei demonstrar o passo-a-passo para configurar o Visual Studio para desenvolver e depurar estratégias e indicadores da TraderEvolution.

Não se esqueça de indicar a Comunidade NeoTraderBot como parceiro na Plataforma TraderEvolution. Vá no menu superior em “Mais” – “Extensões” – “Indique parceiro” e digite o código “NEOTRADERBOT”.

Assim, você reforça sua participação na Comunidade e nos ajuda a pleitear novas funcionalidades e melhorias na plataforma visando o benefício de todos os membros em suas automatizações e desenvolvimento de estratégias.

Ferramentas de Trading

Construtor de Capital – Liberação de acesso à Gamma Levels

Este tutorial visa apresentar o passo a passo para configuração e liberação de acesso aos alunos/assinantes das ferramentas desenvolvidas pela NeoTraderBot para Construtor de Capital na plataforma Meta Trader 5 (MT5). 

Uma vez enviadas as informações de e-mail da assinatura do indicador e número da conta da corretora Exness, a liberação de acesso está condicionada à confirmação de vinculo (aluno) junto à Construtor de Capital e será realizada em até 1 dia útil.

Em caso de dúvidas ou questões relacionadas às ferramentas Construtor de Capital, envie e-mail para contrutordecapital1@gmail.com.

Pré-configurações da MetaTrader

Passo 1: Abra o MetaTrader, vá no menu “Ferramentas” -> “Opções”.

Passo 2: Na tela que abrir, vá na aba “Expert Advisors” e em seguida marque a opção “Relacione no quadro abaixo as URL que deseja permitir a função WebRequest”. Insira na tabela a seguinte URL:

https://drive.usercontent.google.com/

Em seguida, clique em “OK”.

Instalação do Gamma Levels

Existem duas formas de instalar o Gamma Levels na MetaTrader. Recomenda-se que tente-se instalar pela forma 1 (mais simples). Caso o usuário tenha  conhecimento mais aprofundado sobre a plataforma MT5 e/ou tenha mais de uma instalação de MT5 na mesma máquina, pode-se instalar seguindo as instruções da Forma 2.

Forma 1: Ao receber o arquivo GammaLevelsCC_VXX.ex5 (onde XX é a versão da ferramenta), basta clicar duas vezes que o indicador será automaticamente instalado na MetaTrader.

Uma vez instalado, acesse a janela “Navegador” do MetaTrader e você verá dentro de “Consultor Expert” a ferramenta GammaLevels.

Forma 2: Abra o Windows Explorer e digite na barra de navegação %APPDATA%. A partir daí navegue até a pasta MetaQuotes -> Terminal -> Selecione a instalação desejada -> MQL5 -> Experts. 

Copie o arquivo GammaLevelsCC_VXX.ex5 (onde XX é a versão da ferramenta), para dentro dessa pasta e a ferramenta GammaLevels estará disponível nessa instalação específica do MT5.

Informações necessárias para ativação do Gamma Levels

Para realizar a ativação da ferramenta Gamma Levels para MT5, o usuário precisa enviar pelo formulário no final dessa página, o e-mail pelo qual realizou a assinatura do indicador e o número da conta da corretora. 

A informação de número da conta é obtida na janela “Navegador” -> Contas do MT5, conforme pode ser visto abaixo.

Inserindo o Gamma Levels em um gráfico

Uma vez, enviada a solicitação de ativação e confirmada a ativação pelo Construtor de Capital no e-mail informado, o usuário deve realizar os seguintes passos para incluir os níveis gamma em um gráfico.

Passo 1: Abra um gráfico no ativo desejado. Clique sobre o GammaLevels na aba Navegador, arraste e solte dentro do gráfico no qual deseja plotar os níveis Gamma.

Passo 2: Será aberta uma janela com informações do GammaLevels. Habilite a a opção “Permitir algotrading” e, em seguida, acesse a aba “Parâmetros de entrada”.

OBS: O GammaLevels não realiza nenhum tipo de operação automatizada.

Passo 3: Na aba de parâmetros, insira no campo apropriado o seu e-mail de assinatura da ferramenta GammaLevels. Nesta tela o usuário poderá configurar diversas propriedades de exibição de níveis, filtro de níveis por opções, agrupamento de níveis próximos e alarmes de cruzamento de níveis.

Recomenda-se que o usuário salve as configurações em um arquivo para reutilizar suas configurações. Assim, não é necessário configurar tudo novamente caso acrescente o indicador em outro gráfico. Para carregar uma pré-configuração de parâmetros do indicador, utilize a opção “Abrir”.

Clique em “OK”.

Passo 4: Uma vez configurado, o usuário poderá ver detalhes da execução da ferramenta na aba “Experts” em “Caixa de Ferramentas”, logo abaixo do gráfico. Caso a autenticação tenha sido efetuada corretamente, os níveis serão plotados no gráfico com o texto no lado direito. No canto superior direito do gráfico, o usuário verificará o texto “GammaLevelsCC” indicando que a ferramenta está aplicada naquele gráfico.

Liberação de Acesso - Ferramentas Construtor de Capital MT5
Este formulário visa recepcionar as chaves dos usuários para liberação de uso das ferramentas e códigos desenvolvidos pela NeoTraderBot para Construtor de Capital na plataforma Meta Trader 5 (MT5)

Documentação: Integração com Telegram

Você já pensou em conectar os seus robôs e indicadores que rodam na Trader Evolution ao Telegram? Quer receber mensagens quando uma posição é aberta ou uma operação é encerrada? Acompanhar de onde estiver, por meio de mensagens no Telegram, o resultado das suas operações e de suas estratégias automatizadas é possível com a ferramenta de Integração da NeoTraderBot!

Nesta página você terá acesso a todas as informações necessárias para que suas estratégias lhe enviem mensagens pelo Telegram!

O que é a ferramenta de Integração da NeoTraderBot?

É uma biblioteca que permite qualquer robô/indicador implementado em EvoCode enviar mensagens de texto e fotos pelo Telegram. Assim, as possibilidades de uso são muito amplas, podendo servir, por exemplo, para:

          • Acompanhamento da execução de Estratégias/Robôs próprios;
          • Notificações na abertura ou encerramento de posições com o resultado da operação;
          • Envio de notificações para grupo Telegram baseado em filtro automatizado de ativos (Screenings);
          • Envio de alarmes em condições específicas de mercado;
          • Envio automatizado de informações de mercado (preço de ações, preços de abertura, etc..);
          • Acompanhamento do valor patrimonial de uma carteira de ações;
          • Compartilhamento de ordens geradas/executadas por estratégias.

Temos uma versão FREE para você começar a agora a integrar  o seu trading com o Telegram! Além disso, disponibilizamos outras versões com funcionalidades ampliadas.

Pré-configuração, Tutoriais e Documentação

Uma vez contratada/adquirida a ferramenta de Integração TraderEvolution/Telegram, e após a instalação  básica (roteiro aqui), serão necessárias algumas configurações específicas para integração com o Telegram. 

Siga o passo-a-passo abaixo para realizar as pré-configurações e poder utilizar a integração de Telegram em suas estratégias (cada item contém um vídeo de tutorial).

Pronto! Agora você já pode fazer suas estratégias/robôs enviarem mensagens pelo Telegram! Clique aqui para ver as perguntas mais frequentes e exemplos de códigos para adaptar a sua necessidade.

Como criar seu bot para Telegram

A ferramenta de Integração TraderEvolution / Telegram, desenvolvida pela NeoTraderBot, necessita que você crie um bot no Telegram.

Veja abaixo o passo-a-passo para criar o seu próprio bot no Telegram. O procedimento pode ser realizado tanto no Telegram Web quanto eu seu próprio aplicativo no celular.

Reproduzir vídeo

TUTORIAL - PASSO 1: Como criar seu bot para Telegram

1) Acesse o Telegram Web ou abra o app em seu celular
2) Pesquise por botFather

A pesquisa irá buscar os perfis públicos com este nome. Certifique de que irá selecionar o perfil correto conforme abaixo com a verificação do Telegram.

3) Inicie um chat com o perfil @BotFather
4) Digite o comando /newbot

Isto irá iniciar o processo de geração de um bot para Telegram.

5) Em seguida o @botFather irá lhe perguntar qual é o nome do seu bot. Escolha um nome conforme sua conveniência.

No exemplo abaixo, escolhemos o nome “TesteCriacaoBot”

6) No próximo passo, o @botFather irá lhe perguntar por um username que deve terminar com a palavra bot.

O username (nome de usuário) é uma chave única no Telegram e, portanto, alguns nomes podem estar ocupados.

No exemplo abaixo, tentamos “TesteCricaoBot” e fomos avisados de que esse username já havia sido escolhido. Na segunda tentativa, escolhemos o username testeCriacao1bot.

7) Salve em local seguro o token de acesso do seu bot e inicie um chat com o seu bot

Uma vez que o username seja aceito, o @botFather irá gerar um token de acesso ao bot. Esse token de acesso permite administrar o bot criado e, portanto, você deve guardar essa chave em um lugar seguro.

Em seguida, clique na URL indicada no início da mensagem e encaminhe um texto qualquer ao seu bot, para que o mesmo conste na sua lista de Grupos/Chats do Telegram.

 

Próximo passo...

Ok! Criamos com sucesso o nosso bot de Telegram o qual irá enviar mensagens dentro da estratégias e indicadores da TraderEvolution utilizando a ferramenta da NeoTraderBot.

No próximo passo iremos criar o grupo no qual o bot irá encaminhar mensagens (caso você ainda não tenha) e atribuir permissão de administrador ao seu bot recém-criado.

Atribuindo permissões para o bot

Uma vez criado um bot dentro do Telegram, ou já tendo um bot para finalidade de integração com a TraderEvolution. o próximo passo é atribuir permissão de administrador ao bot nos grupos que receberão mensagens pelas suas estratégias, robôs e indicadores da TraderEvolution.

O procedimento pode ser realizado tanto no Telegram Web quanto eu seu próprio aplicativo no celular.

Reproduzir vídeo

TUTORIAL - PASSO 2: Atribuindo ao bot permissão de Administrador

1) Acesse o Telegram Web ou abra o app em seu celular
2) Crie um novo Grupo

Caso já possua um grupo para o qual suas estratégias encaminharão mensagens, vá para o Passo 3.

Neste primeiro momento, não iremos adicionar nenhum membro ao grupo. Clique no botão avançar no canto inferior direito.

Escolha um nome para o grupo que está criando. Nesse exemplo, utilizamos o nome “Grupo Teste”.

3) Inclusão do bot como membro do grupo

Selecione o grupo na listagem lateral esquerda. Em seguida, clique no cabeçalho superior onde há a informação do nome do grupo e quantidade de membros.

Será exibido um painel no lado direito da tela. Clique sobre o ícone de lápis no canto superior direito para abrir o painel de administração.

Em seguida clique no item “Members”, conforme demonstrado abaixo.

Uma vez exibida a listagem de membros atuais, clique no botão de adicionar novos membros no canto inferior direito.

Busque pelo nome do bot desejado. Como há muitos bots públicos, certifique-se de que está selecionando corretamente o bot que criou.

4) Atribua permissão de administrador ao bot

Agora que o bot já é membro do grupo, volte ao painel de administração e clique em “Administrators”.

Será exibida uma listagem com os atuais membros do grupo. Selecione o bot que acabou de adicionar como membro do grupo.

Em geral, não há necessidade de alterar as permissões já configuradas por padrão. Assim, clique na seta de voltar.

5) Certifique que seu bot é administrador do grupo

Ao voltar, você verá novamente a relação de administradores do grupo, onde deve constar o nome do bot e a observação de que você concedeu a permissão de administrador ao bot.

Próximo passo...

Já temos um bot do Telegram e um grupo para receber as mensagens das nossas estratégias da TraderEvolution.

O próximo passo, será identificar o ID do grupo que criamos, pois precisaremos desse ID para encaminhar as mensagens pela ferramenta de integração da NeoTraderBot.

Como obter IDs de Grupos

 

para enviarmos mensagens a partir de suas estratégias da TraderEvolution para um grupo do Telegram, precisamos identificar qual é o ID do grupo desejado, o qual criamos no passo anterior.

Reproduzir vídeo

TUTORIAL - PASSO 3: Identificando o ID dos grupos do Telegram

1) Acesse o Telegram Web ou abra o app em seu celular
2) Envie uma mensagem qualquer dentro do grupo

Para essa etapa é importante garantir que o seu bot é membro do grupo (fizemos isso no passo 2).

Vamos utilizar essa mensagem para localizar no histórico do bot, a partir de qual grupo (ID) a mensagem foi recebida.

3) Acesse o site www.hoppscotch.io

Este site gratuito nos fornece uma interface gráfica para realizarmos requisições web.

Vamos selecionar uma requisição do tipo POST para a URL: “https://api.telegram.org/bot<TOKEN>/getUpdates”.

Você lembra do token gerado pelo @botFather que pedi para guardar em lugar seguro!? Você deve substituir “<TOKEN>” pelo token do seu bot.

Em seguida, clique em “Mandar” ou “Send”, dependendo do idioma configurado em sua máquina.

4) Verificando o retorno da requisição web

A requisição que enviamos, caso esteja correta, será respondida com um primeiro campo “ok” com o valor “true”. Caso encontre algum erro nessa etapa, verifique a URL, pois possivelmente há algum erro na mesma ou quando colou o TOKEN de seu bot sobre o texto <TOKEN>.

Há um outro campo chamado “result” o que irá apresentar as atualizações de atividade mais recente do seu bot. Você deverá visualizar a mensagem que recebeu por meio do grupo criado.

Procure na resposta da requisição por um campo chamado “chat” (podem haver vários, caso tenham encaminhado mais de uma mensagem no grupo). Dentro desse campo haverá 3 subcampos: id, title e type.

Verifique se o campo title coincide com o nome do grupo que deseja encaminhar mensagens pela TraderEvolution. Caso positivo, o ID desse grupo estará no campo id (geralmente é um valor negativo).

Copie esse o valor do ID e o nome do grupo para um bloco de notas, preferencialmente, no mesmo local onde armazenou o token do seu bot. Vamos precisar dessas informações para configurar as estratégias a enviarem mensagens pelo bot para o grupo desejado.

Próximo passo...

No próximo passo iremos instalar a ferramenta de Integração TraderEvolution-Telegram, desenvolvida pela NeoTraderBot, na sua instalação da plataforma Trader Evolution.

Instalando a ferramenta na TraderEvolution

Nesse último passo de pré-configuração, iremos instalar a ferramenta da NeoTraderBot que permitirá integrar suas estratégias da TraderEvolution com grupos no Telegram.

Reproduzir vídeo

TUTORIAL - PASSO 4: Instalando a ferramenta de integração na TraderEvolution

1) Abra uma janela do Windows Explorer (Tecla de atalho: WINDOWS + E)
2) Acesse a pasta de aplicativos do seu usuário windows

Clique na barra de endereço do Windows Explorer, digite “%APPDATA%” e aperte ENTER.

3) Acesse a pasta da TraderEvolution

No diretório de aplicativos, localize a pasta “TraderEvolution Brasil” e acesse-a.

4) Cole o arquivo da ferramenta de integração dentro da pasta "TraderEvolution Brasil"

Você deverá colar o arquivo “NTB_TE_IntegrationTelegram.dll”, baixado no site da NeoTraderBot para dentro dessa pasta. Trata-se de uma biblioteca compilada da NeoTraderBot contendo os requisitos necessários para permitir a integração da TraderEvolution com Telegram.

Pré-configurações efetuadas!

Agora que já realizamos as pré-configurações, podemos incluir o código necessário dentro de nossas estratégias para realizar o envio de mensagens para o Telegram.

Confira aqui um tutorial com exemplos de código fonte para você incluir em suas estratégias e indicadores da TraderEvolution.

Perguntas Frequentes (FAQ) & Exemplos de Código

Nesta seção vamos apresentar exemplos de códigos e respostas às perguntas frequentes para que você comece a usar a integração com o Telegram de maneira mais rápida possível. Caso tenha alguma dúvida, deixe nos comentários que iremos atualizar esta seção de acordo com a demanda.

Como eu incluo a ferramenta de integração com o telegram no meu código?

O primeiro passo é instalar a ferramenta em sua plataforma TraderEvolution. Para isso, basta seguir o roteiro apresentado neste link.

Uma vez instalada a ferramenta, no seu código fonte você deve referenciar a biblioteca de Integração com Telegram (desenvolvida pela NeoTraderBot) na seção de using. Como segue abaixo:

				
					using NTB_IntegrationServices_TE;
				
			

Em seguida, instancie um objeto no para integraçao com o Telegram, conforme segue abaixo:

				
					TelegramIntegration telegramConn;
				
			

Por fim, no método Init do seu código, você pode utilizar a seguinte estrutura de inicialização da biblioteca de integração com o Telegram.

				
					try
    {
        string botToken = "INSIRA AQUI O TOKEN DO SEU BOT";
        string emailAutenticacao = "seuEmail@teste.com";
        string versaoFerramenta = "PREMIUM";
        telegramConn = TelegramIntegration.GetTelegramConn;
        telegramConn.Authenticate(emailAutenticacao, this.AccountManager.Current, versaoFerramenta);
        
        //Registra o robô, grupos e tópicos com suas IDs
        telegramConn.AddBot("NeoTraderBot", botToken);
        telegramConn.AddGroup("NeoTraderBot", "Meus códigos TraderEvolution", "-1001909578209");
        telegramConn.AddTopic("NeoTraderBot", "Meus códigos TraderEvolution", "Alarme Volatilidade", "124");
        telegramConn.AddTopic("NeoTraderBot", "Meus códigos TraderEvolution", "Carteira de ações", "2");
        telegramConn.AddTopic("NeoTraderBot", "Meus códigos TraderEvolution", "Screening Opening Range", "60");
        telegramConn.AddTopic("NeoTraderBot", "Meus códigos TraderEvolution", "Grid Trading", "57");
    }
    catch (Exception ex)
    {
        Notification.Alert("Não autenticou a ferramenta de integração com telegram: " + ex.Message);
    }
				
			

Pronto! Caso não haja problema na Autenticação do seu usuário no servidor da NeoTraderBot, você já poderá utilizar os métodos para envio de mensagens no seu código.

Ah…eu quero guardar o token do meu bot e ler a partir de um arquivo. Ok! Use o snippet abaixo, o qual fará a leitura do arquivo “meuTokenTelegram.txt” na pasta “Meus Documentos”. O arquivo contém unica e exclusivamente o token do bot.

				
								try
			{
				string botToken = "";
				string logPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "meuTokenTelegram.txt");
	            using (StreamReader inputFile = new StreamReader(logPath))
	            {
	            	botToken = inputFile.ReadLine();
	            }
				
			    string emailAutenticacao = "seuEmail@teste.com";
			    string versaoFerramenta = "FREE";
			    telegramConn = TelegramIntegration.GetTelegramConn;
			    telegramConn.Authenticate(emailAutenticacao, this.AccountManager.Current, versaoFerramenta);
			
			    //Registra o robô, grupos e tópicos com suas IDs
			    telegramConn.AddBot("NeoTraderBot", botToken);
			    telegramConn.AddGroup("NeoTraderBot", "Meus códigos TraderEvolution", "-1001909578209");
			}
			catch (Exception ex)
			{
			    Notification.Alert("Não autenticou a ferramenta de integração com telegram: " + ex.Message);
			}	
				
			

Quais são os métodos para envio de mensagens?

Uma vez instanciado um objeto, conforme instruções da pergunta anterior, você irá utilizar o método SendMessage para enviar mensagens para um grupo do Telegram ou tópicos dentro dos grupos.

Cabe ressaltar que você deve verificar se sua versão contratada possui a funcionalidade desejada. Por exemplo, a versão FREE não permite o envio de mensagens para tópicos específicos de um grupo. Ela permite o envio apenas para o tópico principal.

Assim, existem 2 sobrecargas para o método SendMessage: uma para envio de mensagem para um grupo e outra para envio de mensagem para tópico de um grupo.

OBS: É necessário adicionar as IDs e texto de identificação de grupos e tópicos, antes de enviar as mensagens. Pois os grupos e tópicos serão referenciados pelo texto de identificação fornecido.

Enviando mensagem para um Grupo | SendMessage(string botName, string groupName, string message)

No exemplo abaixo, estamos utilizando o objeto telegramConn para enviar uma mensagem utilizando o bot “NeoTraderBot” para o grupo “Meus códigos TraderEvolution”. A mensagem enviada é: “Teste de envio!”.

				
					telegramConn.SendMessage("NeoTraderBot", "Meus códigos TraderEvolution", 
                         "Teste de envio!");
				
			
Enviando mensagem para um Tópico | SendMessage(string botName, string groupName, string topicName, string message)

No exemplo abaixo, estamos utilizando o objeto telegramConn para enviar uma mensagem utilizando o bot “NeoTraderBot” para o tópico “Carteira de ações” do grupo “Meus códigos TraderEvolution”. A mensagem enviada é: “21/nov/2023 – Valor atual da carteira: R$ 89.780,00”.

				
					telegramConn.SendMessage("NeoTraderBot", "Meus códigos TraderEvolution", 
                         "Carteira de ações", 
                         "21/nov/2023 - Valor atual da carteira: R$ 89.780,00");
				
			

Posso enviar emojis nas mensagens de texto?

Sim, claro! Talvez você queira utilizar elementos visuais em suas mensagens de texto. Você pode utilizar os códigos padronizados de emojis os quais estão disponíveis em diversos sites. 

Você pode utilizar o https://emojipedia.org/ como referencia ou copiar as figuras abaixo e colar nas suas mensagens.

OBS: A renderização do emoji (figura a ser desenhada) depende do ambiente no qual está utilizando (Windows/Mac/Telegram/Facebook/Twitter…).

TEMPO:

⏰  ⏲️  ⏳

PERCEPÇÃO DO MERCADO:

🌡️   🔥   🚀  💣 😱  ❄️ 🛒

TENDÊNCIA:

🔼 🔻 📉  📈

DESTAQUES:

⭐ 👀 🔎

ANÚNCIOS:

📢 🔔

ALERTAS:

⚠️  ⛔  🛑  🟢  🔴  🔵  🟡  🟠

RESULTADO:

💰  🤑  💲 🎉 💀 💩

Eu posso enviar imagens (arquivos jpg, png,...)?

Sim. Assim como o método SendMessage permite enviar mensagens de texto, o método SendPicture permite enviar mensagens contendo imagens e uma legenda.

Também há duas sobrecargas do método SendPicture para diferenciar o envio para grupo e tópicos específicos dentro de um grupo.

Veja o exemplo abaixo no qual é enviada uma mensagem contendo uma figura localizada na máquina local (em C:\\Users\\johna\\OneDrive\\Documents\\bulls_bears.jpg) com a legenda “Aqui você escreve o caption!” para o grupo “Meus códigos TraderEvolution” utilizando o bot “NeoTraderBot”.

				
					telegramConn.SendPicture("NeoTraderBot", "Meus códigos TraderEvolution", 
                         "C:\\Users\\johna\\OneDrive\\Documents\\bulls_bears.jpg", 
                         "Aqui você escreve o caption!");
				
			

Por questões de segurança, não é possível referenciar URLs de imagens na internet para envio de mensagens. Assim, recomendamos que baixe as imagens e salve em um diretório local para referenciar em seus códigos.

Não estou conseguindo enviar mensagens. O que pode estar acontecendo?

Caso ocorra alguma inconsistência no envio de alguma mensagem, a biblioteca de integração com o telegram foi projetada para não lançar exceções a fim de não causar distúrbios na execução dos códigos do usuário. Assim, para identificar o problema precisamos eliminar as causas de maneira gradativa.

1) Problemas relacionados à Autenticação do usuário

A primeira causa para você não conseguir enviar mensagens seria algum problema relacionado ao processo de autenticação da ferramenta vinculado ao e-mail e conta do usuário. Certifique-se que a autenticação está ocorrendo adequadamente.

Caso haja alguma falha de comunicação com o servidor de autenticação ou o usuário não esteja cadastrado, isso irá gerar uma exceção ainda no método Init, antes do código iniciar o processamento.

2) Problemas relacionados ao cadastro de token do Bot

Certifique-se de que você está inserindo o token do seu Bot Telegram por meio do método AddBot com o token correto. Atente-se para as funcionalidades da sua versão contratada, pois pode haver limitação da quantidade de bots a serem utilizados em um único código.

3) Permissões do Bot nos grupos destinatários

É importante verificar se você atribuiu as permissões necessárias ao Bot dentro dos grupos destinatários. Clique aqui para ver um roteiro passo a passo de como atribuir corretamente as permissões nos grupos.

4) Problemas relacionados a vinculação de ID para grupos e tópicos

Certifique-se de que você está inserindo os IDs de grupos e seus respectivos textos de identificação (método AddGroup). Ao enviar mensagens, o destinatário deverá ser referenciado pelo mesmo texto identificador. Clique aqui para ver um roteiro passo a passo de como identificar os IDs de grupos e tópicos.

Somente após cadastrar os grupos é que você deve inserir os tópicos do grupo, utilizando o método AddTopic.

Atente-se para as restrições da sua versão em uso, pois podem haver limitações de envio para mais de um grupo ou tópicos dentro dos grupos.

Por fim, certifique-se que as IDs de grupos e tópicos foram devidamente incluídas nos métodos AddGroup e AddTopic.

Sugestão: Inicie um código simples de indicador e insira apenas o código necessário para instanciar a sua conexão com a ferramenta de integração do Telegram e enviar uma única mensagem para um grupo. Uma vez validado esse funcionamento básico, você pode ir aos poucos incluindo outras tarefas no código e copiar essa estrutura para dentro dos seus códigos que deseja integrar com o Telegram.

Como enviar mensagens apenas quando minha estratégia/robô estiver analisando dados em tempo real?

Este controle de fluxo deve ser implementado pelo próprio usuário, pois a ferramenta foi criada para ser flexivel o suficiente para rodar em dados históricos em casos de inicializações com o mercado já aberto e envio de informações referentes a por exemplo a abertura do mercado.

Você possivelmente sabe que o código é processado algumas vezes para cada barra histórica, iniciando na barra mais antiga de dado disponível. As barras são percorridas sequencialmente até chegarmos a última barra, a qual se o mercado estiver aberto, estará sendo atualizada em tempo real.

Assim, para criar um controle de fluxo, no qual você irá enviar mensagens pelo Telegram apenas na última barra do gráfico, ou seja, na barra em tempo real, precisamos declarar uma variável auxiliar no seu código, conforme segue abaixo:

				
					private bool realTime;
				
			

Em seguida, insira no método Update de seu código a estrutura abaixo. Ela permitirá identificar em que momento seu código passará a processar barras em tempo real. Assim, basta você inserir a ação que deseja executar no fechamento da barra ou a cada nova cotação.

				
					public override void Update(TickStatus args)
{
    if (!realTime && (args == TickStatus.IsBar))
    { realTime = true; }
    else
    {
        if (args == TickStatus.IsQuote)   
        {
            //Insira aqui o que deseja executar sempre que tem nova cotação
        }
        else
        if (args == TickStatus.IsBar)
        {
            //Insira aqui o que deseja executar no fechamento da barra
        }
    }
}
				
			

Como eu posso fazer minha estratégia mandar mensagens pelo Telegram?

O código de estratégia abaixo é meramente ilustrativo, mas você pode copiar e rodar em sua conta de simulação na Trader Evolution. O que ele faz basicamente é a cada timeSpaceMinutes (parâmetro da estratégia) verificar se há uma posição aberta e se não houver a estratégia irá comprar ou vender (aleatoriamente) colocando ordens de stop e alvo em ticks, conforme definido nos parâmetros.

As mensagens enviadas para o telegram, nesse caso, foram realizadas sempre que uma ordem é posicionada e executada, bem como quando uma posição é aberta e encerrada. No exemplo, utilizamos sobrecarga de métodos nos eventos já disponíveis no EvoCode. Mas você pode encaminhar mensagens pelo Telegram nas condições que desejar.

				
					using System;
using Runtime.Script;
using TradeApi;
using TradeApi.History;
using TradeApi.Instruments;
using TradeApi.ToolBelt;
using TradeApi.Trading;
using NTB_IntegrationServices_TE;

namespace NeoTraderBotExemplos
{
    public class TimeSpacedOrdersExample : StrategyBuilder
    {
        [InputParameterAttribute(InputType.Color, "Abrir posição a cada (minutos)", 2)]
        [SimpleNumeric(1D, 2400D)]
        public int timeSpaceMinutes = 2;

        [InputParameterAttribute(InputType.Color, "Tamanho da exposição", 3)]
        [SimpleNumeric(1D, int.MaxValue)]
        public int orderQty = 1;

        [InputParameterAttribute(InputType.Color, "OCO - Stoploss (TICKS)", 4)]
        [SimpleNumeric(1D, int.MaxValue, 0, 1)]
        public int stoplossTicks = 10;

        [InputParameterAttribute(InputType.Color, "OCO - Take profit (TICKS)", 5)]
        [SimpleNumeric(1D, int.MaxValue, 0, 1)]
        public int takeProfitTicks = 10;

        TelegramIntegration telegramConn;

        BarData dadosCandle;
        private bool realTime;
        private double positionSize;
        private Random rndSignal;
        public TimeSpacedOrdersExample()
            : base()
        {
            #region Initialization
            Credentials.Author = "Johnathas Carvalho";
            Credentials.Company = "NeoTraderBot";
            Credentials.Copyrights = "NeoTraderBot";
            Credentials.DateOfCreation = new DateTime(2023, 10, 07);
            Credentials.ExpirationDate = DateTime.MinValue;
            Credentials.Version = "1.0";
            Credentials.Password = "66b4a6416f59370e942d353f08a9ae36";
            Credentials.ProjectName = "Estratégia integrada com Telegram";
            #endregion

            SeparateWindow = false;
        }
        public override void Init()
        {
            try
            {
                string botToken = "INSIRA SEU TOKEN AQUI";
                telegramConn = TelegramIntegration.GetTelegramConn;
                telegramConn.Authenticate("seuEmail@gmail.com", this.AccountManager.Current, "SUA VERSAO CONTRATADA");
                telegramConn.AddBot("NeoTraderBot", botToken);
                telegramConn.AddGroup("NeoTraderBot", "Meus códigos TraderEvolution", "INSIRA O ID DO SEU GRUPO AQUI");
            }
            catch (Exception ex)
            {
                Notification.Alert("Não autenticou a ferramenta de integração com telegram: " + ex.Message);
            }

            dadosCandle = (HistoryDataSeries as BarData);
            realTime = false;

            OrdersManager.OnFill += OnOrderFill;
            OrdersManager.OnPlace += OnOrderPlaced;
            PositionsManager.OnOpen += OnOpenPosition;
            PositionsManager.OnClose += OnClosePosition;

            //Gestão de posição
            positionSize = 0;
            
            //Geração de sinais aleatórios
            rndSignal = new Random();

        }

       public override void Update(TickStatus args)
        {

            if (!realTime && (args == TickStatus.IsBar))
            {
                realTime = true;
            }

            if (realTime)
            {
                if (args == TickStatus.IsQuote)   //Atua sempre que tem nova cotação
                {
                    
                }
                else
                if (args == TickStatus.IsBar)    //Atua no fechamento da barra
                {
                    positionSize = GetPositionSize();

                    if ((positionSize == 0) && ( ((dadosCandle.GetTimeUtc().TimeOfDay.TotalMinutes - 9*60) % timeSpaceMinutes) == 0))
                    {
                        if (rndSignal.Next(0, 2) == 0)
                            BuyAtMarket(orderQty, CalculationMode.TICKS, takeProfitTicks, stoplossTicks);
                        else SellAtMarket(orderQty, CalculationMode.TICKS, takeProfitTicks, stoplossTicks);
                    }
                }
            }
        }

        public override void Complete()
        {
            OrdersManager.OnFill -= OnOrderFill;
            OrdersManager.OnPlace -= OnOrderPlaced;

            PositionsManager.OnOpen -= OnOpenPosition;
            PositionsManager.OnClose -= OnClosePosition;

            telegramConn.SendMessage("NeoTraderBot", "Meus códigos TraderEvolution", "A estratégia exemplo de ordens espaçadas no tempo foi encerrada.");
        }

        private TradeResult BuyAtMarket(int qty, CalculationMode mode, double takeProfitUnits, double stoplossUnits)
        {
            OrderRequest request = null;
            TradeResult order;

            request = new OrderRequest(OrderType.Market,
                InstrumentsManager.Current,
                AccountManager.Current,
                OrderSide.Buy, quantity: qty)
            {
                SLTPPriceType = SLTPPriceType.Ticks,
                StopLossPrice = stoplossUnits,
                TakeProfitPrice = takeProfitUnits
            };

            order = OrdersManager.Send(request);
            return order;
        }

        private TradeResult SellAtMarket(int qty, CalculationMode mode, double takeProfitUnits, double stoplossUnits)
        {
            OrderRequest request = null;
            TradeResult order;

            request = new OrderRequest(OrderType.Market,
                InstrumentsManager.Current,
                AccountManager.Current,
                OrderSide.Sell, quantity: qty)
            {
                SLTPPriceType = SLTPPriceType.Ticks,
                StopLossPrice = stoplossUnits,
                TakeProfitPrice = takeProfitUnits
            };

            order = OrdersManager.Send(request);
            return order;
        }

        private void ClosePositions()
        {
            OrderRequest request = null;

            foreach (Position p in PositionsManager.GetPositions())
            {
                request = new OrderRequest(OrderType.Market, InstrumentsManager.Current, AccountManager.Current, (p.Side == PositionSide.Long) ? OrderSide.Sell : OrderSide.Buy, p.Quantity);
                OrdersManager.Send(request);
            }
        }

        private double GetPositionSize()
        {
            double posSize = 0;
            foreach (Position p in PositionsManager.GetPositions(po => po.Instrument == InstrumentsManager.Current))
            {
                Notification.Alert("Posição é de " + p.Quantity);
                posSize += ((p.Side == PositionSide.Long) ? 1 : -1) * p.Quantity;
            }

            return posSize;
        }


        #region callback for Orders and Position events
        private void OnOrderFill(Order order)
        {
            double price = (AccountManager.Current.Name.ToUpper().Contains("DEMO")) ? order.Price : order.AverageFilledPrice;
            double quantity = (AccountManager.Current.Name.ToUpper().Contains("DEMO")) ? order.Quantity : order.FilledQuantity;

            string msg = "Foi executada uma " + ((order.Side == OrderSide.Buy) ? "compra" : "venda") + $" de {quantity} @ {price}";
            telegramConn.SendMessage("NeoTraderBot", "Meus códigos TraderEvolution", ((order.Side == OrderSide.Buy) ? "🔼" : "🔻") + " " + msg);
        }

        private void OnOrderPlaced(Order order)
        {
            double price = order.Price;
            double quantity = order.Quantity;

            string msg = "Foi apregoada uma ordem de " + ((order.Side == OrderSide.Buy) ? "compra" : "venda") + $" de {quantity} @ {price}";
            telegramConn.SendMessage("NeoTraderBot", "Meus códigos TraderEvolution", "👀" + " " + msg);
        }

        private void OnOpenPosition(Position position)
        {
            string msg = "Foi aberta uma posição " + ((position.Side == PositionSide.Long ? "comprada" : "vendida")) + $" de {position.Quantity} @ {position.OpenPrice}";
            telegramConn.SendMessage("NeoTraderBot", "Meus códigos TraderEvolution", "⚠️" + " " + msg);
        }

        private void OnClosePosition(Position position)
        {
            string msg = "Foi encerrada uma posição " + ((position.Side == PositionSide.Long ? "comprada" : "vendida")) + $" de {position.Quantity} com resultado líquido de {position.NetPnL}";
            telegramConn.SendMessage("NeoTraderBot", "Meus códigos TraderEvolution", ((position.NetPnL >= 0) ? "🟢" : "🔴") + " " + msg);

        }

        #endregion

        private enum CalculationMode
        {
            PRICE,
            TICKS,
            PERCENTAGE,
        }

    }
}
				
			

Como obter IDs de Grupos

 

para enviarmos mensagens a partir de suas estratégias da TraderEvolution para um grupo do Telegram, precisamos identificar qual é o ID do grupo desejado, o qual criamos no passo anterior.

Reproduzir vídeo

TUTORIAL - PASSO 3: Identificando o ID dos grupos do Telegram

1) Acesse o Telegram Web ou abra o app em seu celular
2) Envie uma mensagem qualquer dentro do grupo

Para essa etapa é importante garantir que o seu bot é membro do grupo (fizemos isso no passo 2).

Vamos utilizar essa mensagem para localizar no histórico do bot, a partir de qual grupo (ID) a mensagem foi recebida.

3) Acesse o site www.hoppscotch.io

Este site gratuito nos fornece uma interface gráfica para realizarmos requisições web.

Vamos selecionar uma requisição do tipo POST para a URL: “https://api.telegram.org/bot<TOKEN>/getUpdates”.

Você lembra do token gerado pelo @botFather que pedi para guardar em lugar seguro!? Você deve substituir “<TOKEN>” pelo token do seu bot.

Em seguida, clique em “Mandar” ou “Send”, dependendo do idioma configurado em sua máquina.

4) Verificando o retorno da requisição web

A requisição que enviamos, caso esteja correta, será respondida com um primeiro campo “ok” com o valor “true”. Caso encontre algum erro nessa etapa, verifique a URL, pois possivelmente há algum erro na mesma ou quando colou o TOKEN de seu bot sobre o texto <TOKEN>.

Há um outro campo chamado “result” o que irá apresentar as atualizações de atividade mais recente do seu bot. Você deverá visualizar a mensagem que recebeu por meio do grupo criado.

Procure na resposta da requisição por um campo chamado “chat” (podem haver vários, caso tenham encaminhado mais de uma mensagem no grupo). Dentro desse campo haverá 3 subcampos: id, title e type.

Verifique se o campo title coincide com o nome do grupo que deseja encaminhar mensagens pela TraderEvolution. Caso positivo, o ID desse grupo estará no campo id (geralmente é um valor negativo).

Copie esse o valor do ID e o nome do grupo para um bloco de notas, preferencialmente, no mesmo local onde armazenou o token do seu bot. Vamos precisar dessas informações para configurar as estratégias a enviarem mensagens pelo bot para o grupo desejado.

Próximo passo...

No próximo passo iremos instalar a ferramenta de Integração TraderEvolution-Telegram, desenvolvida pela NeoTraderBot, na sua instalação da plataforma Trader Evolution.

Como instalar o Pacote de Indicadores GRATUITOS?

Se você está nessa página é porque provavelmente recebeu um e-mail contendo as instruções para instalação do PACOTE DE INDICADORES GRATUITOS para TRADER EVOLUTION desenvolvidos pela NeoTraderBot e RNEC indicadores.

Caso queira baixar o pacote de indicadores, clique no botão abaixo.

Localizando o diretório de instalação da Trader Evolution

1) Acesse o Windows Explorer e digite na barra de navegação %APPDATA% e aperte ENTER. Localize o diretório “Trader Evolution Brasil”.

2) Dentro do diretório “Trader Evolution Brasil” acesse as pastas “Scripts” -> “Indicadores”.

3) Dentro da pasta “Indicators” você irá visualizar os indicadores da Trader Evolution instalados nativamente em seu computador. Devemos extrair o conteúdo do arquivo zip do PACOTE DE INDICADORES para esta pasta.

4) Pronto! Agora os indicadores já podem ser aplicados aos gráficos dentro da Plataforma Trader Evolution!

Estratégias

Gestão de risco do robô

Nesse grupo de parâmetros, pode-se configurar alguns aspectos da gestão de risco do robô, tais a interrupção do robô após uma quantidade máxima de trades no dia, ou de trades com prejuízo (consecutivos ou não). Também é possível configurar um stoploss temporizado em função da quantidade de barras após a abertura da posição.

pHabilitaLimiteQtdeTrades (boolean)

Quando true, e estando o robô-trader no modo DayTrade, não serão permitidas mais operações do que a quantidade informada no parâmetro pQtdeMaxOperacoesDiarias. Desta forma, a estratégia será interrompida uma vez que tenham sido realizadas a quantidade de operações definada no parâmetro pQtdeMaxOperacoesDiarias. 

Caso este parâmetro seja false, ou o robô-trader não esteja no modo DayTrade, a quantidade informada em pQtdeMaxOperacoesDiarias será desconsiderada.

pQtdeMaxOperacoesDiarias (integer)

Este parâmetro refere-se a quantidade limite de operações diárias quando o robô-trader estiver no modo DayTrade e pHabilitaLImiteQtdeTrades receber o valor true.

pHabilitaLimiteTradesPrejuizo (boolean)

Quando true, e estando o robô-trader no modo DayTrade, a estratégia não irá mais abrir posições no dia, caso tenha sido atingido o limite total de posições encerradas com prejuízo (definido no parâmetro pQtdeMaxTradesPrejuizoPorDia) ou o limite de posições encerradas consecutivamente com prejuízo (definido no parâmetro pQtdeMaxTradesPrejuizo ConsecutivosPorDia). 

Caso este parâmetro seja false, ou o robô-trader não esteja no modo DayTrade, as quantidades informadas nos parâmetros pQtdeMaxTradesPrejuizoPorDia epQtdeMaxTradesPrejuizoConsecutivosPorDia serão desconsideradas.

pQtdeMaxTradesPrejuizoPorDia (integer)

Este parâmetro refere-se a quantidade total limite de operações diárias com prejuízo quando o robô-trader estiver no modo DayTrade e pHabilitaLimiteTradesPrejuizo receber o valor true.

pQtdeMaxTradesPrejuizoConsecutivosPorDia (integer)

Este parâmetro refere-se a quantidade limite de operações consecutivas e diárias com prejuízo quando o robô-trader estiver no modo DayTrade e pHabilitaLimiteTradesPrejuizo receber o valor true.

pHabilitaStopTemporizado (boolean)

Quando true, as operações serão encerradas após a quantidade de barras definida no parâmetro pQtdeBarrasStopTemporizado. 

Esta funcionalidade aplica-se tanto ao modo daytrade ou swing trade.

pQtdeBarrasStopTemporizado (integer)

Este parâmetro refere-se a quantidade limite de barras para uma posição aberta. A contagem inclui a barra de abertura da posição.

Por exemplo, se o valor desse parâmetro for 3, a posição será encerrada na 2 barra após a barra de abertura da posição, caso a posição não tenha sido encerrada anteriormente por atingir o stop ou alvo.

Ordens OCO - RG Fixo

A administração das posições pode ser realizada por meio de ordens OCO (One-Cancel-Others) de stoploss e alvo, conforme demonstrado na figura abaixo (a qual aplicou-se também o stoploss Breakeven concomitantemente).

A vantagem de utilizar as ordens OCO é o gerenciamento automático da plataforma em relação ao cancelamento da ordem na ponta contrária à ordem executada. Por exemplo, se sua operação atingir o alvo, a ordem de stoploss é automaticamente cancelada.

Caso o usuário não utilize esta fucionalidade, as operações pode ser revertidas por meio do sinal de reversão (bSinalReversao) ou encerradas por meio do sinal bSinalEncerramento, a serem definidos pelo usuário.

Diferentemente da execução dos sinais que ocorrerá por ordens a mercado no fechamento da barra, as ordens OCO são apregoadas e, portanto, executadas quando o preço é atingido. A ordem de stoploss será sempre uma ordem do tipo stop (passível de slippage devido à sua natureza), enquanto as ordens de alvo será do tipo limitadas (compondo o book de ofertas).

pOCO_RGFixo (boolean)

Quando true, este parâmetro irá habilitar a funcionalidade de ordens OCO de stoploss e alvo. Uma vez aberta uma posição, o usuário irá observar na linha branca o preço médio de sua posição, na linha vermelha a posição do stoploss e na linha azul a posição do alvo.

Obs: as linhas no gráfico serão plotadas apenas se o usuário configurar o parâmetro pPlotarLinhasOCO para true.

pStopFixoEmTicks (integer)

Este parâmetro é utilizado para definir o stoploss inicial da operação em relação ao preço médio na unidade de ticks. Por exemplo, no caso do mini-contrato de índice, um tick possui 5 pontos. Assim, caso o stop desejado seja de 50 pontos, isto representa 10 ticks.

Se o usuário habilitar a funcionalidade de Stop Breakeven, o stop inicialmente configurado será deslocado caso o gatilho de breakeven seja atingido.

pAlvoFixoEmTicks (integer)

Este parâmetro é utilizado para definir o alvo das operações em função do preço médio da posição na unidade de ticks. 

Por exemplo, no caso de um operação no mini-contrato de dólar, onde cada tick equivale a 0,5 pontos. Caso o usuário deseje um alvo de 10 pontos, isto será representado por 20 ticks.

Aula 03 - Controles de Fluxo

Controles de fluxo (Loops) são essenciais em programação. Nesta aula veremos:

Reproduzir vídeo

1. Introdução

Se na vida sempre chega uma hora que não dá para seguir o fluxo e temos que tomar decisões importantes, na programação isso acontece quase o tempo todo!

Lembra-se da parte da definição de algoritmo que diz ser uma sequência finita de ações!? Então…os programas são estruturados para serem executados de forma sequencial, eles seguem um fluxo que inicia na primeira linha de código e vai executando cada linha até chegar a última linha (a sequência precisa ser finita, ou seu computador vai ficar travado….rsrsrs)!

Se não pudéssemos alterar este fluxo, certamente a nossa capacidade de resolver problemas por meio de algoritmos seria muito reduzida. Assim, sistematizou-se a programação com estruturas básicas de controle de fluxo (ou Loops em inglês), as quais dividem-se em dois grandes grupos: CONTROLES DE SELEÇÃO e CONTROLES DE REPETIÇÃO. Vamos ver a seguir o que significa cada tipo de controle e como é sua estrutura.

2. Controles de seleção

Em nossas vidas, é muito comum condicionarmos as nossas ações à determinadas situações ou eventos. Você já deve ter pego a si mesmo dizendo algo do tipo: “Se eu ganhar na megasena eu compraria …”? Isso é um exemplo de controle de fluxo de seleção porque existe uma condição que é “ganhar na megasena”. SE essa condição for verdadeira, iremos SELECIONAR uma ação ou mais para serem executadas, no caso: “comprar alguma coisa”. Naturalmente que é muito improvável que este exemplo de condição seja verdadeira…mas não custa nada sonhar!

Sempre que dissermos condição podemos estar tratando na verdade de uma fórmula booleana tão complexa quanto fosse necessário…por exemplo: Se eu ganhar na megasena E (não tivesse filhos OU não fosse casado(a)), eu iria viajar 2 anos pelo mundo!

Dizem que para entendermos melhor basta desenhar…vamos tentar então! Veja a figura abaixo, ela é a estrutura básica de um controle de seleção. É a famosa estrutura if, em português: se!

A estrutura de fluxo do tipo if serve para realizar alguma ação dada que uma condição foi satisfeita, ou seja, é verdadeira. Se a condição for falsa, o programa continuará sua execução até o fim.

Podemos elaborar um pouco mais essa estrutura de seleção resultando na estrutura if..else (se…senão). Nessa estrutura além de um conjunto de ações ser executado se a condição for verdadeira, caso a condição seja falsa, é executado outro conjunto de ações, antes que o programa continue até o fim. Em diagrama, a estrutura if…else é representada da seguinte forma:

A partir dessa estrutura básica if…else, poderíamos colocar estruturas if…else dentro de uma estrutura if…else. Isso é o que chamamos em programação de aninhar (veja um exemplo na figura abaixo).

Ou seja, poderíamos aninhar uma estrutura if…else na parte else de outra estrutura, quantas vezes desejássemos (também poderia-se aninhar na parte if). Vamos a um exemplo abaixo em homenagem ao dia dos pais:

				
					definirPresenteDiaDosPais(Idade_pai: Integer:
  IF Idade_pai >= 20 AND Idade_pai <= 25:
     presente = comprar(“carteira”);
  ELSE
    IF Idade_pai > 25 AND Idade_pai <= 35:
      presente = comprar(“camiseta/calça”);
    ELSE
      IF Idade_pai > 35 AND Idade_pai <= 45:
        presente = comprar(“kit_ferramentas”);
      ELSE
        IF Idade_pai > 45 AND Idade_pai <= 55:
          presente = comprar(“conjunto_churrasco”);
        ELSE
          IF Idade_pai > 55 AND Idade_pai <= 65:
            presente = comprar(“sapato”);
          ELSE
            presente = comprar(“meias”);

  return presente;
				
			

Nada muito complicado, certo!? Mas o aninhamento descrito acima poderia ser escrito em uma sintaxe de melhor compreensão, que é a estrutura switch. É importante ressaltar que esse tipo de estrutura não está presente em todas as linguagens. Se fossemos reescrever o algoritmo acima utilizando a estututura switch, seria assim:

				
					definirPresenteDiaDosPais(Idade_pai: Integer:
  switch(Idade_pai):
    case Idade_pai >= 20 AND Idade_pai <= 25:
      presente = comprar(“carteira”);
    case Idade_pai > 25 AND Idade_pai <= 35:
      presente = comprar(“camiseta/calça”);
    case Idade_pai > 35 AND Idade_pai <= 45:
      presente = comprar(“kit_ferramentas”);
    case Idade_pai > 45 AND Idade_pai <= 55:
      presente = comprar(“conjunto_churrasco”);
    case Idade_pai > 55 AND Idade_pai <= 65:
      presente = comprar(“sapato”);
    default:
      presente = comprar(“meias”);
   end switch;

  return presente;
				
			

Com isso encerramos o que precisamos saber sobre estruturas de controle de fluxo de seleção. Espero que tenha entendido os conceitos até o momento!

3. Controles de repetição

Às vezes, para resolver determinado problema, precisamos repetir uma sequência de ações até que uma situação seja alcançada. Para estes casos, iremos utilizar os controles de repetição, cuja ideia geral está apresentada na figura abaixo:

Basicamente, enquanto uma condição for verdadeira, iremos executar algumas ações repetidamente. Após cada execução desse conjunto de ações, iremos verificar novamente se a condição é verdadeira, se for falsa o interromperá o loop de repetição e seguirá sua execução. Os tipos mais comuns de controles de repetição que encontramos nas linguagens de programação são: FOR e WHILE.

A estrutura FOR é geralmente utilizada quando queremos passar por uma sequência de dados e fazer algum tipo de operação para cada elemento. Em linguagem mais técnica, o processo de percorrer uma sequência de dados chama-se iterar.

No caso da estrutura FOR, geralmente temos uma variável inteira que inicia com determinado valor, e a cada execução do controle FOR esse valor é somado/subtraído de um passo (valor constante) até que chegue a um valor limite. Ou seja a quantidade de repetições é dada em função dessa variável que chamamos de iterador e seus limites inferior, superior e passo.

Por exemplo, vamos supor que tenhamos um array chamado NATURAIS, de números inteiros de 1 a 10, ou seja 10 elementos. Vamos supor ainda que tenhamos uma variável inteira chamada i, que é um índice para iterarmos sobre os valores do array. O primeiro elemento do array pode ser referenciado como NATURAIS[i] se i for igual a 1, e o valor de NATURAIS[1] é 1. Logicamente, o último elemento da lista será NATURAIS[10] e seu valor será 10.

Caso desejássemos obter o somatório de todos elementos do array, poderíamos utilizar o seguinte algoritmo:

				
					
soma = 0;
for i=1 until 10 step 1 do:
  soma = soma + NATURAIS[i];
				
			

Fácil, né!? Em linguagens de programação mais antigas, os iteradores eram apenas números inteiros. Algumas linguagens mais recentes permitem iterar de maneiras mais naturais e você certamente aprenderá esses detalhes mais específicos quando escolher uma linguagem para trabalhar.

A segunda estrutura de controle que utilizamos com frequência é WHILE. Nessa estrutura não temos um iterador explícito. Temos apenas a avaliação de uma condição que enquanto for verdadeira irá executar as ações previstas dentro do controle WHILE. Quando a condição se tornar falsa, o programa voltará ao seu fluxo de execução até o final.

Vamos a um exemplo simples…Suponha que queiramos “imprimir” na tela os números de 1 a 100. Você certamente pensou que podemos fazer isso facilmente com um controle FOR, mas vamos exercitar fazer isso com um controle WHILE:

				
					i = 1;
WHILE(i <= 100)
{
  Imprimir(i);
  i = i + 1;
}

				
			

Nas linguagens mais antigas havia variações da estrutura WHILE. Por exemplo, tem uma estrutura que se chama DO…WHILE, a qual executa primeiro as ações do controle WHILE antes de fazer a verificação da condição. Com isso, o controle de repetição é executado sempre ao menos uma vez. Novamente, não precisamos nos preocupar com essas peculiaridades, pois cada linguagem, embora haja muita semelhança entre elas, possuí sintaxes e características diferentes. E é mais oportuno aprofundar nisso quando você decidir por uma linguagem de programação para estudar.

4. Recapitulando

Tentamos ao longo dessa aula passar os conceitos gerais do que são os controles de fluxo sem entrar em detalhes específicos de linguagem de programação. É muito importante que tenhamos o entendimento do que são os controles de fluxo e como podemos utilizá-los para resolver problemas. Enquanto os controles de seleção nos permitem executar ações quando determinada condição (ou expressão booleana) for verdadeira, os controles de repetição nos permitirão repetir a execução de ações enquanto uma condição for verdadeira.

Ressaltei que neste momento, você não precisa se preocupar com peculiaridades de programação, pois você terá a oportunidade de aprender em maior profundidade quando escolher uma linguagem específica para trabalhar.

Como obter o MachineID da minha NinjaTrader?

Este tutorial visa apresentar o passo a passo para gerar um MachineID da sua NinjaTrader. Uma vez adquirido qualquer add-on, esta chave deve ser informada à NeoTraderBot para ativação do uso do add-on em sua máquina.

Gerando o seu MachineID

Passo 1: No Control Center, clique em “Help” -> “3rd Party Licensing”.

Passo 2: Na tela que abrir, você deve digitar “NeoTraderBot” no campo “Vendor name” e inserir o seu e-mail no campo “User defined ID”, ou em caso de erro por caracteres especiais, insira o seu nome completo sem espaços ou acentos. Em seguida, clique em “Submit”.

Será gerado uma chave de Machine ID, a qual você deve copiar e enviar para nós, por meio do formulário a seguir. Copie a chave completa (ela será composta também pelas informações que você inseriu no campo User defined ID (ID do usuário).

Ativando as ferramentas/add-ons com MachineID

Passo 1: Caso tenha adquirido a licença de uso de alguma ferramenta, contratado a assinatura ou serviço de programação da NeoTraderBot, informe pelo formulário abaixo as suas informações para fins de liberação de uso do código baixado/enviado para o seu e-mail.

OBS: Para o período de 7 dias de teste das ferramentas, não é obrigatório o envio do Machine ID. Uma vez enviado o Machine ID, iremos liberar o uso da ferramenta em um prazo máximo de 1 dia útil.

Liberação de Acesso NinjaTrader
Este formulário visa recepcionar as chaves dos usuários para liberação de uso das ferramentas e códigos desenvolvidos pela NeoTraderBot

Gráficos na TraderEvolution [PARTE 1- Configuração e Funcionalidades]

Reproduzir vídeo

Neste vídeo da séria “Conhecendo a Trader Evolution” vamos explorar as configurações e funcionalidades básicas de Gráficos. Vamos ver como configurar a série de dados do gráfico, a representação gráfica, o tamanho da janela histórica, como personalizar as cores de barras, fundo e outra propriedades.

Também veremos como incluir o volume das barras, adicionar o Volume Profile e Livro visual no gráfico. Ao final, demonstraremos como salvar um modelo de gráfico para ser reutilizado posteriormente e onde os arquivos de templates ficam armazenados.

Caso queira fazer o download da configuração realizada nesse vídeo, basta baixar o arquivo abaixo e descompactar na pasta indicada no vídeo.

      🤖 https://github.com/johnathas/NeoTrade…

Biblioteca NeoTraderBot

Apresentação

A Biblioteca NeoTraderBot foi desenvolvida com o objetivo de facilitar a implementação de estratégias e indicadores em EvoCode.

Assim, o trader pode dedicar mais tempo ao desenvolvimento de estratégias do que quebrando a cabeça para resolver problemas de código fonte ou tentando descobrir como executar determinadas tarefas.

Neste repositório você irá encontrar a documentação de todas as funções da Biblioteca com exemplos de uso.

Aguarde…em implementação!

 

Tipos de estratégias

Reproduzir vídeo

Neste documento vamos conhecer os tipos de estratégias que podem ser automatizadas no Profit Chart, para que serve cada estratégia, se é possível automatizá-las sem programação e serão apresentados exemplos para que fique bem clara a explicação. A ideia é que você tenha um panorama geral das possibilidades dentro do Profit Chart, pois em outros documentos iremos aprofundar em detalhes sobre como programar cada tipo de estratégia!

Caso tenha algum interesse por um tipo específico de estratégia, utilize o menu lateral direito para ir direto ao ponto desejado.

Então vamos começar tentando estruturar de uma forma mais simples o que seriam as estratégias principais e secundárias. Esta divisão foi criada por mim apenas para facilitar o entendimento. As estratégias principais são aquelas que estão diretamente relacionadas a setups operacionais, motivo que as tornam bastante difundidas e utilizadas. Já as estratégias secundárias, as quais são tão importantes quanto as principais, são relacionadas a outros aspectos de trading, tais como seleção de ativos,  gestão de risco, alarmes e tarefas mais simples como escrever texto em gráficos. Gostaria de ressaltar que as estratégias secundárias são tão importantes quanto às principais, sendo esta classificação adotada apenas para fins didáticos.

Estratégias Principais:

Estratégias Secundárias:

Vamos apresentar a seguir a definição e informações de cada tipo  de estratégia do Profit Chart.

Estratégia de Coloração

As estratégias de coloração são utilizadas para pintar os gráficos de acordo com a lógica que o trader desejar. Você pode pintar gráficos de preço, tais como candles, linhas, renko, ponto, o que quiser e também de volume! Você pode pintar o corpo dos candles, ou se preferir, o fundo do gráfico referente àquele candle!

Para que serve uma estratégia de coloração? Uma estratégia de coloração serve para automatizar uma análise que você faz manualmente. Serve para te liberar o tempo, atenção e foco que você dá para fazer esta análise…E o que você ganha com isso? Você ganha tempo e atenção para dedicar a algo mais importante…para entender o que de fato está acontecendo com o mercado e que se reflete nos movimentos de preço.

Exemplo 1: Colorindo InsideBar (Harami)

Este exemplo ilustra a coloração de candles classificados como InsideBar ou Harami (em japonês). E o que é um InsideBar? É um padrão gráfico no qual um candle possui o preço máximo menor que o preço máximo do candle anterior, bem como o preço mínimo maior que o preço mínimo do candle anterior.

A identificação de InsideBar é importante para alguns setup operacionais que utilizam esse padrão gráfico para iniciar posições. O gráfico abaixo exemplifica a aplicação de uma estratégia de coloração que pinta a barra de InsideBar na cor amarela.

Exempo 2: Double Crossover

Os setups de cruzamento de média (crossover) são amplamente utilizados em análise técnica e foram criados muito antes do uso intensivo de computadores no mercado financeiro.

Neste exemplo clássico de cruzamento de duas médias (double crossover), vamos colorir um gráfico de preço baseado no cruzamento de duas médias do preço de fechamento dos candles. Uma média rápida sobre os preços dos últimos 9 períodos e uma média lenta baseada no preços dos últimos 20 períodos. Obs: as quantidades de períodos das médias podem ser configuradas nos setup operacionais e  otimizadas de acordo com o ativo ou momento de mercado.

Quando a média rápida estiver acima da média lenta, isso sugere um movimento de alta e o gráfico será colorido de verde. Quando a média rápida estiver abaixo da média lenta, isso sugere um movimento de baixa e o gráfico será colorido de vermelho. Na figura abaixo, utilizamos a estratégia de coloração para pintar os candles do gráfico.

Na figura abaixo, utilizamos a mesma estratégia de coloração de cruzamento de média, mas dessa vez colorindo o fundo do gráfico.

Exemplo 3: Volume de agressão

Neste terceiro exemplo, vamos aplicar uma estratégia de coloração à um gráfico de saldo de agressão (que na verdade é um indicador!).

A estratégia de coloração consiste em identificar os momentos nos quais o saldo de agressão supera em duas unidades o desvio padrão da amostra dos últimos N períodos. Onde N para gráficos de 1 minuto poderia ser o valor de 2400 (5 dias x 8 horas x 60 minutos), o que abrange os últimos 5 dias de negociação.

Ou seja, se o saldo de agressão for comprador e for maior do que duas unidades de desvio padrão, a barra de saldo de agressão será pintada de verde. Se o saldo de agressão for vendedor e maior (em valor absoluto) que duas unidades de desvio padrão, a barra de saldo de agressão será pintada de vermelho.

A figura abaixo demonstra a aplicação da estratégia de coloração baseada em volume de agressão.

Estratégia de Indicador

As estratégias de indicadores plotam em um gráfico determinada série calculada com a lógica que o trader desejar. Pode ser tanto no gráfico de preço do próprio ativo, como em um subgráfico separado, geralmente abaixo do gráfico principal.

Criar um indicador que seja útil para tomar decisões não é uma tarefa muito fácil…Você precisa conhecer muito bem a lógica do mercado financeiro, as particularidades do tipo de ativo que está operando e transcrever em fórmulas matemáticas o cálculo de uma variável (o indicador) que lhe traga informação com valor agregado, informação útil para tomada de decisão. Geralmente, os indicadores estão muito vinculados a um determinado padrão de operação e são baseados em análise técnica. São exemplos de indicadores técnicos já consagrados pelo uso, as médias móveis, MACD, Índice de força relativa (IFR), entre outros.

Exemplo 1: Acumulação de Volume Agressor

Neste exemplo de indicador, vamos plotar um histograma em um subgráfico com a acumulação do saldo de agressão enquanto o saldo de agressão da barra permanecer do mesmo lado.

Por exemplo, uma vez que o saldo de agressão é comprador, a acumulação de saldo de agressão inicia. Para cada novo dado, se o saldo de agressão continuar sendo comprador, o indicador continuará acumulando o saldo. Caso haja um saldo vendedor de agressão, a acumulação é zerada e começa a acumular as agressões de venda, até que haja uma reversão de saldo de agressão para compra.

Veja a figura abaixo do indicador implementado de acumulação de Volume Agressor.

Exemplo 2: Administração de stoploss pela volatilidade média

Neste segundo exemplo de estratégia de indicador, vamos plotar no gráfico principal um limite de preço para administração manual de stoploss.

O usuário fornecerá como parâmetro o preço de entrada de uma operação de compra ou venda, bem como o horário de abertura da posição. O usuário também deve fornecer um múltiplo N da volatilidade média (a estratégia usa internamente o indicador ATR) para posicionar a linha área limite para posicionamento do stoploss.

Para cada candle fechado, o qual o preço tenha andado a favor da operação, o stoploss é atualizado para refletir o preço de fechamento deslocado de N ATRs.

Observe na figura abaixo, que o usuário sinalizou ao indicador uma compra às 13:58 no preço de R$ 31,11 no ativo PETR4. O stoploss foi configurado na estratégia para ficar 2 ATRs atrás do preço de fechamento dos candles. Observe que a operação deveria ser stopada manualmente no preço de R$ 31,13 conforme os parâmetros fornecidos.

Na próxima figura, é apresentado o caso de uma venda à R$ 31,28 às 15:47 no ativo PETR4. Nesse momento o usuário optou por um distanciamento de 3 ATRs do preço de fechamento para cálculo do stoploss.

Estratégia de Execução (Robôs)

Até semana passada eu diria que o nome estratégia de execução é uma nomenclatura ruim…porque no Profit a estratégia de execução não executa nada em conta real. Mas quem assistiu ao nosso vídeo falando sobre o novo módulo de Automação de Estratégias viu que tem novidades surgindo no Profit Chart! A estratégia de execução, ou os chamados robôs, já podem ser rodados em conta de simulador e em breve poderão rodar em conta real!

Então, além de poder fazer backtest em dados históricos, para verificar estatisticamente o desempenho de determinado setup operacional, em pouco tempo, vamos poder transformar essas estratégias de execução em robôs para rodar em conta real. Para os mais afoitos, isso não significa que você vai ficar rico pegando qualquer robô por aí na internet….Encontrar um robô lucrativo é uma tarefa muito exaustiva.

Os robôs talvez sejam o tipo de estratégia mais fácil de imaginar, pois todo mundo já visualiza ordens sendo colocadas no book de forma automática e toda administração das operações também sendo realizada de forma autônoma. E é exatamente para isso que se propõe os robôs, para automatizar um setup operacional e garantir consistência na execução do setup.

Vou apresentar a seguir um exemplo clássico e didático, que não representa nenhuma recomendação de uso, serve apenas para exemplificar as estratégias de execução ou robôs.

Exemplo: Cruzamento de 3 médias móveis (Triple crossover)

Nesse tipo de setup temos 3 médias móveis: uma média móvel rápida, uma intermediária e uma lenta. Cada média atuará sobre uma quantidade de períodos diferentes, sendo a rápida sobre menor quantidade de períodos, refletindo o movimento de preço mais recente suavizado e a média lenta englobando maio quantidade de períodos, representando a tendência principal do ativo em janelas gráficas maiores.

Assim, a quantidade de períodos são parâmetros que devem ser otimizados na estratégia. Por ora, vamos arbitrar a utilização dos seguintes valores 5, 10 e 20.

Observe que a estratégia foi implementada para que os sinais de compra sejam ativados quando a média rápida estiver acima da média intermediária e esta última cruzar para cima a média lenta. O sinal de liquidação da posição de compra ocorrerá quando a média rápida cruzar para baixo a média intermediária.

O sinal de venda é análogo e ocorre quando a média rápida estiver abaixo da média intermediária e houver o cruzamento para baixo desta última com a média lenta. O sinal de liquidação da posição vendida ocorre quando houver um cruzamento da média rápida acima da média intermediária.

Estratégia de Seleção (Screening)

Screening significa manter em tela, no seu campo de visão, alguma informação para monitoramento…Com as Estratégias de Seleção (screenings) podemos monitorar , em tempo real, todos os ativos da B3, ou um subconjunto que o trader escolher, por um padrão de movimentação ou situação também determinado pelo trader.

Ou seja, com os screenings poderemos automatizar a seleção das melhores oportunidades entre os ativos da B3 que se enquadrem em determinado operacional. Isto liberará o trader de tarefas manuais e repetitivas para poder se dedicar foco e atenção à analise dos movimentos do mercado e outras atividades que julgar importantes.

Os screenings podem ser aplicados em periodicidades de dados de 1 minuto, 15 minutos, dias, semanas….ou seja, pode usar dessa automação tanto para daytrading quanto para suas operações de swing trade.

Exemplo 1: Seleção de ativos em valorização nos últimos 3 dias

Nesse primeiro exemplo, ilustro a aplicação de um Screening para listar os ativos do índice IBOV que em periodicidade diária apresentaram valorização nos últimos 3 períodos, ou seja, 3 dias. É um caso de utilização das Estratégias de Seleção para filtrar oportunidades de swing trade.

As figuras abaixo ilustram a definição da regra de screening pela interface gráfica e a lista de ativos gerada a partir da regra definida.

Exemplo 2: Seleção de ativos em condição de InsideBar para operações de daytrading

Nesse segundo exemplo, verificamos a utilização de uma estratégia de seleção de InsideBar para aplicação de um Screening sobre uma lista de 6 ativos da B3 na periodicidade de dados de 1 minuto. É um exemplo de aplicação de screening para operações de daytrading.

As figuras abaixo demonstram a utilização de uma regra de alarme que também contém seleção no Screening e a lista de ativos gerada a partir da estratégia de seleção.

Estratégia de Alarme

Alarmes não tem a ver somente com tempo! Podemos até criar alarmes 10 minutos antes da liberação de dados importantes como Payroll…Mas o verdadeiro ganho das Estratégias de Alarme é exibir uma notificação em tela, geralmente acompanhado de um som, quando determinada situação ocorrer em um ativo específico!

As Estratégias de Alarme são configuradas no Profit por ativo dentro do Gerenciador de Alarmes. É necessário incluir as estratégias para cada ativo que desejar, e podem basear-se em periodicidades de 1 minuto, 15 minutos, 1 dia…a periodicidade de dados desejada! Assim, o trader não precisa ficar o tempo todo com as janelas dos ativos que está monitorando abertas, consumindo processamento do computador. O trader será notificado assim que ocorrer a condição programada por ele na estratégia de alarme, no ativo e na periodicidade de dado configurada.

As estratégias de alarme podem ser usadas de duas formas! Configurando no Gerenciador de Alarmes ou incluindo alarmes dentro de uma estratégia de coloração ou de execução. As estratégias podem estar associadas a mais de um tipo! Podemos ter uma estratégia de coloração que também gera alarmes! Porém, nesse caso, diferentemente do gerenciador de alarmes, é preciso deixar o gráfico aberto em tela para poder gerar o alarme.

Exemplo: Estratégia de alarme baseada em InsideBar (Gerenciador de Alarmes)

A figura abaixo demonstra a configuração no Gerenciador de Alarmes de um alarme baseado em uma Estratégia de Alarme de InsideBar para o ativo WINV22 na periodicidade de 1 minuto, quando o candle fechar. Em seguida, a próxima figura apresenta a notificação gerada pela estratégia de alarme.

Estratégia de Texto

As estratégias de texto são bastante simples e são utilizadas para apresentar determinado texto em uma barra (Candle ou Renko) quando a condição programada pelo trader ocorrer.

As estratégias de texto podem estar associadas às estratégias de indicadores ou estratégias de coloração. A figura abaixo apresenta um exemplo simples de apresentação do texto “IB” quando há identificação do padrão gráfico de InsideBar.

Estratégia de Negociação

Em resumo, as Estratégias de Negociação permitem definir ordens de stoploss e take profit, com saídas parciais ou não, para automatizar o posicionamento de ordens quando o trader abrir uma posição em um ativo.

As Estratégias de Negociação são configuradas poela interface gráfica, dentro do “Chart Trading” e é um excelente primeiro passo para automatização de setup operacional em conjunto com as Estratégias de Stoploss. Assista ao vídeo que explica o passo-a-passo de como configurar as estratégias de negociação publicado no Canal Youtube da Comunidade.

É importante ressaltar que quando se está implementando Robôs (Estratégias de Execução) no Profit, as Estratégias de Negociação ficam entrelaçadas no código-fonte. Dentro do código há muito mais liberdade para definir uma estratégia de negociação  porque depende apenas de como o código é estruturado. A administração de um trade aberto, pode ser feito usando breakeven, stop fixo ou stop móvel, basta  programar a gestão das posições da maneira que o trader desejar.

Reproduzir vídeo

Estratégia de Stoploss

Por fim, o último tipo de estratégia passível de automatização que iremos abordar são as Estratégias de Stoploss. Estas podem ser configuradas pela interface gráfica utilizando as técnicas de Autobreakeven e Stop móvel, sem necessidade de código fonte, e utilizadas em conjunto com as Estratégias de Negociação.

Assim como as estratégias de negociação, também é possível programar ordens de breakeven e stop móvel no código fonte das Estratégias de Execução (Robôs). Assista ao vídeo do Canal explicando como configurar uma estratégia de stoploss, pela interface gráfica, utilizando as técnicas de Autobreakeven e stop móvel em conjunto.

Reproduzir vídeo

Finalizando...

Este documento apresentou um panorama geral das estratégias que podem ser automatizadas no Profit Chart. 

Percebe-se que há muitas possibilidades de automação, desde pequenas tarefas pontuais como a possibilidade de automatizar todo o setup operacional.

O trader que deseja especializar-se no mercado financeiro precisa dominar as ferramentas de automatização para liberar seu tempo de tarefas rotineiras e manuais, permitindo ter atenção para analisar e estudar os movimentos de preço dos ativos, aprimorando assim seu conhecimento sobre o mercado financeiro.

Espero que tenha aproveitado o conteúdo!, pois nos próximos documentos iremos implementar  passo a passo cada tipo de estratégia!

NinjaTrader

Esta biblioteca contém material introdutório sobre programação em NinjaScript e a plataforma NinjaTrader, para que você inicie sua jornada de implementação de estratégias automatizadas de forma objetiva e gradual em uma das melhores plataformas do mercado mundial.

Conhecendo a NinjaTrader

Esta é uma série de vídeos para apresentar as principais funcionalidades da interface gráfica da plataforma NinjaTrader.

Lançamento da NinjaTrader para operações na B3

Reproduzir vídeo

Após um longo período de espera, finalmente, a Plataforma NinjaTrader foi homologada para operar na B3. Desde o dia 03/jan/2023 é possível contratar esta Plataforma pela Corretora Órama.

Conforme antecipado nos planos da Comunidade @neotraderbot, iremos gerar conteúdo informativo de diferentes plataformas de trading para que os membros da comunidade tenham informações do que é possível realizar em outros ambientes. Reforço que não estamos realizando nenhuma recomendação para mudança de Plataforma e que a decisão de migrar parte ou todo o processo de desenvolvimento e execução das estratégias automatizadas é muito pessoal e cabe apenas ao trader decidir sobre tal assunto.

Neste primeiro video sobre a Plataforma NinjaTrader vamos abordar as principais características do software: modelo de negócios, modularização do software, ecosistema de desenvolvimento, custos de contratação, detalhes gerais relacionados à automatização de estratégias.

Nas próximas semanas iremos gerar quase diariamente, seg a sexta, conteúdo sobre essa Plataforma antes de abordarmos em profunidade o desenvolvimento de estratégias em NinjaTrader Script!

Instalando NT8 e Configurando Market Data

Reproduzir vídeo

Neste video iremos apresentar passo a passo para instalar a Plataforma NinjaTrader e realizar a configuração o Market Data, tanto para acesso a dados das Bolsas Americanas (NYSE, NASDAQ, CME, etc…) e B3.

Após um longo período de espera, finalmente, a Plataforma NinjaTrader foi homologada para operar na B3. Desde o dia 03/jan/2023 é possível contratar esta Plataforma pela Corretora Órama.

Conforme antecipado nos planos da Comunidade @neotraderbot, iremos gerar conteúdo informativo de diferentes plataformas de trading para que os membros da comunidade tenham informações do que é possível realizar em outros ambientes.

Reforço que não estamos realizando nenhuma recomendação para mudança de Plataforma e que a decisão de migrar parte ou todo o processo de desenvolvimento e execução das estratégias automatizadas é muito pessoal e cabe apenas ao trader decidir sobre tal assunto.

Explorando o Control Center

Reproduzir vídeo

Neste video iremos explicar tudo sobre a principal janela do NinjaTrader: Centro de Controle (Control Center). Esta é a janela mais importante do NinjaTrader, por onde o usuário terá acesso a todas as funcionalidades da Plataforma.

Assista nesse video uma explicação didática de como utilizar a Plataforma para operá-la como um professional!

Após um longo período de espera, finalmente, a Plataforma NinjaTrader foi homologada para operar na B3. Desde o dia 03/jan/2023 é possível contratar esta Plataforma pela Corretora Órama.

Conforme antecipado nos planos da Comunidade @neotraderbot, iremos gerar conteúdo informative de diferentes plataformas de trading para que os membros da comunidade tenham informações do que é possível realizar em outros ambientes.

Reforço que não estamos realizando nenhuma recomendação para mudança de Plataforma e que a decisão de migrar parte ou todo o processo de desenvolvimento e execução das estratégias automatizadas é muito pessoal e cabe apenas ao trader decidir sobre tal assunto.

Como manipular gráficos na NT8 (Funcionalidades básicas)

Reproduzir vídeo

Neste video iremos apresentar todas as funcionalidades básicas relacionadas a gráficos na Plataforma NinjaTrader.

Este é um conteúdo informativo sobre NinjaTrader para que os membros da comunidade tenham informações do que é possível realizar em outros ambientes.

Reforço que não estamos realizando nenhuma recomendação para mudança de Plataforma e que a decisão de migrar parte ou todo o processo de desenvolvimento e execução das estratégias automatizadas é muito pessoal e cabe apenas ao trader decidir sobre tal assunto.

Recursos avançados de Subgráficos e Multigráficos na NT8

Reproduzir vídeo

Neste video iremos apresentar as funcionalidades avançadas relacionadas a gráficos na Plataforma NinjaTrader.

Você perceberá como o NinjaTrader possui funcionalidades que não se encontra em outras plataformas, como a capacidade de plotar mais de um ativo no mesmo gráfico, ou de até mesmo plotar tempos gráficos diferentes do mesmo ativo no mesmo gráfico.

Por exemplo, em um mesmo gráfico ver o box de 15 minutos e candles de 1 minuto. A Plataforma permite configurar e personalizar todas formas diferentes de subgráficos e multigráficos que expande bastante a capacidade analítica na leitura de gráficos e permite uma flexibilidade muito grande para plotagem de indicadores customizados.

Este é um conteúdo informativo sobre NinjaTrader para que os membros da comunidade tenham informações do que é possível realizar em outros ambientes.

Reforço que não estamos realizando nenhuma recomendação para mudança de Plataforma e que a decisão de migrar parte ou todo o processo de desenvolvimento e execução das estratégias automatizadas é muito pessoal e cabe apenas ao trader decidir sobre tal assunto.

Como adicionar Indicadores aos gráficos

Reproduzir vídeo

Neste video iremos demonstrar passo-a-passo como incluir indicadores em gráficos na Plataforma NinjaTrader.

Iremos apresentar exemplos de indicadores técnicos disponíveis na versão gratuita. A Plataforma permite configurar e personalizar todas formas diferentes de subgráficos e multigráficos que expande bastante a capacidade analítica na leitura de gráficos e permite uma flexibilidade muito grande para plotagem de indicadores customizados.

Este é um conteúdo informativo sobre NinjaTrader para que os membros da comunidade tenham informações do que é possível realizar em outros ambientes.

Reforço que não estamos realizando nenhuma recomendação para mudança de Plataforma e que a decisão de migrar parte ou todo o processo de desenvolvimento e execução das estratégias automatizadas é muito pessoal e cabe apenas ao trader decidir sobre tal assunto.

Como desenhar estudos nos gráficos da NinjaTrader

Reproduzir vídeo

Neste video iremos demonstrar passo-a-passo como incluir estudos ou desenhar elementos nos gráficos na Plataforma NinjaTrader.

A Plataforma permite configurar e personalizar todas formas diferentes de subgráficos e multigráficos que expande bastante a capacidade analítica na leitura de gráficos e permite uma flexibilidade muito grande para plotagem de indicadores customizados.

Este é um conteúdo informativo sobre NinjaTrader para que os membros da comunidade tenham informações do que é possível realizar em outros ambientes. Reforço que não estamos realizando nenhuma recomendação para mudança de Plataforma e que a decisão de migrar parte ou todo o processo de desenvolvimento e execução das estratégias automatizadas é muito pessoal e cabe apenas ao trader decidir sobre tal assunto.

Monitore o mercado com o Market Analyzer e Market Watch

Reproduzir vídeo

Neste video iremos demonstrar passo-a-passo como analisar o mercado de maneira global utilizando a ferramenta MARKET ANALYZER E MARKET WATCH na NinjaTrader.

Vamos ensinar PASSO-A-PASSO como configurar esta ferramenta poderosa de análise disponível na Ninja Trader e que permite a inclusão de indicadores customizados que poderão agregar muito valor ao seu operacional, permitindo a realização de screenings muito mais sofisticados do que estamos acostumados a criar em plataformas brasileiras.

Este é um conteúdo informativo sobre NinjaTrader para que os membros da comunidade tenham informações do que é possível realizar em outros ambientes.

Reforço que não estamos realizando nenhuma recomendação para mudança de Plataforma e que a decisão de migrar parte ou todo o processo de desenvolvimento e execução das estratégias automatizadas é muito pessoal e cabe apenas ao trader decidir sobre tal assunto.

Como agrupar gráficos/janelas e utilizar Crosshair

Reproduzir vídeo

Neste video iremos demonstrar passo-a-passo como agilizar a sua navegação entre gráficos na NinjaTrader.

Vamos ensinar PASSO-A-PASSO como configurar o Market Analyzer para ao selecionar um ativo, modificar a exibição em múltiplas janelas ao mesmo tempo, permitindo mais velocidade ao analisar o mercado.

Também demonstraremos como vincular janelas diferentes a um mesmo ativo, ou até mesmo como vincular gráficos de ativos diferentes a um mesmo tempo gráfico, de tal forma que uma alteração em um gráfico reflita nas demais janelas.

Por fim, iremos apresentar a funcionalidade de CROSSHAIR a qual permite realizar inspeção gráfico em diferentes janelas de ativos de maneira muito prática, inclusive em gráficos com séries de dados distintas, ex: entre um gráfico de renko e outro de candle.

Estas funcionalidades disponíveis na NinjaTrader são um diferencial em termos de uso e navegação pelo sistema, que não estão disponíveis com este potencial em outras plataformas.

Este é um conteúdo informativo sobre NinjaTrader para que os membros da comunidade tenham informações do que é possível realizar em outros ambientes.

Reforço que não estamos realizando nenhuma recomendação para mudança de Plataforma e que a decisão de migrar parte ou todo o processo de desenvolvimento e execução das estratégias automatizadas é muito pessoal e cabe apenas ao trader decidir sobre tal assunto.

Alertas e Serviços de Compartilhamento (Envio de E-mail)

Reproduzir vídeo

Neste video iremos demonstrar DIVERSAS FORMAS de CRIAR ALERTAS na NinjaTrader, sejam pop-ups, avisos sonoros, envio de e-mail, publicação de post no Twitter ou envio de ordens.

Começaremos apresentando formas de gerar alertas no Market Analyzer. O que permite criar alertas para ativos individuais ou para toda uma carteira de ativos.

Com os alertas também é possível criar screenings sofisticados com a utilização de indicadores, principalmente customizados.

Em seguida apresentarei os recursos avançados de criação de alertas sobre figuras e elementos de estudos inseridos em gráficos. Iremos demonstrar também como enviar e-mails quando um alerta for acionado.

Por fim, será apresentada a tela de Log de Alertas que reúne todos os alertas sinalizados pela plataforma com informações de ativo, origem, criticidade, data e hora.

A utilização de alertas na plataforma NinjaTrader é bastante abrangente e integrado com serviços de e-mails e redes sociais, o que permitirá ao trader criar mecanismos sofisticados para monitoramento e sinalização de situações de mercado em múltiplos ativos e com indicadores complexos.

Este é um conteúdo informativo sobre NinjaTrader para que os membros da comunidade tenham informações do que é possível realizar em outros ambientes.

Reforço que não estamos realizando nenhuma recomendação para mudança de Plataforma e que a decisão de migrar parte ou todo o processo de desenvolvimento e execução das estratégias automatizadas é muito pessoal e cabe apenas ao trader decidir sobre tal assunto.

Como importar dados históricos para NT8 (OHLCV 1 min e Ticks)

Reproduzir vídeo

Neste video irei demonstrar como IMPORTAR DADOS HISTÓRICOS OHLCV (1 MIN) e de TICKS para plataforma NINJATRADER.

No decorrer do vídeo farei a conversão dos dados exportados a partir da MetaTrader para o formato aceito para importação na plataforma NinjaTrader. Você perceberá que é possível fazer os ajustes necessários tanto com excel e um bloco de notas ou automatizando a conversão por um código em Python, caso a quantidade de arquivos a ser importada seja muito grande.

O benefício de ter mais dados históricos é poder realizar o BACKTESTING de sua estratégia ou robô em uma janela histórica mais longa, permitindo maior significância estatística nos resultados encontrados.

Reforço que não estamos realizando nenhuma recomendação para mudança de Plataforma e que a decisão de migrar parte ou todo o processo de desenvolvimento e execução das estratégias automatizadas é muito pessoal e cabe apenas ao trader decidir sobre tal assunto.

Rodando e gravando dados de Replay de Mercado

Reproduzir vídeo

Neste video irei demonstrar como HABILITAR A GRAVAÇÃO de DADOS DE MERCADO em seu computador utilizando a plataforma NINJATRADER.

Com a gravação de dados habilitada, você poderá criar uma base de dados de replay de mercado contendo informação de Book de Oferta.

Outra opção disponível na plataforma é solicitar o download de MARKET REPLAY do seu provedor de MARKET DATA.

Por fim, também demonstrarei como executar um REPLAY DE MERCADO com os dados históricos de tick na sua base da NinjaTrader. Estes dados podem inclusive terem sido importados para dentro da plataforma.

Como criar robô/estratégia do ZERO com o Strategy Builder

Reproduzir vídeo

Neste vídeo irei demonstrar como CRIAR um ROBÔ ou ESTRATÉGIA do ZERO, e sem programar nenhuma linha de código, com a ferramenta STRATEGY BUILDER da plataforma NINJATRADER (em português: Construtor de Estratégia).

Você perceberá que mesmo sendo uma ferramenta gráfica NO CODE, o usuário tem muita flexibilidade para configurar e definir a estratégia a ser criada.

Há muita liberdade para configurar indicadores, funções prontas pra verificar cruzamento de séries no instante atual ou passado recente, lucro/prejuízo realizado pela estratégia ou em aberto, configuração de cálculo da estratégia (fechamento de barra, tick ou mudança de preço) e etc.

Além disso, é possível utilizar séries de dados de outros ativos ou até o mesmo ativo em outra escala de tempo ou tipo de série.

A estratégia pode disparar a criação todos os objetos de estudo dentro dos gráficos, rotear ordens, enviar e-mails, criar alertas visuais sonoros e muito mais.

Como rodar backtesting na NinjaTrader

Reproduzir vídeo

Neste video irei demonstrar como rodar BACKTESTING de ESTRATÉGIAS e ROBÔS na plataforma NINJATRADER.

Você verá a riqueza de funcionalidades, métricas e personalização do ambiente de backtesting da NinjaTrader. O que demonstra o cuidado do desenolvimento da plataforma para usuários que desejam automatizar seus setups operacionais.

Por fim, demonstrarei a vantagem de poder carregar dados históricos para plataforma e poder realizar backtesting em uma janela adequada de dados.

Programando em NinjaScript

Nesta seção iremos abordar os conceitos básicos necessários para implementar códigos em NinjaScript, tais como indicadores e robôs.

Introdução ao NinjaScript Editor

Reproduzir vídeo

Este vídeo visa apresentar o ambiente de programação NinjaScript Editor da NinjaTrader, bem como a integração com a IDE Visual Studio da Microsoft.

Todos os programas em NT8 são escritos na linguagem NinjaScript que é baseada em C#, possuindo orientação à objeto e permitindo tratamento de eventos.

Recomendamos a leitura da Documentação NinjaTrader no link a seguir, de preferência em inglês: https://ninjatrader.com/support/helpG…

Link para baixar a IDE Visual Studio: https://visualstudio.microsoft.com/pt…

Snippets e How-to

Aprender a programar envolve esforço, persistência e também colaboração com outros programadores (esse é um dos benefícios de participar de uma Comunidade como a NeoTraderBot!).

Pensando em acelerar a curva de aprendizado e reduzir o tempo que ficamos presos com problemas de programação, organizamos esta área de Snippets e de How-To (tutoriais) para elaboração de estratégias e indicadores na TraderEvolution utilizando EvoCode.

Os Snippets são trechos de códigos independentes criados para executar uma determinada tarefa. Eles podem ser copiados e modificados de acordo com a necessidade do usuário

Navegue abaixo pelas categorias disponíveis e caso tenha alguma sugestão de nova categoria ou tarefa, comente nas áreas apropriadas. Caso tenha colegas que também possam fazer bom uso e contribuir com a Comunidade, compartilhe esta área do site pelos ícones abaixo.

 

Compartilhe essa página!

Share on facebook
Facebook
Share on telegram
Telegram
Share on whatsapp
WhatsApp
Share on email
Email

Snippets para Localização Temporal

Nesta área você terá acesso a pedaços de códigos fontes para localização da estratégia em relação ao tempo.

Tarefas disponibilizadas:

Snippets para Manipulação de Gráficos

Nesta área você terá acesso a pedaços de códigos fontes para manipular plot, cores de plotagem, espessura, tipo de gráfico, etc.

Tarefas disponibilizadas:

 

Snippets para Utilização de Indicadores da Plataforma

Nesta área você terá acesso a pedaços de códigos fontes para utilizar os indicadores disponibilizados por padrão na Plataforma.

Tarefas disponibilizadas:

 

Snippets para Ordens e Administração de Trade

Nesta área você terá acesso a pedaços de códigos fontes para execução de ordens e administração de trade (técnicas de stoploss e takeprofit).

Tarefas disponibilizadas:

Outros Snippets

Nesta área você terá acesso a pedaços de códigos fontes para objetivos não abrangidos pelas categorias acima.

Tarefas disponibilizadas:

 

Tutoriais sobre Estrutura de Código

Introdução

Esta seção visa apresentar trechos de códigos com funcionalidades relativas à estrutura do código de indicadores e estratégias. Por exemplo, como criar parâmetros de entrada.

Você pode acessar os Snippets/Tutoriais diretamente pelo menu lateral direito, ou fazendo CTRL+F (CTRL+L) para localizar algum texto específico na página, uma vez que o conteúdo tende a crescer ao longo do tempo, dificultando a navegação pelo menu.

Caso tenham sugestões de código para acrescentar à lista, gentileza deixar o código nos comentários com o link para seu perfil em rede social (para devido crédito de autoria).

Snippets/Tutoriais

Como criar parâmetros no meu indicador/estratégia?

Reproduzir vídeo

Os parâmetros de uma estratégia ou indicador são declarados como atributos da classe.

O que diferencia esses atributos dos demais atributos são as anotações (em C# chama-se Annotations e são contidas entre [ ]) que realizamos imediatamente antes da definição dos atributos. Vamos ver abaixo como criar diferentes tipos de parâmetros, como definir seu valor padrão, qual texto será exibido na interface de configuração da estratégia/indicador e pré-validações.

Os tipos de parâmetros possíveis em NinjaScript são: bool, int, double, string, DateTime e Brush. Ainda é possível utilizar eNum renderizando em formato de dropdown na GUI (veremos mais detalhes no exemplo completo).

A primeira anotação que realizamos é [NinjaScriptProperty]. Esta anotação irá informar ao pré-processador que no momento da compilação que o atributo deve ser exibido na interface de configuração do Indicador ou estratégia como parâmetro.

 

A segunda anotação que pode ser utilizada é um validador [Range()]. A função Range permite definir o valor mínimo e máximo no caso de parâmetros do tipo inteiro e double, permitindo a validação do valor inserido pela interface gráfica. No caso de parâmetros de data ou horário (DateTime), ao invés de utilizarmos Range, podemos fazer a anotação [PropertyEditor(“NinjaTrader.Gui.Tools.DateTimeEditorKey”)], onde “DateTimeEditorKey” será usado quando você quiser renderizar um seletor de datas e “TimeEditorKey” caso deseje-se renderizar um seletor de horário.

A terceira anotação é a chamada a função Display, que nos permitirá atribuir um nome ao parâmetro na interface gráfica, juntamente com um texto a ser apresentado como Tooltip (ou seja, quando o mouse passar sobre o nome do parâmetro), a ordem de exibição e o grupo no qual o parâmetro será exibido na tela de configuração.

Os valores padrão dos parâmetros devem ser definidos no estado SetDefaults quando chamado o método OnStateChange.

 

Veja a seguir alguns exemplos de definição de parâmetros para estratégia:

Parâmetro Inteiro (Exemplo: Qtde de períodos de uma média móvel)

No código abaixo a tela de configuração da estratégia/indicador apresentará como segundo parâmetro do grupo “Setup (by NeoTraderBot)” a ser definido a “Média rápida – Qtde de periodos” que é do tipo numérico e inteiro, variando entre 1 e o maior valor inteiro possível.

				
							[NinjaScriptProperty]
		[Range(1, int.MaxValue)]
		[Display(Name="Periods", Description="Number of period for MA", Order=2, GroupName="Setup (by NeoTraderBot)")]
		public int period
		{ get; set; }
				
			
Parâmetro Brush (Paleta de cores)

No código abaixo a tela de configuração da estratégia/indicador apresentará como segundo parâmetro do grupo “Appereance (by NeoTraderBot)” a ser definido o texto “Plot color”, que apresentará em uma caixa de seleção de paleta de cor. Observe a existência da anotação XmlIgnore, cujo propósito é evitar a serialização desse parâmetro ao salvar um template do indicador, pois isto poderia gerar erro na plataforma (esta anotação é incluída automaticamente pelo NinjaScript Wizard).

				
							[NinjaScriptProperty]
		[XmlIgnore]
		[Display(Name="Plot color", Description="Example how to use brush as a parameter", Order=2, GroupName="Appearence (by NeoTraderBot)")]
		public Brush plotColor
		{ get; set; }
				
			
Código de um indicador com TODOS os tipos de parâmetros em NinjaScript

No código abaixo você encontrará um exemplo de um indicador com todos os tipos de parâmetros possíveis em NinjaScript.

				
					#region Using declarations
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Xml.Serialization;
using NinjaTrader.Cbi;
using NinjaTrader.Gui;
using NinjaTrader.Gui.Chart;
using NinjaTrader.Gui.SuperDom;
using NinjaTrader.Gui.Tools;
using NinjaTrader.Data;
using NinjaTrader.NinjaScript;
using NinjaTrader.Core.FloatingPoint;
using NinjaTrader.NinjaScript.DrawingTools;
#endregion

//This namespace holds Indicators in this folder and is required. Do not change it. 
namespace NinjaTrader.NinjaScript.Indicators
{
	[Gui.CategoryOrder("Setup (by NeoTraderBot)", 1)]
	[Gui.CategoryOrder("Trading intervals (by NeoTraderBot)", 2)]
	[Gui.CategoryOrder("Appearence (by NeoTraderBot)", 3)]		
	public class _NTB_UserDefinedParameters : Indicator
	{
		protected override void OnStateChange()
		{
			if (State == State.SetDefaults)
			{
				Description									= @"Just a demonstration on how to include User Defined Parameters";
				Name										= "_NTB_UserDefinedParameters";
				Calculate									= Calculate.OnBarClose;
				IsOverlay									= false;
				DisplayInDataBox							= true;
				DrawOnPricePanel							= true;
				DrawHorizontalGridLines						= true;
				DrawVerticalGridLines						= true;
				PaintPriceMarkers							= true;
				ScaleJustification							= NinjaTrader.Gui.Chart.ScaleJustification.Right;
				//Disable this property if your indicator requires custom values that cumulate with each new market data event. 
				//See Help Guide for additional information.
				IsSuspendedWhileInactive					= true;
				
				avgType					= NeoTraderBot.MAType.SMA;
				period					= 9;
				percBand				= 2.0;
				msg						= @"Example of a msg to display on the chart!";
				daytradingMode			= true;
				DontTradeOn				= DateTime.Now;
				TradingStartAfter		= DateTime.Parse("09:00", System.Globalization.CultureInfo.InvariantCulture);
				TradingCloseAt			= DateTime.Parse("12:00", System.Globalization.CultureInfo.InvariantCulture);				
				plotColor				= Brushes.Orange;
				
			}
			else if (State == State.Configure)
			{
			}
		}

		protected override void OnBarUpdate()
		{
			//Add your custom indicator logic here.
		}

		#region Properties
		[Display(Name="MA Type", Description="Example of Dropbox parameter with enum", Order=1, GroupName="Setup (by NeoTraderBot)")]
		public NeoTraderBot.MAType avgType
		{ get; set; }	
		
		[NinjaScriptProperty]
		[Range(1, int.MaxValue)]
		[Display(Name="Periods", Description="Number of period for MA", Order=2, GroupName="Setup (by NeoTraderBot)")]
		public int period
		{ get; set; }

		[NinjaScriptProperty]
		[Range(1, double.MaxValue)]
		[Display(Name="% band around VWAP", Description="Just an example of double parameter", Order=3, GroupName="Setup (by NeoTraderBot)")]
		public double percBand
		{ get; set; }

		[NinjaScriptProperty]
		[Display(Name="Enable Daytrading mode", Order=4, GroupName="Setup (by NeoTraderBot)")]
		public bool daytradingMode
		{ get; set; }


		[NinjaScriptProperty]
		[PropertyEditor("NinjaTrader.Gui.Tools.DateTimeEditorKey")]
		[Display(Name="Dont Trade on", Description="Just an example of Date parameter", Order=1, GroupName="Trading intervals (by NeoTraderBot)")]
		public DateTime DontTradeOn
		{ get; set; }		
		
		[NinjaScriptProperty]
		[PropertyEditor("NinjaTrader.Gui.Tools.TimeEditorKey")]
		[Display(Name="Start trading after", Description="Time after the strategy will start to trade", Order=2, GroupName="Trading intervals (by NeoTraderBot)")]
		public DateTime TradingStartAfter
		{ get; set; }
		
		[NinjaScriptProperty]
		[PropertyEditor("NinjaTrader.Gui.Tools.TimeEditorKey")]
		[Display(Name="Trading close at", Description="Time at the strategy will stop trading and close open positions", Order=3, GroupName="Trading intervals (by NeoTraderBot)")]
		public DateTime TradingCloseAt
		{ get; set; }		


		
		
		[NinjaScriptProperty]
		[Display(Name="Display message", Description="Just an example of string parameter", Order=1, GroupName="Appearence (by NeoTraderBot)")]
		public string msg
		{ get; set; }		
		
		[NinjaScriptProperty]
		[XmlIgnore]
		[Display(Name="Plot color", Description="Example how to use brush as a parameter", Order=2, GroupName="Appearence (by NeoTraderBot)")]
		public Brush plotColor
		{ get; set; }

		[Browsable(false)]
		public string Teste6Serializable
		{
			get { return Serialize.BrushToString(plotColor); }
			set { plotColor = Serialize.StringToBrush(value); }
		}			
		#endregion

	}
}

namespace NeoTraderBot
{
	public enum MAType
	{
		SMA,
		EMA,
		WMA,
	}
}

#region NinjaScript generated code. Neither change nor remove.

namespace NinjaTrader.NinjaScript.Indicators
{
	public partial class Indicator : NinjaTrader.Gui.NinjaScript.IndicatorRenderBase
	{
		private _NTB_UserDefinedParameters[] cache_NTB_UserDefinedParameters;
		public _NTB_UserDefinedParameters _NTB_UserDefinedParameters(int period, double percBand, bool daytradingMode, DateTime dontTradeOn, DateTime tradingStartAfter, DateTime tradingCloseAt, string msg, Brush plotColor)
		{
			return _NTB_UserDefinedParameters(Input, period, percBand, daytradingMode, dontTradeOn, tradingStartAfter, tradingCloseAt, msg, plotColor);
		}

		public _NTB_UserDefinedParameters _NTB_UserDefinedParameters(ISeries<double> input, int period, double percBand, bool daytradingMode, DateTime dontTradeOn, DateTime tradingStartAfter, DateTime tradingCloseAt, string msg, Brush plotColor)
		{
			if (cache_NTB_UserDefinedParameters != null)
				for (int idx = 0; idx < cache_NTB_UserDefinedParameters.Length; idx++)
					if (cache_NTB_UserDefinedParameters[idx] != null && cache_NTB_UserDefinedParameters[idx].period == period && cache_NTB_UserDefinedParameters[idx].percBand == percBand && cache_NTB_UserDefinedParameters[idx].daytradingMode == daytradingMode && cache_NTB_UserDefinedParameters[idx].DontTradeOn == dontTradeOn && cache_NTB_UserDefinedParameters[idx].TradingStartAfter == tradingStartAfter && cache_NTB_UserDefinedParameters[idx].TradingCloseAt == tradingCloseAt && cache_NTB_UserDefinedParameters[idx].msg == msg && cache_NTB_UserDefinedParameters[idx].plotColor == plotColor && cache_NTB_UserDefinedParameters[idx].EqualsInput(input))
						return cache_NTB_UserDefinedParameters[idx];
			return CacheIndicator<_NTB_UserDefinedParameters>(new _NTB_UserDefinedParameters(){ period = period, percBand = percBand, daytradingMode = daytradingMode, DontTradeOn = dontTradeOn, TradingStartAfter = tradingStartAfter, TradingCloseAt = tradingCloseAt, msg = msg, plotColor = plotColor }, input, ref cache_NTB_UserDefinedParameters);
		}
	}
}

namespace NinjaTrader.NinjaScript.MarketAnalyzerColumns
{
	public partial class MarketAnalyzerColumn : MarketAnalyzerColumnBase
	{
		public Indicators._NTB_UserDefinedParameters _NTB_UserDefinedParameters(int period, double percBand, bool daytradingMode, DateTime dontTradeOn, DateTime tradingStartAfter, DateTime tradingCloseAt, string msg, Brush plotColor)
		{
			return indicator._NTB_UserDefinedParameters(Input, period, percBand, daytradingMode, dontTradeOn, tradingStartAfter, tradingCloseAt, msg, plotColor);
		}

		public Indicators._NTB_UserDefinedParameters _NTB_UserDefinedParameters(ISeries<double> input , int period, double percBand, bool daytradingMode, DateTime dontTradeOn, DateTime tradingStartAfter, DateTime tradingCloseAt, string msg, Brush plotColor)
		{
			return indicator._NTB_UserDefinedParameters(input, period, percBand, daytradingMode, dontTradeOn, tradingStartAfter, tradingCloseAt, msg, plotColor);
		}
	}
}

namespace NinjaTrader.NinjaScript.Strategies
{
	public partial class Strategy : NinjaTrader.Gui.NinjaScript.StrategyRenderBase
	{
		public Indicators._NTB_UserDefinedParameters _NTB_UserDefinedParameters(int period, double percBand, bool daytradingMode, DateTime dontTradeOn, DateTime tradingStartAfter, DateTime tradingCloseAt, string msg, Brush plotColor)
		{
			return indicator._NTB_UserDefinedParameters(Input, period, percBand, daytradingMode, dontTradeOn, tradingStartAfter, tradingCloseAt, msg, plotColor);
		}

		public Indicators._NTB_UserDefinedParameters _NTB_UserDefinedParameters(ISeries<double> input , int period, double percBand, bool daytradingMode, DateTime dontTradeOn, DateTime tradingStartAfter, DateTime tradingCloseAt, string msg, Brush plotColor)
		{
			return indicator._NTB_UserDefinedParameters(input, period, percBand, daytradingMode, dontTradeOn, tradingStartAfter, tradingCloseAt, msg, plotColor);
		}
	}
}

#endregion

				
			

Quando é chamado o método OnBarUpdate?

Reproduzir vídeo

Como criar estratégias/indicadores em múltiplos tempos gráficos (MTF)?

O código de exemplo abaixo apresenta um exemplo completo para você criar indicadores e estratégias em múltiplos tempos gráficos. Assista ao vídeo acima para entender o passo a passo da estruturação de um código MTF (multi Timeframe).

				
					#region Using declarations
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Xml.Serialization;
using NinjaTrader.Cbi;
using NinjaTrader.Gui;
using NinjaTrader.Gui.Chart;
using NinjaTrader.Gui.SuperDom;
using NinjaTrader.Gui.Tools;
using NinjaTrader.Data;
using NinjaTrader.NinjaScript;
using NinjaTrader.Core.FloatingPoint;
using NinjaTrader.NinjaScript.Indicators;
using NinjaTrader.NinjaScript.DrawingTools;
#endregion

//This namespace holds Strategies in this folder and is required. Do not change it. 
namespace NinjaTrader.NinjaScript.Strategies
{
	public class MTF_ExemploNeoTraderBot : Strategy
	{
		protected override void OnStateChange()
		{
			if (State == State.SetDefaults)
			{
				Description									= @"Example of NeoTraderBot";
				Name										= "MTF_ExemploNeoTraderBot";
				Calculate									= Calculate.OnBarClose;
				EntriesPerDirection							= 1;
				EntryHandling								= EntryHandling.AllEntries;
				IsExitOnSessionCloseStrategy				= true;
				ExitOnSessionCloseSeconds					= 30;
				IsFillLimitOnTouch							= false;
				MaximumBarsLookBack							= MaximumBarsLookBack.TwoHundredFiftySix;
				OrderFillResolution							= OrderFillResolution.Standard;
				Slippage									= 0;
				StartBehavior								= StartBehavior.WaitUntilFlat;
				TimeInForce									= TimeInForce.Gtc;
				TraceOrders									= false;
				RealtimeErrorHandling						= RealtimeErrorHandling.StopCancelClose;
				StopTargetHandling							= StopTargetHandling.PerEntryExecution;
				BarsRequiredToTrade							= 20;
				// Disable this property for performance gains in Strategy Analyzer optimizations
				// See the Help Guide for additional information
				IsInstantiatedOnEachOptimizationIteration	= true;
				
				AddPlot(new Stroke(Brushes.White, DashStyleHelper.Dash, 1), PlotStyle.Line, "EMA_CHART");
				AddPlot(new Stroke(Brushes.Yellow, DashStyleHelper.Solid, 1), PlotStyle.Line, "EMA_5MIN");
				AddPlot(new Stroke(Brushes.Blue, DashStyleHelper.Dash, 2), PlotStyle.Line, "EMA_15MIN");
				AddPlot(new Stroke(Brushes.Orange, DashStyleHelper.Solid, 2), PlotStyle.Line, "EMA_60MIN");
				
				
			}
			else if (State == State.Configure)
			{
				AddDataSeries(BarsPeriodType.Minute, 5);
				AddDataSeries(BarsPeriodType.Minute, 15);
				AddDataSeries(BarsPeriodType.Minute, 60);
			}
		}

		protected override void OnBarUpdate()
		{
			if (CurrentBars[0] < BarsRequiredToPlot || CurrentBars[1] < BarsRequiredToPlot || CurrentBars[2] < BarsRequiredToPlot
				|| CurrentBars[3] < BarsRequiredToPlot)
				return;
			
			Values[0][0] = EMA(Closes[0], 20)[0];
			Values[1][0] = EMA(Closes[1], 20)[0];
			Values[2][0] = EMA(Closes[2], 20)[0];
			Values[3][0] = EMA(Closes[3], 20)[0];
			
			if (BarsInProgress == 2) 
				BackBrushes[0] = Brushes.Olive;
			
		}
	}
}

				
			

Snippets para Manipulação de Gráficos

Esta seção visa apresentar trechos de códigos com funcionalidades relativas à manipulação de gráficos.

Você pode acessar os Snippets diretamente pelo menu lateral direito, ou fazendo CRL+F (CTRL+L) para localizar algum texto específico na página, uma vez que o conteúdo tende a crescer ao longo do tempo, dificultando a navegação pelo menu.

Caso tenham sugestões de código para acrescentar à lista, gentileza deixar o código nos comentários com o link para seu perfil em rede social (para devido crédito de autoria).

Snippets

Como configurar as propriedades de Plots nos Indicadores?

Reproduzir vídeo

Praticamente todas as propriedades de um plot no NinjaScript podem ser definidas no método AddPlot. Este método possui duas sobrecargas.

A primeira versão cria apenas uma linha sólida com cor específica. Na segunda versão de AddPlot, os parâmetros permitem maior flexibilidade na configuração, conforme pode ser visto no exemplo abaixo.

				
					AddPlot(new Stroke(Brushes.LimeGreen, DashStyleHelper.Solid, 1, 10), PlotStyle.Bar, "Plot1");
Plots[0].Autowidth = true;
				
			

No exemplo acima, criamos um plot chamado “Plot1” que é uma barra na cor verde limão, sólida, com opacidade em 10%. Também configuramos a largura da barra para ser a mesma da série de dados do gráfico.

O objeto Stroke permite definir a cor do plot pelo parâmetro da classe Brush, o tipo de traçado pelo parâmetro da classe DashStyleHelper, a espessura e transparência do plot. A transparência é o único parâmetro que não pode ser configurado na interface gráfica.

Existem diversos tipos de plots na NinjaTrader, tais como linhas, barras, gráfico em degrau, linha horizontal, marcações em bloco, cruz, triangulos, pontos. E também é possível não exibir o plot no gráfico, mas apenas no DataBox, passando como parâmetro o tipo PlotStyle.PriceBox.

Como alterar a cor da barra e do fundo do gráfico?

Reproduzir vídeo

Em NinjaScript é possível pintar a barra e o fundo do gráfico utilizando a lógica que desejar. Além disso, você pode em qualquer momento do tempo refazer a pintura de qualquer barra ou fundo de barra no gráfico, o que dá uma grande flexibilidade ao trader programador.

Veja abaixo exemplo de como pintar para o momento atual uma barra de azul e o fundo de oliva. Caso deseje pintar uma barra do passado, basta usar o indexador da série com o valor desejado. Por exemplo, BarBrushes[1] refere-se a cor da penúltima barra do gráfico em relação a barra processada no momento.

				
					BarBrushes[0] = Brushes.Blue;
BackBrushes[0] = Brushes.Olive;

				
			

OBS: Caso você deseje retirar a cor atribuído a um desses elementos basta atribuir o valor null a série desejada.

Como plotar indicadores em estratégias em painel separado?

Reproduzir vídeo

Essa é uma tarefa que pode ser realizada em uma única linha de comando no NinjaScript. Basta no método OnStateChange, quando o estado do ninjascript for DataLoaded, ou seja, quando já tiver carregado todos os dados do gráfico, você chamar o método AddChartIndicator, conforme demonstrado abaixo.

				
					if (State == State.DataLoaded)
{
    AddChartIndicator(MACD(12,26,9));
}

				
			

Pintando uma região entre duas médias ou séries

Seguem abaixo dois exemplos de pintura de região entre as médias exponencias de 9 e 90 períodos utilizando diferentes sobrecargas do método Draw.Region. Na primeira sobrecarga, vamos pintar essa região desde o início do gráfico utilizando os índices de barras e na segunda sobrecarga, vamos pintar apenas um intervalo de datahora específico.

				
					protected override void OnBarUpdate()
{
    //Pinta a região entre as duas médias em todo o gráfico
    Draw.Region(this, "pinturaRegiao", CurrentBar, 0, EMA(9), EMA(90), Brushes.White, Brushes.Blue, 30);
    
    //Pinta a região entre as médias apenas no intervalo de data informado
    Draw.Region(this, "pinturaTempo", new DateTime(2023,8,30), new DateTime(2023,8,31,9,5,30), EMA(9), EMA(90), Brushes.Blue, Brushes.Yellow, 80);
}
				
			

Como escrever texto nas barras e em região fixa do gráfico?

Reproduzir vídeo

Seguem abaixo dois exemplos de pintura de região entre as médias exponencias de 9 e 90 períodos utilizando diferentes sobrecargas do método Draw.Region. Na primeira sobrecarga, vamos pintar essa região desde o início do gráfico utilizando os índices de barras e na segunda sobrecarga, vamos pintar apenas um intervalo de datahora específico.

				
					protected override void OnBarUpdate()
{
    //Cria texto nas barras que fecharam acima da barra anterior
    if (isRising(Close))
        Draw.Text(this, "Barra" + CurrentBar.ToString(), true, Close[0].ToString(), Close[0], 0, Brushes.White, new SimpleFont(), TextAlignment.Left, Brushes.Yellow, Brushes.Blue, 20);
        
    //Cria um texto em região específica do gráfico
    Draw.TextFixed(this, "TextoFixo", "Coded by NeoTraderBot\n", TextPosition.BottomRight);
}
				
			

Snippets para Utilização de Indicadores da Plataforma

Introdução

Esta seção visa apresentar trechos de códigos com exemplos de utilização dos indicadores disponibilizados na plataforma.

Você pode acessar os Snippets diretamente pelo menu lateral direito, ou fazendo CRL+F (CTRL+L) para localizar algum texto específico na página, uma vez que o conteúdo tende a crescer ao longo do tempo, dificultando a navegação pelo menu.

Caso tenham sugestões de código para acrescentar à lista, gentileza deixar o código nos comentários com o link para seu perfil em rede social (para devido crédito de autoria).

Snippets

Como instanciar um indicador nativo - Ex: Bandas de Bollinger?

Reproduzir vídeo

Os indicadores podem ser utilizados apenas chamando seus métodos, não havendo necessidade de atribuir a uma variável da classe do seu NinjaScript. Veja o exemplo abaixo no qual apenas plotamos a Banda de Bollinger, utilizando o indicador nativo da plataforma.

				
					#region Using declarations
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Xml.Serialization;
using NinjaTrader.Cbi;
using NinjaTrader.Gui;
using NinjaTrader.Gui.Chart;
using NinjaTrader.Gui.SuperDom;
using NinjaTrader.Gui.Tools;
using NinjaTrader.Data;
using NinjaTrader.NinjaScript;
using NinjaTrader.Core.FloatingPoint;
using NinjaTrader.NinjaScript.DrawingTools;
#endregion

//This namespace holds Indicators in this folder and is required. Do not change it. 
namespace NinjaTrader.NinjaScript.Indicators
{
	public class testeBollinger : Indicator
	{
		protected override void OnStateChange()
		{
			if (State == State.SetDefaults)
			{
				Description									= @"Enter the description for your new custom Indicator here.";
				Name										= "testeBollinger";
				Calculate									= Calculate.OnBarClose;
				IsOverlay									= false;
				DisplayInDataBox							= true;
				DrawOnPricePanel							= true;
				DrawHorizontalGridLines						= true;
				DrawVerticalGridLines						= true;
				PaintPriceMarkers							= true;
				ScaleJustification							= NinjaTrader.Gui.Chart.ScaleJustification.Right;
				//Disable this property if your indicator requires custom values that cumulate with each new market data event. 
				//See Help Guide for additional information.
				IsSuspendedWhileInactive					= true;
				AddPlot(Brushes.Orange, "BandaSuperior");
				AddPlot(Brushes.White, "BandaCentral");
				AddPlot(Brushes.Orange, "BandaInferior");
			}
			else if (State == State.Configure)
			{
			}
		}

		protected override void OnBarUpdate()
		{
			BandaSuperior[0] = Bollinger(2.0,20).Upper[0];
			BandaCentral[0] = Bollinger(2.0,20).Middle[0];
			BandaInferior[0] = Bollinger(2.0,20).Lower[0];

		}

		#region Properties

		[Browsable(false)]
		[XmlIgnore]
		public Series<double> BandaSuperior
		{
			get { return Values[0]; }
		}

		[Browsable(false)]
		[XmlIgnore]
		public Series<double> BandaCentral
		{
			get { return Values[1]; }
		}

		[Browsable(false)]
		[XmlIgnore]
		public Series<double> BandaInferior
		{
			get { return Values[2]; }
		}
		#endregion

	}
}

#region NinjaScript generated code. Neither change nor remove.

namespace NinjaTrader.NinjaScript.Indicators
{
	public partial class Indicator : NinjaTrader.Gui.NinjaScript.IndicatorRenderBase
	{
		private testeBollinger[] cachetesteBollinger;
		public testeBollinger testeBollinger()
		{
			return testeBollinger(Input);
		}

		public testeBollinger testeBollinger(ISeries<double> input)
		{
			if (cachetesteBollinger != null)
				for (int idx = 0; idx < cachetesteBollinger.Length; idx++)
					if (cachetesteBollinger[idx] != null &&  cachetesteBollinger[idx].EqualsInput(input))
						return cachetesteBollinger[idx];
			return CacheIndicator<testeBollinger>(new testeBollinger(), input, ref cachetesteBollinger);
		}
	}
}

namespace NinjaTrader.NinjaScript.MarketAnalyzerColumns
{
	public partial class MarketAnalyzerColumn : MarketAnalyzerColumnBase
	{
		public Indicators.testeBollinger testeBollinger()
		{
			return indicator.testeBollinger(Input);
		}

		public Indicators.testeBollinger testeBollinger(ISeries<double> input )
		{
			return indicator.testeBollinger(input);
		}
	}
}

namespace NinjaTrader.NinjaScript.Strategies
{
	public partial class Strategy : NinjaTrader.Gui.NinjaScript.StrategyRenderBase
	{
		public Indicators.testeBollinger testeBollinger()
		{
			return indicator.testeBollinger(Input);
		}

		public Indicators.testeBollinger testeBollinger(ISeries<double> input )
		{
			return indicator.testeBollinger(input);
		}
	}
}

#endregion

				
			

Snippets para Ordens e Administração de Trade

Esta seção visa apresentar trechos de códigos com exemplos de envio de ordens e administração de trade utilizando técnicas de stoploss (fixo, móvel, breakeven) e take profit.

Você pode acessar os Snippets diretamente pelo menu lateral direito, ou fazendo CRL+F (CTRL+L) para localizar algum texto específico na página, uma vez que o conteúdo tende a crescer ao longo do tempo, dificultando a navegação pelo menu.

Caso tenham sugestões de código para acrescentar à lista, gentileza deixar o código nos comentários com o link para seu perfil em rede social (para devido crédito de autoria).

Snippets

Como rotear ordens de maneira fácil (Modo gerenciado)?

Reproduzir vídeo

A NinjaTrader possui em seu NinjaScript uma camada de abstração para envio e gestão de ordens. Este modo é chamado de modo gerenciado e seu funcionamento torna bem simples a implementação de estratégias para iniciantes e até mesmo pessoas com conhecimento intermediário.

No modo gerenciado, as ordens são válidas apenas até o próximo candle/barra, o que simplifica a gestão de ordens abertas e cancelamentos. E também há diversos controles que reduzem a chance de problemas na administração da posição da estratégia.

Veja abaixo um exemplo do envio de ordens em NinjaScript utilizando o modo gerenciado.

				
					#region Using declarations
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Xml.Serialization;
using NinjaTrader.Cbi;
using NinjaTrader.Gui;
using NinjaTrader.Gui.Chart;
using NinjaTrader.Gui.SuperDom;
using NinjaTrader.Gui.Tools;
using NinjaTrader.Data;
using NinjaTrader.NinjaScript;
using NinjaTrader.Core.FloatingPoint;
using NinjaTrader.NinjaScript.Indicators;
using NinjaTrader.NinjaScript.DrawingTools;
#endregion

//This namespace holds Strategies in this folder and is required. Do not change it. 
namespace NinjaTrader.NinjaScript.Strategies
{
	public class TestingOrdersStrategy : Strategy
	{
		private TimeSpan tsOpen;
		private TimeSpan tsClose;
		private Order myOrder;
		
		
		protected override void OnStateChange()
		{
			if (State == State.SetDefaults)
			{
				Description									= @"Enter the description for your new custom Strategy here.";
				Name										= "TestingOrdersStrategy";
				Calculate									= Calculate.OnBarClose;
				EntriesPerDirection							= 1;
				EntryHandling								= EntryHandling.AllEntries;
				IsExitOnSessionCloseStrategy				= true;
				ExitOnSessionCloseSeconds					= 30;
				IsFillLimitOnTouch							= false;
				MaximumBarsLookBack							= MaximumBarsLookBack.TwoHundredFiftySix;
				OrderFillResolution							= OrderFillResolution.Standard;
				Slippage									= 0;
				StartBehavior								= StartBehavior.WaitUntilFlat;
				TimeInForce									= TimeInForce.Gtc;
				TraceOrders									= false;
				RealtimeErrorHandling						= RealtimeErrorHandling.StopCancelClose;
				StopTargetHandling							= StopTargetHandling.PerEntryExecution;
				BarsRequiredToTrade							= 20;
				// Disable this property for performance gains in Strategy Analyzer optimizations
				// See the Help Guide for additional information
				IsInstantiatedOnEachOptimizationIteration	= true;
				PositionOpeningTime				= DateTime.Parse("10:30", System.Globalization.CultureInfo.InvariantCulture);
				PositionClosingTime				= DateTime.Parse("10:36", System.Globalization.CultureInfo.InvariantCulture);
			}
			else if (State == State.Configure)
			{
				tsOpen = new TimeSpan(PositionOpeningTime.Hour, PositionOpeningTime.Minute, 0);
				tsClose = new TimeSpan(PositionClosingTime.Hour, PositionClosingTime.Minute, 0);				
			}
		}

		protected override void OnBarUpdate()
		{
			//Match real-time order object based on a historical order object (run just once)
			if (myOrder != null && myOrder.IsBacktestOrder && State == State.Realtime)
      			myOrder = GetRealtimeOrder(myOrder);			
			
			//Open position at specified time (tsOpen)
			if ((Time[0].TimeOfDay == tsOpen) && (Position.MarketPosition == MarketPosition.Flat))
            {
				myOrder = EnterLong("openingSignal");
				//myOrder = EnterLongLimit(4451.25, "openingSignal");
				//myOrder = EnterLongStopMarket(4454.50, "openingSignal");
				
				
				//This will not open position, since the price reach that price a few bars after the order was submitted (Managed orders)
				//myOrder = EnterLongLimit(4450, "openingSignal");
				
				//This will not open position, since the price reach that price only 2 bars after the order was submitted (Managed orders)
				//myOrder = EnterLongStopMarket(4455, "openingSignal");
			}
			
			//Close position at specified time (tsClose)
			if (Time[0].TimeOfDay == tsClose)
            {
				if (Position.MarketPosition == MarketPosition.Long) { ExitLong("openingSignal"); }
				if (Position.MarketPosition == MarketPosition.Short) { ExitShort("openingSignal"); }
			}			
			
				
		}

		#region Properties
		[NinjaScriptProperty]
		[PropertyEditor("NinjaTrader.Gui.Tools.TimeEditorKey")]
		[Display(Name="OpeningTIime", Order=1, GroupName="Parameters")]
		public DateTime PositionOpeningTime
		{ get; set; }

		[NinjaScriptProperty]
		[PropertyEditor("NinjaTrader.Gui.Tools.TimeEditorKey")]
		[Display(Name="ClosingTime", Order=2, GroupName="Parameters")]
		public DateTime PositionClosingTime
		{ get; set; }
		#endregion

	}
}

				
			

Como fazer Gestão de Risco das operações de maneira simples (Stoploss/TakeProfit)?

Reproduzir vídeo

No âmbito da camada de abstração do NinjaScript, existem algumas funções que facilitam bastante a adoção de práticas de gestão de risco para operações no código fonte. 

Veja abaixo duas formas de definir o stoploss e alvo (take profit) das operações de maneira estática, ou seja, fixa durante toda a execução da estratégia, ou de maneira dinâmica, ajustando o risco de acordo com as condições do mercado.

Gestão de risco estática

Nesta situação, os parâmetros para o stoploss e alvo das operações são definidos na transição para o estado Configure da estratégia, podendo inclusive, serem utilizados parâmetros de entrada para fins de otimização futura.

				
					#region Using declarations
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Xml.Serialization;
using NinjaTrader.Cbi;
using NinjaTrader.Gui;
using NinjaTrader.Gui.Chart;
using NinjaTrader.Gui.SuperDom;
using NinjaTrader.Gui.Tools;
using NinjaTrader.Data;
using NinjaTrader.NinjaScript;
using NinjaTrader.Core.FloatingPoint;
using NinjaTrader.NinjaScript.Indicators;
using NinjaTrader.NinjaScript.DrawingTools;
#endregion

//This namespace holds Strategies in this folder and is required. Do not change it.
namespace NinjaTrader.NinjaScript.Strategies
{
	public class TestingOpRiskManagement : Strategy
	{
		private TimeSpan tsOpen;
		private TimeSpan tsClose;
		private Order myOrder;


		protected override void OnStateChange()
		{
			if (State == State.SetDefaults)
			{
				Description									= @"Enter the description for your new custom Strategy here.";
				Name										= "TestingOpRiskManagement";
				Calculate									= Calculate.OnBarClose;
				EntriesPerDirection							= 1;
				EntryHandling								= EntryHandling.AllEntries;
				IsExitOnSessionCloseStrategy				= true;
				ExitOnSessionCloseSeconds					= 30;
				IsFillLimitOnTouch							= false;
				MaximumBarsLookBack							= MaximumBarsLookBack.TwoHundredFiftySix;
				OrderFillResolution							= OrderFillResolution.Standard;
				Slippage									= 0;
				StartBehavior								= StartBehavior.WaitUntilFlat;
				TimeInForce									= TimeInForce.Gtc;
				TraceOrders									= false;
				RealtimeErrorHandling						= RealtimeErrorHandling.StopCancelClose;
				StopTargetHandling							= StopTargetHandling.PerEntryExecution;
				BarsRequiredToTrade							= 20;
				// Disable this property for performance gains in Strategy Analyzer optimizations
				// See the Help Guide for additional information
				IsInstantiatedOnEachOptimizationIteration	= true;
				PositionOpeningTime				= DateTime.Parse("10:30", System.Globalization.CultureInfo.InvariantCulture);
				PositionClosingTime				= DateTime.Parse("16:00", System.Globalization.CultureInfo.InvariantCulture);
			}
			else if (State == State.Configure)
			{
				tsOpen = new TimeSpan(PositionOpeningTime.Hour, PositionOpeningTime.Minute, 0);
				tsClose = new TimeSpan(PositionClosingTime.Hour, PositionClosingTime.Minute, 0);
				
				// Static risk management. Stoploss and Target are defined and maintained fixed through the strategy lifetime
				SetStopLoss(CalculationMode.Ticks, 20);
				//SetTrailStop(CalculationMode.Ticks, 24);
				SetProfitTarget(CalculationMode.Ticks, 60);
			}
		}

		protected override void OnBarUpdate()
		{
			if (myOrder != null && myOrder.IsBacktestOrder && State == State.Realtime)
      			myOrder = GetRealtimeOrder(myOrder);

			//Open position at specified time (tsOpen)
			if ((Time[0].TimeOfDay == tsOpen) && (Position.MarketPosition == MarketPosition.Flat))
            {
				Random rnd = new Random();

				if (rnd.Next(0,2) == 0)
					myOrder = EnterLong("openingSignal");
				else
					myOrder = EnterShort("openingSignal");
			}

			//Close position at specified time (tsClose)
			if (Time[0].TimeOfDay == tsClose)
            {
				if (Position.MarketPosition == MarketPosition.Long) { ExitLong("openingSignal"); }
				if (Position.MarketPosition == MarketPosition.Short) { ExitShort("openingSignal"); }
			}


		}

		#region Properties
		[NinjaScriptProperty]
		[PropertyEditor("NinjaTrader.Gui.Tools.TimeEditorKey")]
		[Display(Name="OpeningTIime", Order=1, GroupName="Parameters")]
		public DateTime PositionOpeningTime
		{ get; set; }

		[NinjaScriptProperty]
		[PropertyEditor("NinjaTrader.Gui.Tools.TimeEditorKey")]
		[Display(Name="ClosingTime", Order=2, GroupName="Parameters")]
		public DateTime PositionClosingTime
		{ get; set; }
		#endregion

	}
}
				
			

Gestão de risco dinâmica

Nesta situação, os parâmetros para o stoploss e alvo das operações são definidos no método onBarUpdate e a frequencia de atualização dependerá da propriedade da estratégia relacionada a frequência de cálculo. Neste modo, o trader pode utilizar qualquer lógica que desejar, podendo inclusive utilizar indicadores técnicos, a exemplo do ATR (Average True Range).

				
					#region Using declarations
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Xml.Serialization;
using NinjaTrader.Cbi;
using NinjaTrader.Gui;
using NinjaTrader.Gui.Chart;
using NinjaTrader.Gui.SuperDom;
using NinjaTrader.Gui.Tools;
using NinjaTrader.Data;
using NinjaTrader.NinjaScript;
using NinjaTrader.Core.FloatingPoint;
using NinjaTrader.NinjaScript.Indicators;
using NinjaTrader.NinjaScript.DrawingTools;
#endregion

//This namespace holds Strategies in this folder and is required. Do not change it.
namespace NinjaTrader.NinjaScript.Strategies
{
	public class TestingOpRiskManagement : Strategy
	{
		private TimeSpan tsOpen;
		private TimeSpan tsClose;
		private Order myOrder;


		protected override void OnStateChange()
		{
			if (State == State.SetDefaults)
			{
				Description									= @"Enter the description for your new custom Strategy here.";
				Name										= "TestingOpRiskManagement";
				Calculate									= Calculate.OnBarClose;
				EntriesPerDirection							= 1;
				EntryHandling								= EntryHandling.AllEntries;
				IsExitOnSessionCloseStrategy				= true;
				ExitOnSessionCloseSeconds					= 30;
				IsFillLimitOnTouch							= false;
				MaximumBarsLookBack							= MaximumBarsLookBack.TwoHundredFiftySix;
				OrderFillResolution							= OrderFillResolution.Standard;
				Slippage									= 0;
				StartBehavior								= StartBehavior.WaitUntilFlat;
				TimeInForce									= TimeInForce.Gtc;
				TraceOrders									= false;
				RealtimeErrorHandling						= RealtimeErrorHandling.StopCancelClose;
				StopTargetHandling							= StopTargetHandling.PerEntryExecution;
				BarsRequiredToTrade							= 20;
				// Disable this property for performance gains in Strategy Analyzer optimizations
				// See the Help Guide for additional information
				IsInstantiatedOnEachOptimizationIteration	= true;
				PositionOpeningTime				= DateTime.Parse("10:30", System.Globalization.CultureInfo.InvariantCulture);
				PositionClosingTime				= DateTime.Parse("16:00", System.Globalization.CultureInfo.InvariantCulture);
			}
			else if (State == State.Configure)
			{
				tsOpen = new TimeSpan(PositionOpeningTime.Hour, PositionOpeningTime.Minute, 0);
				tsClose = new TimeSpan(PositionClosingTime.Hour, PositionClosingTime.Minute, 0);
				
				// Static risk management. Stoploss and Target are defined and maintained fixed through the strategy lifetime
				//SetStopLoss(CalculationMode.Ticks, 20);
				//SetTrailStop(CalculationMode.Ticks, 24);
				//SetProfitTarget(CalculationMode.Ticks, 60);
			}
		}

		protected override void OnBarUpdate()
		{
			if (myOrder != null && myOrder.IsBacktestOrder && State == State.Realtime)
      			myOrder = GetRealtimeOrder(myOrder);

			//Open position at specified time (tsOpen)
			if ((Time[0].TimeOfDay == tsOpen) && (Position.MarketPosition == MarketPosition.Flat))
            {
				Random rnd = new Random();
				double volatility = Math.Ceiling(ATR(500)[0]/TickSize);
				double stoplossTicks = 5*volatility;
				double takeProfitTicks = 3*stoplossTicks;
				
				
				// Dynamic risk management. Stoploss and Target are adapted to market conditions
				SetTrailStop(CalculationMode.Ticks, stoplossTicks);
				SetProfitTarget(CalculationMode.Ticks, takeProfitTicks);
				Print("CurrentBar: " + CurrentBar.ToString() + " - Stoploss: " + stoplossTicks.ToString() + " ticks | Target: " 
				                     + takeProfitTicks.ToString() + " ticks");
				
					
				if (rnd.Next(0,2) == 0)
					myOrder = EnterLong("openingSignal");
				else
					myOrder = EnterShort("openingSignal");
			}

			//Close position at specified time (tsClose)
			if (Time[0].TimeOfDay == tsClose)
            {
				if (Position.MarketPosition == MarketPosition.Long) { ExitLong("openingSignal"); }
				if (Position.MarketPosition == MarketPosition.Short) { ExitShort("openingSignal"); }
			}


		}

		#region Properties
		[NinjaScriptProperty]
		[PropertyEditor("NinjaTrader.Gui.Tools.TimeEditorKey")]
		[Display(Name="OpeningTIime", Order=1, GroupName="Parameters")]
		public DateTime PositionOpeningTime
		{ get; set; }

		[NinjaScriptProperty]
		[PropertyEditor("NinjaTrader.Gui.Tools.TimeEditorKey")]
		[Display(Name="ClosingTime", Order=2, GroupName="Parameters")]
		public DateTime PositionClosingTime
		{ get; set; }
		#endregion

	}
}
				
			

Snippets para Implementação de estratégias

Outros Snippets

Esta seção visa apresentar outros exemplos de trechos de códigos que não se enquadram nas categorias anteriores.

Você pode acessar os Snippets diretamente pelo menu lateral direito, ou fazendo CRL+F (CTRL+L) para localizar algum texto específico na página, uma vez que o conteúdo tende a crescer ao longo do tempo, dificultando a navegação pelo menu.

Caso tenham sugestões de código para acrescentar à lista, gentileza deixar o código nos comentários com o link para seu perfil em rede social (para devido crédito de autoria).

Snippets

Como escrever log com o horário de abertura da candle/barra para facilitar depuração (debug)?

Gerar log de execução de uma estratégia é a melhor forma de rastrear possíveis problemas de lógica ou de execução quando seu robô já está operando. Segue abaixo um trecho que identifica no texto a ser escrito no log o dia/hora início da barra/candle.

OBS: Uma maneira muito efetiva de depurar problemas no seu NinjaScript é utilizar a depuração no Visual Studio! Esta é a maneira recomendável de se aprofundar no estudo de problemas do seu NinjaScript.

				
					string msg = "Mensagem de Teste;
NinjaTrader.Code.Output.Process(Time[0].ToString() + " - " + msg, PrintTo.OutputTab2);
				
			

Da maneira acima, você pode selecionar em qual aba da janela de saída gostaria de imprimir a mensagem de log. Abaixo tem um forma resumida de escrever na saída 1.

				
					string msg = "Mensagem de Teste;
Print(Time[0].ToString() + " - " + msg);
				
			

Snippets para Localização Temporal

Esta seção visa apresentar trechos de códigos com funcionalidades relativas à localização temporal da estratégia. Por exemplo, identificar se a atual barra é a primeira barra do dia para verificar gap diário.

Você pode acessar os Snippets diretamente pelo menu lateral direito, ou fazendo CTRL+F (CTRL+L) para localizar algum texto específico na página, uma vez que o conteúdo tende a crescer ao longo do tempo, dificultando a navegação pelo menu.

Caso tenham sugestões de código para acrescentar à lista, gentileza deixar o código nos comentários com o link para seu perfil em rede social (para devido crédito de autoria).

Snippets

Identificação de primeira barra da sessão ou do dia

Algumas estratégias necessitam da identificação da primeira barra do dia ou da primeira barra da sessão de negociação atual para executar determinada ação ou calcular o gap em relação ao fechamento da sessão anterior. Segue abaixo um trecho de código para identificar essas barras.

				
					namespace NinjaTrader.NinjaScript.Indicators
{
	public class NTB_Ex_FirstSessionBar : Indicator
	{
		protected override void OnStateChange()
		{

			if (State == State.SetDefaults)
			{ 
				Description									= @"NeoTraderBot Example: How to locate first bar of Session or Day";
				Name										= "NTB_Ex_FirstSessionBar";
				Calculate									= Calculate.OnBarClose;
				IsOverlay									= false;
				DisplayInDataBox							= true;
				DrawOnPricePanel							= true;
				DrawHorizontalGridLines						= true;
				DrawVerticalGridLines						= true;
				PaintPriceMarkers							= true;
				ScaleJustification							= NinjaTrader.Gui.Chart.ScaleJustification.Right;
				//Disable this property if your indicator requires custom values that cumulate with each new market data event. 
				//See Help Guide for additional information.
				IsSuspendedWhileInactive					= true;
				
            }
		}

		protected override void OnBarUpdate()
		{
            
			// Uncomment line below if you want to locate the first bar of the day
			//if (Time[0].Date != Time[1].Date)
            // Uncomment line below if you want to locate the first bar of the session
			if (Bars.IsFirstBarOfSession)
            {
				DateTime datahora = Time[0];
				NinjaTrader.Code.Output.Process("[" + datahora.ToString() + "] - The bar was located!", PrintTo.OutputTab1);
				BackBrushes[0] = Brushes.Blue;
            }
		}

	}
}
				
			

Identificação do primeiro tick de uma barra

Algumas estratégias podem necessitar de uma atuação mais tempestiva, porém, o programador gostaria de selecionar quais ações seria executadas no tick e quais seriam no fechamento da barra. Para isso, podemos criar um NinjaScript com a propriedade de cálculo configurada em Calculate.OnEachTick, e filtrar nas chamadas ao método OnBarUpdate o primeiro tick da barra, sinalizando o fechamento da barra anterior.

Assim temos liberdade para programar o NinjaScript para executar ações tanto no fechamento da barra quanto durante a formação de uma barra. Veja o código de exemplo abaixo:

				
					namespace NinjaTrader.NinjaScript.Indicators
{
	public class NTB_Ex_FirstTickOfBar : Indicator
	{
		protected override void OnStateChange()
		{

			if (State == State.SetDefaults)
			{ 
				Description									= @"NeoTraderBot Example: How to locate first bar of Session or Day";
				Name										= "NTB_Ex_FirstTickOfBar";
				Calculate									= Calculate.OnEachTick;
				IsOverlay									= false;
				DisplayInDataBox							= true;
				DrawOnPricePanel							= true;
				DrawHorizontalGridLines						= true;
				DrawVerticalGridLines						= true;
				PaintPriceMarkers							= true;
				ScaleJustification							= NinjaTrader.Gui.Chart.ScaleJustification.Right;
				//Disable this property if your indicator requires custom values that cumulate with each new market data event. 
				//See Help Guide for additional information.
				IsSuspendedWhileInactive					= true;
				
            }
		}

		protected override void OnBarUpdate()
		{
			if ( IsFirstTickOfBar)
			{
				Draw.Text(this,"teste","Primeiro Tick!",0,Close[0]);
			}
			else Draw.Text(this,"teste","Outros Ticks!",0,Close[0]);
		}

	}
}
				
			

Identificação de barra por data e hora específicos

Reproduzir vídeo

Este código localiza a barra (candle ou box) por uma data e hora desejados. Onde a hora é referente ao horário de abertura do candle desejado.

Observe que criamos um parâmetro no qual o usuário pode inserir um horário para facilitar os testes. O código pode tanto colorir o fundo da barra no horário especificado no dia atual ou nesse mesmo horário em todos os dias de negociação.

				
					namespace NinjaTrader.NinjaScript.Indicators
{
	public class NTB_Ex_DateTime : Indicator
	{
		public TimeSpan TimeOfDay;

		protected override void OnStateChange()
		{

			if (State == State.SetDefaults)
			{
				Description									= @"NeoTraderBot Example: How to find bars at specific Time or DateTime";
				Name										= "NTB_Ex_DateTime";
				Calculate									= Calculate.OnBarClose;
				IsOverlay									= false;
				DisplayInDataBox							= true;
				DrawOnPricePanel							= true;
				DrawHorizontalGridLines						= true;
				DrawVerticalGridLines						= true;
				PaintPriceMarkers							= true;
				ScaleJustification							= NinjaTrader.Gui.Chart.ScaleJustification.Right;
				//Disable this property if your indicator requires custom values that cumulate with each new market data event.
				//See Help Guide for additional information.
				IsSuspendedWhileInactive					= true;
				DesiredDateTime								= DateTime.Parse("10:31", System.Globalization.CultureInfo.InvariantCulture);

            }
			else if (State == State.Configure)
			{
				TimeOfDay = new TimeSpan(DesiredDateTime.Hour, DesiredDateTime.Minute, 0);
			}
				
		}

		protected override void OnBarUpdate()
		{

			// Uncomment line below if you want to sign the bar at a specific time just for the current date
			//if (Time[0] == DesiredDateTime)
            // Uncomment line below if you want to sign the bar at a specific time each day
			if (Time[0].TimeOfDay == TimeOfDay)
            {
				DateTime datahora = Time[0];
				NinjaTrader.Code.Output.Process("[" + datahora.ToString() + "] - This is the desired bar!", PrintTo.OutputTab1);
				BackBrushes[0] = Brushes.Blue;
            }
		}

		#region Properties
		[NinjaScriptProperty]
		[PropertyEditor("NinjaTrader.Gui.Tools.TimeEditorKey")]
		[Display(Name="DesiredDateTime", Order=1, GroupName="Parameters")]
		public DateTime DesiredDateTime
		{ get; set; }
		#endregion

	}
}
				
			

Ferramentas de Trading

Nesta seção vamos apresentar informações sobre as ferramentas de trading desenvolvidas pela NeoTraderBot para NinjaTrader, bem como informações relevantes para instalação e configuração em sua plataforma.

Como instalar/remover as ferramentas na NinjaTrader?

Este tutorial visa apresentar o passo a passo para instalação e remoção de uma add-on na plataforma NinjaTrader, o que aplica-se às ferramentas e códigos compilados da NeoTraderBot.

Instalando as ferramentas da NeoTraderBot na NinjaTrader

Passo 1: No Control Center, clique em “Tools” -> “Import” -> “NinjaScript Add-On…”

Passo 2: Em seguida, selecione o arquivo “.zip” da ferramenta de deseja instalar na sua NinjaTrader

Passo 3: Caso a importação ocorra com sucesso, você deve visualizar uma mensagem semelhante a da imagem abaixo.

Se houver algum problema na importação, a NinjaTrader irá sinalizar uma mensagem de erro.

Acesse o Control Center e vá na aba “Log” (conforme imagem abaixo). Copie a mensagem de erro relacionada à importação da ferramenta e encaminhe um email para neotraderbot@gmail.com.

Removendo ferramentas (Add-ons) da NinjaTrader

Passo 1: No Control Center, clique em “Tools” -> “Remove NinjaScript Assembly”

Passo 2: Selecione o Add-on que deseja remover da sua plataforma

Passo 3: Uma caixa de diálogo irá aparecer para solicitar a confirmação da remoção. Certifique-se de que está removendo o add-on correto antes de confirmar.

Passo 4: Uma vez removido o Add-on, será exibida uma janela de confirmação da remoção (conforme imagem abaixo).

Como obter o MachineID da minha NinjaTrader?

Este tutorial visa apresentar o passo a passo para gerar um MachineID da sua NinjaTrader. Uma vez adquirido qualquer add-on, esta chave deve ser informada à NeoTraderBot para ativação do uso do add-on em sua máquina.

Gerando o seu MachineID

Passo 1: No Control Center, clique em “Help” -> “3rd Party Licensing”.

Passo 2: Na tela que abrir, você deve digitar “NeoTraderBot” no campo “Vendor name” e inserir o seu e-mail no campo “User defined ID”, ou em caso de erro por caracteres especiais, insira o seu nome completo sem espaços ou acentos. Em seguida, clique em “Submit”.

Será gerado uma chave de Machine ID, a qual você deve copiar e enviar para nós, por meio do formulário a seguir. Copie a chave completa (ela será composta também pelas informações que você inseriu no campo User defined ID (ID do usuário).

Ativando as ferramentas/add-ons com MachineID

Passo 1: Caso tenha adquirido a licença de uso de alguma ferramenta, contratado a assinatura ou serviço de programação da NeoTraderBot, informe pelo formulário abaixo as suas informações para fins de liberação de uso do código baixado/enviado para o seu e-mail.

OBS: Para o período de 7 dias de teste das ferramentas, não é obrigatório o envio do Machine ID. Uma vez enviado o Machine ID, iremos liberar o uso da ferramenta em um prazo máximo de 1 dia útil.

Liberação de Acesso NinjaTrader
Este formulário visa recepcionar as chaves dos usuários para liberação de uso das ferramentas e códigos desenvolvidos pela NeoTraderBot

Documentação - Flash Click

Esta página visa apresentar uma documentação completa da ferramenta Flash Click para fins de referência em caso de dúvidas.

Assim, sugerimos utilizar o menu lateral direito de conteúdo para ir direto nas seções de interesse.

Ressaltamos que as orientações para instalação e ativação da licença contratada foram enviadas por e-mail no momento da contratação.

Objetivo da ferramenta e funcionalidades disponíveis

O objetivo principal da ferramenta Flash Click é permitir uma ação ágil por parte do trader aos rápidos movimentos do mercado, bem como mensurar da maneira adequada os riscos de cada posição a ser aberta, criando as ordens de maneira natural com um clique do mouse no gráfico.

Como sempre gostamos de entregar um pouco mais, você perceberá alguns detalhes e funcionalidades adicionais no decorrer do conteúdo dessa página.

Veja abaixo as funcionalidades disponíveis na Flash Click:

        • Cria ordens diretamente no gráfico por meio da combinação de uma tecla (Ctrl, Alt ou Shift) com o botão esquerdo do mouse
        • Funciona com estratégias ATM em qualquer configuração (ticks, preço, financeiro, pips…)
        • Apresenta as linhas de entrada, alvo e stop da sua estratégia ATM antes de posicionar a ordem
        • Ferramenta 100% customizada (teclas de atalho, cores, tracejados, espessura, …)
        • Permite configurar ordens stop como Stop-limit ou Stop a mercado
        • Barra superior de ativação, configuração e situação da posição atual (em valores financeiros e ticks)

Como abrir a Flash Click em um gráfico da NinjaTrader

A ferramenta Flash Click deve ser adicionada a um gráfico como indicador. Para isso você pode clicar no ícone referente a indicadores na barra superior do gráfico (conforme figura abaixo) ou usar o atalho CTRL+I.

Nos indicadores disponíveis, você irá encontrar uma pasta com o nome “NeoTraderBot_Indicators”. Abra essa pasta e clique clique duas vezes sobre “NTB_FlashClick” (ou clique no botão add na parte inferior da janela).

Você perceberá que o indicador passará para área de indicadores configurados e a caixa de propriedades à direita estará editável para configurações da ferramenta.

Clique em “OK”. A janela irá se fechar e a ferramenta será aplicada ao gráfico. Caso apareça a mensagem abaixo, significa que você precisa habilitar o ChartTrader no gráfico, seja no modo visível ou escondido, pois a FlashClick utiliza dados das estratégias ATM e quantidades a serem negociadas a partir do ChartTrader.

Após habilitar o ChartTrader, basta apertar F5 para recarregar os indicadores. A mensagem visualizada anteriormente não deve se apresentar. Você pode se certificar que a Flash Click está carregada ao visualizar sua barra de configuração na parte superior do gráfico (conforme imagem abaixo).

Configurações da ferramenta pela Barra de Ferramentas

Uma vez aplicada ao gráfico, você poderá pela barra superior da ferramenta Flash Click, habilitar ou desabilitar a criação de ordens pelo mouse. Por padrão, a ferramenta é carregada no modo OFF, evitando erros de criação de ordens na inicialização da ferramenta.

Também é possível configurar qual o tipo de ordem stop será criada: Stop à mercado ou Stop-limit. As ordens stop a mercado servem para criar ordens visando o rompimento de um nível de preço. Por serem ordens a mercado, pode-se incorrer em elevados níveis de slippage a depender da situação do mercado. 

As ordens stop-limit, visam reduzir o efeito de slippage. Uma vez rompido o nível de preço da ordem, é posicionada uma ordem limitada.

Por fim, a barra superior da Flash Click também apresenta informação sobre a conta operada e posição corrente com o resultado aberto em termos financeiros e em ticks.

Configurações e Parâmetros (Janela de configuração de indicador)

Ao acessar os indicadores do gráfico (CTRL+I), você poderá configurar várias propriedades da ferramenta Flash Click.

No grupo “FlashClick settings” é possível configurar o tipo de ordem stop a ser utilizado, bem como as teclas de atalho para compra e venda em conjunção com o clique esquerdo do mouse.

No grupo “Entry/Take Profit/Stoploss lines”, o usuário pode habilitar ou desabilitar a plotagem de linhas conforme estratégia ATM aplicada no ChartTrader. É possível personalizar a cor das linhas, tipo de tracejado e espessura.

No grupo “Info box settings”, o usuário pode habilitar/desabilitar a caixa de informações exibida quando se aperta uma das teclas de ordem (compra/venda). Pode também configurar os aspectos visuais da caixa, tais como cor da fonte, do fundo, tamanho do texto, posição da caixa de informação e opacidade.

Visualizando os Níveis de preço das ordens da estratégia ATM e criando ordens

Estando a Flash Click habilitada, ao pressionar uma das teclas de atalho (compra/venda) configuradas na ferramenta, e havendo uma estratégia ATM selecionada, o usuário irá verificar no gráfico as linhas de alvo e stoploss configuradas na estratégia ATM. A Flash Click calcula as linhas em qualquer unidade definida nas estratégias ATM (preço, ticks, percentual ou pips).

Ao manter a tecla pressionada e movimentar o mouse, as linhas irão acompanhar o movimento, projetando as ordens de alvo/stop, bem como a caixa de informação com o valor da ordem de abertura de posição (caso esteja habilitada).

Caso o usuário solte a tecla de atalho, as linhas são removidas do gráfico. Se o usuário clicar com o botão esquerdo do mouse, serão criadas ordens do tipo stop ou limitada de acordo com o lado da operação e posição em relação ao valor atualmente negociado.

Visualizando as ordens criadas

As imagens abaixo demonstram a visualização de uma ordem de venda Stop-Limit (sigla SLM) e uma ordem de compra stop a mercado (sigla STP).

Barra de Ferramentas: Resultado da posição corrente

As imagens abaixo demonstram a visualização na barra de ferramentas criada pela Flash Click o resultado aberto em valores financeiros e em ticks. A barra apresentará o texto em verde caso o resultado da operação seja positivo. Em vermelho, se o resultado corrente da operação for negativo. E em branco se o resultado aberto for igual a zero ou não haver posição aberta.

É interessante observar que mesmo havendo uma posição aberta, a Flash Trader continua a apresentar as projeções de uma nova abertura de posição, caso uma das teclas de atalho seja acionada (conforme figura abaixo).

Documentação - IntelliRisk

Esta página visa apresentar uma documentação completa da ferramenta IntelliRisk para fins de referência em caso de dúvidas.

Assim, sugerimos utilizar o menu lateral direito de conteúdo para ir direto nas seções de interesse.

Ressaltamos que as orientações para instalação e ativação da licença contratada foram enviadas por e-mail no momento da contratação.

Objetivo da ferramenta e funcionalidades disponíveis

O objetivo principal da ferramenta IntelliRisk é fornecer as informações adequadas para que o trader possa tomar decisões sobre o risco de suas operações e conta, principalmente, para aqueles que estão participando de testes de mesas proprietárias (tais como Apex, TopStep, Bulenox, entre outras).

 

Veja abaixo as funcionalidades disponíveis na IntelliRisk:

        • Calcula o preço médio da sua posição de acordo com a montagem e realização parcial de sua posição
        • Apresenta o valor financeiro e em ticks em cada ordem de alvo e stop no gráfico, facilitando a sua gestão de risco da operação
        • Calcula o ponto de cobertura da sua conta (Daily Breakven). Uma vez com posição aberta, você saberá qual o nível de preço você ficaria com o resultado da sessão zerado.
        • Plota linha de limite de perda de mesas proprietárias: Trailling drawdown, static drawdown ou end of day. Permite monitorar em tempo real, uma vez posicionado, qual seria o nível de preço de risco máximo da conta.
        • Flexibilidade para escolher quais linhas deseja-se plotar no gráfico: preço médio, ponto de cobertura, limite de risco da conta
        • Ferramenta 100% customizada (cores, texto, plot de linhas, …)
        • Funciona em qualquer ativo, tipo de gráfico, tempo gráfico, janelas com multigráficos e multiabas

Como abrir a IntelliRisk em um gráfico da NinjaTrader

A ferramenta IntelliRisk deve ser adicionada a um gráfico como indicador. Para isso você pode clicar no ícone referente a indicadores na barra superior do gráfico (conforme figura abaixo) ou usar o atalho CTRL+I.

Documentação - Gain Guardian

Construtor de Capital - Liberação de acesso a Ferramentas

Este tutorial visa apresentar o passo a passo para liberação de acesso aos alunos/assinantes das ferramentas desenvolvidas pela NeoTraderBot para Construtor de Capital

Uma vez enviada a MachineID por meio do formulário ao final desta página, a liberação de acesso está condicionada à confirmação de vinculo (aluno) junto à Construtor de Capital e será realizada em até 1 dia útil.

Em caso de dúvidas ou questões relacionadas às ferramentas Construtor de Capital, envie e-mail para contrutordecapital1@gmail.com.

Gerando o seu MachineID

Passo 1: No Control Center, clique em “Help” -> “3rd Party Licensing”.

Passo 2: Na tela que abrir, você deve digitar “NeoTraderBot” no campo “Vendor name” e inserir o seu e-mail no campo “User defined ID”, ou em caso de erro por caracteres especiais, insira o seu nome completo sem espaços ou acentos e em letra minúscula. EM SEGUIDA, CLIQUE EM “SUBMIT” (ENVIAR).

Será gerada uma chave de Machine ID, a qual você deve copiar e enviar para nós, por meio do formulário a seguir. 

ATENÇÃO: Copie a chave completa (ela será composta também pelas informações que você inseriu no campo User defined ID (ID do usuário).

Liberação de Acesso - Ferramentas Construtor de Capital
Este formulário visa recepcionar as chaves dos usuários para liberação de uso das ferramentas e códigos desenvolvidos pela NeoTraderBot para Construtor de Capital

Snippets e How-to

Aprender a programar envolve esforço, persistência e também colaboração com outros programadores (esse é um dos benefícios de participar de uma Comunidade como a NeoTraderBot!).

Pensando em acelerar a curva de aprendizado e reduzir o tempo que ficamos presos com problemas de programação, organizamos esta área de Snippets e de How-To (tutoriais) para elaboração de estratégias e indicadores na TraderEvolution utilizando EvoCode.

Os Snippets são trechos de códigos independentes criados para executar uma determinada tarefa. Eles podem ser copiados e modificados de acordo com a necessidade do usuário

Navegue abaixo pelas categorias disponíveis e caso tenha alguma sugestão de nova categoria ou tarefa, comente nas áreas apropriadas. Caso tenha colegas que também possam fazer bom uso e contribuir com a Comunidade, compartilhe esta área do site pelos ícones abaixo.

 

Compartilhe essa página!

Share on facebook
Facebook
Share on telegram
Telegram
Share on whatsapp
WhatsApp
Share on email
Email

Snippets para Localização Temporal

Nesta área você terá acesso a pedaços de códigos fontes para localização da estratégia em relação ao tempo.

Tarefas disponibilizadas:

Snippets para Manipulação de Gráficos

Nesta área você terá acesso a pedaços de códigos fontes para manipular plot, cores de plotagem, espessura, tipo de gráfico, etc.

Tarefas disponibilizadas:

 

Snippets para Utilização de Indicadores da Plataforma

Nesta área você terá acesso a pedaços de códigos fontes para utilizar os indicadores disponibilizados por padrão na Plataforma.

Tarefas disponibilizadas:

 

Snippets para Ordens e Administração de Trade

Nesta área você terá acesso a pedaços de códigos fontes para execução de ordens e administração de trade (técnicas de stoploss e takeprofit).

Tarefas disponibilizadas:

Outros Snippets

Nesta área você terá acesso a pedaços de códigos fontes para objetivos não abrangidos pelas categorias acima.

Tarefas disponibilizadas:

 

Tutoriais sobre Estrutura de Código

Introdução

Esta seção visa apresentar trechos de códigos com funcionalidades relativas à estrutura do código de indicadores e estratégias. Por exemplo, como criar parâmetros de entrada.

Você pode acessar os Snippets/Tutoriais diretamente pelo menu lateral direito, ou fazendo CTRL+F (CTRL+L) para localizar algum texto específico na página, uma vez que o conteúdo tende a crescer ao longo do tempo, dificultando a navegação pelo menu.

Caso tenham sugestões de código para acrescentar à lista, gentileza deixar o código nos comentários com o link para seu perfil em rede social (para devido crédito de autoria).

Snippets/Tutoriais

Como criar parâmetros no meu indicador/estratégia?

Reproduzir vídeo

Os parâmetros de uma estratégia ou indicador são declarados como atributos da classe.

O que diferencia esses atributos dos demais atributos são as anotações (em C# chama-se Annotations e são contidas entre [ ]) que realizamos imediatamente antes da definição dos atributos. Vamos ver abaixo como criar diferentes tipos de parâmetros, como definir seu valor padrão, qual texto será exibido na interface de configuração da estratégia/indicador e pré-validações.

Os tipos de parâmetros possíveis em NinjaScript são: bool, int, double, string, DateTime e Brush. Ainda é possível utilizar eNum renderizando em formato de dropdown na GUI (veremos mais detalhes no exemplo completo).

A primeira anotação que realizamos é [NinjaScriptProperty]. Esta anotação irá informar ao pré-processador que no momento da compilação que o atributo deve ser exibido na interface de configuração do Indicador ou estratégia como parâmetro.

 

A segunda anotação que pode ser utilizada é um validador [Range()]. A função Range permite definir o valor mínimo e máximo no caso de parâmetros do tipo inteiro e double, permitindo a validação do valor inserido pela interface gráfica. No caso de parâmetros de data ou horário (DateTime), ao invés de utilizarmos Range, podemos fazer a anotação [PropertyEditor(“NinjaTrader.Gui.Tools.DateTimeEditorKey”)], onde “DateTimeEditorKey” será usado quando você quiser renderizar um seletor de datas e “TimeEditorKey” caso deseje-se renderizar um seletor de horário.

A terceira anotação é a chamada a função Display, que nos permitirá atribuir um nome ao parâmetro na interface gráfica, juntamente com um texto a ser apresentado como Tooltip (ou seja, quando o mouse passar sobre o nome do parâmetro), a ordem de exibição e o grupo no qual o parâmetro será exibido na tela de configuração.

Os valores padrão dos parâmetros devem ser definidos no estado SetDefaults quando chamado o método OnStateChange.

 

Veja a seguir alguns exemplos de definição de parâmetros para estratégia:

Parâmetro Inteiro (Exemplo: Qtde de períodos de uma média móvel)

No código abaixo a tela de configuração da estratégia/indicador apresentará como segundo parâmetro do grupo “Setup (by NeoTraderBot)” a ser definido a “Média rápida – Qtde de periodos” que é do tipo numérico e inteiro, variando entre 1 e o maior valor inteiro possível.

				
							[NinjaScriptProperty]
		[Range(1, int.MaxValue)]
		[Display(Name="Periods", Description="Number of period for MA", Order=2, GroupName="Setup (by NeoTraderBot)")]
		public int period
		{ get; set; }
				
			
Parâmetro Brush (Paleta de cores)

No código abaixo a tela de configuração da estratégia/indicador apresentará como segundo parâmetro do grupo “Appereance (by NeoTraderBot)” a ser definido o texto “Plot color”, que apresentará em uma caixa de seleção de paleta de cor. Observe a existência da anotação XmlIgnore, cujo propósito é evitar a serialização desse parâmetro ao salvar um template do indicador, pois isto poderia gerar erro na plataforma (esta anotação é incluída automaticamente pelo NinjaScript Wizard).

				
							[NinjaScriptProperty]
		[XmlIgnore]
		[Display(Name="Plot color", Description="Example how to use brush as a parameter", Order=2, GroupName="Appearence (by NeoTraderBot)")]
		public Brush plotColor
		{ get; set; }
				
			
Código de um indicador com TODOS os tipos de parâmetros em NinjaScript

No código abaixo você encontrará um exemplo de um indicador com todos os tipos de parâmetros possíveis em NinjaScript.

				
					#region Using declarations
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Xml.Serialization;
using NinjaTrader.Cbi;
using NinjaTrader.Gui;
using NinjaTrader.Gui.Chart;
using NinjaTrader.Gui.SuperDom;
using NinjaTrader.Gui.Tools;
using NinjaTrader.Data;
using NinjaTrader.NinjaScript;
using NinjaTrader.Core.FloatingPoint;
using NinjaTrader.NinjaScript.DrawingTools;
#endregion

//This namespace holds Indicators in this folder and is required. Do not change it. 
namespace NinjaTrader.NinjaScript.Indicators
{
	[Gui.CategoryOrder("Setup (by NeoTraderBot)", 1)]
	[Gui.CategoryOrder("Trading intervals (by NeoTraderBot)", 2)]
	[Gui.CategoryOrder("Appearence (by NeoTraderBot)", 3)]		
	public class _NTB_UserDefinedParameters : Indicator
	{
		protected override void OnStateChange()
		{
			if (State == State.SetDefaults)
			{
				Description									= @"Just a demonstration on how to include User Defined Parameters";
				Name										= "_NTB_UserDefinedParameters";
				Calculate									= Calculate.OnBarClose;
				IsOverlay									= false;
				DisplayInDataBox							= true;
				DrawOnPricePanel							= true;
				DrawHorizontalGridLines						= true;
				DrawVerticalGridLines						= true;
				PaintPriceMarkers							= true;
				ScaleJustification							= NinjaTrader.Gui.Chart.ScaleJustification.Right;
				//Disable this property if your indicator requires custom values that cumulate with each new market data event. 
				//See Help Guide for additional information.
				IsSuspendedWhileInactive					= true;
				
				avgType					= NeoTraderBot.MAType.SMA;
				period					= 9;
				percBand				= 2.0;
				msg						= @"Example of a msg to display on the chart!";
				daytradingMode			= true;
				DontTradeOn				= DateTime.Now;
				TradingStartAfter		= DateTime.Parse("09:00", System.Globalization.CultureInfo.InvariantCulture);
				TradingCloseAt			= DateTime.Parse("12:00", System.Globalization.CultureInfo.InvariantCulture);				
				plotColor				= Brushes.Orange;
				
			}
			else if (State == State.Configure)
			{
			}
		}

		protected override void OnBarUpdate()
		{
			//Add your custom indicator logic here.
		}

		#region Properties
		[Display(Name="MA Type", Description="Example of Dropbox parameter with enum", Order=1, GroupName="Setup (by NeoTraderBot)")]
		public NeoTraderBot.MAType avgType
		{ get; set; }	
		
		[NinjaScriptProperty]
		[Range(1, int.MaxValue)]
		[Display(Name="Periods", Description="Number of period for MA", Order=2, GroupName="Setup (by NeoTraderBot)")]
		public int period
		{ get; set; }

		[NinjaScriptProperty]
		[Range(1, double.MaxValue)]
		[Display(Name="% band around VWAP", Description="Just an example of double parameter", Order=3, GroupName="Setup (by NeoTraderBot)")]
		public double percBand
		{ get; set; }

		[NinjaScriptProperty]
		[Display(Name="Enable Daytrading mode", Order=4, GroupName="Setup (by NeoTraderBot)")]
		public bool daytradingMode
		{ get; set; }


		[NinjaScriptProperty]
		[PropertyEditor("NinjaTrader.Gui.Tools.DateTimeEditorKey")]
		[Display(Name="Dont Trade on", Description="Just an example of Date parameter", Order=1, GroupName="Trading intervals (by NeoTraderBot)")]
		public DateTime DontTradeOn
		{ get; set; }		
		
		[NinjaScriptProperty]
		[PropertyEditor("NinjaTrader.Gui.Tools.TimeEditorKey")]
		[Display(Name="Start trading after", Description="Time after the strategy will start to trade", Order=2, GroupName="Trading intervals (by NeoTraderBot)")]
		public DateTime TradingStartAfter
		{ get; set; }
		
		[NinjaScriptProperty]
		[PropertyEditor("NinjaTrader.Gui.Tools.TimeEditorKey")]
		[Display(Name="Trading close at", Description="Time at the strategy will stop trading and close open positions", Order=3, GroupName="Trading intervals (by NeoTraderBot)")]
		public DateTime TradingCloseAt
		{ get; set; }		


		
		
		[NinjaScriptProperty]
		[Display(Name="Display message", Description="Just an example of string parameter", Order=1, GroupName="Appearence (by NeoTraderBot)")]
		public string msg
		{ get; set; }		
		
		[NinjaScriptProperty]
		[XmlIgnore]
		[Display(Name="Plot color", Description="Example how to use brush as a parameter", Order=2, GroupName="Appearence (by NeoTraderBot)")]
		public Brush plotColor
		{ get; set; }

		[Browsable(false)]
		public string Teste6Serializable
		{
			get { return Serialize.BrushToString(plotColor); }
			set { plotColor = Serialize.StringToBrush(value); }
		}			
		#endregion

	}
}

namespace NeoTraderBot
{
	public enum MAType
	{
		SMA,
		EMA,
		WMA,
	}
}

#region NinjaScript generated code. Neither change nor remove.

namespace NinjaTrader.NinjaScript.Indicators
{
	public partial class Indicator : NinjaTrader.Gui.NinjaScript.IndicatorRenderBase
	{
		private _NTB_UserDefinedParameters[] cache_NTB_UserDefinedParameters;
		public _NTB_UserDefinedParameters _NTB_UserDefinedParameters(int period, double percBand, bool daytradingMode, DateTime dontTradeOn, DateTime tradingStartAfter, DateTime tradingCloseAt, string msg, Brush plotColor)
		{
			return _NTB_UserDefinedParameters(Input, period, percBand, daytradingMode, dontTradeOn, tradingStartAfter, tradingCloseAt, msg, plotColor);
		}

		public _NTB_UserDefinedParameters _NTB_UserDefinedParameters(ISeries<double> input, int period, double percBand, bool daytradingMode, DateTime dontTradeOn, DateTime tradingStartAfter, DateTime tradingCloseAt, string msg, Brush plotColor)
		{
			if (cache_NTB_UserDefinedParameters != null)
				for (int idx = 0; idx < cache_NTB_UserDefinedParameters.Length; idx++)
					if (cache_NTB_UserDefinedParameters[idx] != null && cache_NTB_UserDefinedParameters[idx].period == period && cache_NTB_UserDefinedParameters[idx].percBand == percBand && cache_NTB_UserDefinedParameters[idx].daytradingMode == daytradingMode && cache_NTB_UserDefinedParameters[idx].DontTradeOn == dontTradeOn && cache_NTB_UserDefinedParameters[idx].TradingStartAfter == tradingStartAfter && cache_NTB_UserDefinedParameters[idx].TradingCloseAt == tradingCloseAt && cache_NTB_UserDefinedParameters[idx].msg == msg && cache_NTB_UserDefinedParameters[idx].plotColor == plotColor && cache_NTB_UserDefinedParameters[idx].EqualsInput(input))
						return cache_NTB_UserDefinedParameters[idx];
			return CacheIndicator<_NTB_UserDefinedParameters>(new _NTB_UserDefinedParameters(){ period = period, percBand = percBand, daytradingMode = daytradingMode, DontTradeOn = dontTradeOn, TradingStartAfter = tradingStartAfter, TradingCloseAt = tradingCloseAt, msg = msg, plotColor = plotColor }, input, ref cache_NTB_UserDefinedParameters);
		}
	}
}

namespace NinjaTrader.NinjaScript.MarketAnalyzerColumns
{
	public partial class MarketAnalyzerColumn : MarketAnalyzerColumnBase
	{
		public Indicators._NTB_UserDefinedParameters _NTB_UserDefinedParameters(int period, double percBand, bool daytradingMode, DateTime dontTradeOn, DateTime tradingStartAfter, DateTime tradingCloseAt, string msg, Brush plotColor)
		{
			return indicator._NTB_UserDefinedParameters(Input, period, percBand, daytradingMode, dontTradeOn, tradingStartAfter, tradingCloseAt, msg, plotColor);
		}

		public Indicators._NTB_UserDefinedParameters _NTB_UserDefinedParameters(ISeries<double> input , int period, double percBand, bool daytradingMode, DateTime dontTradeOn, DateTime tradingStartAfter, DateTime tradingCloseAt, string msg, Brush plotColor)
		{
			return indicator._NTB_UserDefinedParameters(input, period, percBand, daytradingMode, dontTradeOn, tradingStartAfter, tradingCloseAt, msg, plotColor);
		}
	}
}

namespace NinjaTrader.NinjaScript.Strategies
{
	public partial class Strategy : NinjaTrader.Gui.NinjaScript.StrategyRenderBase
	{
		public Indicators._NTB_UserDefinedParameters _NTB_UserDefinedParameters(int period, double percBand, bool daytradingMode, DateTime dontTradeOn, DateTime tradingStartAfter, DateTime tradingCloseAt, string msg, Brush plotColor)
		{
			return indicator._NTB_UserDefinedParameters(Input, period, percBand, daytradingMode, dontTradeOn, tradingStartAfter, tradingCloseAt, msg, plotColor);
		}

		public Indicators._NTB_UserDefinedParameters _NTB_UserDefinedParameters(ISeries<double> input , int period, double percBand, bool daytradingMode, DateTime dontTradeOn, DateTime tradingStartAfter, DateTime tradingCloseAt, string msg, Brush plotColor)
		{
			return indicator._NTB_UserDefinedParameters(input, period, percBand, daytradingMode, dontTradeOn, tradingStartAfter, tradingCloseAt, msg, plotColor);
		}
	}
}

#endregion

				
			

Quando é chamado o método OnBarUpdate?

Reproduzir vídeo

Como criar estratégias/indicadores em múltiplos tempos gráficos (MTF)?

O código de exemplo abaixo apresenta um exemplo completo para você criar indicadores e estratégias em múltiplos tempos gráficos. Assista ao vídeo acima para entender o passo a passo da estruturação de um código MTF (multi Timeframe).

				
					#region Using declarations
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Xml.Serialization;
using NinjaTrader.Cbi;
using NinjaTrader.Gui;
using NinjaTrader.Gui.Chart;
using NinjaTrader.Gui.SuperDom;
using NinjaTrader.Gui.Tools;
using NinjaTrader.Data;
using NinjaTrader.NinjaScript;
using NinjaTrader.Core.FloatingPoint;
using NinjaTrader.NinjaScript.Indicators;
using NinjaTrader.NinjaScript.DrawingTools;
#endregion

//This namespace holds Strategies in this folder and is required. Do not change it. 
namespace NinjaTrader.NinjaScript.Strategies
{
	public class MTF_ExemploNeoTraderBot : Strategy
	{
		protected override void OnStateChange()
		{
			if (State == State.SetDefaults)
			{
				Description									= @"Example of NeoTraderBot";
				Name										= "MTF_ExemploNeoTraderBot";
				Calculate									= Calculate.OnBarClose;
				EntriesPerDirection							= 1;
				EntryHandling								= EntryHandling.AllEntries;
				IsExitOnSessionCloseStrategy				= true;
				ExitOnSessionCloseSeconds					= 30;
				IsFillLimitOnTouch							= false;
				MaximumBarsLookBack							= MaximumBarsLookBack.TwoHundredFiftySix;
				OrderFillResolution							= OrderFillResolution.Standard;
				Slippage									= 0;
				StartBehavior								= StartBehavior.WaitUntilFlat;
				TimeInForce									= TimeInForce.Gtc;
				TraceOrders									= false;
				RealtimeErrorHandling						= RealtimeErrorHandling.StopCancelClose;
				StopTargetHandling							= StopTargetHandling.PerEntryExecution;
				BarsRequiredToTrade							= 20;
				// Disable this property for performance gains in Strategy Analyzer optimizations
				// See the Help Guide for additional information
				IsInstantiatedOnEachOptimizationIteration	= true;
				
				AddPlot(new Stroke(Brushes.White, DashStyleHelper.Dash, 1), PlotStyle.Line, "EMA_CHART");
				AddPlot(new Stroke(Brushes.Yellow, DashStyleHelper.Solid, 1), PlotStyle.Line, "EMA_5MIN");
				AddPlot(new Stroke(Brushes.Blue, DashStyleHelper.Dash, 2), PlotStyle.Line, "EMA_15MIN");
				AddPlot(new Stroke(Brushes.Orange, DashStyleHelper.Solid, 2), PlotStyle.Line, "EMA_60MIN");
				
				
			}
			else if (State == State.Configure)
			{
				AddDataSeries(BarsPeriodType.Minute, 5);
				AddDataSeries(BarsPeriodType.Minute, 15);
				AddDataSeries(BarsPeriodType.Minute, 60);
			}
		}

		protected override void OnBarUpdate()
		{
			if (CurrentBars[0] < BarsRequiredToPlot || CurrentBars[1] < BarsRequiredToPlot || CurrentBars[2] < BarsRequiredToPlot
				|| CurrentBars[3] < BarsRequiredToPlot)
				return;
			
			Values[0][0] = EMA(Closes[0], 20)[0];
			Values[1][0] = EMA(Closes[1], 20)[0];
			Values[2][0] = EMA(Closes[2], 20)[0];
			Values[3][0] = EMA(Closes[3], 20)[0];
			
			if (BarsInProgress == 2) 
				BackBrushes[0] = Brushes.Olive;
			
		}
	}
}

				
			

Snippets para Manipulação de Gráficos

Esta seção visa apresentar trechos de códigos com funcionalidades relativas à manipulação de gráficos.

Você pode acessar os Snippets diretamente pelo menu lateral direito, ou fazendo CRL+F (CTRL+L) para localizar algum texto específico na página, uma vez que o conteúdo tende a crescer ao longo do tempo, dificultando a navegação pelo menu.

Caso tenham sugestões de código para acrescentar à lista, gentileza deixar o código nos comentários com o link para seu perfil em rede social (para devido crédito de autoria).

Snippets

Como configurar as propriedades de Plots nos Indicadores?

Reproduzir vídeo

Praticamente todas as propriedades de um plot no NinjaScript podem ser definidas no método AddPlot. Este método possui duas sobrecargas.

A primeira versão cria apenas uma linha sólida com cor específica. Na segunda versão de AddPlot, os parâmetros permitem maior flexibilidade na configuração, conforme pode ser visto no exemplo abaixo.

				
					AddPlot(new Stroke(Brushes.LimeGreen, DashStyleHelper.Solid, 1, 10), PlotStyle.Bar, "Plot1");
Plots[0].Autowidth = true;
				
			

No exemplo acima, criamos um plot chamado “Plot1” que é uma barra na cor verde limão, sólida, com opacidade em 10%. Também configuramos a largura da barra para ser a mesma da série de dados do gráfico.

O objeto Stroke permite definir a cor do plot pelo parâmetro da classe Brush, o tipo de traçado pelo parâmetro da classe DashStyleHelper, a espessura e transparência do plot. A transparência é o único parâmetro que não pode ser configurado na interface gráfica.

Existem diversos tipos de plots na NinjaTrader, tais como linhas, barras, gráfico em degrau, linha horizontal, marcações em bloco, cruz, triangulos, pontos. E também é possível não exibir o plot no gráfico, mas apenas no DataBox, passando como parâmetro o tipo PlotStyle.PriceBox.

Como alterar a cor da barra e do fundo do gráfico?

Reproduzir vídeo

Em NinjaScript é possível pintar a barra e o fundo do gráfico utilizando a lógica que desejar. Além disso, você pode em qualquer momento do tempo refazer a pintura de qualquer barra ou fundo de barra no gráfico, o que dá uma grande flexibilidade ao trader programador.

Veja abaixo exemplo de como pintar para o momento atual uma barra de azul e o fundo de oliva. Caso deseje pintar uma barra do passado, basta usar o indexador da série com o valor desejado. Por exemplo, BarBrushes[1] refere-se a cor da penúltima barra do gráfico em relação a barra processada no momento.

				
					BarBrushes[0] = Brushes.Blue;
BackBrushes[0] = Brushes.Olive;

				
			

OBS: Caso você deseje retirar a cor atribuído a um desses elementos basta atribuir o valor null a série desejada.

Como plotar indicadores em estratégias em painel separado?

Reproduzir vídeo

Essa é uma tarefa que pode ser realizada em uma única linha de comando no NinjaScript. Basta no método OnStateChange, quando o estado do ninjascript for DataLoaded, ou seja, quando já tiver carregado todos os dados do gráfico, você chamar o método AddChartIndicator, conforme demonstrado abaixo.

				
					if (State == State.DataLoaded)
{
    AddChartIndicator(MACD(12,26,9));
}

				
			

Pintando uma região entre duas médias ou séries

Seguem abaixo dois exemplos de pintura de região entre as médias exponencias de 9 e 90 períodos utilizando diferentes sobrecargas do método Draw.Region. Na primeira sobrecarga, vamos pintar essa região desde o início do gráfico utilizando os índices de barras e na segunda sobrecarga, vamos pintar apenas um intervalo de datahora específico.

				
					protected override void OnBarUpdate()
{
    //Pinta a região entre as duas médias em todo o gráfico
    Draw.Region(this, "pinturaRegiao", CurrentBar, 0, EMA(9), EMA(90), Brushes.White, Brushes.Blue, 30);
    
    //Pinta a região entre as médias apenas no intervalo de data informado
    Draw.Region(this, "pinturaTempo", new DateTime(2023,8,30), new DateTime(2023,8,31,9,5,30), EMA(9), EMA(90), Brushes.Blue, Brushes.Yellow, 80);
}
				
			

Como escrever texto nas barras e em região fixa do gráfico?

Reproduzir vídeo

Seguem abaixo dois exemplos de pintura de região entre as médias exponencias de 9 e 90 períodos utilizando diferentes sobrecargas do método Draw.Region. Na primeira sobrecarga, vamos pintar essa região desde o início do gráfico utilizando os índices de barras e na segunda sobrecarga, vamos pintar apenas um intervalo de datahora específico.

				
					protected override void OnBarUpdate()
{
    //Cria texto nas barras que fecharam acima da barra anterior
    if (isRising(Close))
        Draw.Text(this, "Barra" + CurrentBar.ToString(), true, Close[0].ToString(), Close[0], 0, Brushes.White, new SimpleFont(), TextAlignment.Left, Brushes.Yellow, Brushes.Blue, 20);
        
    //Cria um texto em região específica do gráfico
    Draw.TextFixed(this, "TextoFixo", "Coded by NeoTraderBot\n", TextPosition.BottomRight);
}
				
			

Snippets para Utilização de Indicadores da Plataforma

Introdução

Esta seção visa apresentar trechos de códigos com exemplos de utilização dos indicadores disponibilizados na plataforma.

Você pode acessar os Snippets diretamente pelo menu lateral direito, ou fazendo CRL+F (CTRL+L) para localizar algum texto específico na página, uma vez que o conteúdo tende a crescer ao longo do tempo, dificultando a navegação pelo menu.

Caso tenham sugestões de código para acrescentar à lista, gentileza deixar o código nos comentários com o link para seu perfil em rede social (para devido crédito de autoria).

Snippets

Como instanciar um indicador nativo - Ex: Bandas de Bollinger?

Reproduzir vídeo

Os indicadores podem ser utilizados apenas chamando seus métodos, não havendo necessidade de atribuir a uma variável da classe do seu NinjaScript. Veja o exemplo abaixo no qual apenas plotamos a Banda de Bollinger, utilizando o indicador nativo da plataforma.

				
					#region Using declarations
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Xml.Serialization;
using NinjaTrader.Cbi;
using NinjaTrader.Gui;
using NinjaTrader.Gui.Chart;
using NinjaTrader.Gui.SuperDom;
using NinjaTrader.Gui.Tools;
using NinjaTrader.Data;
using NinjaTrader.NinjaScript;
using NinjaTrader.Core.FloatingPoint;
using NinjaTrader.NinjaScript.DrawingTools;
#endregion

//This namespace holds Indicators in this folder and is required. Do not change it. 
namespace NinjaTrader.NinjaScript.Indicators
{
	public class testeBollinger : Indicator
	{
		protected override void OnStateChange()
		{
			if (State == State.SetDefaults)
			{
				Description									= @"Enter the description for your new custom Indicator here.";
				Name										= "testeBollinger";
				Calculate									= Calculate.OnBarClose;
				IsOverlay									= false;
				DisplayInDataBox							= true;
				DrawOnPricePanel							= true;
				DrawHorizontalGridLines						= true;
				DrawVerticalGridLines						= true;
				PaintPriceMarkers							= true;
				ScaleJustification							= NinjaTrader.Gui.Chart.ScaleJustification.Right;
				//Disable this property if your indicator requires custom values that cumulate with each new market data event. 
				//See Help Guide for additional information.
				IsSuspendedWhileInactive					= true;
				AddPlot(Brushes.Orange, "BandaSuperior");
				AddPlot(Brushes.White, "BandaCentral");
				AddPlot(Brushes.Orange, "BandaInferior");
			}
			else if (State == State.Configure)
			{
			}
		}

		protected override void OnBarUpdate()
		{
			BandaSuperior[0] = Bollinger(2.0,20).Upper[0];
			BandaCentral[0] = Bollinger(2.0,20).Middle[0];
			BandaInferior[0] = Bollinger(2.0,20).Lower[0];

		}

		#region Properties

		[Browsable(false)]
		[XmlIgnore]
		public Series<double> BandaSuperior
		{
			get { return Values[0]; }
		}

		[Browsable(false)]
		[XmlIgnore]
		public Series<double> BandaCentral
		{
			get { return Values[1]; }
		}

		[Browsable(false)]
		[XmlIgnore]
		public Series<double> BandaInferior
		{
			get { return Values[2]; }
		}
		#endregion

	}
}

#region NinjaScript generated code. Neither change nor remove.

namespace NinjaTrader.NinjaScript.Indicators
{
	public partial class Indicator : NinjaTrader.Gui.NinjaScript.IndicatorRenderBase
	{
		private testeBollinger[] cachetesteBollinger;
		public testeBollinger testeBollinger()
		{
			return testeBollinger(Input);
		}

		public testeBollinger testeBollinger(ISeries<double> input)
		{
			if (cachetesteBollinger != null)
				for (int idx = 0; idx < cachetesteBollinger.Length; idx++)
					if (cachetesteBollinger[idx] != null &&  cachetesteBollinger[idx].EqualsInput(input))
						return cachetesteBollinger[idx];
			return CacheIndicator<testeBollinger>(new testeBollinger(), input, ref cachetesteBollinger);
		}
	}
}

namespace NinjaTrader.NinjaScript.MarketAnalyzerColumns
{
	public partial class MarketAnalyzerColumn : MarketAnalyzerColumnBase
	{
		public Indicators.testeBollinger testeBollinger()
		{
			return indicator.testeBollinger(Input);
		}

		public Indicators.testeBollinger testeBollinger(ISeries<double> input )
		{
			return indicator.testeBollinger(input);
		}
	}
}

namespace NinjaTrader.NinjaScript.Strategies
{
	public partial class Strategy : NinjaTrader.Gui.NinjaScript.StrategyRenderBase
	{
		public Indicators.testeBollinger testeBollinger()
		{
			return indicator.testeBollinger(Input);
		}

		public Indicators.testeBollinger testeBollinger(ISeries<double> input )
		{
			return indicator.testeBollinger(input);
		}
	}
}

#endregion

				
			

Snippets para Ordens e Administração de Trade

Esta seção visa apresentar trechos de códigos com exemplos de envio de ordens e administração de trade utilizando técnicas de stoploss (fixo, móvel, breakeven) e take profit.

Você pode acessar os Snippets diretamente pelo menu lateral direito, ou fazendo CRL+F (CTRL+L) para localizar algum texto específico na página, uma vez que o conteúdo tende a crescer ao longo do tempo, dificultando a navegação pelo menu.

Caso tenham sugestões de código para acrescentar à lista, gentileza deixar o código nos comentários com o link para seu perfil em rede social (para devido crédito de autoria).

Snippets

Como rotear ordens de maneira fácil (Modo gerenciado)?

Reproduzir vídeo

A NinjaTrader possui em seu NinjaScript uma camada de abstração para envio e gestão de ordens. Este modo é chamado de modo gerenciado e seu funcionamento torna bem simples a implementação de estratégias para iniciantes e até mesmo pessoas com conhecimento intermediário.

No modo gerenciado, as ordens são válidas apenas até o próximo candle/barra, o que simplifica a gestão de ordens abertas e cancelamentos. E também há diversos controles que reduzem a chance de problemas na administração da posição da estratégia.

Veja abaixo um exemplo do envio de ordens em NinjaScript utilizando o modo gerenciado.

				
					#region Using declarations
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Xml.Serialization;
using NinjaTrader.Cbi;
using NinjaTrader.Gui;
using NinjaTrader.Gui.Chart;
using NinjaTrader.Gui.SuperDom;
using NinjaTrader.Gui.Tools;
using NinjaTrader.Data;
using NinjaTrader.NinjaScript;
using NinjaTrader.Core.FloatingPoint;
using NinjaTrader.NinjaScript.Indicators;
using NinjaTrader.NinjaScript.DrawingTools;
#endregion

//This namespace holds Strategies in this folder and is required. Do not change it. 
namespace NinjaTrader.NinjaScript.Strategies
{
	public class TestingOrdersStrategy : Strategy
	{
		private TimeSpan tsOpen;
		private TimeSpan tsClose;
		private Order myOrder;
		
		
		protected override void OnStateChange()
		{
			if (State == State.SetDefaults)
			{
				Description									= @"Enter the description for your new custom Strategy here.";
				Name										= "TestingOrdersStrategy";
				Calculate									= Calculate.OnBarClose;
				EntriesPerDirection							= 1;
				EntryHandling								= EntryHandling.AllEntries;
				IsExitOnSessionCloseStrategy				= true;
				ExitOnSessionCloseSeconds					= 30;
				IsFillLimitOnTouch							= false;
				MaximumBarsLookBack							= MaximumBarsLookBack.TwoHundredFiftySix;
				OrderFillResolution							= OrderFillResolution.Standard;
				Slippage									= 0;
				StartBehavior								= StartBehavior.WaitUntilFlat;
				TimeInForce									= TimeInForce.Gtc;
				TraceOrders									= false;
				RealtimeErrorHandling						= RealtimeErrorHandling.StopCancelClose;
				StopTargetHandling							= StopTargetHandling.PerEntryExecution;
				BarsRequiredToTrade							= 20;
				// Disable this property for performance gains in Strategy Analyzer optimizations
				// See the Help Guide for additional information
				IsInstantiatedOnEachOptimizationIteration	= true;
				PositionOpeningTime				= DateTime.Parse("10:30", System.Globalization.CultureInfo.InvariantCulture);
				PositionClosingTime				= DateTime.Parse("10:36", System.Globalization.CultureInfo.InvariantCulture);
			}
			else if (State == State.Configure)
			{
				tsOpen = new TimeSpan(PositionOpeningTime.Hour, PositionOpeningTime.Minute, 0);
				tsClose = new TimeSpan(PositionClosingTime.Hour, PositionClosingTime.Minute, 0);				
			}
		}

		protected override void OnBarUpdate()
		{
			//Match real-time order object based on a historical order object (run just once)
			if (myOrder != null && myOrder.IsBacktestOrder && State == State.Realtime)
      			myOrder = GetRealtimeOrder(myOrder);			
			
			//Open position at specified time (tsOpen)
			if ((Time[0].TimeOfDay == tsOpen) && (Position.MarketPosition == MarketPosition.Flat))
            {
				myOrder = EnterLong("openingSignal");
				//myOrder = EnterLongLimit(4451.25, "openingSignal");
				//myOrder = EnterLongStopMarket(4454.50, "openingSignal");
				
				
				//This will not open position, since the price reach that price a few bars after the order was submitted (Managed orders)
				//myOrder = EnterLongLimit(4450, "openingSignal");
				
				//This will not open position, since the price reach that price only 2 bars after the order was submitted (Managed orders)
				//myOrder = EnterLongStopMarket(4455, "openingSignal");
			}
			
			//Close position at specified time (tsClose)
			if (Time[0].TimeOfDay == tsClose)
            {
				if (Position.MarketPosition == MarketPosition.Long) { ExitLong("openingSignal"); }
				if (Position.MarketPosition == MarketPosition.Short) { ExitShort("openingSignal"); }
			}			
			
				
		}

		#region Properties
		[NinjaScriptProperty]
		[PropertyEditor("NinjaTrader.Gui.Tools.TimeEditorKey")]
		[Display(Name="OpeningTIime", Order=1, GroupName="Parameters")]
		public DateTime PositionOpeningTime
		{ get; set; }

		[NinjaScriptProperty]
		[PropertyEditor("NinjaTrader.Gui.Tools.TimeEditorKey")]
		[Display(Name="ClosingTime", Order=2, GroupName="Parameters")]
		public DateTime PositionClosingTime
		{ get; set; }
		#endregion

	}
}

				
			

Como fazer Gestão de Risco das operações de maneira simples (Stoploss/TakeProfit)?

Reproduzir vídeo

No âmbito da camada de abstração do NinjaScript, existem algumas funções que facilitam bastante a adoção de práticas de gestão de risco para operações no código fonte. 

Veja abaixo duas formas de definir o stoploss e alvo (take profit) das operações de maneira estática, ou seja, fixa durante toda a execução da estratégia, ou de maneira dinâmica, ajustando o risco de acordo com as condições do mercado.

Gestão de risco estática

Nesta situação, os parâmetros para o stoploss e alvo das operações são definidos na transição para o estado Configure da estratégia, podendo inclusive, serem utilizados parâmetros de entrada para fins de otimização futura.

				
					#region Using declarations
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Xml.Serialization;
using NinjaTrader.Cbi;
using NinjaTrader.Gui;
using NinjaTrader.Gui.Chart;
using NinjaTrader.Gui.SuperDom;
using NinjaTrader.Gui.Tools;
using NinjaTrader.Data;
using NinjaTrader.NinjaScript;
using NinjaTrader.Core.FloatingPoint;
using NinjaTrader.NinjaScript.Indicators;
using NinjaTrader.NinjaScript.DrawingTools;
#endregion

//This namespace holds Strategies in this folder and is required. Do not change it.
namespace NinjaTrader.NinjaScript.Strategies
{
	public class TestingOpRiskManagement : Strategy
	{
		private TimeSpan tsOpen;
		private TimeSpan tsClose;
		private Order myOrder;


		protected override void OnStateChange()
		{
			if (State == State.SetDefaults)
			{
				Description									= @"Enter the description for your new custom Strategy here.";
				Name										= "TestingOpRiskManagement";
				Calculate									= Calculate.OnBarClose;
				EntriesPerDirection							= 1;
				EntryHandling								= EntryHandling.AllEntries;
				IsExitOnSessionCloseStrategy				= true;
				ExitOnSessionCloseSeconds					= 30;
				IsFillLimitOnTouch							= false;
				MaximumBarsLookBack							= MaximumBarsLookBack.TwoHundredFiftySix;
				OrderFillResolution							= OrderFillResolution.Standard;
				Slippage									= 0;
				StartBehavior								= StartBehavior.WaitUntilFlat;
				TimeInForce									= TimeInForce.Gtc;
				TraceOrders									= false;
				RealtimeErrorHandling						= RealtimeErrorHandling.StopCancelClose;
				StopTargetHandling							= StopTargetHandling.PerEntryExecution;
				BarsRequiredToTrade							= 20;
				// Disable this property for performance gains in Strategy Analyzer optimizations
				// See the Help Guide for additional information
				IsInstantiatedOnEachOptimizationIteration	= true;
				PositionOpeningTime				= DateTime.Parse("10:30", System.Globalization.CultureInfo.InvariantCulture);
				PositionClosingTime				= DateTime.Parse("16:00", System.Globalization.CultureInfo.InvariantCulture);
			}
			else if (State == State.Configure)
			{
				tsOpen = new TimeSpan(PositionOpeningTime.Hour, PositionOpeningTime.Minute, 0);
				tsClose = new TimeSpan(PositionClosingTime.Hour, PositionClosingTime.Minute, 0);
				
				// Static risk management. Stoploss and Target are defined and maintained fixed through the strategy lifetime
				SetStopLoss(CalculationMode.Ticks, 20);
				//SetTrailStop(CalculationMode.Ticks, 24);
				SetProfitTarget(CalculationMode.Ticks, 60);
			}
		}

		protected override void OnBarUpdate()
		{
			if (myOrder != null && myOrder.IsBacktestOrder && State == State.Realtime)
      			myOrder = GetRealtimeOrder(myOrder);

			//Open position at specified time (tsOpen)
			if ((Time[0].TimeOfDay == tsOpen) && (Position.MarketPosition == MarketPosition.Flat))
            {
				Random rnd = new Random();

				if (rnd.Next(0,2) == 0)
					myOrder = EnterLong("openingSignal");
				else
					myOrder = EnterShort("openingSignal");
			}

			//Close position at specified time (tsClose)
			if (Time[0].TimeOfDay == tsClose)
            {
				if (Position.MarketPosition == MarketPosition.Long) { ExitLong("openingSignal"); }
				if (Position.MarketPosition == MarketPosition.Short) { ExitShort("openingSignal"); }
			}


		}

		#region Properties
		[NinjaScriptProperty]
		[PropertyEditor("NinjaTrader.Gui.Tools.TimeEditorKey")]
		[Display(Name="OpeningTIime", Order=1, GroupName="Parameters")]
		public DateTime PositionOpeningTime
		{ get; set; }

		[NinjaScriptProperty]
		[PropertyEditor("NinjaTrader.Gui.Tools.TimeEditorKey")]
		[Display(Name="ClosingTime", Order=2, GroupName="Parameters")]
		public DateTime PositionClosingTime
		{ get; set; }
		#endregion

	}
}
				
			

Gestão de risco dinâmica

Nesta situação, os parâmetros para o stoploss e alvo das operações são definidos no método onBarUpdate e a frequencia de atualização dependerá da propriedade da estratégia relacionada a frequência de cálculo. Neste modo, o trader pode utilizar qualquer lógica que desejar, podendo inclusive utilizar indicadores técnicos, a exemplo do ATR (Average True Range).

				
					#region Using declarations
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Xml.Serialization;
using NinjaTrader.Cbi;
using NinjaTrader.Gui;
using NinjaTrader.Gui.Chart;
using NinjaTrader.Gui.SuperDom;
using NinjaTrader.Gui.Tools;
using NinjaTrader.Data;
using NinjaTrader.NinjaScript;
using NinjaTrader.Core.FloatingPoint;
using NinjaTrader.NinjaScript.Indicators;
using NinjaTrader.NinjaScript.DrawingTools;
#endregion

//This namespace holds Strategies in this folder and is required. Do not change it.
namespace NinjaTrader.NinjaScript.Strategies
{
	public class TestingOpRiskManagement : Strategy
	{
		private TimeSpan tsOpen;
		private TimeSpan tsClose;
		private Order myOrder;


		protected override void OnStateChange()
		{
			if (State == State.SetDefaults)
			{
				Description									= @"Enter the description for your new custom Strategy here.";
				Name										= "TestingOpRiskManagement";
				Calculate									= Calculate.OnBarClose;
				EntriesPerDirection							= 1;
				EntryHandling								= EntryHandling.AllEntries;
				IsExitOnSessionCloseStrategy				= true;
				ExitOnSessionCloseSeconds					= 30;
				IsFillLimitOnTouch							= false;
				MaximumBarsLookBack							= MaximumBarsLookBack.TwoHundredFiftySix;
				OrderFillResolution							= OrderFillResolution.Standard;
				Slippage									= 0;
				StartBehavior								= StartBehavior.WaitUntilFlat;
				TimeInForce									= TimeInForce.Gtc;
				TraceOrders									= false;
				RealtimeErrorHandling						= RealtimeErrorHandling.StopCancelClose;
				StopTargetHandling							= StopTargetHandling.PerEntryExecution;
				BarsRequiredToTrade							= 20;
				// Disable this property for performance gains in Strategy Analyzer optimizations
				// See the Help Guide for additional information
				IsInstantiatedOnEachOptimizationIteration	= true;
				PositionOpeningTime				= DateTime.Parse("10:30", System.Globalization.CultureInfo.InvariantCulture);
				PositionClosingTime				= DateTime.Parse("16:00", System.Globalization.CultureInfo.InvariantCulture);
			}
			else if (State == State.Configure)
			{
				tsOpen = new TimeSpan(PositionOpeningTime.Hour, PositionOpeningTime.Minute, 0);
				tsClose = new TimeSpan(PositionClosingTime.Hour, PositionClosingTime.Minute, 0);
				
				// Static risk management. Stoploss and Target are defined and maintained fixed through the strategy lifetime
				//SetStopLoss(CalculationMode.Ticks, 20);
				//SetTrailStop(CalculationMode.Ticks, 24);
				//SetProfitTarget(CalculationMode.Ticks, 60);
			}
		}

		protected override void OnBarUpdate()
		{
			if (myOrder != null && myOrder.IsBacktestOrder && State == State.Realtime)
      			myOrder = GetRealtimeOrder(myOrder);

			//Open position at specified time (tsOpen)
			if ((Time[0].TimeOfDay == tsOpen) && (Position.MarketPosition == MarketPosition.Flat))
            {
				Random rnd = new Random();
				double volatility = Math.Ceiling(ATR(500)[0]/TickSize);
				double stoplossTicks = 5*volatility;
				double takeProfitTicks = 3*stoplossTicks;
				
				
				// Dynamic risk management. Stoploss and Target are adapted to market conditions
				SetTrailStop(CalculationMode.Ticks, stoplossTicks);
				SetProfitTarget(CalculationMode.Ticks, takeProfitTicks);
				Print("CurrentBar: " + CurrentBar.ToString() + " - Stoploss: " + stoplossTicks.ToString() + " ticks | Target: " 
				                     + takeProfitTicks.ToString() + " ticks");
				
					
				if (rnd.Next(0,2) == 0)
					myOrder = EnterLong("openingSignal");
				else
					myOrder = EnterShort("openingSignal");
			}

			//Close position at specified time (tsClose)
			if (Time[0].TimeOfDay == tsClose)
            {
				if (Position.MarketPosition == MarketPosition.Long) { ExitLong("openingSignal"); }
				if (Position.MarketPosition == MarketPosition.Short) { ExitShort("openingSignal"); }
			}


		}

		#region Properties
		[NinjaScriptProperty]
		[PropertyEditor("NinjaTrader.Gui.Tools.TimeEditorKey")]
		[Display(Name="OpeningTIime", Order=1, GroupName="Parameters")]
		public DateTime PositionOpeningTime
		{ get; set; }

		[NinjaScriptProperty]
		[PropertyEditor("NinjaTrader.Gui.Tools.TimeEditorKey")]
		[Display(Name="ClosingTime", Order=2, GroupName="Parameters")]
		public DateTime PositionClosingTime
		{ get; set; }
		#endregion

	}
}
				
			

Snippets para Implementação de estratégias

Outros Snippets

Esta seção visa apresentar outros exemplos de trechos de códigos que não se enquadram nas categorias anteriores.

Você pode acessar os Snippets diretamente pelo menu lateral direito, ou fazendo CRL+F (CTRL+L) para localizar algum texto específico na página, uma vez que o conteúdo tende a crescer ao longo do tempo, dificultando a navegação pelo menu.

Caso tenham sugestões de código para acrescentar à lista, gentileza deixar o código nos comentários com o link para seu perfil em rede social (para devido crédito de autoria).

Snippets

Como escrever log com o horário de abertura da candle/barra para facilitar depuração (debug)?

Gerar log de execução de uma estratégia é a melhor forma de rastrear possíveis problemas de lógica ou de execução quando seu robô já está operando. Segue abaixo um trecho que identifica no texto a ser escrito no log o dia/hora início da barra/candle.

OBS: Uma maneira muito efetiva de depurar problemas no seu NinjaScript é utilizar a depuração no Visual Studio! Esta é a maneira recomendável de se aprofundar no estudo de problemas do seu NinjaScript.

				
					string msg = "Mensagem de Teste;
NinjaTrader.Code.Output.Process(Time[0].ToString() + " - " + msg, PrintTo.OutputTab2);
				
			

Da maneira acima, você pode selecionar em qual aba da janela de saída gostaria de imprimir a mensagem de log. Abaixo tem um forma resumida de escrever na saída 1.

				
					string msg = "Mensagem de Teste;
Print(Time[0].ToString() + " - " + msg);
				
			

Snippets para Localização Temporal

Esta seção visa apresentar trechos de códigos com funcionalidades relativas à localização temporal da estratégia. Por exemplo, identificar se a atual barra é a primeira barra do dia para verificar gap diário.

Você pode acessar os Snippets diretamente pelo menu lateral direito, ou fazendo CTRL+F (CTRL+L) para localizar algum texto específico na página, uma vez que o conteúdo tende a crescer ao longo do tempo, dificultando a navegação pelo menu.

Caso tenham sugestões de código para acrescentar à lista, gentileza deixar o código nos comentários com o link para seu perfil em rede social (para devido crédito de autoria).

Snippets

Identificação de primeira barra da sessão ou do dia

Algumas estratégias necessitam da identificação da primeira barra do dia ou da primeira barra da sessão de negociação atual para executar determinada ação ou calcular o gap em relação ao fechamento da sessão anterior. Segue abaixo um trecho de código para identificar essas barras.

				
					namespace NinjaTrader.NinjaScript.Indicators
{
	public class NTB_Ex_FirstSessionBar : Indicator
	{
		protected override void OnStateChange()
		{

			if (State == State.SetDefaults)
			{ 
				Description									= @"NeoTraderBot Example: How to locate first bar of Session or Day";
				Name										= "NTB_Ex_FirstSessionBar";
				Calculate									= Calculate.OnBarClose;
				IsOverlay									= false;
				DisplayInDataBox							= true;
				DrawOnPricePanel							= true;
				DrawHorizontalGridLines						= true;
				DrawVerticalGridLines						= true;
				PaintPriceMarkers							= true;
				ScaleJustification							= NinjaTrader.Gui.Chart.ScaleJustification.Right;
				//Disable this property if your indicator requires custom values that cumulate with each new market data event. 
				//See Help Guide for additional information.
				IsSuspendedWhileInactive					= true;
				
            }
		}

		protected override void OnBarUpdate()
		{
            
			// Uncomment line below if you want to locate the first bar of the day
			//if (Time[0].Date != Time[1].Date)
            // Uncomment line below if you want to locate the first bar of the session
			if (Bars.IsFirstBarOfSession)
            {
				DateTime datahora = Time[0];
				NinjaTrader.Code.Output.Process("[" + datahora.ToString() + "] - The bar was located!", PrintTo.OutputTab1);
				BackBrushes[0] = Brushes.Blue;
            }
		}

	}
}
				
			

Identificação do primeiro tick de uma barra

Algumas estratégias podem necessitar de uma atuação mais tempestiva, porém, o programador gostaria de selecionar quais ações seria executadas no tick e quais seriam no fechamento da barra. Para isso, podemos criar um NinjaScript com a propriedade de cálculo configurada em Calculate.OnEachTick, e filtrar nas chamadas ao método OnBarUpdate o primeiro tick da barra, sinalizando o fechamento da barra anterior.

Assim temos liberdade para programar o NinjaScript para executar ações tanto no fechamento da barra quanto durante a formação de uma barra. Veja o código de exemplo abaixo:

				
					namespace NinjaTrader.NinjaScript.Indicators
{
	public class NTB_Ex_FirstTickOfBar : Indicator
	{
		protected override void OnStateChange()
		{

			if (State == State.SetDefaults)
			{ 
				Description									= @"NeoTraderBot Example: How to locate first bar of Session or Day";
				Name										= "NTB_Ex_FirstTickOfBar";
				Calculate									= Calculate.OnEachTick;
				IsOverlay									= false;
				DisplayInDataBox							= true;
				DrawOnPricePanel							= true;
				DrawHorizontalGridLines						= true;
				DrawVerticalGridLines						= true;
				PaintPriceMarkers							= true;
				ScaleJustification							= NinjaTrader.Gui.Chart.ScaleJustification.Right;
				//Disable this property if your indicator requires custom values that cumulate with each new market data event. 
				//See Help Guide for additional information.
				IsSuspendedWhileInactive					= true;
				
            }
		}

		protected override void OnBarUpdate()
		{
			if ( IsFirstTickOfBar)
			{
				Draw.Text(this,"teste","Primeiro Tick!",0,Close[0]);
			}
			else Draw.Text(this,"teste","Outros Ticks!",0,Close[0]);
		}

	}
}
				
			

Identificação de barra por data e hora específicos

Reproduzir vídeo

Este código localiza a barra (candle ou box) por uma data e hora desejados. Onde a hora é referente ao horário de abertura do candle desejado.

Observe que criamos um parâmetro no qual o usuário pode inserir um horário para facilitar os testes. O código pode tanto colorir o fundo da barra no horário especificado no dia atual ou nesse mesmo horário em todos os dias de negociação.

				
					namespace NinjaTrader.NinjaScript.Indicators
{
	public class NTB_Ex_DateTime : Indicator
	{
		public TimeSpan TimeOfDay;

		protected override void OnStateChange()
		{

			if (State == State.SetDefaults)
			{
				Description									= @"NeoTraderBot Example: How to find bars at specific Time or DateTime";
				Name										= "NTB_Ex_DateTime";
				Calculate									= Calculate.OnBarClose;
				IsOverlay									= false;
				DisplayInDataBox							= true;
				DrawOnPricePanel							= true;
				DrawHorizontalGridLines						= true;
				DrawVerticalGridLines						= true;
				PaintPriceMarkers							= true;
				ScaleJustification							= NinjaTrader.Gui.Chart.ScaleJustification.Right;
				//Disable this property if your indicator requires custom values that cumulate with each new market data event.
				//See Help Guide for additional information.
				IsSuspendedWhileInactive					= true;
				DesiredDateTime								= DateTime.Parse("10:31", System.Globalization.CultureInfo.InvariantCulture);

            }
			else if (State == State.Configure)
			{
				TimeOfDay = new TimeSpan(DesiredDateTime.Hour, DesiredDateTime.Minute, 0);
			}
				
		}

		protected override void OnBarUpdate()
		{

			// Uncomment line below if you want to sign the bar at a specific time just for the current date
			//if (Time[0] == DesiredDateTime)
            // Uncomment line below if you want to sign the bar at a specific time each day
			if (Time[0].TimeOfDay == TimeOfDay)
            {
				DateTime datahora = Time[0];
				NinjaTrader.Code.Output.Process("[" + datahora.ToString() + "] - This is the desired bar!", PrintTo.OutputTab1);
				BackBrushes[0] = Brushes.Blue;
            }
		}

		#region Properties
		[NinjaScriptProperty]
		[PropertyEditor("NinjaTrader.Gui.Tools.TimeEditorKey")]
		[Display(Name="DesiredDateTime", Order=1, GroupName="Parameters")]
		public DateTime DesiredDateTime
		{ get; set; }
		#endregion

	}
}
				
			

Snippets para Utilização de Indicadores da Plataforma

Introdução

Esta seção visa apresentar trechos de códigos com exemplos de utilização dos indicadores disponibilizados na plataforma.

Você pode acessar os Snippets diretamente pelo menu lateral direito, ou fazendo CRL+F (CTRL+L) para localizar algum texto específico na página, uma vez que o conteúdo tende a crescer ao longo do tempo, dificultando a navegação pelo menu.

Caso tenham sugestões de código para acrescentar à lista, gentileza deixar o código nos comentários com o link para seu perfil em rede social (para devido crédito de autoria).

Snippets

Como instanciar um indicador nativo - Ex: Bandas de Bollinger?

Reproduzir vídeo

Os indicadores podem ser utilizados apenas chamando seus métodos, não havendo necessidade de atribuir a uma variável da classe do seu NinjaScript. Veja o exemplo abaixo no qual apenas plotamos a Banda de Bollinger, utilizando o indicador nativo da plataforma.

				
					#region Using declarations
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Xml.Serialization;
using NinjaTrader.Cbi;
using NinjaTrader.Gui;
using NinjaTrader.Gui.Chart;
using NinjaTrader.Gui.SuperDom;
using NinjaTrader.Gui.Tools;
using NinjaTrader.Data;
using NinjaTrader.NinjaScript;
using NinjaTrader.Core.FloatingPoint;
using NinjaTrader.NinjaScript.DrawingTools;
#endregion

//This namespace holds Indicators in this folder and is required. Do not change it. 
namespace NinjaTrader.NinjaScript.Indicators
{
	public class testeBollinger : Indicator
	{
		protected override void OnStateChange()
		{
			if (State == State.SetDefaults)
			{
				Description									= @"Enter the description for your new custom Indicator here.";
				Name										= "testeBollinger";
				Calculate									= Calculate.OnBarClose;
				IsOverlay									= false;
				DisplayInDataBox							= true;
				DrawOnPricePanel							= true;
				DrawHorizontalGridLines						= true;
				DrawVerticalGridLines						= true;
				PaintPriceMarkers							= true;
				ScaleJustification							= NinjaTrader.Gui.Chart.ScaleJustification.Right;
				//Disable this property if your indicator requires custom values that cumulate with each new market data event. 
				//See Help Guide for additional information.
				IsSuspendedWhileInactive					= true;
				AddPlot(Brushes.Orange, "BandaSuperior");
				AddPlot(Brushes.White, "BandaCentral");
				AddPlot(Brushes.Orange, "BandaInferior");
			}
			else if (State == State.Configure)
			{
			}
		}

		protected override void OnBarUpdate()
		{
			BandaSuperior[0] = Bollinger(2.0,20).Upper[0];
			BandaCentral[0] = Bollinger(2.0,20).Middle[0];
			BandaInferior[0] = Bollinger(2.0,20).Lower[0];

		}

		#region Properties

		[Browsable(false)]
		[XmlIgnore]
		public Series<double> BandaSuperior
		{
			get { return Values[0]; }
		}

		[Browsable(false)]
		[XmlIgnore]
		public Series<double> BandaCentral
		{
			get { return Values[1]; }
		}

		[Browsable(false)]
		[XmlIgnore]
		public Series<double> BandaInferior
		{
			get { return Values[2]; }
		}
		#endregion

	}
}

#region NinjaScript generated code. Neither change nor remove.

namespace NinjaTrader.NinjaScript.Indicators
{
	public partial class Indicator : NinjaTrader.Gui.NinjaScript.IndicatorRenderBase
	{
		private testeBollinger[] cachetesteBollinger;
		public testeBollinger testeBollinger()
		{
			return testeBollinger(Input);
		}

		public testeBollinger testeBollinger(ISeries<double> input)
		{
			if (cachetesteBollinger != null)
				for (int idx = 0; idx < cachetesteBollinger.Length; idx++)
					if (cachetesteBollinger[idx] != null &&  cachetesteBollinger[idx].EqualsInput(input))
						return cachetesteBollinger[idx];
			return CacheIndicator<testeBollinger>(new testeBollinger(), input, ref cachetesteBollinger);
		}
	}
}

namespace NinjaTrader.NinjaScript.MarketAnalyzerColumns
{
	public partial class MarketAnalyzerColumn : MarketAnalyzerColumnBase
	{
		public Indicators.testeBollinger testeBollinger()
		{
			return indicator.testeBollinger(Input);
		}

		public Indicators.testeBollinger testeBollinger(ISeries<double> input )
		{
			return indicator.testeBollinger(input);
		}
	}
}

namespace NinjaTrader.NinjaScript.Strategies
{
	public partial class Strategy : NinjaTrader.Gui.NinjaScript.StrategyRenderBase
	{
		public Indicators.testeBollinger testeBollinger()
		{
			return indicator.testeBollinger(Input);
		}

		public Indicators.testeBollinger testeBollinger(ISeries<double> input )
		{
			return indicator.testeBollinger(input);
		}
	}
}

#endregion

				
			

Snippets para Utilização de Indicadores da Plataforma

Introdução

Esta seção visa apresentar trechos de códigos com exemplos de utilização dos indicadores disponibilizados na plataforma.

Você pode acessar os Snippets diretamente pelo menu lateral direito, ou fazendo CRL+F (CTRL+L) para localizar algum texto específico na página, uma vez que o conteúdo tende a crescer ao longo do tempo, dificultando a navegação pelo menu.

Caso tenham sugestões de código para acrescentar à lista, gentileza deixar o código nos comentários com o link para seu perfil em rede social (para devido crédito de autoria).

Snippets

Como instanciar uma média móvel nativa?

Reproduzir vídeo

Os indicadores devem ser instanciados no método Init e naturalmente também devem ser declarados como atributos da classe.

				
					private BuiltInIndicator fastAvg;

public override void Init()
{
    fastAvg = IndicatorsManager.BuildIn.MA(HistoryDataSeries, 20, MAMode.SMA, 0, PriceType.Close);
} 
				
			

Como instanciar um indicador criado por você dentro de outra estratégia/indicador?

Reproduzir vídeo

Os indicadores devem ser instanciados no método Init e naturalmente também devem ser declarados como atributos da classe. Veja abaixo um exemplo de instanciação de indicador próprio.

Observe que ao instanciar um indicador próprio com o método custom, fornecemos 3 parâmetros: o nome do indicador (nome da classe), a série de dados, e um array com os valores dos parâmetros.

Instanciando Indicador Próprio chamado "NTB_TripleCrossoverIndicator"
				
					private BuiltInIndicator NTB_3Cross;

public override void Init()
{
	NTB_3Cross = IndicatorsManager.BuildIn.Custom("NTB_TripleCrossoverIndicator" 
	                                              ,	HistoryDataSeries
	                                              , new Object[]{fastestPeriod,
  			                                              	   fastestAvgType,
  			                                              	   fastPeriod,
  			                                              	   fastAvgType,
  			                                              	   slowPeriod,
  			                                              	   slowAvgType})
} 
				
			

Como criar estratégias/indicadores em múltiplos tempos gráficos?

Reproduzir vídeo

O EvoCode permite utilizar séries de dados de diferentes ativos e multiplos tempos gráficos em uma mesma estratégia ou indicador. Segue abaixo um exemplo no qual é implementado um indicador no tempo gráfico primário consistindo em uma média aritmética, bem como uma outra média aritmética utilizando dados de preço do mesmo ativo em um tempo gráfico diferente (5 minutos).

 

Calculando médias em múltiplos tempos gráficos
				
					using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using Runtime.Script;
using TradeApi;
using TradeApi.History;
using TradeApi.Indicators;
using TradeApi.Instruments;
using TradeApi.ToolBelt;
using TradeApi.Trading;
using TradeApi.Quotes;
using NeoTraderBot;

namespace NeoTraderBot
{
    public class MultiTimeFrameIndicator : IndicatorBuilder
    {
        private BuiltInIndicator avg;

        // Secondary timeframe 5 minutes
        private HistoricalData historicalDataSeries2 = null;
        private BuiltInIndicator avg2;

        #region inputs
        [InputParameter(InputType.Numeric, "Primary SMA - Periods", 0)]
        [SimpleNumeric(1D, 9999D)]
        public int periods = 50;

        [InputParameter(InputType.Numeric, "Secondary SMA - Periods", 0)]
        [SimpleNumeric(1D, 9999D)]
        public int periods2 = 10;

        #endregion




        public MultiTimeFrameIndicator()
            : base()
        {
            #region Initialization
            Credentials.Author = "";
            Credentials.Company = "";
            Credentials.Copyrights = "";
            Credentials.DateOfCreation = new DateTime(2023, 7, 18);
            Credentials.ExpirationDate = DateTime.MinValue;
            Credentials.Version = "";
            Credentials.Password = "66b4a6416f59370e942d353f08a9ae36";
            Credentials.ProjectName = "Multi TimeFrame Averages";
            #endregion

            Lines.Set("avg1min");
            Lines["avg1min"].Color = Color.Blue;
            Lines.Set("avg5min");
            Lines["avg5min"].Color = Color.Red;

            SeparateWindow = false;
        }
        public override void Init()
        {
            HistoricalDataManager.OnLoaded += plotHistoryValues;

            InstrumentsManager.Subscribe(InstrumentsManager.Current, QuoteTypes.Trade);
            HistoricalRequest historicalRequest2 = new TimeHistoricalRequest(InstrumentsManager.Current, DataType.Trade, Period.Minute, 5);
            historicalDataSeries2 = HistoricalDataManager.Get(historicalRequest2, new Interval(DateTime.UtcNow.AddDays(-10), DateTime.UtcNow));

            avg = IndicatorsManager.BuildIn.MA(HistoryDataSeries, periods, MAMode.SMA);
            avg2 = IndicatorsManager.BuildIn.MA(historicalDataSeries2, periods2, MAMode.SMA);

            Notification.Comment(  "This is a SNIPPET from NeoTraderBot Community: www.NeoTraderBot.com.\n"
                                 + "In the blue line, we have a SMA of " + periods + " periods in the current timeframe. \n"
                                 + "In the red line, we have a SMA of " + periods2 + " periods in a 5-minutes timeframe on the same symbol.");
        }

       public override void Update(TickStatus args)
        {
            Lines["avg1min"].SetValue(avg.GetValue());
            Lines["avg5min"].SetValue(avg2.GetValue());
        }

        public override void Complete()
        {
            HistoricalDataManager.OnLoaded -= plotHistoryValues;
            InstrumentsManager.UnSubscribe(InstrumentsManager.Current, QuoteTypes.Trade);
        }

        public void plotHistoryValues(HistoricalData hData)
        {
            for (int i = 0; i < HistoryDataSeries.Count; i++)
            {
                int index = historicalDataSeries2.FindInterval(HistoryDataSeries.GetTimeUtc(i));
                Lines["avg5min"].SetValue(avg2.GetValue(index), i);
            }
		}


    }
}


				
			

Técnicas de Otimização robusta

Reproduzir vídeo

Introdução

Até o presente documento vimos os conceitos básicos de otimização. Abordamos dois algoritmos bastante utilizados para otimizar estratégias baseadas em indicadores técnicos: Grid Search e Algoritmo Genético – e abordamos sobre segregação de dados e overfitting.

Aqui vamos avançar um pouco mais e falaremos sobre técnicas de otimização robusta. Tais técnicas consistem em realizar a otimização e verificar o quão sensível é o desempenho de uma dada estratégia a diferentes situações de mercado e variações dos parâmetros ótimos.

O domínio de técnicas de otimização robusta é fundamental para execução de um processo de otimização de estratégias de maneira mais consistente, fornecendo mais informações para análise do possível desempenho e identificação de estratégia com maior potencial de serem lucrativas quando submetidas a dados novos.

A técnica de otimização robusta mais difundida é denominada Walk Forward Optimization.

Walk Forward Optimization (WFO)

A técnica de Walk Forward Optimization (WFO) foi apresentada inicialmente por Robert Pardo em seu livro “The Evaluation and Optimization of Trading Strategies” de janeiro/2008. Pra quem entende de aprendizado de máquina, é bastante claro que se trata de uma técnica baseada em validações cruzadas (como um k-fold).

A técnica WFO consiste em utilizar os dados históricos e simular como se a estratégia estivesse fazendo trading real. Ou seja, os dados históricos são fatiados em períodos de duração fixa, onde uma parte será utilizada para otimização (dados in sample) e outra parte para realização de backtesting (dados out of sample).

Iniciando pelos dados mais antigos, realizamos uma otimização simples (da maneira tradicional) e obtemos os parâmetros ótimos para avaliar o desempenho da estratégias nos dados out of sample do primeiro período.

Daí simulamos que o tempo passou e obtemos mais dados históricos. Isso equivale a arrastar a janela de dados pela mesma duração do backtesting em direção aos dados mais recentes. Esta nova configuração de dados da janela deslizante será o Período 2, o qual terá uma interseção dos dados in sample do período 1. No entanto, não terá interseção entre os dados de backtesting dos períodos 1 e 2.

A duração (fixa) dos dados de backtesting de cada período e a duração total dos dados históricos irão permitir calcular quantas janelas distintas de otimização poderão ser executadas nos dados históricos. A figura abaixo ilustra o conceito das janelas deslizantes.

Observe que, ao invés de procedermos uma única otimização nos dados históricos disponíveis, a técnica WFO visa realizar múltiplas otimizações para que seja possível realizar uma análise do desempenho da estratégia otimizada de maneira geral levando em consideração o desempenho em cada janela de backtesting. A esse processo de análise se dá o nome de Walk Forward Analysis (WFA).

Walk Forward Analysis (WFA)

Espero que tenha ficado claro na seção anterior que a estratégia é reotimizada para cada período de dados. A análise, portanto, consiste em comparar o desempenho da estratégia reotimizada no dados de backtesting do período atual, com o desempenho nesses mesmos dados utilizando a estratégia otimizada no período anterior, e portanto, não reotimizada para o período atual de dados.

A pergunta a ser respondida pela WFA é: vale a pena reotimizar a estratégia periodicamente? Em outras palavras, é possível um resultado final melhor do que não reotimizar a estratégia?

Intuitivamente, ao reotimizarmos uma estratégia utilizando uma janela deslizante estamos focando a otimização apenas nos dados mais recentes, que podem representar recortes distintos da dinâmica de negociação do ativo. Pode ser que um período seja marcado por uma tendência de alta, enquanto o próximo período terá um comportamento de retração (correção de preço), seguido pelo próximo período de consolidação…e assim por diante.

Perceba que a ideia de utilizar janelas deslizantes é permitir a obtenção de parâmetros ótimos mais adequados a situação recente dando possibilidade a estratégia de se ajustar as diferentes dinâmicas. Diferentemente de uma otimização simples sobre todos os dados históricos que buscaria uma configuração média que seria ótima globalmente, mas que não poderia ser ótima para diferentes subconjuntos desses dados históricos.

O que nos permitirá comparar o desempenho de duas configurações diferentes da estratégias em dados de backtesting (reotimizada e não reotimizada) é a Eficiência da estratégia, que definiremos a seguir.

Cálculo de Eficiência

A Eficiência consiste na razão entre o desempenho da estratégia nos dados out of sample (backtesting) e o desempenho nos dados in sample. O desempenho deve ser medido, preferencialmente, utilizando a mesma métrica utilizada como função objetivo da otimização, a fim de manter a consistência do processo.

Vale ressaltar que a janela de dados de backtesting é bem menor (geralmente) que a janela de dados in sample, e por isso, para tecer uma comparação de desempenho justa, torna-se necessário normalizar a medida de desempenho.

A normalização sempre será necessária quando os valores possíveis para a métrica de desempenho puderem ter limites mínimos e máximos diferentes dependendo do tamanho da janela de dados (ex: lucro líquido). A normalização não é necessária, por exemplo, se a métrica for taxa de acerto, pois o seu valor estará sempre entre 0 e 100%, independentemente do tamanho da janela de dados.

Veja na figura abaixo, um exemplo de cálculo de normalização de lucro líquido e eficiência em diferentes períodos de otimização de uma estratégia.

Estas perguntas nos levam a próxima técnica conhecida como Walk Forward Matix (WFM).

Observa-se que no Período 2 e 3, a estratégia reotimizada apresentou melhor eficiência do que a estratégia não reotimizada. Ao passo que no Período 4, a estratégia não reotimizada é que apresentou melhor eficiência.

A técnica de WFA consiste exatamente em verificar se há predominância de melhor eficiência nas estratégias reotimizadas para concluir se vale a pena reotimizar períodicamente a estratégia.

Caso identifique-se que não é interessante reotimizar a estratégia periodicamente, esse achado não é conclusivo. Pois poderíamos realizar a seguinte pergunta: será que se utilizassemos uma janela de otimização diferente com uma janela de backtesting menor poderíamos obter um resultado melhor em relação à reotimização de estratégias? Ou mesmo se concluíssemos que para o tamanho da janela atual é interessante reotimizar periodicamente, será que esta periodicidade é a periodicidade ótima?

Walk Forward Matrix (WFM)

A técnica WFM nada mais é do que rodar o processo de WFA para diferentes possibilidades de tamanho da janela de dados e percentual de dados out of sample desta janela, utilizando o algoritmo de já vimos de grid search.

Em outras palavras, consiste em realizar a otimização da técnica WFA. É importante ressaltar que a execução de WFM é bastante cara computacionalmente e, portanto, recomenda-se não gerar muitas possibilidades no processo. Além disso, a automatização do processo de WFM é praticamente um pré-requisito, são tantos dados que precisam ser armazenados para se realizar a adequada análise dos resultados, que torna-se fundamental ter um fluxo automatizado para execução do WFM.

Ao final das contas, queremos verificar se a estratégia é robusta a diferentes janelas de otimização e backtesting, bem como identificar o tamanho ótimo da janela de dados de otimização e periodicidade de reotimização.

Conclusão

Neste documento exploramos os conceitos e ideias por trás das técnicas de otimização robusta: WFA e WFM, a qual estão cobertas pelo conceito de Walk Forward Optimization.

Como sugestão, recomenda-se sempre iniciar de maneira simples e complicar a medida que for necessário. Assim, não é recomendável já iniciarmos a otimização de uma estratégia com WFM, pois seria como dar um tiro de canhão em uma mosca.

Comece realizando um otimização simples e verificando se a estratégia é lucrativa em backtesting. Em seguida, pode-se verificar pela aplicação da técnica WFA se há benefício em reotimizar a estratégia períodicamente em uma janela que o trader julgar pertinente. Caso seja observado um potencial de melhoria na otimização da janela de dados e de backtesting, aí sim, deve-se proceder com a técnica WFM.

Espero que este conteúdo tenha sido esclarecedor para o leitor e tenha contribuído para ampliar o conhecimento a respeito do tema otimização de estratégias.

Acompanhe a publicação de vídeos no Canal do Youtube da Comunidade, pois nos próximos conteúdos nós iremos aplicar passo a passo cada técnica apresentada na prática e otimizar estratégias utilizando diferentes plataformas e soluções.

Explorando o Control Center

Reproduzir vídeo

Neste video iremos explicar tudo sobre a principal janela do NinjaTrader: Centro de Controle (Control Center). Esta é a janela mais importante do NinjaTrader, por onde o usuário terá acesso a todas as funcionalidades da Plataforma.

Assista nesse video uma explicação didática de como utilizar a Plataforma para operá-la como um professional!

Após um longo período de espera, finalmente, a Plataforma NinjaTrader foi homologada para operar na B3. Desde o dia 03/jan/2023 é possível contratar esta Plataforma pela Corretora Órama.

Conforme antecipado nos planos da Comunidade @neotraderbot, iremos gerar conteúdo informative de diferentes plataformas de trading para que os membros da comunidade tenham informações do que é possível realizar em outros ambientes.

Reforço que não estamos realizando nenhuma recomendação para mudança de Plataforma e que a decisão de migrar parte ou todo o processo de desenvolvimento e execução das estratégias automatizadas é muito pessoal e cabe apenas ao trader decidir sobre tal assunto.

Como CRIAR DO ZERO um INDICADOR NA TRADER EVOLUTION

Reproduzir vídeo

Neste vídeo, irei demonstrar o passo-a-passo como criar a partir do zero um indicador na plataforma TraderEvolution, escrevendo o código em EVOCODE. Para isso, iremos criar um indicador de volatilidade média.

Você pode fazer o download do indicador com CÓDIGO FONTE ABERTO pelo link abaixo:

        🤖 https://neotraderbot.com/indicador-de…

Não se esqueça de indicar a Comunidade NeoTraderBot como parceiro na Plataforma TraderEvolution. Vá no menu superior em “Mais” – “Extensões” – “Indique parceiro” e digite o código “NEOTRADERBOT”.

Assim, você reforça sua participação na Comunidade e nos ajuda a pleitear novas funcionalidades e melhorias na plataforma visando o benefício de todos os membros em suas automatizações e desenvolvimento de estratégias.

Gestão de risco financeiro

Nesse grupo de parâmetros é possível configurar limites diários para perda ou objetivos de ganho para a estratégia.

pHabilitaLimitePerdaDiaria (boolean)

Quando true, e estando o robô-trader no modo DayTrade, a estratégia não irá mais abrir posições no dia, caso tenha sido atingido o limite de perda financeira definido no parâmetro pLimitePerdaDiaria.

Por exemplo, se o usuário não deseja perder mais do que R$ 100 no dia, ele deve colocar este valor no parâmetro pLimitePerdaDiaria.

É importante observar que a estratégia será interrompida após o limite ter sido atingido. Como as operações são encerradas geralmente no fechamento das barras por ordens a mercado, a perda diária ficará próxima do valor de referência informado mas não coincidirá com o limite estabelecido. Ou seja, as posições abertas não serão estopadas exatamente no limite da perda diária definida.

Caso este parâmetro seja false, ou o robô-trader não esteja no modo DayTrade, o valor informado no parâmetro pLimitePerdaDiaria será desconsiderado.

pLimitePerdaDiaria (integer)

Este parâmetro refere-se ao valor financeiro de referência a ser utilizado como limite de perdas diárias. Uma vez ultrapassado esse limite, a estratégia será interrompida após o encerramento da posição.

pHabilitaObjetivoGanhoDiario (boolean)

Quando true, e estando o robô-trader no modo DayTrade, a estratégia não irá mais abrir posições no dia, caso tenha sido atingido o objetivo de ganho definido no parâmetro pObjetivoGanhoDiario.

Por exemplo, se o usuário tiver como objetivo  R$ 300 no dia, ele deve colocar este valor no parâmetro pObjetivoGanhoDiario.

É importante observar que a estratégia será interrompida após o objetivo ter sido atingido. Como as operações são encerradas geralmente no fechamento das barras por ordens a mercado, o ganho diário ficará próximo do valor de referência informado mas não coincidirá com o objetivo estabelecido. Ou seja, as posições abertas não serão encerradas exatamente no objetivo de ganho diário definido.

Caso este parâmetro seja false, ou o robô-trader não esteja no modo DayTrade, o valor informado no parâmetro pObjetivoGanhoDiario será desconsiderado.

pObjetivoGanhoDiario (integer)

Este parâmetro refere-se ao valor financeiro de referência a ser utilizado como objetivo de ganho diário. Uma vez ultrapassado esse objetivo, a estratégia será interrompida após o encerramento da posição.

Frameworks de Programação

Um framework de programação é uma estrutura de código padronizada que possui diversas funcionalidades típicas já implementadas, sendo necessário apenas a parametrização. Com isso você ganha tempo, pois pode parametrizar em curto espaço de tempo diferentes ideias de trading, testar diferentes combinações de técnicas sem precisar ter um conhecimento profundo de programação (embora ainda seja necessário uma pequena noção de código para parametrizar estratégias). A economia de tempo de programação é da ordem de 80 a 95%.

Não existe um código que funciona para tudo. Se prezamos pela simplicidade e casos mais comuns, quem tem necessidades mais complexas não é atendido. Se fazemos algo já complexo e altamente parametrizável, isso pode causar um custo de processamento muito grande para a maioria dos casos que são simples.

Assim, a Comunidade NeoTraderBot disponibiliza diferentes versões de framework, compondo um portfolio em nível incremental de funcionalidades e complexidade. Veja abaixo um quadro comparativo de funcionalidades das versões:

FUNCIONALIDADES

MODO

Modo Daytrade e Swing Trade

ORDENS

Ordens de abertura de posição
Somente à mercado
Mercado/Limitada/Stop
Tamanho de posições
Fixo (Parametrizável)
Variável (via código)
Sinal de reversão ou encerramento
Filtro de Compra Venda

ADM TRADE

Ordens OCO para Stop/Alvo
Risco/Ganho definido em parâmetro
Definição de Preço de Stop/Alvo via código

-

TÉCNICA DE STOPLOSS

Stop Breakeven
Stop Móvel (Trailing Stop)
-

Versão contínua

Stop temporizado
-

GESTÃO OPERACIONAL

E FINANCEIRA

Limitação de qtde de trades por dia
Interrupção diária da estratégia por limite de trades com prejuízo
-
Interrupção diária da estratégia por trades com prejuízo consecutivos
-
Restrição de Perdas/Objetivo de Ganho diário
-
Contador de Trades com prejuízo/lucro
-
Contador de Trades consecutivos com prejuízo/lucro
-
Janelas de negociação para abertura de posição
1
até 4
Encerramento de posição em horário limite

Recursos Visuais

Plot das linhas de Alvo/Stoploss/Gatilho BreakEven

SUPORTE TÉCNICO

Resolução de Dúvidas pelo Discord (Tópico Exclusivo)

-

VALOR DO FRAMEWORK

Gratuito

R$ 649

(pagamento único)

O usuário que adquirir o framework THUNDER tem direito às atualizações do framework e também desconto no valor de futuras versões de framework com mais funcionalidades (referente ao valor já pago).

Desejamos sucesso no desenvolvimento de suas estratégias e robôs traders!

Versão LIGHT

FRAMEWORK-ntsl-light

Esta é a primeira versão de framework lançada pela Comunidade NeoTraderBot. É uma versão gratuita e simples, mas que possui algumas funcionalidades básicas de gestão de robô e de operações.

A ideia principal do Framework NTSL LIGHT é que o usuário entenda como se utiliza um framework e como ele pode se beneficiar de funcionalidades já implementadas, bastando programar os sinais desejados de abertura de posição, reversão e encerramento.

FRAMEWORK NTSL LIGHT é uma versão de demonstração, sem custo e com o código fonte aberto. Ele foi concebido para ser executado em gráficos temporais e os sinais fornecidos pelo usuário serão executados com ordens a mercado.

FRAMEWORK NTSL LIGHT

Coded by NeoTraderBot
R$ 0 Sem custo
  • Modo Daytrade e Swing Trade
  • Gerenciamento de abertura de posição de tamanho fixo
  • Administração de trade via sinal de reversão ou encerramento
  • Administração de trade com Risco/Ganho pré-definido
  • Ordens OCO de Stoploss e TakeProfit
  • Plot das linhas de Alvo/Stoploss/Gatilho Breakeven
  • Limitação de quantidade de trades por dia
  • Janela de negociação para abertura de posição
  • Encerramento de posição em horário limite
CÓD ABERTO

Versão THUNDER

FRAMEWORK ntsl THUNDER

O FRAMEWORK NTSL THUNDER é uma versão com mais funcionalidades que a versão gratuita e direito a suporte técnico. Com a versão THUNDER o trader terá ainda mais possibilidades para realizar seus backtests! 

Esta versão também foi concebida para ser executada em gráficos temporais e, além das funcionalidades da versão LIGHT, ela também possui os seguintes diferenciais:

      • Possibilidade de configuração do tamanho das posições;
      • Possibilidade de roteamento de ordens stop e limitadas;
      • Filtro de posição comprada/vendida;
      • Interrupção diária da estratégia em função da qtde de trades com prejuízo (total e/ou consecutivos);
      • Stoploss temporizado em função da qtde de barras transcorridas após abertura da posição;
      • Gestão de risco financeiro com limite de perda e objetivo de ganho;
      • Possibilidade de aplicação de técnica de Stop móvel (individualmente ou em conjunção com RG Fixo e Breakeven);
      • Configuração de até 4 janelas de negociação;

Um quadro comparativo completo das funcionalidades das versões de framework pode ser visto nesta página.

FRAMEWORK NTSL THUNDER

Coded by NeoTraderBot
R$ 649 pagamento único
  • Direito a suporte técnico
  • Direito a atualizações da versão
  • Desconto do valor pago em caso de upgrade de versão
* Após a compra, você receberá um e-mail com o link para download do Framework.

Documentação

Esta é a documentação dos Frameworks NTSL criados pela NeoTraderBot. Um primeiro ponto a ressaltar é que todos os frameworks disponibilizados pela Comunidade NeoTraderBot possuem a FINALIDADE EXCLUSIVAMENTE EDUCACIONAL. Não obstante serem compatíveis com o Módulo de Automação, eles devem ser utilizados apenas em backtesting e Conta de Simulação.

A razão pela qual a NeoTraderBot não disponibiliza frameworks destinados para execução no Módulo de Automação é porque entendemos que para colocar uma estratégia ou setup para operar em conta real são necessárias otimizações de código, proteções contra falhas e situações atípicas, entre outras particularidades que dependem da estratégia a ser executada. Assim, ou o trader realiza esses ajustes sobre o código utilizado no backtesting (caso tenha conhecimento para tal) ou pode realizar a contratação de algum profissional que faça a programação adequada, tendo em vista que a estratégia foi validada em backtesting.

Este manual está organizado de acordo com as sessões de parâmetros do framework e o seu conteúdo será atualizado a medida que surgirem demandas por maiores esclarecimentos acerca de suas funcionalidades.

O suporte técnico de dúvidas sobre os Frameworks (para quem adquiriu alguma versão paga) é realizado pelo Servidor Discord (acessível por este link). Pedimos a gentileza de manifestar que realizaram a compra do código ao entrar no grupo para que receba a permisssão para o tópico exclusivo dos frameworks.

Caso deseje alguma funcionalidade ainda não contemplada nas versões de framework disponíveis, você pode sugerir ou recomendar novas funcionalidades/melhorias no formulário abaixo.

Sugestão de Funcionalidades para Frameworks NTSL

Configurações gerais

Os parâmetros de configurações gerais definem o modo de funcionamento do robô-trader e como este irá funcionar em backtesting.

Todos os frameworks da NeoTraderBot realizam uma verificação básica de consistência dos parâmetros fornecidos e, em caso de erro, o robô trader não é executado e uma mensagem constará na aba “Compilação” do Editor de Estratégias. Devido à dificuldades do ambiente de log da Nelogica, os erros são pontuados um de cada vez, não sendo exibidos todos em uma única mensagem.

Os parâmetros do framework relacionados a gestão de risco das operações são tratados em termos de unidades de ticks (menor variação do ativo) devida a maior generalização do código fonte.

Devido a ausência de funcionalidade para modificação dos parâmetros em ambiente de backtesting, recomenda-se alterar o valor padrão de cada parâmetro para fins de simulação no Editor de Estratégias.

 
pModoDayTrade (boolean)

Este parâmetro deve ser true quando o setup implementado contemplar apenas operações intradiárias. Caso o parâmetro seja false, o robô-trader será assumido como um setup de swing trade atuando em tempos gráfico acima da periodicidade diária.

O modo DayTrade (valor true) pressupõe que o tempo gráfico deve ser na escala de segundos ou minutos. Uma vez habilitado este modo, serão habilitadas as funcionalidades de limitação de quantidade diária de trades, horário de encerramento automático de posição e janelas temporais para abertura de posição.

No caso do modo DayTrade não estar ativado, os parâmetros pHorarioEncerramentoPosicao, pJanelaNegocIni0X e pJanelaNegocFim0X perdem sua utilidade uma vez que o tempo gráfico será maior que a periodicidade diária.

pHorarioEncerramentoPosicao (integer)

Este parâmetro é aplicável apenas quando o modo DayTrade está ativado e refere-se ao horário no formato HHMM no qual as posições abertas devem ser encerradas a fim de evitar o carregamento da posição para o dia seguinte.

Por exemplo, caso o trader deseje encerrar suas operações às 17:00, o valor desse parâmetro deve ser 1700.

É importante observar que em backtesting o encerramento de posição se dará com uma ordem à mercado e será executado no preço de abertura da próxima barra.

pQtdeLotesMinimosNegociados (integer)

Este parâmetro irá definir a quantidade de lotes a serem negociados e, portanto, deverá ser um número inteiro.

Por exemplo, se o trader deseja negociar 5 mini-contratos de índice, o valor do parâmetro deve ser 5.

pQtdeLotesConfiguravel (boolean)

Este parâmetro permite que o trader defina pelo código fonte, no momento da abertura das posições o temanho da exposição, ou seja, a quantidade de papeis a serem negociados. Esta quantidade pode variar de posição para posição conforme programação do trader.

A configuração do tamanho da posição a ser aberta é realizada pela variável fQtdeLotesAberturaPosicao.

pStopOffsetEmTicks (integer)

Este parâmetro bem poderia ser definido como constante. Trata-se do offset fornecido nas ordens stop, que é o caso da ordem de stoploss.

Recomenda-se utilizar um valor bem generoso a fim de evitar o pulo de ordem no ambiente de backtesting devido à gaps, embora o framework já preveja o encerramento a mercado em caso de pulo da ordem stop.

Em simulações de estratégias que operam intraday não é tão comum a ocorrência de grandes gaps entre as barras. Assim, um valor de 10 ticks para este parâmetro costuma ser adequado na maior parte das situações.

pOperarComprado (boolean)
  THUNDER  

Este parâmetro, se true, irá permitir apenas que posições compradas sejam abertas pela estratégia no backtest.

pOperarVendido (boolean)

Este parâmetro, se true, irá permitir apenas que posições vendidas sejam abertas pela estratégia no backtest.

pAbrirPosicaoSomenteAMercado (boolean)

Se este parâmetro for true, todas as operações realizadas pela estratégia serão realizadas a mercado, ou seja, as ordens serão sempre executadas após fechamento da barra e no preço de abertura da próxima barra.

Caso o parâmetro seja false, o trader deve definir via código o preço desejado de abertura das posições (variável fPrecoAberturaPosicao). O framework irá definir se a ordem a ser roteada será uma ordem do tipo stop ou limitada, dependendo do preço negociado no backtest.

Gestão de risco do robô

Nesse grupo de parâmetros, pode-se configurar alguns aspectos da gestão de risco do robô, tais a interrupção do robô após uma quantidade máxima de trades no dia, ou de trades com prejuízo (consecutivos ou não). Também é possível configurar um stoploss temporizado em função da quantidade de barras após a abertura da posição.

pHabilitaLimiteQtdeTrades (boolean)

Quando true, e estando o robô-trader no modo DayTrade, não serão permitidas mais operações do que a quantidade informada no parâmetro pQtdeMaxOperacoesDiarias. Desta forma, a estratégia será interrompida uma vez que tenham sido realizadas a quantidade de operações definada no parâmetro pQtdeMaxOperacoesDiarias. 

Caso este parâmetro seja false, ou o robô-trader não esteja no modo DayTrade, a quantidade informada em pQtdeMaxOperacoesDiarias será desconsiderada.

pQtdeMaxOperacoesDiarias (integer)

Este parâmetro refere-se a quantidade limite de operações diárias quando o robô-trader estiver no modo DayTrade e pHabilitaLImiteQtdeTrades receber o valor true.

pHabilitaLimiteTradesPrejuizo (boolean)

Quando true, e estando o robô-trader no modo DayTrade, a estratégia não irá mais abrir posições no dia, caso tenha sido atingido o limite total de posições encerradas com prejuízo (definido no parâmetro pQtdeMaxTradesPrejuizoPorDia) ou o limite de posições encerradas consecutivamente com prejuízo (definido no parâmetro pQtdeMaxTradesPrejuizo ConsecutivosPorDia). 

Caso este parâmetro seja false, ou o robô-trader não esteja no modo DayTrade, as quantidades informadas nos parâmetros pQtdeMaxTradesPrejuizoPorDia epQtdeMaxTradesPrejuizoConsecutivosPorDia serão desconsideradas.

pQtdeMaxTradesPrejuizoPorDia (integer)

Este parâmetro refere-se a quantidade total limite de operações diárias com prejuízo quando o robô-trader estiver no modo DayTrade e pHabilitaLimiteTradesPrejuizo receber o valor true.

pQtdeMaxTradesPrejuizoConsecutivosPorDia (integer)

Este parâmetro refere-se a quantidade limite de operações consecutivas e diárias com prejuízo quando o robô-trader estiver no modo DayTrade e pHabilitaLimiteTradesPrejuizo receber o valor true.

pHabilitaStopTemporizado (boolean)

Quando true, as operações serão encerradas após a quantidade de barras definida no parâmetro pQtdeBarrasStopTemporizado. 

Esta funcionalidade aplica-se tanto ao modo daytrade ou swing trade.

pQtdeBarrasStopTemporizado (integer)

Este parâmetro refere-se a quantidade limite de barras para uma posição aberta. A contagem inclui a barra de abertura da posição.

Por exemplo, se o valor desse parâmetro for 3, a posição será encerrada na 2 barra após a barra de abertura da posição, caso a posição não tenha sido encerrada anteriormente por atingir o stop ou alvo.

Ordens OCO - RG Fixo

A administração das posições pode ser realizada por meio de ordens OCO (One-Cancel-Others) de stoploss e alvo, conforme demonstrado na figura abaixo (a qual aplicou-se também o stoploss Breakeven concomitantemente).

A vantagem de utilizar as ordens OCO é o gerenciamento automático da plataforma em relação ao cancelamento da ordem na ponta contrária à ordem executada. Por exemplo, se sua operação atingir o alvo, a ordem de stoploss é automaticamente cancelada.

Caso o usuário não utilize esta fucionalidade, as operações pode ser revertidas por meio do sinal de reversão (bSinalReversao) ou encerradas por meio do sinal bSinalEncerramento, a serem definidos pelo usuário.

Diferentemente da execução dos sinais que ocorrerá por ordens a mercado no fechamento da barra, as ordens OCO são apregoadas e, portanto, executadas quando o preço é atingido. A ordem de stoploss será sempre uma ordem do tipo stop (passível de slippage devido à sua natureza), enquanto as ordens de alvo será do tipo limitadas (compondo o book de ofertas).

pOCO_RGFixo (boolean)

Quando true, este parâmetro irá habilitar a funcionalidade de ordens OCO de stoploss e alvo. Uma vez aberta uma posição, o usuário irá observar na linha branca o preço médio de sua posição, na linha vermelha a posição do stoploss e na linha azul a posição do alvo.

Obs: as linhas no gráfico serão plotadas apenas se o usuário configurar o parâmetro pPlotarLinhasOCO para true.

pStopFixoEmTicks (integer)

Este parâmetro é utilizado para definir o stoploss inicial da operação em relação ao preço médio na unidade de ticks. Por exemplo, no caso do mini-contrato de índice, um tick possui 5 pontos. Assim, caso o stop desejado seja de 50 pontos, isto representa 10 ticks.

Se o usuário habilitar a funcionalidade de Stop Breakeven, o stop inicialmente configurado será deslocado caso o gatilho de breakeven seja atingido.

pAlvoFixoEmTicks (integer)

Este parâmetro é utilizado para definir o alvo das operações em função do preço médio da posição na unidade de ticks. 

Por exemplo, no caso de um operação no mini-contrato de dólar, onde cada tick equivale a 0,5 pontos. Caso o usuário deseje um alvo de 10 pontos, isto será representado por 20 ticks.

Gestão de risco financeiro

Nesse grupo de parâmetros é possível configurar limites diários para perda ou objetivos de ganho para a estratégia.

pHabilitaLimitePerdaDiaria (boolean)

Quando true, e estando o robô-trader no modo DayTrade, a estratégia não irá mais abrir posições no dia, caso tenha sido atingido o limite de perda financeira definido no parâmetro pLimitePerdaDiaria.

Por exemplo, se o usuário não deseja perder mais do que R$ 100 no dia, ele deve colocar este valor no parâmetro pLimitePerdaDiaria.

É importante observar que a estratégia será interrompida após o limite ter sido atingido. Como as operações são encerradas geralmente no fechamento das barras por ordens a mercado, a perda diária ficará próxima do valor de referência informado mas não coincidirá com o limite estabelecido. Ou seja, as posições abertas não serão estopadas exatamente no limite da perda diária definida.

Caso este parâmetro seja false, ou o robô-trader não esteja no modo DayTrade, o valor informado no parâmetro pLimitePerdaDiaria será desconsiderado.

pLimitePerdaDiaria (integer)

Este parâmetro refere-se ao valor financeiro de referência a ser utilizado como limite de perdas diárias. Uma vez ultrapassado esse limite, a estratégia será interrompida após o encerramento da posição.

pHabilitaObjetivoGanhoDiario (boolean)

Quando true, e estando o robô-trader no modo DayTrade, a estratégia não irá mais abrir posições no dia, caso tenha sido atingido o objetivo de ganho definido no parâmetro pObjetivoGanhoDiario.

Por exemplo, se o usuário tiver como objetivo  R$ 300 no dia, ele deve colocar este valor no parâmetro pObjetivoGanhoDiario.

É importante observar que a estratégia será interrompida após o objetivo ter sido atingido. Como as operações são encerradas geralmente no fechamento das barras por ordens a mercado, o ganho diário ficará próximo do valor de referência informado mas não coincidirá com o objetivo estabelecido. Ou seja, as posições abertas não serão encerradas exatamente no objetivo de ganho diário definido.

Caso este parâmetro seja false, ou o robô-trader não esteja no modo DayTrade, o valor informado no parâmetro pObjetivoGanhoDiario será desconsiderado.

pObjetivoGanhoDiario (integer)

Este parâmetro refere-se ao valor financeiro de referência a ser utilizado como objetivo de ganho diário. Uma vez ultrapassado esse objetivo, a estratégia será interrompida após o encerramento da posição.

Stop Breakeven

O Stop Breakeven consiste em uma gestão de risco da operação na qual uma vez atingido determinado lucro, o stoploss é deslocado para uma posição na qual a operação não renderá mais prejuízo, podendo ser o preço de abertura da posição ou uma proteção parcial de ganhos.

Veja a figura abaixo a qual apresenta um exemplo de Stop Breakeven e será usada como referência para explicar a função de cada parâmetro de configuração.

pStopBreakEven (boolean)
  LIGHT       THUNDER  

Quando true, este parâmetro irá habilitar a funcionalidade de stop Breakeven. Observe que o uso do StopBreakEven não é vinculado ao uso de ordens OCO de stoploss e alvo, e também pode ser usado junto com o Stop móvel (trailling stop) presente na versão THUNDER. Em outras palavras, o usuário pode utilizar apenas a gestão de risco da operação pelo StopBreakEven, o que deixará a operação desprotegida até que o gatilho do breakeven seja acionado.,

pGatilhoNoPrecoFechamento (boolean)
  LIGHT       THUNDER  

Este parâmetro quando true, irá realizar o deslocamento ou posicionamento de stop na posição configurada apenas quando uma barra fechar acima do gatilho de breakeven no caso de uma posição comprada ou abaixo do gatilho quando a operação for de venda.

Caso o parâmetro seja false, o deslocamento ou posicionamento de stop na posição será realizado se em algum momento a máxima de uma barra fechar acima do gatilho de breakeven no caso de uma posição comprada ou a mínima de uma barra fechar abaixo do gatilho quando a operação for de venda.

É importante ressaltar que devido ao funcionamento do modelo de execução da Nelogica, a atualização ou posicionamento do stopBreakeven, independente da configuração de pGatilhonoPrecoFechamento, será realizada apenas após o fechamento da barra na qual a condição de gatilho foi satisfeita.

Observe pela figura acima que apenas após o preço superar a linha de breakeven (linha tracejada amarela), o stop foi deslocado para a posição configurada, o que ocorreu no fechamento da barra.

pGatilhoBreakEvenEmTicks (integer)
  LIGHT       THUNDER  

Este parâmetro é utilizado para definir quantos ticks uma operação deve andar a favor até que seja aplicado o Stoploss Breakeven.

pLucroPreservadoEmTicks (integer)
  LIGHT       THUNDER  

Este parâmetro é utilizado para configurar a posição do stop Breakeven. Caso seu valor seja zero, uma vez acionado o gatilho, o stop será colocado no mesmo preço da posição.

O usuário também pode colocar um valor positivo. Assim, o stop será posicionado ou deslocado para uma posição na qual se a operação for stopada haverá a garantia de realização de lucro parcial.

Stop Móvel (Trailling stop)

O Stop Móvel (Trailling Stop) consiste em uma gestão de risco da operação na qual uma vez atingido determinado gatilho, o stoploss passa a ser atualizado para ficar sempre uma determinada distância atrás do preço de fechamento da barra, reduzindo assim o prejuízo de um eventual loss ou garantindo uma proteção parcial de ganhos, a depender da posição definida para o gatilho.

Veja a figura abaixo a qual apresenta um exemplo da aplicação individual do Stop Móvel e que será usada como referência para explicar a função de cada parâmetro de configuração.

pStopMovel (boolean)
  THUNDER  

Quando true, este parâmetro irá habilitar a funcionalidade de stop móvel. Observe que o stop móvel pode ser usado individualmente ou em concomitância com o Stop BreakEven e as configuração de RG FIXO.

Assim, o usuário pode utilizar apenas a gestão de risco da operação pelo Stop móvel, o que deixará a operação desprotegida até que o gatilho do stop móvel seja acionado. Ou de maneira mais prudente, com a aplicação de ordens OCO RG Fixo. Ainda pode fazer uma combinação com o Stop BreakEven, gerando assim uma administração completa de risco da operação.

pGatilhoStopMovelNoPrecoFechamento (boolean)
  THUNDER  

Este parâmetro quando true, irá realizar o deslocamento ou posicionamento de stop na posição configurada apenas quando uma barra fechar acima do gatilho de stop móvel no caso de uma posição comprada ou abaixo do gatilho quando a operação for de venda.

Caso o parâmetro seja false, o deslocamento ou posicionamento de stop na posição será realizado se em algum momento a máxima de uma barra fechar acima do gatilho de breakeven no caso de uma posição comprada ou a mínima de uma barra fechar abaixo do gatilho quando a operação for de venda.

É importante ressaltar que devido ao funcionamento do modelo de execução da Nelogica, a atualização ou posicionamento do stop, independente da configuração de pGatilhoNoPrecoFechamento, será realizada apenas após o fechamento da barra na qual a condição de gatilho foi satisfeita.

Observe pela figura acima que apenas após o preço superar a linha de gatilho do stop móvel (linha tracejada em vermelho escuro), o stop foi deslocado para a posição configurada, o que ocorreu no fechamento da barra.

pGatilhoStopMovelEmTicks (integer)
  THUNDER  

Este parâmetro é utilizado para definir quantos ticks uma operação deve andar a favor até que seja ativado o Stoploss móvel.

Se o trader definir o valor zero, isso significa que o stop móvel será habilitado já na abertura da posição.

pAncorarStopMovelXTicksAtras (integer)
  THUNDER  

Este parâmetro é utilizado para, uma vez ativado o stop móvel, definir quantos ticks o stoploss deve ficar atrás do preço de fechamento da barra.

É importante ressaltar que o stop móvel não retrocede o valor do stoploss. Ou seja, uma vez deslocado o stoploss para mais próximo do preço negociado, o stoploss não retroage para uma posição mais distante do preço negociado.

Janelas de negociação

Nos frameworks é possível configurar uma janela temporal para aplicação das ordens advindas dos sinais do robô-trader. Assim, o usuário pode controlar o período do dia em que as posições podem ser abertas.

Na versão LIGHT o usuário pode configurar apenas 1 janela de negociação, ao passo que na versão THUNDER, o usuário pode configurar até 4 janelas de negociação.

Caso o robô-trader esteja configurado para executar em um tempo gráfico com periodicidade acima da diária, as configurações de janela de negociação não serão aplicáveis, dada a impossibilidade de gerir o funcionamento da estratégia dentro de uma barra em ambiente de backtesting com dados históricos OHLCV de maneira confiável (condições de funcionamento do Editor de Estratégia da Nelogica).

pJanelaNegocIni0X (integer)
  LIGHT       THUNDER  

Este parâmetro recebe um horário no formato HHMM para definir a partir de qual horário uma posição pode ser aberta. O horário utilizado para esta funcionalidade é o retorno da função nativa da ntsl “Time”, a qual retorna o horário de abertura da barra.

pJanelaNegocFim0X (integer)
  LIGHT       THUNDER  

Este parâmetro recebe um horário no formato HHMM para definir até qual horário  uma posição pode ser aberta. O horário utilizado para esta funcionalidade é o retorno da função nativa da ntsl “Time”, a qual retorna o horário de abertura da barra.

Recursos gráficos

Os frameworks possuem a funcionalidade de plotar as linhas de stoploss, alvo, gatilho de breakeven, gatilho de stop móvel e preço médio da posição, bem como aplicar coloração quando os sinais definidos pelo usuário forem satisfeitos e estiverem em condição adequada para que ordens sejam roteada, conforme pode ser observado na figura abaixo.

pPlotarLinhasOCO (boolean)
  LIGHT       THUNDER  

Quando true, este parâmetro irá habilitar o plot das linhas de stoploss (sólida na cor vermelho), alvo da operação (sólida na cor azul), preço médio da posição (sólido na cor branca) e os níveis de preço dos gatilhos de breakeven (tracejada na cor amarelo) e stop móvel (tracejada na cor vermelho escuro), enquanto os mesmos não forem acionados.

pPintarBarrasDeSinal (boolean)
  LIGHT       THUNDER  

Quando true, este parâmetro irá habilitar a funcionalidade de colorir as barras de sinal configuradas pelo usuário e que esteja em condições adequadas para execução:

        • Sinal de compra pintará a barra de verde caso não haja posição aberta;
        • Sinal de venda pintará a barra de vermelho caso não haja posição aberta;
        • Sinal de reversão pintará a barra de amarelo caso haja posição aberta;
        • Sinal de fechamento pintará a barra de azul caso haja posição aberta.

Como aprender?

Stop Breakeven

O Stop Breakeven consiste em uma gestão de risco da operação na qual uma vez atingido determinado lucro, o stoploss é deslocado para uma posição na qual a operação não renderá mais prejuízo, podendo ser o preço de abertura da posição ou uma proteção parcial de ganhos.

Veja a figura abaixo a qual apresenta um exemplo de Stop Breakeven e será usada como referência para explicar a função de cada parâmetro de configuração.

pStopBreakEven (boolean)
  LIGHT       THUNDER  

Quando true, este parâmetro irá habilitar a funcionalidade de stop Breakeven. Observe que o uso do StopBreakEven não é vinculado ao uso de ordens OCO de stoploss e alvo, e também pode ser usado junto com o Stop móvel (trailling stop) presente na versão THUNDER. Em outras palavras, o usuário pode utilizar apenas a gestão de risco da operação pelo StopBreakEven, o que deixará a operação desprotegida até que o gatilho do breakeven seja acionado.,

pGatilhoNoPrecoFechamento (boolean)
  LIGHT       THUNDER  

Este parâmetro quando true, irá realizar o deslocamento ou posicionamento de stop na posição configurada apenas quando uma barra fechar acima do gatilho de breakeven no caso de uma posição comprada ou abaixo do gatilho quando a operação for de venda.

Caso o parâmetro seja false, o deslocamento ou posicionamento de stop na posição será realizado se em algum momento a máxima de uma barra fechar acima do gatilho de breakeven no caso de uma posição comprada ou a mínima de uma barra fechar abaixo do gatilho quando a operação for de venda.

É importante ressaltar que devido ao funcionamento do modelo de execução da Nelogica, a atualização ou posicionamento do stopBreakeven, independente da configuração de pGatilhonoPrecoFechamento, será realizada apenas após o fechamento da barra na qual a condição de gatilho foi satisfeita.

Observe pela figura acima que apenas após o preço superar a linha de breakeven (linha tracejada amarela), o stop foi deslocado para a posição configurada, o que ocorreu no fechamento da barra.

pGatilhoBreakEvenEmTicks (integer)
  LIGHT       THUNDER  

Este parâmetro é utilizado para definir quantos ticks uma operação deve andar a favor até que seja aplicado o Stoploss Breakeven.

pLucroPreservadoEmTicks (integer)
  LIGHT       THUNDER  

Este parâmetro é utilizado para configurar a posição do stop Breakeven. Caso seu valor seja zero, uma vez acionado o gatilho, o stop será colocado no mesmo preço da posição.

O usuário também pode colocar um valor positivo. Assim, o stop será posicionado ou deslocado para uma posição na qual se a operação for stopada haverá a garantia de realização de lucro parcial.

Ferramentas de Trading

Nesta seção vamos apresentar informações sobre as ferramentas de trading desenvolvidas pela NeoTraderBot para NinjaTrader, bem como informações relevantes para instalação e configuração em sua plataforma.

Como instalar/remover as ferramentas na NinjaTrader?

Este tutorial visa apresentar o passo a passo para instalação e remoção de uma add-on na plataforma NinjaTrader, o que aplica-se às ferramentas e códigos compilados da NeoTraderBot.

Instalando as ferramentas da NeoTraderBot na NinjaTrader

Passo 1: No Control Center, clique em “Tools” -> “Import” -> “NinjaScript Add-On…”

Passo 2: Em seguida, selecione o arquivo “.zip” da ferramenta de deseja instalar na sua NinjaTrader

Passo 3: Caso a importação ocorra com sucesso, você deve visualizar uma mensagem semelhante a da imagem abaixo.

Se houver algum problema na importação, a NinjaTrader irá sinalizar uma mensagem de erro.

Acesse o Control Center e vá na aba “Log” (conforme imagem abaixo). Copie a mensagem de erro relacionada à importação da ferramenta e encaminhe um email para neotraderbot@gmail.com.

Removendo ferramentas (Add-ons) da NinjaTrader

Passo 1: No Control Center, clique em “Tools” -> “Remove NinjaScript Assembly”

Passo 2: Selecione o Add-on que deseja remover da sua plataforma

Passo 3: Uma caixa de diálogo irá aparecer para solicitar a confirmação da remoção. Certifique-se de que está removendo o add-on correto antes de confirmar.

Passo 4: Uma vez removido o Add-on, será exibida uma janela de confirmação da remoção (conforme imagem abaixo).

Como obter o MachineID da minha NinjaTrader?

Este tutorial visa apresentar o passo a passo para gerar um MachineID da sua NinjaTrader. Uma vez adquirido qualquer add-on, esta chave deve ser informada à NeoTraderBot para ativação do uso do add-on em sua máquina.

Gerando o seu MachineID

Passo 1: No Control Center, clique em “Help” -> “3rd Party Licensing”.

Passo 2: Na tela que abrir, você deve digitar “NeoTraderBot” no campo “Vendor name” e inserir o seu e-mail no campo “User defined ID”, ou em caso de erro por caracteres especiais, insira o seu nome completo sem espaços ou acentos. Em seguida, clique em “Submit”.

Será gerado uma chave de Machine ID, a qual você deve copiar e enviar para nós, por meio do formulário a seguir. Copie a chave completa (ela será composta também pelas informações que você inseriu no campo User defined ID (ID do usuário).

Ativando as ferramentas/add-ons com MachineID

Passo 1: Caso tenha adquirido a licença de uso de alguma ferramenta, contratado a assinatura ou serviço de programação da NeoTraderBot, informe pelo formulário abaixo as suas informações para fins de liberação de uso do código baixado/enviado para o seu e-mail.

OBS: Para o período de 7 dias de teste das ferramentas, não é obrigatório o envio do Machine ID. Uma vez enviado o Machine ID, iremos liberar o uso da ferramenta em um prazo máximo de 1 dia útil.

Liberação de Acesso NinjaTrader
Este formulário visa recepcionar as chaves dos usuários para liberação de uso das ferramentas e códigos desenvolvidos pela NeoTraderBot

Documentação - Flash Click

Esta página visa apresentar uma documentação completa da ferramenta Flash Click para fins de referência em caso de dúvidas.

Assim, sugerimos utilizar o menu lateral direito de conteúdo para ir direto nas seções de interesse.

Ressaltamos que as orientações para instalação e ativação da licença contratada foram enviadas por e-mail no momento da contratação.

Objetivo da ferramenta e funcionalidades disponíveis

O objetivo principal da ferramenta Flash Click é permitir uma ação ágil por parte do trader aos rápidos movimentos do mercado, bem como mensurar da maneira adequada os riscos de cada posição a ser aberta, criando as ordens de maneira natural com um clique do mouse no gráfico.

Como sempre gostamos de entregar um pouco mais, você perceberá alguns detalhes e funcionalidades adicionais no decorrer do conteúdo dessa página.

Veja abaixo as funcionalidades disponíveis na Flash Click:

        • Cria ordens diretamente no gráfico por meio da combinação de uma tecla (Ctrl, Alt ou Shift) com o botão esquerdo do mouse
        • Funciona com estratégias ATM em qualquer configuração (ticks, preço, financeiro, pips…)
        • Apresenta as linhas de entrada, alvo e stop da sua estratégia ATM antes de posicionar a ordem
        • Ferramenta 100% customizada (teclas de atalho, cores, tracejados, espessura, …)
        • Permite configurar ordens stop como Stop-limit ou Stop a mercado
        • Barra superior de ativação, configuração e situação da posição atual (em valores financeiros e ticks)

Como abrir a Flash Click em um gráfico da NinjaTrader

A ferramenta Flash Click deve ser adicionada a um gráfico como indicador. Para isso você pode clicar no ícone referente a indicadores na barra superior do gráfico (conforme figura abaixo) ou usar o atalho CTRL+I.

Nos indicadores disponíveis, você irá encontrar uma pasta com o nome “NeoTraderBot_Indicators”. Abra essa pasta e clique clique duas vezes sobre “NTB_FlashClick” (ou clique no botão add na parte inferior da janela).

Você perceberá que o indicador passará para área de indicadores configurados e a caixa de propriedades à direita estará editável para configurações da ferramenta.

Clique em “OK”. A janela irá se fechar e a ferramenta será aplicada ao gráfico. Caso apareça a mensagem abaixo, significa que você precisa habilitar o ChartTrader no gráfico, seja no modo visível ou escondido, pois a FlashClick utiliza dados das estratégias ATM e quantidades a serem negociadas a partir do ChartTrader.

Após habilitar o ChartTrader, basta apertar F5 para recarregar os indicadores. A mensagem visualizada anteriormente não deve se apresentar. Você pode se certificar que a Flash Click está carregada ao visualizar sua barra de configuração na parte superior do gráfico (conforme imagem abaixo).

Configurações da ferramenta pela Barra de Ferramentas

Uma vez aplicada ao gráfico, você poderá pela barra superior da ferramenta Flash Click, habilitar ou desabilitar a criação de ordens pelo mouse. Por padrão, a ferramenta é carregada no modo OFF, evitando erros de criação de ordens na inicialização da ferramenta.

Também é possível configurar qual o tipo de ordem stop será criada: Stop à mercado ou Stop-limit. As ordens stop a mercado servem para criar ordens visando o rompimento de um nível de preço. Por serem ordens a mercado, pode-se incorrer em elevados níveis de slippage a depender da situação do mercado. 

As ordens stop-limit, visam reduzir o efeito de slippage. Uma vez rompido o nível de preço da ordem, é posicionada uma ordem limitada.

Por fim, a barra superior da Flash Click também apresenta informação sobre a conta operada e posição corrente com o resultado aberto em termos financeiros e em ticks.

Configurações e Parâmetros (Janela de configuração de indicador)

Ao acessar os indicadores do gráfico (CTRL+I), você poderá configurar várias propriedades da ferramenta Flash Click.

No grupo “FlashClick settings” é possível configurar o tipo de ordem stop a ser utilizado, bem como as teclas de atalho para compra e venda em conjunção com o clique esquerdo do mouse.

No grupo “Entry/Take Profit/Stoploss lines”, o usuário pode habilitar ou desabilitar a plotagem de linhas conforme estratégia ATM aplicada no ChartTrader. É possível personalizar a cor das linhas, tipo de tracejado e espessura.

No grupo “Info box settings”, o usuário pode habilitar/desabilitar a caixa de informações exibida quando se aperta uma das teclas de ordem (compra/venda). Pode também configurar os aspectos visuais da caixa, tais como cor da fonte, do fundo, tamanho do texto, posição da caixa de informação e opacidade.

Visualizando os Níveis de preço das ordens da estratégia ATM e criando ordens

Estando a Flash Click habilitada, ao pressionar uma das teclas de atalho (compra/venda) configuradas na ferramenta, e havendo uma estratégia ATM selecionada, o usuário irá verificar no gráfico as linhas de alvo e stoploss configuradas na estratégia ATM. A Flash Click calcula as linhas em qualquer unidade definida nas estratégias ATM (preço, ticks, percentual ou pips).

Ao manter a tecla pressionada e movimentar o mouse, as linhas irão acompanhar o movimento, projetando as ordens de alvo/stop, bem como a caixa de informação com o valor da ordem de abertura de posição (caso esteja habilitada).

Caso o usuário solte a tecla de atalho, as linhas são removidas do gráfico. Se o usuário clicar com o botão esquerdo do mouse, serão criadas ordens do tipo stop ou limitada de acordo com o lado da operação e posição em relação ao valor atualmente negociado.

Visualizando as ordens criadas

As imagens abaixo demonstram a visualização de uma ordem de venda Stop-Limit (sigla SLM) e uma ordem de compra stop a mercado (sigla STP).

Barra de Ferramentas: Resultado da posição corrente

As imagens abaixo demonstram a visualização na barra de ferramentas criada pela Flash Click o resultado aberto em valores financeiros e em ticks. A barra apresentará o texto em verde caso o resultado da operação seja positivo. Em vermelho, se o resultado corrente da operação for negativo. E em branco se o resultado aberto for igual a zero ou não haver posição aberta.

É interessante observar que mesmo havendo uma posição aberta, a Flash Trader continua a apresentar as projeções de uma nova abertura de posição, caso uma das teclas de atalho seja acionada (conforme figura abaixo).

Documentação - IntelliRisk

Esta página visa apresentar uma documentação completa da ferramenta IntelliRisk para fins de referência em caso de dúvidas.

Assim, sugerimos utilizar o menu lateral direito de conteúdo para ir direto nas seções de interesse.

Ressaltamos que as orientações para instalação e ativação da licença contratada foram enviadas por e-mail no momento da contratação.

Objetivo da ferramenta e funcionalidades disponíveis

O objetivo principal da ferramenta IntelliRisk é fornecer as informações adequadas para que o trader possa tomar decisões sobre o risco de suas operações e conta, principalmente, para aqueles que estão participando de testes de mesas proprietárias (tais como Apex, TopStep, Bulenox, entre outras).

 

Veja abaixo as funcionalidades disponíveis na IntelliRisk:

        • Calcula o preço médio da sua posição de acordo com a montagem e realização parcial de sua posição
        • Apresenta o valor financeiro e em ticks em cada ordem de alvo e stop no gráfico, facilitando a sua gestão de risco da operação
        • Calcula o ponto de cobertura da sua conta (Daily Breakven). Uma vez com posição aberta, você saberá qual o nível de preço você ficaria com o resultado da sessão zerado.
        • Plota linha de limite de perda de mesas proprietárias: Trailling drawdown, static drawdown ou end of day. Permite monitorar em tempo real, uma vez posicionado, qual seria o nível de preço de risco máximo da conta.
        • Flexibilidade para escolher quais linhas deseja-se plotar no gráfico: preço médio, ponto de cobertura, limite de risco da conta
        • Ferramenta 100% customizada (cores, texto, plot de linhas, …)
        • Funciona em qualquer ativo, tipo de gráfico, tempo gráfico, janelas com multigráficos e multiabas

Como abrir a IntelliRisk em um gráfico da NinjaTrader

A ferramenta IntelliRisk deve ser adicionada a um gráfico como indicador. Para isso você pode clicar no ícone referente a indicadores na barra superior do gráfico (conforme figura abaixo) ou usar o atalho CTRL+I.

Documentação - Gain Guardian

Construtor de Capital - Liberação de acesso a Ferramentas

Este tutorial visa apresentar o passo a passo para liberação de acesso aos alunos/assinantes das ferramentas desenvolvidas pela NeoTraderBot para Construtor de Capital

Uma vez enviada a MachineID por meio do formulário ao final desta página, a liberação de acesso está condicionada à confirmação de vinculo (aluno) junto à Construtor de Capital e será realizada em até 1 dia útil.

Em caso de dúvidas ou questões relacionadas às ferramentas Construtor de Capital, envie e-mail para contrutordecapital1@gmail.com.

Gerando o seu MachineID

Passo 1: No Control Center, clique em “Help” -> “3rd Party Licensing”.

Passo 2: Na tela que abrir, você deve digitar “NeoTraderBot” no campo “Vendor name” e inserir o seu e-mail no campo “User defined ID”, ou em caso de erro por caracteres especiais, insira o seu nome completo sem espaços ou acentos e em letra minúscula. EM SEGUIDA, CLIQUE EM “SUBMIT” (ENVIAR).

Será gerada uma chave de Machine ID, a qual você deve copiar e enviar para nós, por meio do formulário a seguir. 

ATENÇÃO: Copie a chave completa (ela será composta também pelas informações que você inseriu no campo User defined ID (ID do usuário).

Liberação de Acesso - Ferramentas Construtor de Capital
Este formulário visa recepcionar as chaves dos usuários para liberação de uso das ferramentas e códigos desenvolvidos pela NeoTraderBot para Construtor de Capital

Aula 04 - Reutilizando código

Funções são essenciais na programação.

No mundo da programação há um constante esforço por tornar as linguagens cada vez mais naturais para nós seres humano (mais fáceis de programar), bem como mais eficientes (consumirem menos recursos computacionais).

Para o programador não é diferente, ele sempre está tentando programar cada vez melhor e mais rápido tendo em vista sua experiência acumulada, refletindo em códigos mais concisos (menos linhas de código) e mais eficientes.

A forma mais primitiva de ganhar velocidade em sua programação seria COPIAR e COLAR o que já fez no passado para resolver um problema e adaptá-lo para o problema que está tentando resolver. Acredite! Como programadores, fazemos muito isso! Mas uma forma mais estruturada de reutilizar código é por meio da criação de funções, o que veremos a seguir.

Reproduzir vídeo

O que são funções?

Antes de definirmos as funções vamos pensar melhor sobre o que é um programa! Um programa é a transcrição de um algoritmo em um código fonte que pode receber parâmetros, executar um conjunto de ações e retornar um resultado.

As funções também fazem exatamente isso, talvez pela única exceção de que elas estão contidas dentro dos programas. As funções são pedaços de código fonte que podem receber parâmetros, executam um conjunto de ações e podem retornar um resultado.

E quando é que criamos funções? Quando queremos fazer exatamente uma coisa que já fizemos em outro momento no nosso programa, ou seja, reutilizar código.

Qual a vantagem de usar funções? A gente economiza linhas de código e se precisar alterar as ações executadas, precisaremos mudar apenas em um lugar (dentro da função), ou seja, para facilitar a menutenção do código. Caso não tivesse uma função, o mesmo pedaço de código poderia estar replicado em vários lugares do seu programa! Tornando mais trabalhoso e susceptível a erros uma correção no código.

Assim, as funções servem também para generalizar em função dos parâmetros. Dentro delas podemos ter declaração de variáveis que serão conhecidas como variáveis locais, ou seja, são apenas utilizadas dentro da função.

Vamos a um exemplo para ilustrar isso melhor. Suponha que tenhamos um programa que calcule área de uma circunferência diversas vezes, o que você sabe que basta fazer a seguinte conta: pi*r**2 (onde r é o raio da circunferência). Assim, eu poderia criar uma função para realizar esse cálculo:

				
					
calculaAreaCircunferencia(raio: Real)
  real área;
  area = 3.1415*raio**2;
  
  return área;
				
			

Quando precisássemos calcular a área de uma circunferência com raio 10, apenas iríamos chamar a função calculaAreaCircunferencia(10) que ela retornaria o valor desejado.

É importante ressaltar que uma função pode receber mais de um parâmetro, mas geralmente retorna apenas uma estrutura de dados. Eu disse geralmente porque também há linguagens de programação que permitem às funções retornarem mais de uma estrutura.

Em algumas linguagens de programação são dados nomes diferentes para funções, a depender se retornam ou não valores. Por exemplo, tem linguagem que dá o nome procedure quando não há retorno de valor e function quando retorna…Novamente ressalto que estas especificidades de cada linguagem e é algo que será estudado quando você for se aprofundar em alguma delas. Para o momento, basta que tenha compreendido o diagrama abaixo que representa uma função.

Concluindo...

Ao longo das últimas quatro aulas, vimos de forma bem objetiva e prática os conceitos mais básicos da programação, passando por algoritmos, estrutura de dados, código fonte, compiladores, tipos básicos de dados, estruturas de controle e funções.

Com a informação apresentada até o momento, você já tem uma base inicial para implementarmos seus primeiros programas em uma linguagem específica. Isto é o que faremos na próxima aula! Nos vemos lá!

Documentação - Flash Click

Esta página visa apresentar uma documentação completa da ferramenta Flash Click para fins de referência em caso de dúvidas.

Assim, sugerimos utilizar o menu lateral direito de conteúdo para ir direto nas seções de interesse.

Ressaltamos que as orientações para instalação e ativação da licença contratada foram enviadas por e-mail no momento da contratação.

Objetivo da ferramenta e funcionalidades disponíveis

O objetivo principal da ferramenta Flash Click é permitir uma ação ágil por parte do trader aos rápidos movimentos do mercado, bem como mensurar da maneira adequada os riscos de cada posição a ser aberta, criando as ordens de maneira natural com um clique do mouse no gráfico.

Como sempre gostamos de entregar um pouco mais, você perceberá alguns detalhes e funcionalidades adicionais no decorrer do conteúdo dessa página.

Veja abaixo as funcionalidades disponíveis na Flash Click:

        • Cria ordens diretamente no gráfico por meio da combinação de uma tecla (Ctrl, Alt ou Shift) com o botão esquerdo do mouse
        • Funciona com estratégias ATM em qualquer configuração (ticks, preço, financeiro, pips…)
        • Apresenta as linhas de entrada, alvo e stop da sua estratégia ATM antes de posicionar a ordem
        • Ferramenta 100% customizada (teclas de atalho, cores, tracejados, espessura, …)
        • Permite configurar ordens stop como Stop-limit ou Stop a mercado
        • Barra superior de ativação, configuração e situação da posição atual (em valores financeiros e ticks)

Como abrir a Flash Click em um gráfico da NinjaTrader

A ferramenta Flash Click deve ser adicionada a um gráfico como indicador. Para isso você pode clicar no ícone referente a indicadores na barra superior do gráfico (conforme figura abaixo) ou usar o atalho CTRL+I.

Nos indicadores disponíveis, você irá encontrar uma pasta com o nome “NeoTraderBot_Indicators”. Abra essa pasta e clique clique duas vezes sobre “NTB_FlashClick” (ou clique no botão add na parte inferior da janela).

Você perceberá que o indicador passará para área de indicadores configurados e a caixa de propriedades à direita estará editável para configurações da ferramenta.

Clique em “OK”. A janela irá se fechar e a ferramenta será aplicada ao gráfico. Caso apareça a mensagem abaixo, significa que você precisa habilitar o ChartTrader no gráfico, seja no modo visível ou escondido, pois a FlashClick utiliza dados das estratégias ATM e quantidades a serem negociadas a partir do ChartTrader.

Após habilitar o ChartTrader, basta apertar F5 para recarregar os indicadores. A mensagem visualizada anteriormente não deve se apresentar. Você pode se certificar que a Flash Click está carregada ao visualizar sua barra de configuração na parte superior do gráfico (conforme imagem abaixo).

Configurações da ferramenta pela Barra de Ferramentas

Uma vez aplicada ao gráfico, você poderá pela barra superior da ferramenta Flash Click, habilitar ou desabilitar a criação de ordens pelo mouse. Por padrão, a ferramenta é carregada no modo OFF, evitando erros de criação de ordens na inicialização da ferramenta.

Também é possível configurar qual o tipo de ordem stop será criada: Stop à mercado ou Stop-limit. As ordens stop a mercado servem para criar ordens visando o rompimento de um nível de preço. Por serem ordens a mercado, pode-se incorrer em elevados níveis de slippage a depender da situação do mercado. 

As ordens stop-limit, visam reduzir o efeito de slippage. Uma vez rompido o nível de preço da ordem, é posicionada uma ordem limitada.

Por fim, a barra superior da Flash Click também apresenta informação sobre a conta operada e posição corrente com o resultado aberto em termos financeiros e em ticks.

Configurações e Parâmetros (Janela de configuração de indicador)

Ao acessar os indicadores do gráfico (CTRL+I), você poderá configurar várias propriedades da ferramenta Flash Click.

No grupo “FlashClick settings” é possível configurar o tipo de ordem stop a ser utilizado, bem como as teclas de atalho para compra e venda em conjunção com o clique esquerdo do mouse.

No grupo “Entry/Take Profit/Stoploss lines”, o usuário pode habilitar ou desabilitar a plotagem de linhas conforme estratégia ATM aplicada no ChartTrader. É possível personalizar a cor das linhas, tipo de tracejado e espessura.

No grupo “Info box settings”, o usuário pode habilitar/desabilitar a caixa de informações exibida quando se aperta uma das teclas de ordem (compra/venda). Pode também configurar os aspectos visuais da caixa, tais como cor da fonte, do fundo, tamanho do texto, posição da caixa de informação e opacidade.

Visualizando os Níveis de preço das ordens da estratégia ATM e criando ordens

Estando a Flash Click habilitada, ao pressionar uma das teclas de atalho (compra/venda) configuradas na ferramenta, e havendo uma estratégia ATM selecionada, o usuário irá verificar no gráfico as linhas de alvo e stoploss configuradas na estratégia ATM. A Flash Click calcula as linhas em qualquer unidade definida nas estratégias ATM (preço, ticks, percentual ou pips).

Ao manter a tecla pressionada e movimentar o mouse, as linhas irão acompanhar o movimento, projetando as ordens de alvo/stop, bem como a caixa de informação com o valor da ordem de abertura de posição (caso esteja habilitada).

Caso o usuário solte a tecla de atalho, as linhas são removidas do gráfico. Se o usuário clicar com o botão esquerdo do mouse, serão criadas ordens do tipo stop ou limitada de acordo com o lado da operação e posição em relação ao valor atualmente negociado.

Visualizando as ordens criadas

As imagens abaixo demonstram a visualização de uma ordem de venda Stop-Limit (sigla SLM) e uma ordem de compra stop a mercado (sigla STP).

Barra de Ferramentas: Resultado da posição corrente

As imagens abaixo demonstram a visualização na barra de ferramentas criada pela Flash Click o resultado aberto em valores financeiros e em ticks. A barra apresentará o texto em verde caso o resultado da operação seja positivo. Em vermelho, se o resultado corrente da operação for negativo. E em branco se o resultado aberto for igual a zero ou não haver posição aberta.

É interessante observar que mesmo havendo uma posição aberta, a Flash Trader continua a apresentar as projeções de uma nova abertura de posição, caso uma das teclas de atalho seja acionada (conforme figura abaixo).

Gráficos na TraderEvolution [PARTE 2- Configuração e Funcionalidades]

Reproduzir vídeo

Neste vídeo da séria “Conhecendo a Trader Evolution” vamos explorar as configurações e funcionalidades básicas de Gráficos.

Nesta segunda parte iremos demonstrar como incluir estudos em gráficos, criar e gerenciar alarmes, inserir indicadores, operar pelo gráfico e exibir os trades realizados no gráfico.

Instalando a ferramenta na TraderEvolution

Nesse último passo de pré-configuração, iremos instalar a ferramenta da NeoTraderBot que permitirá integrar suas estratégias da TraderEvolution com grupos no Telegram.

Reproduzir vídeo

TUTORIAL - PASSO 4: Instalando a ferramenta de integração na TraderEvolution

1) Abra uma janela do Windows Explorer (Tecla de atalho: WINDOWS + E)
2) Acesse a pasta de aplicativos do seu usuário windows

Clique na barra de endereço do Windows Explorer, digite “%APPDATA%” e aperte ENTER.

3) Acesse a pasta da TraderEvolution

No diretório de aplicativos, localize a pasta “TraderEvolution Brasil” e acesse-a.

4) Cole o arquivo da ferramenta de integração dentro da pasta "TraderEvolution Brasil"

Você deverá colar o arquivo “NTB_TE_IntegrationTelegram.dll”, baixado no site da NeoTraderBot para dentro dessa pasta. Trata-se de uma biblioteca compilada da NeoTraderBot contendo os requisitos necessários para permitir a integração da TraderEvolution com Telegram.

Pré-configurações efetuadas!

Agora que já realizamos as pré-configurações, podemos incluir o código necessário dentro de nossas estratégias para realizar o envio de mensagens para o Telegram.

Confira aqui um tutorial com exemplos de código fonte para você incluir em suas estratégias e indicadores da TraderEvolution.

Snippets e How-to

Aprender a programar envolve esforço, persistência e também colaboração com outros programadores (esse é um dos benefícios de participar de uma Comunidade como a NeoTraderBot!).

Pensando em acelerar a curva de aprendizado e reduzir o tempo que ficamos presos com problemas de programação, organizamos esta área de Snippets e de How-To (tutoriais) para elaboração de estratégias e indicadores na TraderEvolution utilizando EvoCode.

Os Snippets são trechos de códigos independentes criados para executar uma determinada tarefa. Eles podem ser copiados e modificados de acordo com a necessidade do usuário

Navegue abaixo pelas categorias disponíveis e caso tenha alguma sugestão de nova categoria ou tarefa, comente nas áreas apropriadas. Caso tenha colegas que também possam fazer bom uso e contribuir com a Comunidade, compartilhe esta área do site pelos ícones abaixo.

 

Compartilhe essa página!

Share on facebook
Facebook
Share on telegram
Telegram
Share on whatsapp
WhatsApp
Share on email
Email

Tutoriais sobre Estrutura de código

Nesta área você terá acesso a informações relacionadas a estrutura de um código fonte em EvoCode.

Tarefas/Tutoriais disponibilizados:

Snippets para Localização Temporal

Nesta área você terá acesso a pedaços de códigos fontes para localização da estratégia em relação ao tempo.

Tarefas disponibilizadas:

Snippets para Manipulação de Gráficos

Nesta área você terá acesso a pedaços de códigos fontes para manipular plot, cores de plotagem, espessura, tipo de gráfico, etc.

Tarefas disponibilizadas:

 

Snippets para Utilização de Indicadores da Plataforma

Nesta área você terá acesso a pedaços de códigos fontes para utilizar os indicadores disponibilizados por padrão na Plataforma.

Tarefas disponibilizadas:

 

Snippets para Ordens e Administração de Trade

Nesta área você terá acesso a pedaços de códigos fontes para execução de ordens e administração de trade (técnicas de stoploss e takeprofit).

Tarefas disponibilizadas:

Snippets para Implementação de estratégias

Nesta área você terá acesso a pedaços de códigos fontes para subtarefas comuns na implementação de estratégias.

Tarefas disponibilizadas:

 

Outros Snippets

Nesta área você terá acesso a pedaços de códigos fontes para objetivos não abrangidos pelas categorias acima.

Tarefas disponibilizadas:

 

Tutoriais sobre Estrutura do código

Introdução

Esta seção visa apresentar trechos de códigos com funcionalidades relativas à estrutura do código de indicadores e estratégias. Por exemplo, como criar parâmetros de entrada.

Você pode acessar os Snippets/Tutoriais diretamente pelo menu lateral direito, ou fazendo CTRL+F (CTRL+L) para localizar algum texto específico na página, uma vez que o conteúdo tende a crescer ao longo do tempo, dificultando a navegação pelo menu.

Caso tenham sugestões de código para acrescentar à lista, gentileza deixar o código nos comentários com o link para seu perfil em rede social (para devido crédito de autoria).

Snippets/Tutoriais

Como criar parâmetros no meu indicador/estratégia?

Os parâmetros de uma estratégia ou indicador são declarados como atributos da classe.

O que diferencia esses atributos dos demais atributos são as anotações (em C# chama-se Annotations e são contidas entre [ ]) que realizamos imediatamente antes da definição dos atributos. Vamos ver abaixo como criar diferentes tipos de parâmetros, como definir seu valor padrão, qual texto será exibido na interface de configuração da estratégia/indicador e pré-validações.

A primeira anotação que realizamos é invocar a função InputParameter. Esta função recebe 3 parâmetros: Tipo do parâmetro da estratégia, Texto a ser exibido na interface de configuração e a ordem de apresentação.

Os tipos de parâmetros possíveis em EvoCode são: Combobox, Checkbox, Numeric ,Color, Instrument, Account, String, DateTime e TimeSpan. Sendo Numeric e ComboBox os mais utilizados. O texto a ser exibido consiste em uma string de sua livre escolha e a ordem deve ser um inteiro iniciando em zero o qual irá ordenar a exibição dos parâmetros na janela de configuração da estratégia.

Existe também uma sobrecarga da função InputParameter, na qual não é necessário informar o parâmetro de ordem. Ao utilizar essa função, os parâmetros da estratégia terão exatamente a ordem na qual são criados no código-fonte.

A segunda anotação que pode ser utilizada é um validador. O usuário pode ver no dicionário EvoCode que existem uma função de validação para parâmetros numéricos chamada SimpleNumericAttribute. Este método é sobrecarregado, ou seja, possui diferentes combinações de parâmetros que realizam diferentes validações. Nos exemplos abaixo, ficará claro o uso desse método.

A terceira anotação possível é utilizada no caso de parâmetros exibidos no formato de ComboBox, ou seja, caixa de seleção. Nesse caso, podem ser inseridas quantas anotações forem necessárias para cada opção do ComboBox, invocando a função ComboBoxItem e passando como parâmetro a chave e o valor. Entenda chave como a string que será apresentada no combobox e valor como a representação da opção selecionada, que pode ser um número inteiro ou um enum.

Veja a seguir alguns exemplos de definição de parâmetros para estratégia:

Parâmetro Inteiro (Exemplo: Qtde de períodos de uma média móvel)

No código abaixo a tela de configuração da estratégia/indicador apresentará como primeiro parâmetro a ser definido a “Média rápida – Qtde de periodos” que é do tipo numérico e inteiro, variando entre 1 e 9999. Dentro do código esse parâmetro é reconhecido pelo nome fastestPeriod e a caixa de texto da tela de configuração já irá exibir o valor padrão igual a 5, conforme definido no código.

				
					[InputParameter(InputType.Numeric, "Média rápida - Qtde de periodos", 0)]
		[SimpleNumeric(1D,9999D)]
		public int fastestPeriod = 5;
				
			
Parâmetro ComboBox (Exemplo: Tipo da média móvel)

No código abaixo a tela de configuração da estratégia/indicador apresentará como segundo parâmetro a ser definido a “Média rápida – Tipo da média”, que apresentará em um comboBox as seguintes opções: SMA, EMA, SMMA, LWMA. O valor padrão desse parâmetro será a média aritmética. Observe que dentro do código, esse parâmetro de tipo de média utiliza um eNum pré-definido do EvoCode chamado MAMode.

Caso haja até 3 opções de seleção, a renderização desse componente na interface gráfica da plataforma será no formato de RadioBox ou invés de ComboBox (Caixa de seleção).

				
							[InputParameterAttribute(InputType.Combobox, "Média rápida - Tipo da média", 1)]
		[ComboboxItem("Aritmética (SMA)", MAMode.SMA)]
		[ComboboxItem("Exponencial (EMA)", MAMode.EMA)]
		[ComboboxItem("Amortecida (SMMA)", MAMode.SMMA)]		
		[ComboboxItem("Ponderada Linear (LWMA)", MAMode.LWMA)]		
		public MAMode fastestAvgType = MAMode.SMA;
				
			
Parâmetro Percentual

No código abaixo a tela de configuração da estratégia/indicador apresentará como primeiro parâmetro a ser definido a “bandPct”, que apresentará em uma caixa de texto com valor padrão igual a 2. É um parâmetro do tipo double e observe a anotação de validação possui 4 parâmetros, o que validará: valor mínimo (0.0), valor máximo (9999) precisão numérica (1 casa decimal) e incremento mínimo (0.1).

				
					        [InputParameter(InputType.Numeric, "bandPct", 0)]
        [SimpleNumeric(0.0D, 9999D, 1, 0.1)]
        public double bandPct = 2;
				
			
Código de um indicador com TODOS os tipos de parâmetros em EvoCode

No código abaixo você encontrará um exemplo de um indicador com todos os tipos de parâmetros possíveis em EvoCode.

				
					using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using Runtime.Script;
using TradeApi;
using TradeApi.History;
using TradeApi.Indicators;
using TradeApi.Instruments;
using TradeApi.ToolBelt;
using TradeApi.Trading;


namespace NeoTraderBot
{
    /// <summary>
    /// Indicator
    /// 
    /// </summary>
    public class TestingParameters : IndicatorBuilder 
    {
    	//Exemplo de parâmetro numérico inteiro
		[InputParameter(InputType.Numeric, "Periods", 0)]
		[SimpleNumeric(1D,9999D)]
		public int periods = 5;

		//Exemplo de parâmetro numérico percentual		
		[InputParameter(InputType.Numeric, "Percentage band (%)", 1)]
		[SimpleNumeric(0.0D, 9999D, 1, 0.1)]
		public double bandPct = 2.3;		

		//Exemplo de parâmetro ComboBox		
		[InputParameterAttribute(InputType.Combobox, "Average type", 2)]
		[ComboboxItem("Aritmética (SMA)", MAMode.SMA)]
		[ComboboxItem("Exponencial (EMA)", MAMode.EMA)]
		[ComboboxItem("Amortecida (SMMA)", MAMode.SMMA)]
		[ComboboxItem("Ponderada Linear (LWMA)", MAMode.LWMA)]
		public MAMode avgType = MAMode.SMA;
		
		[InputParameterAttribute(InputType.Checkbox, "Daytrade mode", 3)]
		public Boolean dayTradeMode;
		
		[InputParameterAttribute(InputType.String, "Input message", 4)]
		public string msg = "Hello EvoCode!";
		
		[InputParameterAttribute(InputType.Color, "Color", 5)]
		public Color someColor = Color.Orange;
		
		[InputParameterAttribute(InputType.Instrument, "Symbol", 6)]
		public Instrument instrument;		
		
		[InputParameterAttribute(InputType.DateTime, "Trading start on:", 7)]
		public DateTime startDateTime = DateTime.Now.AddDays(-3);
		
		[InputParameterAttribute(InputType.TimeSpan, "Open position after:", 8)]
		public TimeSpan openPosAfter = DateTime.Now.TimeOfDay;
    	
        public TestingParameters()
            : base()
        {
			#region Initialization
            Credentials.Author = "";
            Credentials.Company = "";
            Credentials.Copyrights = "";
            Credentials.DateOfCreation = new DateTime(2023, 7, 21);
            Credentials.ExpirationDate = DateTime.MinValue;
            Credentials.Version = "";
            Credentials.Password = "66b4a6416f59370e942d353f08a9ae36";
            Credentials.ProjectName = "TestingParameters";
            #endregion 
            
            Lines.Set("indicator");
			Lines["indicator"].Color = Color.Blue;

            SeparateWindow = false;
        }
        
        /// <summary>
        /// This function will be called after creating
        /// </summary>
		public override void Init()
		{
			string param = "Parâmetros:\n";
			param += "Periods: " + periods.ToString() + "\n";
			param += "Percentage band (%): " + bandPct.ToString() + "\n";
			param += "Average type: " + avgType.ToString() + "\n";
			param += "Daytrade mode: " + dayTradeMode.ToString() + "\n";
			param += "Input message: " + msg + "\n";
			param += "Color: " + someColor.Name + "\n";
			param += "Symbol: " + instrument.Symbol.ToString() + "\n";
			param += "Trading start on: " + startDateTime.ToLongDateString() + "\n";
			param += "Open position after: " + openPosAfter.ToString() + "\n";
		
			Notification.Comment(param);
			
		}        
 
        /// <summary>
        /// Entry point. This function is called when new quote comes or new bar created
        /// </summary>
        public override void Update(TickStatus args)
        {
			Lines["indicator"].SetValue(HistoryDataSeries.GetValue(PriceType.Close));
        }
        
        /// <summary>
        /// This function will be called before removing
        /// </summary>
		public override void Complete()
		{
			
		} 
     }
}

				
			

O que são as credenciais do meu código?

As credenciais servem para identificar a sua estratégia com os atributos de Autor, Empresa, Direitos Autorais (se for o caso), Data de criação do código, Data de Expiração, Versão do código, Senha e Nome do Projeto (este é o nome que irá aparecer nas listagens dentro da plataforma). 

A utilização de #region não tem nenhum impacto sobre o código, sendo apenas uma funcionalidade .NET para poder expandir ou colapsar blocos de código na IDE (ambiente de desenvolvimento).

OBS: É importante ressaltar que se você configurar a data de expiração para um valor diferente de “DateTime.MinValue”, compilar o seu código e compartilhar ele com alguém, o código executará apenas até a data de expiração.

				
					#region Initialization
Credentials.Author = "Johnathas Carvalho";
Credentials.Company = "Comunidade NeoTraderBot";
Credentials.Copyrights = "";
Credentials.DateOfCreation = new DateTime(2023, 5, 16);
Credentials.ExpirationDate = DateTime.MinValue;
Credentials.Version = "1.0";
Credentials.Password = "66b4a6416f59370e942d353f08a9ae36";
Credentials.ProjectName = "NTB_TripleCrossoverIndicator";
Credentials.Description = "Descrição";
#endregion 
				
			

Como definir texto a ser apresentado no cabeçalho do gráfico o indicador?

A definição do texto a ser apresentado no cabeçalho do gráfico, quando seu indicador for aplicado deve ser realizada no método Init. Conforme exemplo abaixo.

É importante dizer que ScriptShortName é um atributo da Classe IndicatorBuilder e o que estamos fazendo é simplesmente atribuir valor a essa variável com uma string. Utilizou-se também a função de formatação de string que permite colocar placeholders (reserva de espaço) dentro da string e definir seus valores nos próximos parâmetros da função string.Format. A sequencia {0} é um placeholder que irá ser substituída pelo primeiro parâmetro, no caso, fastestAvgType.

 

				
					public override void Init()
{

ScriptShortName = (string.Format("NTB Crossover: {0}({1}) | {2}({3}) | {4}({5})",
                              fastestAvgType, fastestPeriod, fastAvgType, fastPeriod, slowAvgType, slowPeriod));

}  
				
			

Quais são os principais eventos que serão tratados pelo método Update?

As classes de indicador e estratégia (IndicatorBuilder e StrategyBuilder) podem lidar com diferentes tipos de eventos. Não obstante, existem 3 eventos que são comuns nessas duas classes e que exigem a implementação de 3 métodos, a saber: Init, Update e Complete.

O Método Init será executado sempre que um indicador/estratégia for inicializado dentro da plataforma TraderEvolution. Ou seja, quando o indicador for incluído em um gráfico um uma estratégia iniciar sua execução.

De maneira análoga, o método Complete é chamado ao final da execução do indicador ou estratégia.

Assim, resta falar do método Update que podemos dizer se tratar do coração do indicador/estratégia. Todos eventos durante a execução do seu código devem ser tratados no método Update, o qual recebe como parâmetro um objeto do tipo TickStatus chamado args).

O valor de args pode ser um dos três valores possíveis do eNum TickStatus: IsBar, IsQuote e IsHistory. Vamos explicar cada um desses eventos abaixo:

      • isBar: quando uma barra é encerrada, gera-se uma chamada ao método Update com o valor de args igual a isBar. Assim, o programador pode definir o que fazer no fechamento das barras no código dentro de Update. Sempre após um evento isBar, o método Update é chamado com um evento isQuote.
      • isQuote: este evento é sempre disparado para cada negociação recebida pela sua plataforma cliente (seu programa TraderEvolution). Assim, o programador pode definir o que fazer no tick. Nos dados históricos, isQuote é disparado 4 vezes para cada barra.
      • isHistory: este evento é disparado para cada barra enquanto seu código processa os dados históricos. Uma vez em tempo real, esse evento não é mais disparado.

Quais são as informações que consigo obter da conta do usuário logado pelo código?

Todas as estratégias/indicador tem acesso às informações da conta logada por meio da classe AccountManager, a qual pode retornar a conta atual e seus detalhes. O código abaixo demonstra como obter o e-mail do usuário que está executando o código.

Posição do DicionárioPropriedade
[0]Conta
[1]Saldo
[2]Saldo bloqueado
[3]L/P líquido aberto
[4]L/P bruto aberto
[5]Saldo projetado
[6]Nº de ordens
[7]Nº de posições
[8]Margem Inicial
[9]Nível de risco
[10]Nível de alerta de margem
[11]Nível “Stop Out”
[12]Fundos disponíveis
[13]Alerta de margem
[14]Manutenção de Margem
[15]Disponível para Retirada
[16]ID do usuário
[17]Login do usuário
[18]Cliente
[19]E-mail
[20]Bruto de hoje
[21]Taxas de hoje
[22]Líquido de hoje
[23]Volume de hoje
[24]Nº de negociações de hoje
[25]Valor da Ação
[26]Saldo em dinheiro
[27]Número do telefone
[28]Margem inicial
[29]Saldo + Risco total
[30]Situação da negociação
[31]Limite diário de perda
[32]Contagem máxima de ordens por dia
[33]Nº máximo de posições
[34]Nº máximo de ordens pendentes
[35]Capital de ordem máximo
[36]Margem disponível
[37]Valor de crédito
[38]Modo da conta
[39]Ativo
[40]Descrição do Ativo
[41]Tipo de conta
[42]Tipo de Ativo
[43]Taxa de juros
[44]Descontos de hoje
[45]Bloqueado para ‘Ações’
[46]Ganho incerto
[47]Modificar nivel de rebaixamento
[48]Quantidade máxima da posição
[49]Limite de perda semanal
[50]Perda diária
[51]Perda semanal
[52]Ordens de ações
[53]Valor da Opção
[54]Liquidez de Ações
[55]Perda não realizada
[56]Limite de perda não realizado
[57]Objetivo de lucro diário
[58]Limite de volume de ações
[59]Limite de volume futuro
[60]Limite de volume de opções
[61]Procuração
[62]Valor da ordem máximo
[63]Req. de prêmio de opção
[64]Rebaixamento Máximo
[65]Margem isenta
[66]Warn. margin req.
[67]Warn. margin req.%
[68]Margin before warning
Obtendo e-mail do usuário
				
					Dictionary<string, string> detalhesConta = AccountManager.Current.GetAccountDetails();
string email = "";
if (detalhesConta.TryGetValue("E-mail", out email))
{
    Notification.Print(email);
}
				
			

Como identificar se o código está rodando em conta real ou conta demo?

				
					string tipoConta = "";
Boolean contaReal = false;

Dictionary<string, string> detalhesConta = AccountManager.Current.GetAccountDetails();
if (detalhesConta.TryGetValue("Conta", out tipoConta))
{
    if (!tipoConta.Contains("demo"))
    {
        contaReal = true;
    }
}
				
			

Snippets para Manipulação de Gráficos

Esta seção visa apresentar trechos de códigos com funcionalidades relativas à manipulação de gráficos.

Você pode acessar os Snippets diretamente pelo menu lateral direito, ou fazendo CRL+F (CTRL+L) para localizar algum texto específico na página, uma vez que o conteúdo tende a crescer ao longo do tempo, dificultando a navegação pelo menu.

Caso tenham sugestões de código para acrescentar à lista, gentileza deixar o código nos comentários com o link para seu perfil em rede social (para devido crédito de autoria).

Snippets

Como criar e configurar os atributos gerais de um plot?

Os plots, ou Lines como é definida a Classe dentro do EvoCode devem ser instanciados no construtor do indicador. Cada Line recebe um nome por meio do método Set e assim pode ser indexado.

O programador pode configurar a visbilidade o estilo de linha (histograma, linha, escada, etc…), a cor padrão, a espessura, entre outras propriedades. Veja abaixo um exemplo de como criar 2 plots, um histograma e uma linha pontilhada.

				
					public IndicadorXYZ(): base()
{
    //Linha pontilhada
    Lines.Set("Média rápida");
    Lines["Média rápida"].Color = Color.Red;
	Lines["Média rápida"].Style = LineStyle.DotLine;
	Lines["Média rápida"].Width = 1;
	
	//Histograma
	Lines.Set("Histograma");
    Lines["Histograma"].Color = Color.Gray;
	Lines["Histograma"].Style = LineStyle.Histogram;
}
				
			

Eu posso plotar indicadores em uma estratégia?

Sim! Apesar da classe StrategyBuilder não possuir interface com classe Lines, é possível instanciarmos indicadores dentro das estratégias. Assim, os plots e elementos gráficos dos indicadores também serão exibidos no gráfico ao rodar a estratégia. 

Os indicadores devem ser instanciados no método Init e naturalmente também devem ser declarados como atributos da classe.

Veja abaixo alguns exemplos de instanciação de indicadores:

Instanciando uma média móvel (Indicador nativo)
				
					private BuiltInIndicator fastAvg;

public override void Init()
{
	fastAvg = IndicatorsManager.BuildIn.MA(HistoryDataSeries, fastPeriod, fastAvgType, 0, PriceType.Close);
} 
				
			
Instanciando Average True Range (ATR)
				
					private BuiltInIndicator avgTrueRange;

public override void Init()
{
    avgTrueRange = IndicatorsManager.BuildIn.ATR(HistoryDataSeries, 200);
} 
				
			
Instanciando Indicador Próprio chamado "NTB_TripleCrossoverIndicator"

Observe que ao instanciar um indicador próprio com o método custom, fornecemos 3 parâmetros: o nome do indicador (nome da classe), a série de dados, e um array com os valores dos parâmetros.

				
					private BuiltInIndicator NTB_3Cross;

public override void Init()
{
	NTB_3Cross = IndicatorsManager.BuildIn.Custom("NTB_TripleCrossoverIndicator" 
	                                              ,	HistoryDataSeries
	                                              , new Object[]{fastestPeriod,
  			                                              	   fastestAvgType,
  			                                              	   fastPeriod,
  			                                              	   fastAvgType,
  			                                              	   slowPeriod,
  			                                              	   slowAvgType})
} 
				
			

Como mudar a cor do plot em determinada condição?

As cores de um plot podem ser alteradas para qualquer posição a qualquer instante. Basta atribuir a cor desejada ao marcador da Line. Veja no exemplo abaixo um código que atribui cores a um histograma de maneira condicional: se a barra for de alta usa corAlta, senão usa corBaixa.

				
					public override void Update(TickStatus args)
{
	if (args == TickStatus.IsQuote)
	{
		Color corAlta = Color.FromArgb(0, 51, 0);;
		Color corBaixa = Color.FromArgb(153, 0, 0);;
		
		Lines["Volat."].SetValue(rangeAtual);
    	Lines["Volat."].Markers.Set((barData.GetOpen() < barData.GetClose()) ? corAlta : corBaixa, 0);
	}
}
				
			

Como inserir um texto no cabeçalho do gráfico?

Caso esteja trabalhando com indicadores, é possível inserir um texto no cabeçalho do gráfico (Veja na figura abaixo). Com esta funcionalidade, você pode inserir informações que julgue ser úteis de serem exibidas no gráfico.

				
					Notification.Comment("Aqui é onde ficam os comentários!");
				
			

Como garantir que indicador será aplicado apenas ao gráfico principal?

Em alguns casos, é desejável garantir que o indicador esteja sendo aplicado no gráfico principal ou em um gráfico separado. Caso o usuário tenha aplicado o indicador na janela diferente da esperada, pode-se alertar isso por meio de um texto, conforme figura abaixo.

Para se implementar esta funcionalidade, deve-se incluir a biblioteca Runtime.Scripts.Charts no cabeçalho do código fonte, e dentro da classe do indicador sobrescrever o método onPaintChart, conforme código exemplo abaixo.

				
					using Runtime.Script.Charts;

public override void OnPaintChart(object sender, PaintChartEventArgs args)
{
    var graphic = args.Graphics;
    int windowNumber = ChartSource.FindWindow(this);
	Font fonte = new Font("Arial", 24);
	Brush boxBrush = new SolidBrush(Color.LightGray);
	
	//É o número da janela que define se o indicador está no gráfico principal (= 0)
    if (windowNumber != 0)
    {
        using (StringFormat format = new StringFormat())
        {
            format.LineAlignment = StringAlignment.Center;
            format.Alignment = StringAlignment.Center;

            graphic.DrawString("O indicador deve ser aplicado ao gráfico principal", fonte, boxBrush, args.Rectangle, format);
        }

        return;
    }
}		
				
			

Snippets para Utilização de Indicadores da Plataforma

Introdução

Esta seção visa apresentar trechos de códigos com exemplos de utilização dos indicadores disponibilizados na plataforma.

Você pode acessar os Snippets diretamente pelo menu lateral direito, ou fazendo CRL+F (CTRL+L) para localizar algum texto específico na página, uma vez que o conteúdo tende a crescer ao longo do tempo, dificultando a navegação pelo menu.

Caso tenham sugestões de código para acrescentar à lista, gentileza deixar o código nos comentários com o link para seu perfil em rede social (para devido crédito de autoria).

Snippets

Como instanciar uma média móvel nativa?

Reproduzir vídeo

Os indicadores devem ser instanciados no método Init e naturalmente também devem ser declarados como atributos da classe.

				
					private BuiltInIndicator fastAvg;

public override void Init()
{
    fastAvg = IndicatorsManager.BuildIn.MA(HistoryDataSeries, 20, MAMode.SMA, 0, PriceType.Close);
} 
				
			

Como instanciar um indicador criado por você dentro de outra estratégia/indicador?

Reproduzir vídeo

Os indicadores devem ser instanciados no método Init e naturalmente também devem ser declarados como atributos da classe. Veja abaixo um exemplo de instanciação de indicador próprio.

Observe que ao instanciar um indicador próprio com o método custom, fornecemos 3 parâmetros: o nome do indicador (nome da classe), a série de dados, e um array com os valores dos parâmetros.

Instanciando Indicador Próprio chamado "NTB_TripleCrossoverIndicator"
				
					private BuiltInIndicator NTB_3Cross;

public override void Init()
{
	NTB_3Cross = IndicatorsManager.BuildIn.Custom("NTB_TripleCrossoverIndicator" 
	                                              ,	HistoryDataSeries
	                                              , new Object[]{fastestPeriod,
  			                                              	   fastestAvgType,
  			                                              	   fastPeriod,
  			                                              	   fastAvgType,
  			                                              	   slowPeriod,
  			                                              	   slowAvgType})
} 
				
			

Como criar estratégias/indicadores em múltiplos tempos gráficos?

Reproduzir vídeo

O EvoCode permite utilizar séries de dados de diferentes ativos e multiplos tempos gráficos em uma mesma estratégia ou indicador. Segue abaixo um exemplo no qual é implementado um indicador no tempo gráfico primário consistindo em uma média aritmética, bem como uma outra média aritmética utilizando dados de preço do mesmo ativo em um tempo gráfico diferente (5 minutos).

 

Calculando médias em múltiplos tempos gráficos
				
					using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using Runtime.Script;
using TradeApi;
using TradeApi.History;
using TradeApi.Indicators;
using TradeApi.Instruments;
using TradeApi.ToolBelt;
using TradeApi.Trading;
using TradeApi.Quotes;
using NeoTraderBot;

namespace NeoTraderBot
{
    public class MultiTimeFrameIndicator : IndicatorBuilder
    {
        private BuiltInIndicator avg;

        // Secondary timeframe 5 minutes
        private HistoricalData historicalDataSeries2 = null;
        private BuiltInIndicator avg2;

        #region inputs
        [InputParameter(InputType.Numeric, "Primary SMA - Periods", 0)]
        [SimpleNumeric(1D, 9999D)]
        public int periods = 50;

        [InputParameter(InputType.Numeric, "Secondary SMA - Periods", 0)]
        [SimpleNumeric(1D, 9999D)]
        public int periods2 = 10;

        #endregion




        public MultiTimeFrameIndicator()
            : base()
        {
            #region Initialization
            Credentials.Author = "";
            Credentials.Company = "";
            Credentials.Copyrights = "";
            Credentials.DateOfCreation = new DateTime(2023, 7, 18);
            Credentials.ExpirationDate = DateTime.MinValue;
            Credentials.Version = "";
            Credentials.Password = "66b4a6416f59370e942d353f08a9ae36";
            Credentials.ProjectName = "Multi TimeFrame Averages";
            #endregion

            Lines.Set("avg1min");
            Lines["avg1min"].Color = Color.Blue;
            Lines.Set("avg5min");
            Lines["avg5min"].Color = Color.Red;

            SeparateWindow = false;
        }
        public override void Init()
        {
            HistoricalDataManager.OnLoaded += plotHistoryValues;

            InstrumentsManager.Subscribe(InstrumentsManager.Current, QuoteTypes.Trade);
            HistoricalRequest historicalRequest2 = new TimeHistoricalRequest(InstrumentsManager.Current, DataType.Trade, Period.Minute, 5);
            historicalDataSeries2 = HistoricalDataManager.Get(historicalRequest2, new Interval(DateTime.UtcNow.AddDays(-10), DateTime.UtcNow));

            avg = IndicatorsManager.BuildIn.MA(HistoryDataSeries, periods, MAMode.SMA);
            avg2 = IndicatorsManager.BuildIn.MA(historicalDataSeries2, periods2, MAMode.SMA);

            Notification.Comment(  "This is a SNIPPET from NeoTraderBot Community: www.NeoTraderBot.com.\n"
                                 + "In the blue line, we have a SMA of " + periods + " periods in the current timeframe. \n"
                                 + "In the red line, we have a SMA of " + periods2 + " periods in a 5-minutes timeframe on the same symbol.");
        }

       public override void Update(TickStatus args)
        {
            Lines["avg1min"].SetValue(avg.GetValue());
            Lines["avg5min"].SetValue(avg2.GetValue());
        }

        public override void Complete()
        {
            HistoricalDataManager.OnLoaded -= plotHistoryValues;
            InstrumentsManager.UnSubscribe(InstrumentsManager.Current, QuoteTypes.Trade);
        }

        public void plotHistoryValues(HistoricalData hData)
        {
            for (int i = 0; i < HistoryDataSeries.Count; i++)
            {
                int index = historicalDataSeries2.FindInterval(HistoryDataSeries.GetTimeUtc(i));
                Lines["avg5min"].SetValue(avg2.GetValue(index), i);
            }
		}


    }
}


				
			

Snippets para Ordens e Administração de Trade

Esta seção visa apresentar trechos de códigos com exemplos de envio de ordens e administração de trade utilizando técnicas de stoploss (fixo, móvel, breakeven) e take profit.

Você pode acessar os Snippets diretamente pelo menu lateral direito, ou fazendo CRL+F (CTRL+L) para localizar algum texto específico na página, uma vez que o conteúdo tende a crescer ao longo do tempo, dificultando a navegação pelo menu.

Caso tenham sugestões de código para acrescentar à lista, gentileza deixar o código nos comentários com o link para seu perfil em rede social (para devido crédito de autoria).

Snippets

Como rotear ordens a mercado, stop e limitada?

No código abaixo, você encontra um exemplo de estratégia que abre um posição em uma data/horário específicos. Assim, você poderá testar a abertura de posições por ordens a mercado, limitada ou stop.

O código possui parâmetros para quantidade, horario de encerramento da posição e lado da posição (comprado/vendido).

OBS: É importante ressaltar que uma vez apregoada uma ordem, ela permanecerá ativa e aguardando execução até que o usuário cancele. Não há um auto-gerenciamento de execução apenas para próxima barra como em outras plataformas.

				
					using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using Runtime.Script;
using TradeApi;
using TradeApi.History;
using TradeApi.Indicators;
using TradeApi.Instruments;
using TradeApi.ToolBelt;
using TradeApi.Trading;



namespace ExemplosNeoTraderBot
{
    /// <summary>
    /// Strategy1
    /// 
    /// </summary>
    public class NTB_ExemploRoteamentoOrdens : StrategyBuilder
    {
		private BarData dadosBarra;
		
        public NTB_ExemploRoteamentoOrdens()
            : base()
        {
			#region Initialization
            Credentials.Author = "NeoTraderBot";
            Credentials.Company = "NeoTraderBot";
            Credentials.Copyrights = "";
            Credentials.DateOfCreation = new DateTime(2023, 9, 5);
            Credentials.ExpirationDate = DateTime.MinValue;
            Credentials.Version = "";
            Credentials.Password = "66b4a6416f59370e942d353f08a9ae36";
            Credentials.ProjectName = "exemploOrdensBasicas";
            #endregion 


        }
        
        /// <summary>
        /// This function will be called after creating
        /// </summary>
		public override void Init()
		{
			dadosBarra = (HistoryDataSeries as BarData);
		}        
 
        /// <summary>
        /// Entry point. This function is called when new quote comes or new bar created
        /// </summary>
        public override void Update(TickStatus args)
        {
        	if (args == TickStatus.IsBar)
        	{
        		List<Position> listaPosicoes = PositionsManager.GetPositions();

        		//DATA E HORA PARA ABERTURA DE POSIÇÕES
        		DateTime horarioAbertura = new DateTime(2023, 09, 05, 09, 06, 0);
				DateTime horarioEncerramento = horarioAbertura.AddMinutes(10);
				
				//INFORMAÇÃO PARA ABERTURA DE POSIÇÕES
				OrderSide ladoOperacao = OrderSide.Sell;
				int quantidade = 1;
				double precoOrdemStop = 4977.5;
				double precoOrdemLimitada = 4982.5;
        		
				OrderRequest request = null;
				
				//CRIA ORDENS
        		if ((listaPosicoes.Count == 0) && (dadosBarra.GetTimeUtc(0).ToLocalTime() == horarioAbertura))
        		{
					// ORDEM A MERCADO
					//request = new OrderRequest(OrderType.Market, InstrumentsManager.Current, AccountManager.Current, ladoOperacao, quantidade);
            		
					// ORDEM LIMITADA
					//request = new OrderRequest(OrderType.Limit, InstrumentsManager.Current, AccountManager.Current, ladoOperacao, quantidade, precoOrdemLimitada);
        			
        			// ORDEM STOP
        			request = new OrderRequest(OrderType.Stop, InstrumentsManager.Current, AccountManager.Current, ladoOperacao, quantidade, null, precoOrdemStop);

	        		//ENVIA ORDENS PARA BROKER
	        		OrdersManager.Send(request);
        		}

				
				//CRIA ORDEM DE ENCERRAMENO A MERCADO        		
				if ((listaPosicoes.Count != 0) && (dadosBarra.GetTimeUtc(0).ToLocalTime() == horarioEncerramento))
        		{
					request = new OrderRequest(OrderType.Market, InstrumentsManager.Current, AccountManager.Current, (ladoOperacao == OrderSide.Buy) ? OrderSide.Sell : OrderSide.Buy, quantidade);
            		OrdersManager.Send(request);
        		} 

        	}
			
        }
        
        /// <summary>
        /// This function will be called before removing
        /// </summary>
		public override void Complete()
		{
			
		} 
     }
}

				
			

Como enviar uma ordem a mercado?

Para enviar uma ordem a mercado, é necessário criar uma requisição de ordem (OrderRequest) com a parametrização desejada e, em seguida, solicitar ao Gestor de ordens que envie essa ordem.

O envio de ordem pode ser feito de maneira síncrona ou assincrona. Na primeira forma (síncrona), o código fica aguardando o retorno da função Send. Já no envio assíncrono, o código continua sua execução e o programador fornece uma função callback para ser executada quando houver o resultado do envio da ordem.

Seguem abaixo exemplos de envio de ordens a mercado de compra e venda.

Ordem de compra a mercado (Envio síncrono)
				
					orderSize = 1;

OrderRequest request = new OrderRequest(OrderType.Market, 
                                        InstrumentsManager.Current,
                                        AccountManager.Current,
                                        OrderSide.Buy,
                                        orderSize);
OrdersManager.Send(request); 
				
			
Ordem de venda a mercado (Envio síncrono)
				
					orderSize = 1;

OrderRequest request = new OrderRequest(OrderType.Market, 
                                        InstrumentsManager.Current,
                                        AccountManager.Current,
                                        OrderSide.Sell,
                                        orderSize);
OrdersManager.Send(request); 
				
			

Como abrir uma posição com ordens OCO?

Gestão de risco é essencial para negociação de ativos. O exemplo abaixo demonstra como enviar um ordem de compra a mercado para abertura de posição, acompanhada das ordens de stoploss e alvo em termos de ticks. 

Ordem de compra a mercado com RG 3:1 e Stop de 30 ticks (Envio síncrono)
				
					using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using Runtime.Script;
using TradeApi;
using TradeApi.History;
using TradeApi.Indicators;
using TradeApi.Instruments;
using TradeApi.ToolBelt;
using TradeApi.Trading;



namespace ExemplosNeoTraderBot
{
    /// <summary>
    /// Strategy1
    /// 
    /// </summary>
    public class NTB_ExemploOrdemOCO : StrategyBuilder
    {
		private BarData dadosBarra;
		
        public NTB_ExemploOrdemOCO()
            : base()
        {
			#region Initialization
            Credentials.Author = "NeoTraderBot";
            Credentials.Company = "NeoTraderBot";
            Credentials.Copyrights = "";
            Credentials.DateOfCreation = new DateTime(2023, 9, 5);
            Credentials.ExpirationDate = DateTime.MinValue;
            Credentials.Version = "";
            Credentials.Password = "66b4a6416f59370e942d353f08a9ae36";
            Credentials.ProjectName = "exemploOrdensOCO";
            #endregion 


        }
        
        /// <summary>
        /// This function will be called after creating
        /// </summary>
		public override void Init()
		{
			dadosBarra = (HistoryDataSeries as BarData);
		}        
 
        /// <summary>
        /// Entry point. This function is called when new quote comes or new bar created
        /// </summary>
        public override void Update(TickStatus args)
        {
        	if (args == TickStatus.IsBar)
        	{
        		List<Position> listaPosicoes = PositionsManager.GetPositions();

        		//DATA E HORA PARA ABERTURA DE POSIÇÕES
        		DateTime horarioAbertura = new DateTime(2023, 09, 05, 09, 06, 0);
				DateTime horarioEncerramento = new DateTime(2023, 09, 05, 17, 00, 0);
				
				//INFORMAÇÃO PARA ABERTURA DE POSIÇÕES
				TradeResult ordem;				
				OrderSide ladoOperacao = OrderSide.Sell;
				int quantidade = 1;
				double stoplossTicks = 30;
				double takeProfitTicks = stoplossTicks*3;        		
				
				OrderRequest request = null;
				
				//CRIA ORDEM OCO
        		if ((listaPosicoes.Count == 0) && (dadosBarra.GetTimeUtc(0).ToLocalTime() == horarioAbertura))
        		{
					request = new OrderRequest(OrderType.Market,
					                                        InstrumentsManager.Current,
					                                        AccountManager.Current,
					                                        ladoOperacao, quantity: quantidade)
					{
						SLTPPriceType = SLTPPriceType.Ticks,
        				StopLossPrice = stoplossTicks,
						TakeProfitPrice = takeProfitTicks
					};
					
					//ENVIA ORDENS PARA BROKER
					ordem = OrdersManager.Send(request);

        		}

				
				//CRIA ORDEM DE ENCERRAMENO A MERCADO        		
				if ((listaPosicoes.Count != 0) && (dadosBarra.GetTimeUtc(0).ToLocalTime() == horarioEncerramento))
        		{
					request = new OrderRequest(OrderType.Market, InstrumentsManager.Current, AccountManager.Current, (ladoOperacao == OrderSide.Buy) ? OrderSide.Sell : OrderSide.Buy, quantidade);
            		OrdersManager.Send(request);
        		} 

        	}
			
        }
        
        /// <summary>
        /// This function will be called before removing
        /// </summary>
		public override void Complete()
		{
			
		} 
     }
}

				
			

Snippets para Implementação de estratégias

Esta seção visa apresentar trechos de códigos com funcionalidades relativas à localização temporal da estratégia. Por exemplo, identificar se a atual barra é a primeira barra do dia para verificar gap diário.

Você pode acessar os Snippets diretamente pelo menu lateral direito, ou fazendo CTRL+F (CTRL+L) para localizar algum texto específico na página, uma vez que o conteúdo tende a crescer ao longo do tempo, dificultando a navegação pelo menu.

Caso tenham sugestões de código para acrescentar à lista, gentileza deixar o código nos comentários com o link para seu perfil em rede social (para devido crédito de autoria).

Snippets

Como identificar gap de abertura do dia?

Veja abaixo um exemplo de como estruturar uma lógica para identificar gap de abertura diário pelo EvoCode.

				
					using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using Runtime.Script;
using TradeApi;
using TradeApi.History;
using TradeApi.Indicators;
using TradeApi.Instruments;
using TradeApi.ToolBelt;


namespace Snippets_NeoTraderBot
{
    /// <summary>
    /// Indicator1
    /// 
    /// </summary>
    public class exemploIdentGapAbertura : IndicatorBuilder 
    {
		private BarData dadosCandle;
    	
        public exemploIdentGapAbertura()
            : base()
        {
			#region Initialization
            Credentials.Author = "NeoTraderBot";
            Credentials.Company = "NeoTraderBot";
            Credentials.Copyrights = "";
            Credentials.DateOfCreation = new DateTime(2023, 9, 4);
            Credentials.ExpirationDate = DateTime.MinValue;
            Credentials.Version = "";
            Credentials.Password = "66b4a6416f59370e942d353f08a9ae36";
            Credentials.ProjectName = "exemploIdentGapAbertura";
            #endregion 
            
            Lines.Set("line1");
			Lines["line1"].Color = Color.Blue;

            SeparateWindow = false;
        }
        
        /// <summary>
        /// This function will be called after creating
        /// </summary>
		public override void Init()
		{
			dadosCandle = (HistoryDataSeries as BarData);
		}        
 
        /// <summary>
        /// Entry point. This function is called when new quote comes or new bar created
        /// </summary>
        public override void Update(TickStatus args)
        {
			if (dadosCandle.Count <= 1)
				return;
        	
			if (args != TickStatus.IsQuote)
			{
				if (dadosCandle.GetTimeUtc(0).ToLocalTime().Date != dadosCandle.GetTimeUtc(1).ToLocalTime().Date)
				{
					double gapDoDia = dadosCandle.GetOpen(0) - dadosCandle.GetClose(1);
					Notification.Print(dadosCandle.GetTimeUtc(0).ToLocalTime().ToString() + ": Mercado abriu em gap de " + gapDoDia);
				}
			}
        }
        
        /// <summary>
        /// This function will be called before removing
        /// </summary>
		public override void Complete()
		{
			
		} 
     }
}

				
			

Outros Snippets

Esta seção visa apresentar outros exemplos de trechos de códigos que não se enquadram nas categorias anteriores.

Você pode acessar os Snippets diretamente pelo menu lateral direito, ou fazendo CRL+F (CTRL+L) para localizar algum texto específico na página, uma vez que o conteúdo tende a crescer ao longo do tempo, dificultando a navegação pelo menu.

Caso tenham sugestões de código para acrescentar à lista, gentileza deixar o código nos comentários com o link para seu perfil em rede social (para devido crédito de autoria).

Snippets

Como escrever log com o horário de abertura da candle/barra para facilitar depuração (debug)?

Reproduzir vídeo

Gerar log de execução de uma estratégia é a melhor forma de rastrear possíveis problemas de lógica ou de execução. Segue abaixo um trecho que identifica no texto a ser escrito no log o dia/hora início da barra/candle.

				
					DateTime datahora = HistoryDataSeries.GetTimeUtc(0);
datahora = datahora.ToLocalTime();
Notification.Print("[" + datahora.ToString() + "] " + msg);
				
			

Como gerar Alertas durante a execução da sua estratégia?

Outra forma de sinalizar problemas ou situações que mereçam mais atenção é por meio de alertas. Na Trader Evolution, os alertas são apresentados em uma janela próprio e o usuário pode ver o histórico de alertas.

				
					Notification.Alert(msg);
				
			

Snippets para Localização Temporal

Esta seção visa apresentar trechos de códigos com funcionalidades relativas à localização temporal da estratégia. Por exemplo, identificar se a atual barra é a primeira barra do dia para verificar gap diário.

Você pode acessar os Snippets diretamente pelo menu lateral direito, ou fazendo CTRL+F (CTRL+L) para localizar algum texto específico na página, uma vez que o conteúdo tende a crescer ao longo do tempo, dificultando a navegação pelo menu.

Caso tenham sugestões de código para acrescentar à lista, gentileza deixar o código nos comentários com o link para seu perfil em rede social (para devido crédito de autoria).

Snippets

Identificação de primeira barra do dia

Algumas estratégias necessitam da identificação da primeira barra do dia (candle) para executar determinada ação ou calcular o gap em relação ao fechamento do dia anterior. Segue abaixo um trecho de código para identificar a primeira barra de um dia.

				
					public override void Update(TickStatus args)
{
	if (HistoryDataSeries.GetTimeUtc(0).ToLocalTime().Date != HistoryDataSeries.GetTimeUtc(1).ToLocalTime().Date)
	{
		DateTime datahora = HistoryDataSeries.GetTimeUtc(0);
    	datahora = datahora.ToLocalTime();
    	Notification.Print("[" + datahora.ToString() + "] - Está é a primeira barra do dia!");
	}			
}
				
			

Identificação de barra por data e hora específicos

Reproduzir vídeo

Este código localiza a barra (candle ou box) por uma data e hora desejados. Onde a hora é referente ao horário de abertura do candle desejado.

Observe que criamos uma variável contendo a data/hora “11:03:00 15/06/2023” para exemplificação de código, mas poderia ser substituído por outras variáveis. E para todos os ticks dessa barra será impressa uma notificação, pois não realizamos um filtro de eventos no método Update.

				
					public override void Update(TickStatus args)
{
	DateTime barra = new DateTime(2023, 6, 15, 11, 03, 0, DateTimeKind.Local);
	if (barra == HistoryDataSeries.GetTimeUtc(0).ToLocalTime())
	{
		DateTime datahora = HistoryDataSeries.GetTimeUtc(0);
    	datahora = datahora.ToLocalTime();
		Notification.Print("[" + datahora.ToString() + "] - Está é a barra desejada!");
	}
}
				
			

Identificação do primeiro tick de uma barra

Este código identifica o primeiro tick de uma barra. Esta tarefa é bem facilitada em EvoCode, tendo em vista a existência do TickStatus de nova barra (IsBar).

				
					public override void Update(TickStatus args)
{
	if (args == TickStatus.IsBar)
	{
		DateTime datahora = HistoryDataSeries.GetTimeUtc(0);
    	datahora = datahora.ToLocalTime();
		Notification.Print("[" + datahora.ToString() + "] - Este é o primeiro tick da barra!");					
	}
}
				
			

O que precisa saber antes de começar...

Reproduzir vídeo

Neste documento vamos apresentar aspectos importantes antes que você comece a criar seu robô ou outro tipo de estratégia (indicador, coloração, screening).

Se fossemos classificar as dúvidas apresentadas por pessoas nas redes sociais sobre automatização de estratégias, dividiríamos em 3 grupos: Dúvidas de lógica de programação, Dúvidas sobre funções do Editor de Estratégias e Dúvidas sobre como implementar o operacional desejado.

Para as dúvidas de lógica de programação não há muito segredo, basta fazer um curso introdutório no assunto. Clique aqui e assista à primeira aula do Curso Básico de Lógica de Programação da NeoTraderBot (disponível em uma playlist no Youtube). Trata-se de um curso bem objetivo e que tem a meta de em 5 vídeos curtos te explicar os principais conceitos sobre lógica de programação, sendo o último vídeo uma aula prática de Pascal que é a linguagem de programação mãe da NTSL. Caso ainda não saiba, a NTSL é a sigla para Nelogica Trading System Language, que é a linguagem adaptada do Pascal para uso no Profit Chart.

Para as dúvidas relacionadas às funções do Editor de Estratégias…eu acho bastante compreensível a existência delas. Acredito até que haja mais dúvidas que o esperado devido ao fato da documentação da Nelógica ser muito ruim, além de ser difícil achar boas referências pela Internet (principalmente gratuitas). Pensando nisso, estamos estruturando uma área neste site, aberta para qualquer visitante, explicando melhor as funções embutidas no editor de estratégias, com exemplos e comentários das dúvidas mais frequentes. Além disso, haverá uma seção de Templates (modelos para montar suas estratégias) e Snipets (trechos de código fontes prontos para você utilizar como exemplo e acelerar o seu desenvolvimento).

Chegamos então a parte principal deste texto e que se relaciona com as dúvidas referentes à implementação de setups operacionais.

Algumas dessas dúvidas sobre implementação de operacionais podem recair sobre limitações já conhecidas do Profit. Assista este vídeo que é bem interessante e trata sobre as Limitações do Profit referentes à automatização de estratégias. No decorrer deste texto abordaremos tópicos diferentes, porém complementares.

Ok…Se tirarmos aquilo que o Profit não permite fazer, e que esperamos que sejam disponibilizadas melhorias para sanar, teremos as dúvidas que derivam do fato de as pessoas não entenderem como funciona o processamento das estratégias no Profit. Se os traders que estão buscando automatizar as estratégias entendessem sobre isso, talvez mais da metade dos problemas já seriam resolvidos.

Então vamos abordar a seguir dois pontos muito importantes que você deve saber antes de implementar estratégias no Profit Chart, incluindo robôs: Modelo de dados utilizado pelo Profit e Processamento das Estratégias.

Modelo de dados OHLCV

O modelo de dados utilizado pelo Profit é o OHLCV. Este é o modelo usado por quase 100% das plataformas de backtesting e a sigla OHLCV significa Open, High, Low, Close e Volume.

Trata-se dos dados de preço e volume disponibilizados para realização de backtesting. Quanto maior for a frequência demandada de dados, por exemplo, dados de 1 minuto, maior é o espaço demandado para armazenamento dessas informações.

Se fossemos salvar em nosso computador os dados de cada tick, ou seja, para cada alteração mínima de preço do ativo que estamos negociando, precisaríamos de muito espaço e banda de internet para requisitar os dados. Então torna-se impraticável disponibilizar por padrão dados tick a tick…É claro que isto poderia ser fornecido sob demanda, para não sobrecarregar sua plataforma e os servidores da Nelógica (se houvesse funcionalidade para tal no Profit!).

Então quando realizamos backtesting de uma estratégia, nós não temos os dados tick a tick, temos apenas dados por candle fechado, os já mencionados OHLCV. 

Grandes empresas do mercado financeiro operam algoritmos em alta frequencia, em inglês, High Frequency Trading. Mas eles tem muito dinheiro, os melhores recursos de TI e mentes brilhantes (vários PHDs) para programar e monitorar os algoritmos. Além disso, eles colocam os melhores servidores possíveis de se adquirir, que executam seus algoritmos dentro da B3, fisicamente ao lado dos servidores da B3, a poucos metros de cabo de distância, para reduzir ao máximo a latência, que é o tempo entre envio e a execução da ordem.

Para se ter uma ideia…se quando enviamos uma ordem para nossa corretora, o processo demora 100 milisegundos para a execução, a ordem dessas empresas leva 1 milisegundo para ser executada. Esses não são os valores exatos, é só para ilustrar que a diferença entre a sua latência e deles é muito significativa!

E se isso foi técnico demais, visualize essa cena…você está em uma pista de fórmula 1, dentro de um fusca e vai apostar uma corrida contra um trader de um grande fundo que opera HFT, só que ele está pilotando um Bugatti Veyron…

Acho melhor não compertirmos com esses caras….Nossa chance de sucesso é quase nula!

E por quê estamos  tanto tempo falando sobre isso? Para concluirmos que tentar implementar estratégias SCALP, que dependam de dados tick a tick, não é viável para nós pobres mortais. Nós até conseguimos rodar uma estratégia em tempo real utilizando dados tick a tick, mas não conseguimos fazer backtesting tick a tick, porque não temos os dados, e mesmo se tivéssemos precisaríamos ter um supercomputador para armazenar os dados e processar esse enorme volume de informação. E se não temos como fazer um backtesting adequado, colocar um robô para executar é como jogar na sorte…Não é o que queremos! Queremos rodar um robô que em backtesting tenha um histórico de desempenho favorável para nos dar confiabilidade para rodá-lo em conta real.

O dado OHLCV de maior frequência que conseguimos ter acesso no Profit Chart são dados de 1 minuto, e mesmo assim, atualmente, só conseguimos acessar os 3 últimos meses históricos. Este volume de dados é insuficiente para otimizar e realizar backtesting com confiabilidade adequada. Ou seja, se quiséssemos implementar uma estratégia para gráficos de 1 minuto, encontraríamos também bastante dificuldade.

Então uma dica importante é que as estratégias automatizadas começam a ser uma realidade factível com dados de 5 minutos em diante. A partir dessa frequência gráfica, você começa a ter mais chance de sucesso.

Processamento de Estratégias

Se entendermos bem o que está exposto abaixo, teremos a capacidade de resolver muito mais rapidamente eventuais problemas na hora de implementar nossas estratégias, ou talvez, até não tenhamos tantos problemas assim.

Toda estratégia no Profit Chart é processada sequencialmente, linha a linha, começando pelo begin do seu código fonte até o end.

Para cada novo dado, que em backtesting é sempre um novo candle ou renko fechado, a estratégia é processada novamente. Então se você tivermos, por exemplo, uma janela histórica de dados com 2000 elementos, a estratégia será processada 2000 vezes. Ou seja, uma vez para cada elemento de dado OHLCV, começando pelo mais antigo até o mais recente.

O pulo do gato está nas variáveis globais e a forma como elas são tratadas ao longo dos processamentos.

Por mais que declaremos variáveis globais com tipos básicos como integer ou float, no final das contas, as variáveis globais podem ser tratadas como arrays, ou no vocabulário da Nelogica, como séries. O que isto significa? Vamos a um exemplo.

Suponha que eu tenhamos uma variável global do tipo integer chamada iNum que é inicializada com o valor 1. E o código fonte da estratégia será apenas a atribuição iNum = iNum + 1. No primeiro processamento, antes de executar a linha de atribuição de iNum, iNum tem o valor 1, depois que executar a atribuição,  iNum terá o valor igual a 2., Na próxima execução, iNum começa como 2, mas depois de rodar a linha de atribuição iNum será igual a 3.

Perceba uma coisa interessante, os valores das variáveis globais são mantidos de um processamento para o próximo processamento. E, além disso, outro ponto importante é que cada execução do seu código empilha os valores das variáveis globais. 

Apesar de termos declarado iNum como um integer, esta variável pode ser acessada como se fosse um array. Se fizéssemos a referência de iNum[1], estaríamos acessando o valor de iNum da última execução (no caso, 6). Se nos referíssemos a iNum[2] estaríamos acessando o valor de iNum 2 barras antes do momento atual (no caso, 5), e assim por diante.

Compreender o empilhamento das variáveis globais é muito importante, pois fará diferença na hora de você implementar a sua estratégia/robô.

Um ponto importante a salientar é que, infelizmente, não temos como inicializar as variáveis globais antes de executar o robô ou da estratégia. É uma limitação da plataforma, mas nesse caso ainda tem como dar um jeitinho. Os templates disponibilizados aqui no site da NeoTraderBot já contemplam uma forma de inicializar as variáveis globais.

Seguindo….Como verificamos o impacto de executar o código da estratégia em backtesting apenas quando uma barra é encerrada? Se tivermos uma estratégia aplicada no backtesting a gráficos de 5 minutos, essa estratégia só vai atuar depois que fechar 5 minutos. Se a estratégia disparar uma ordem de compra ou venda a mercado, ela será executada apenas no preço de abertura da próxima barra de dados. Isso ocorre para manter premissas mais coerentes de simulação, uma vez que como não há informação sobre a dinâmica de movimento do preço dentro de uma barra fechada, o preço à mercado só pode ria ser o preço de abertura da próxima barra.

Veja o exemplo abaixo de um robô baseado em um setup de cruzamento de 3 médias, a ordem de compra/venda é realizada no candle no qual há o cruzamento da média, mas a execução sempre ocorre no preço de abertura da próxima barra.

É muito importante entender este aspecto do backtesting porque quando se roda um robô ou estratégia em tempo real, o novo dado OHLCV não é necessariamente de uma barra fechada. Para cada tick, antes de encerrar a barra de 5 minutos, o código da sua estratégia é processado. Então, se não forem tomados os devidos cuidados na programação, o comportamento em tempo real do robô será diferente do comportamento em backtesting…porque no backtesting não havia os dados tick a tick….e isso pode fazer uma grande diferença de desempenho….para melhor ou pior…não tem como saber.

Enquanto o Profit apenas permitia visualizar a estratégia de execução nos gráficos isso era um problema pequeno, porque não efetivava nenhuma ordem automaticamente…mas a partir do momento que os robôs puderem ser executados em conta real, e isto poderá ocorrer agora dia 29/setembro com o lançamento oficial do módulo de Automação de Estratégias, precisaremos ser ainda mais criterioso na escrita do código fonte das estratégias. Se quisermos manter o mesmo comportamento entre backtesting e conta real (e o ideal é isso mesmo), precisaremos garantir que as ações geradas pelo robô sejam feitas apenas no fechamento de uma barra.

É importante observar que na execução de uma estratégia em tempo real, a referência a uma variável global, mesmo que implícita (série de dados de preço do ativo), tal como High ou Máxima, um período antes será sempre o valor da variável global da barra fechada anterior (ex: HIgh[1] é sempre o preço máximo da barra fechada anterior e não o valor no tick anterior!). O valor atual da variável global não será empilhado, pois a barra está aberta, ele será apenas atualizado para cada processamento do código da estratégia, ocorrendo o empilhamento apenas quando a barra atual fechar.

Bônus: Dicas de Backtesting

Por fim, um ponto muito importante para realização adequada de backtesting de uma estratégia é SER CONSERVADOR!

É muito fácil fazer backtesting de estratégias com um desempenho tão incrível que nos faria milionários em pouco tempo de execução na conta real. Sempre desconfie desses bons resultados! Geralmente é sinal de que há algum problema no código fonte da estratégia. Ainda que não tenha gerado erro de compilação, pode ter gerado uma situação não factível no mundo real.

Uma situação muito frequente, seja por desconhecimento ou inexperiência, é programar as estratégias de execução (robôs) com ordens OCO, ou seja, com ordens de stoploss e take profit, enviando primeiramente a ordem de take profit.

Isto não é uma boa prática porque como no backtesting lidamos apenas com dados de barra fechada, o simulador não tem como saber dentro de uma barra OHLCV que engloba tanto o preço do stop quanto do take profit, qual preço foi atingido primeiro.

O simulador então utilizará a ordem que foi enviada primeiro. Assim, é uma boa prática sempre colocar o envio de ordens de stoploss antes das ordens de take profit. Fazendo isso, estaremos sendo conservadores. O desempenho da estratégia pode até ser pior do que seria se houvesse dados de tempo real, mas estremos gerenciando melhor nossa expectativa em relação ao desempenho provável em conta real.

Outra boa prática de backtesting é analisar a sensibilidade do robô a condições de Slippage.

Slippage é o escorregamento de preço de ordens enviadas para corretora. O que significa isso? É a diferença entre o preço da ordem enviada e o preço de execução. Por exemplo, se enviamos uma ordem de compra a mercado quando determinado ativo é  negociado a R$ 23,50, mas a ordem acaba sendo executada a R$ 23,53, tivemos um slippage de 3 centavos.

Felizmente, no Profit Chart é possível simular o desempenho de um robô com slippage de forma bem simples, bastando informar a quantidade de ticks. O slippage será aplicado para cada ordem a mercado enviada. Veja na figura abaixo onde configurar o slippage no backtesting.

Finalizando...

Se achou interessante o conteúdo deste documento e acha que existem outros pontos a serem conhecidos antes que um trader implemente sua primeira estratégia automatizada, deixe seu comentário abaixo!

Nos próximos documentos passaremos enfim para a parte prática: escrever as estratégias em código fonte!

Snippets para Ordens e Administração de Trade

Esta seção visa apresentar trechos de códigos com exemplos de envio de ordens e administração de trade utilizando técnicas de stoploss (fixo, móvel, breakeven) e take profit.

Você pode acessar os Snippets diretamente pelo menu lateral direito, ou fazendo CRL+F (CTRL+L) para localizar algum texto específico na página, uma vez que o conteúdo tende a crescer ao longo do tempo, dificultando a navegação pelo menu.

Caso tenham sugestões de código para acrescentar à lista, gentileza deixar o código nos comentários com o link para seu perfil em rede social (para devido crédito de autoria).

Snippets

Como rotear ordens de maneira fácil (Modo gerenciado)?

Reproduzir vídeo

A NinjaTrader possui em seu NinjaScript uma camada de abstração para envio e gestão de ordens. Este modo é chamado de modo gerenciado e seu funcionamento torna bem simples a implementação de estratégias para iniciantes e até mesmo pessoas com conhecimento intermediário.

No modo gerenciado, as ordens são válidas apenas até o próximo candle/barra, o que simplifica a gestão de ordens abertas e cancelamentos. E também há diversos controles que reduzem a chance de problemas na administração da posição da estratégia.

Veja abaixo um exemplo do envio de ordens em NinjaScript utilizando o modo gerenciado.

				
					#region Using declarations
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Xml.Serialization;
using NinjaTrader.Cbi;
using NinjaTrader.Gui;
using NinjaTrader.Gui.Chart;
using NinjaTrader.Gui.SuperDom;
using NinjaTrader.Gui.Tools;
using NinjaTrader.Data;
using NinjaTrader.NinjaScript;
using NinjaTrader.Core.FloatingPoint;
using NinjaTrader.NinjaScript.Indicators;
using NinjaTrader.NinjaScript.DrawingTools;
#endregion

//This namespace holds Strategies in this folder and is required. Do not change it. 
namespace NinjaTrader.NinjaScript.Strategies
{
	public class TestingOrdersStrategy : Strategy
	{
		private TimeSpan tsOpen;
		private TimeSpan tsClose;
		private Order myOrder;
		
		
		protected override void OnStateChange()
		{
			if (State == State.SetDefaults)
			{
				Description									= @"Enter the description for your new custom Strategy here.";
				Name										= "TestingOrdersStrategy";
				Calculate									= Calculate.OnBarClose;
				EntriesPerDirection							= 1;
				EntryHandling								= EntryHandling.AllEntries;
				IsExitOnSessionCloseStrategy				= true;
				ExitOnSessionCloseSeconds					= 30;
				IsFillLimitOnTouch							= false;
				MaximumBarsLookBack							= MaximumBarsLookBack.TwoHundredFiftySix;
				OrderFillResolution							= OrderFillResolution.Standard;
				Slippage									= 0;
				StartBehavior								= StartBehavior.WaitUntilFlat;
				TimeInForce									= TimeInForce.Gtc;
				TraceOrders									= false;
				RealtimeErrorHandling						= RealtimeErrorHandling.StopCancelClose;
				StopTargetHandling							= StopTargetHandling.PerEntryExecution;
				BarsRequiredToTrade							= 20;
				// Disable this property for performance gains in Strategy Analyzer optimizations
				// See the Help Guide for additional information
				IsInstantiatedOnEachOptimizationIteration	= true;
				PositionOpeningTime				= DateTime.Parse("10:30", System.Globalization.CultureInfo.InvariantCulture);
				PositionClosingTime				= DateTime.Parse("10:36", System.Globalization.CultureInfo.InvariantCulture);
			}
			else if (State == State.Configure)
			{
				tsOpen = new TimeSpan(PositionOpeningTime.Hour, PositionOpeningTime.Minute, 0);
				tsClose = new TimeSpan(PositionClosingTime.Hour, PositionClosingTime.Minute, 0);				
			}
		}

		protected override void OnBarUpdate()
		{
			//Match real-time order object based on a historical order object (run just once)
			if (myOrder != null && myOrder.IsBacktestOrder && State == State.Realtime)
      			myOrder = GetRealtimeOrder(myOrder);			
			
			//Open position at specified time (tsOpen)
			if ((Time[0].TimeOfDay == tsOpen) && (Position.MarketPosition == MarketPosition.Flat))
            {
				myOrder = EnterLong("openingSignal");
				//myOrder = EnterLongLimit(4451.25, "openingSignal");
				//myOrder = EnterLongStopMarket(4454.50, "openingSignal");
				
				
				//This will not open position, since the price reach that price a few bars after the order was submitted (Managed orders)
				//myOrder = EnterLongLimit(4450, "openingSignal");
				
				//This will not open position, since the price reach that price only 2 bars after the order was submitted (Managed orders)
				//myOrder = EnterLongStopMarket(4455, "openingSignal");
			}
			
			//Close position at specified time (tsClose)
			if (Time[0].TimeOfDay == tsClose)
            {
				if (Position.MarketPosition == MarketPosition.Long) { ExitLong("openingSignal"); }
				if (Position.MarketPosition == MarketPosition.Short) { ExitShort("openingSignal"); }
			}			
			
				
		}

		#region Properties
		[NinjaScriptProperty]
		[PropertyEditor("NinjaTrader.Gui.Tools.TimeEditorKey")]
		[Display(Name="OpeningTIime", Order=1, GroupName="Parameters")]
		public DateTime PositionOpeningTime
		{ get; set; }

		[NinjaScriptProperty]
		[PropertyEditor("NinjaTrader.Gui.Tools.TimeEditorKey")]
		[Display(Name="ClosingTime", Order=2, GroupName="Parameters")]
		public DateTime PositionClosingTime
		{ get; set; }
		#endregion

	}
}

				
			

Como fazer Gestão de Risco das operações de maneira simples (Stoploss/TakeProfit)?

Reproduzir vídeo

No âmbito da camada de abstração do NinjaScript, existem algumas funções que facilitam bastante a adoção de práticas de gestão de risco para operações no código fonte. 

Veja abaixo duas formas de definir o stoploss e alvo (take profit) das operações de maneira estática, ou seja, fixa durante toda a execução da estratégia, ou de maneira dinâmica, ajustando o risco de acordo com as condições do mercado.

Gestão de risco estática

Nesta situação, os parâmetros para o stoploss e alvo das operações são definidos na transição para o estado Configure da estratégia, podendo inclusive, serem utilizados parâmetros de entrada para fins de otimização futura.

				
					#region Using declarations
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Xml.Serialization;
using NinjaTrader.Cbi;
using NinjaTrader.Gui;
using NinjaTrader.Gui.Chart;
using NinjaTrader.Gui.SuperDom;
using NinjaTrader.Gui.Tools;
using NinjaTrader.Data;
using NinjaTrader.NinjaScript;
using NinjaTrader.Core.FloatingPoint;
using NinjaTrader.NinjaScript.Indicators;
using NinjaTrader.NinjaScript.DrawingTools;
#endregion

//This namespace holds Strategies in this folder and is required. Do not change it.
namespace NinjaTrader.NinjaScript.Strategies
{
	public class TestingOpRiskManagement : Strategy
	{
		private TimeSpan tsOpen;
		private TimeSpan tsClose;
		private Order myOrder;


		protected override void OnStateChange()
		{
			if (State == State.SetDefaults)
			{
				Description									= @"Enter the description for your new custom Strategy here.";
				Name										= "TestingOpRiskManagement";
				Calculate									= Calculate.OnBarClose;
				EntriesPerDirection							= 1;
				EntryHandling								= EntryHandling.AllEntries;
				IsExitOnSessionCloseStrategy				= true;
				ExitOnSessionCloseSeconds					= 30;
				IsFillLimitOnTouch							= false;
				MaximumBarsLookBack							= MaximumBarsLookBack.TwoHundredFiftySix;
				OrderFillResolution							= OrderFillResolution.Standard;
				Slippage									= 0;
				StartBehavior								= StartBehavior.WaitUntilFlat;
				TimeInForce									= TimeInForce.Gtc;
				TraceOrders									= false;
				RealtimeErrorHandling						= RealtimeErrorHandling.StopCancelClose;
				StopTargetHandling							= StopTargetHandling.PerEntryExecution;
				BarsRequiredToTrade							= 20;
				// Disable this property for performance gains in Strategy Analyzer optimizations
				// See the Help Guide for additional information
				IsInstantiatedOnEachOptimizationIteration	= true;
				PositionOpeningTime				= DateTime.Parse("10:30", System.Globalization.CultureInfo.InvariantCulture);
				PositionClosingTime				= DateTime.Parse("16:00", System.Globalization.CultureInfo.InvariantCulture);
			}
			else if (State == State.Configure)
			{
				tsOpen = new TimeSpan(PositionOpeningTime.Hour, PositionOpeningTime.Minute, 0);
				tsClose = new TimeSpan(PositionClosingTime.Hour, PositionClosingTime.Minute, 0);
				
				// Static risk management. Stoploss and Target are defined and maintained fixed through the strategy lifetime
				SetStopLoss(CalculationMode.Ticks, 20);
				//SetTrailStop(CalculationMode.Ticks, 24);
				SetProfitTarget(CalculationMode.Ticks, 60);
			}
		}

		protected override void OnBarUpdate()
		{
			if (myOrder != null && myOrder.IsBacktestOrder && State == State.Realtime)
      			myOrder = GetRealtimeOrder(myOrder);

			//Open position at specified time (tsOpen)
			if ((Time[0].TimeOfDay == tsOpen) && (Position.MarketPosition == MarketPosition.Flat))
            {
				Random rnd = new Random();

				if (rnd.Next(0,2) == 0)
					myOrder = EnterLong("openingSignal");
				else
					myOrder = EnterShort("openingSignal");
			}

			//Close position at specified time (tsClose)
			if (Time[0].TimeOfDay == tsClose)
            {
				if (Position.MarketPosition == MarketPosition.Long) { ExitLong("openingSignal"); }
				if (Position.MarketPosition == MarketPosition.Short) { ExitShort("openingSignal"); }
			}


		}

		#region Properties
		[NinjaScriptProperty]
		[PropertyEditor("NinjaTrader.Gui.Tools.TimeEditorKey")]
		[Display(Name="OpeningTIime", Order=1, GroupName="Parameters")]
		public DateTime PositionOpeningTime
		{ get; set; }

		[NinjaScriptProperty]
		[PropertyEditor("NinjaTrader.Gui.Tools.TimeEditorKey")]
		[Display(Name="ClosingTime", Order=2, GroupName="Parameters")]
		public DateTime PositionClosingTime
		{ get; set; }
		#endregion

	}
}
				
			

Gestão de risco dinâmica

Nesta situação, os parâmetros para o stoploss e alvo das operações são definidos no método onBarUpdate e a frequencia de atualização dependerá da propriedade da estratégia relacionada a frequência de cálculo. Neste modo, o trader pode utilizar qualquer lógica que desejar, podendo inclusive utilizar indicadores técnicos, a exemplo do ATR (Average True Range).

				
					#region Using declarations
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Xml.Serialization;
using NinjaTrader.Cbi;
using NinjaTrader.Gui;
using NinjaTrader.Gui.Chart;
using NinjaTrader.Gui.SuperDom;
using NinjaTrader.Gui.Tools;
using NinjaTrader.Data;
using NinjaTrader.NinjaScript;
using NinjaTrader.Core.FloatingPoint;
using NinjaTrader.NinjaScript.Indicators;
using NinjaTrader.NinjaScript.DrawingTools;
#endregion

//This namespace holds Strategies in this folder and is required. Do not change it.
namespace NinjaTrader.NinjaScript.Strategies
{
	public class TestingOpRiskManagement : Strategy
	{
		private TimeSpan tsOpen;
		private TimeSpan tsClose;
		private Order myOrder;


		protected override void OnStateChange()
		{
			if (State == State.SetDefaults)
			{
				Description									= @"Enter the description for your new custom Strategy here.";
				Name										= "TestingOpRiskManagement";
				Calculate									= Calculate.OnBarClose;
				EntriesPerDirection							= 1;
				EntryHandling								= EntryHandling.AllEntries;
				IsExitOnSessionCloseStrategy				= true;
				ExitOnSessionCloseSeconds					= 30;
				IsFillLimitOnTouch							= false;
				MaximumBarsLookBack							= MaximumBarsLookBack.TwoHundredFiftySix;
				OrderFillResolution							= OrderFillResolution.Standard;
				Slippage									= 0;
				StartBehavior								= StartBehavior.WaitUntilFlat;
				TimeInForce									= TimeInForce.Gtc;
				TraceOrders									= false;
				RealtimeErrorHandling						= RealtimeErrorHandling.StopCancelClose;
				StopTargetHandling							= StopTargetHandling.PerEntryExecution;
				BarsRequiredToTrade							= 20;
				// Disable this property for performance gains in Strategy Analyzer optimizations
				// See the Help Guide for additional information
				IsInstantiatedOnEachOptimizationIteration	= true;
				PositionOpeningTime				= DateTime.Parse("10:30", System.Globalization.CultureInfo.InvariantCulture);
				PositionClosingTime				= DateTime.Parse("16:00", System.Globalization.CultureInfo.InvariantCulture);
			}
			else if (State == State.Configure)
			{
				tsOpen = new TimeSpan(PositionOpeningTime.Hour, PositionOpeningTime.Minute, 0);
				tsClose = new TimeSpan(PositionClosingTime.Hour, PositionClosingTime.Minute, 0);
				
				// Static risk management. Stoploss and Target are defined and maintained fixed through the strategy lifetime
				//SetStopLoss(CalculationMode.Ticks, 20);
				//SetTrailStop(CalculationMode.Ticks, 24);
				//SetProfitTarget(CalculationMode.Ticks, 60);
			}
		}

		protected override void OnBarUpdate()
		{
			if (myOrder != null && myOrder.IsBacktestOrder && State == State.Realtime)
      			myOrder = GetRealtimeOrder(myOrder);

			//Open position at specified time (tsOpen)
			if ((Time[0].TimeOfDay == tsOpen) && (Position.MarketPosition == MarketPosition.Flat))
            {
				Random rnd = new Random();
				double volatility = Math.Ceiling(ATR(500)[0]/TickSize);
				double stoplossTicks = 5*volatility;
				double takeProfitTicks = 3*stoplossTicks;
				
				
				// Dynamic risk management. Stoploss and Target are adapted to market conditions
				SetTrailStop(CalculationMode.Ticks, stoplossTicks);
				SetProfitTarget(CalculationMode.Ticks, takeProfitTicks);
				Print("CurrentBar: " + CurrentBar.ToString() + " - Stoploss: " + stoplossTicks.ToString() + " ticks | Target: " 
				                     + takeProfitTicks.ToString() + " ticks");
				
					
				if (rnd.Next(0,2) == 0)
					myOrder = EnterLong("openingSignal");
				else
					myOrder = EnterShort("openingSignal");
			}

			//Close position at specified time (tsClose)
			if (Time[0].TimeOfDay == tsClose)
            {
				if (Position.MarketPosition == MarketPosition.Long) { ExitLong("openingSignal"); }
				if (Position.MarketPosition == MarketPosition.Short) { ExitShort("openingSignal"); }
			}


		}

		#region Properties
		[NinjaScriptProperty]
		[PropertyEditor("NinjaTrader.Gui.Tools.TimeEditorKey")]
		[Display(Name="OpeningTIime", Order=1, GroupName="Parameters")]
		public DateTime PositionOpeningTime
		{ get; set; }

		[NinjaScriptProperty]
		[PropertyEditor("NinjaTrader.Gui.Tools.TimeEditorKey")]
		[Display(Name="ClosingTime", Order=2, GroupName="Parameters")]
		public DateTime PositionClosingTime
		{ get; set; }
		#endregion

	}
}
				
			

Templates de Estratégias (Modelos pré-configurados)

Introdução

Os Templates de Estratégias da NeoTraderBot servem para padronizar e organizar a estrutura inicial dos códigos fontes das estratégias que iremos implementar.

Ao invés de abrir o Editor de Estratégias vazio e começar tudo de novo….podemos otimizar nosso tempo com as experiências acumuladas na Comunidade e reutilizar padrões que já contemplam algumas das melhores práticas de desenvolvimento de estratégias e robôs.

Todos os modelos estão salvos no repositório GitHub da NeoTraderBot e, para facilitar ainda mais a nossa vida, eles também estão copiados abaixo em suas últimas versões. Assim, ao invés de você ter que importar os modelos em arquivo .psf, você pode simplesmente copiar o modelo desejado e colar no seu Editor!

Comente as partes que não for utilizar em um primeiro momento pois elas podem vir a ser usadas a medida que o seu código-fonte evolui.

Utilize o menu direito dessa página para ir direto ao Template desejado.

Modelo de Estratégia de Execução (Robôs)

				
					// #######################################################################
// #######################################################################
// #######################################################################
// ######                            O                             #######
// ######                        ____|____                         #######
// ######                      _|         |_                       #######
// ######                     (_|  O   O  |_)                      #######
// ######                       |_________|                        #######
// ######                                                          #######
// ###### ____        __        ____________           ________    #######
// ###### | | \       | |       | |_________|         /  ____  \   #######
// ###### | |\ \      | |       | |                  /  /    \  \  #######
// ###### | | \ \     | |       | |____             |  |      |  | #######
// ###### | |  \ \    | |       | |____|            |  |      |  | #######
// ###### | |   \ \   | |       | |____|            |  |      |  | #######
// ###### | |    \ \  | |       | |                 |  |      |  | #######
// ###### | |     \ \ | |       | |_________         \  \____/  /  #######
// ###### |_|      \_\|_|       |_|_________|         \________/   #######
// ######                                                          #######
// ###### _______  __          __   ____  __   ___    __  _______  #######
// ######    |    |  \   /\   |  \ |     |  \ |   \  /  \    |     #######
// ######    |    |__/  /__\  |   ||__   |__/ |___/ |    |   |     #######
// ######    |    |\   /    \ |   ||     |\   |   \ |    |   |     #######
// ######    |    | \ /      \|__/ |____ | \  |___/  \__/    |     #######
// ######                                                          #######
// ######  Comunidade aberta de automatização de estratégias para  #######
// ######                    negociação de ativos                  #######
// ######                                                          #######
// ######                    www.NeoTraderBot.com                  #######
// #######################################################################
// #######################################################################
// #######################################################################
//
// -----------------------------------------------------------------------
// ---------------------- DADOS DA ESTRATÉGIA ----------------------------
// -----------------------------------------------------------------------
//
// NOME DA ESTRATÉGIA: 
//   DESENVOLVIDA POR: 
//    DATA DE CRIAÇÃO: 
//             VERSÃO: 
//      ATUALIZADA EM: 
// TIPO DE ESTRATÉGIA: ( ) Indicador  ( ) Coloração (X) Execução
//                     ( ) Screening  ( ) Texto     ( ) Alarme
//
// DESCRIÇÃO DA ESTRATÉGIA:
//
//
//
// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
//
// ######################### FIM DO CABEÇALHO ############################
//
//
// -----------------------------------------------------------------------
// -------------------------- Constantes ---------------------------------
// OBS: 
// -----------------------------------------------------------------------
const
  cPlotarIndicadores = true;  
  //
  // ---------------------------------------------------------------------
  // -------------------------- Parâmetros -------------------------------
  // OBS: Segue abaixo a descrição de cada parâmetro
  // 1) pXXXXXX -> 
  // 
  // 2) pYYYYYY -> 
  // 
  // 3) pZZZZZZ -> 
  // ---------------------------------------------------------------------
input
  pXXXXX(5);
  pYYYYY(True);
  pZZZZZ(2.3);

  // ---------------------------------------------------------------------
  // ---------------------- Variáveis globais ----------------------------
  // OBS:
  // ---------------------------------------------------------------------
var
//Estrutura padrão do modelo
bStarted: boolean;
bSinalCompra, bSinalVenda, bSinalLiquida, bSinalReversao : boolean;
bComprado, bVendido : boolean;

//Variáveis personalizadas
iXXXXX, iZZZZZZ: integer;
fXXXXX, fZZZZZZ: float;



begin

  // ---------------------------------------------------------------------
  // ----------------- Inicialização da estratégia -----------------------
  // OBS: Inicialização de variáveis a serem utilizadas na estratégia de 
  // execução
  // ---------------------------------------------------------------------
  if Not bStarted then
  begin
    bStarted := True;
    //Colocar aqui ações que serão executadas apenas no primeiro processamento
    //da estratégia. Por exemplo, inicialização de variáveis.
  end;

  // ---------------------------------------------------------------------
  // ------------ Atribuição de variáveis por processamento --------------
  // ---------------------------------------------------------------------
  //Estrutura padrão do modelo
  bSinalCompra := False;
  bSinalVenda := False;
  bSinalLiquida := False;
  bSinalReversao := False;
  bComprado := isBought();
  bVendido := isSold();

  // Atribuições das variáveis da estratégia




  // ---------------------------------------------------------------------
  // ----------------------- Cálculo dos sinais  -------------------------
  // OBS: Inserir lógica de cálculo dos sinais de compra/venda/liquidação
  // e reversão, se for o caso.
  // ---------------------------------------------------------------------
  if (...) then
      bSinalCompra := True;

  if (...) then
      bSinalVenda := True;

  if bComprado then
    if (...) then
      bSinalLiquida := True;

  if bVendido then
    if (...) then
      bSinalLiquida := True;

  if bComprado or bVendido then
      bSinalReversao := True;                  


  // ---------------------------------------------------------------------
  // -------------- Administração das posições abertas -------------------
  // OBS: Baseando-se na posição aberta, pode-se implementar lógicas para 
  // atualização de alvo ou stoploss
  // ---------------------------------------------------------------------    
  if bComprado then
  begin

  end;

  if bVendido then
  begin

  end;

  // ---------------------------------------------------------------------
  // ------------------- Envia ordens de compra/venda --------------------
  // OBS: Baseando-se nos sinais e na atual posição, cria as ordens de 
  // compra e venda de acordo com o setup desejado
  // --------------------------------------------------------------------- 

  




  // ---------------------------------------------------------------------
  // ------------------------ Plot de Indicadores ------------------------
  // OBS: É sempre interessante incluir indicadores usados pelo robô para
  // poder visualizar no gráfico do Módulo de Automação de Estratégias 
  // --------------------------------------------------------------------- 
  if cPlotarIndicadores then
  begin
    Plot(...);
    Plot2(...);
    Plot3(...);

  end;

end;









				
			

Modelo de Estratégia de Coloração

				
					// #######################################################################
// #######################################################################
// #######################################################################
// ######                            O                             #######
// ######                        ____|____                         #######
// ######                      _|         |_                       #######
// ######                     (_|  O   O  |_)                      #######
// ######                       |_________|                        #######
// ######                                                          #######
// ###### ____        __        ____________           ________    #######
// ###### | | \       | |       | |_________|         /  ____  \   #######
// ###### | |\ \      | |       | |                  /  /    \  \  #######
// ###### | | \ \     | |       | |____             |  |      |  | #######
// ###### | |  \ \    | |       | |____|            |  |      |  | #######
// ###### | |   \ \   | |       | |____|            |  |      |  | #######
// ###### | |    \ \  | |       | |                 |  |      |  | #######
// ###### | |     \ \ | |       | |_________         \  \____/  /  #######
// ###### |_|      \_\|_|       |_|_________|         \________/   #######
// ######                                                          #######
// ###### _______  __          __   ____  __   ___    __  _______  #######
// ######    |    |  \   /\   |  \ |     |  \ |   \  /  \    |     #######
// ######    |    |__/  /__\  |   ||__   |__/ |___/ |    |   |     #######
// ######    |    |\   /    \ |   ||     |\   |   \ |    |   |     #######
// ######    |    | \ /      \|__/ |____ | \  |___/  \__/    |     #######
// ######                                                          #######
// ######  Comunidade aberta de automatização de estratégias para  #######
// ######                    negociação de ativos                  #######
// ######                                                          #######
// ######                    www.NeoTraderBot.com                  #######
// #######################################################################
// #######################################################################
// #######################################################################
//
// -----------------------------------------------------------------------
// ---------------------- DADOS DA ESTRATÉGIA ----------------------------
// -----------------------------------------------------------------------
//
// NOME DA ESTRATÉGIA: 
//   DESENVOLVIDA POR: 
//    DATA DE CRIAÇÃO: 
//             VERSÃO: 
//      ATUALIZADA EM: 
// TIPO DE ESTRATÉGIA: ( ) Indicador  (X) Coloração ( ) Execução
//                     ( ) Screening  ( ) Texto     ( ) Alarme
//
// DESCRIÇÃO DA ESTRATÉGIA:
//     
// 
// 
// 
// 
// 
//
// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
//
// ######################### FIM DO CABEÇALHO ############################
//
//
// -----------------------------------------------------------------------
// -------------------------- Constantes ---------------------------------
// OBS: 
// -----------------------------------------------------------------------
const
  cXXXXXX = true;  
  //
  // ---------------------------------------------------------------------
  // -------------------------- Parâmetros -------------------------------
  // OBS: Segue abaixo a descrição de cada parâmetro
  // 1) pXXXXXX -> 
  // 
  // 2) pYYYYYY -> 
  // 
  // 3) pZZZZZZ -> 
  // ---------------------------------------------------------------------
input
  pXXXXX(5);
  pYYYYY(True);
  pZZZZZ(2.3);

  // ---------------------------------------------------------------------
  // ---------------------- Variáveis globais ----------------------------
  // OBS:
  // ---------------------------------------------------------------------
var
//Estrutura padrão do modelo
bStarted: boolean;


//Variáveis personalizadas
iXXXXX, iZZZZZZ: integer;
fXXXXX, fZZZZZZ: float;


begin
  // ---------------------------------------------------------------------
  // ----------------- Inicialização da estratégia -----------------------
  // OBS: Inicialização de variáveis a serem utilizadas na estratégia de 
  // coloração
  // ---------------------------------------------------------------------
  if Not bStarted then
  begin
    bStarted := True;
    //Colocar aqui ações que serão executadas apenas no primeiro processamento
    //da estratégia. Por exemplo, inicialização de variáveis.
  end;


  // ---------------------------------------------------------------------
  // ------------ Atribuição de variáveis por processamento --------------
  // ---------------------------------------------------------------------
  // Atribuições das variáveis da estratégia



  // ---------------------------------------------------------------------
  // ---------------------- Lógica de coloração  -------------------------
  // OBS: Inserir lógica de cálculo para coloração do gráfico 
  // ---------------------------------------------------------------------
  if (...) then
  begin
    PaintBar()
  end
  else
    if (...) then
    begin
      PaintBar()
    end;

    


end;
































				
			

Modelo de Estratégia de Indicador

				
					// #######################################################################
// #######################################################################
// #######################################################################
// ######                            O                             #######
// ######                        ____|____                         #######
// ######                      _|         |_                       #######
// ######                     (_|  O   O  |_)                      #######
// ######                       |_________|                        #######
// ######                                                          #######
// ###### ____        __        ____________           ________    #######
// ###### | | \       | |       | |_________|         /  ____  \   #######
// ###### | |\ \      | |       | |                  /  /    \  \  #######
// ###### | | \ \     | |       | |____             |  |      |  | #######
// ###### | |  \ \    | |       | |____|            |  |      |  | #######
// ###### | |   \ \   | |       | |____|            |  |      |  | #######
// ###### | |    \ \  | |       | |                 |  |      |  | #######
// ###### | |     \ \ | |       | |_________         \  \____/  /  #######
// ###### |_|      \_\|_|       |_|_________|         \________/   #######
// ######                                                          #######
// ###### _______  __          __   ____  __   ___    __  _______  #######
// ######    |    |  \   /\   |  \ |     |  \ |   \  /  \    |     #######
// ######    |    |__/  /__\  |   ||__   |__/ |___/ |    |   |     #######
// ######    |    |\   /    \ |   ||     |\   |   \ |    |   |     #######
// ######    |    | \ /      \|__/ |____ | \  |___/  \__/    |     #######
// ######                                                          #######
// ######  Comunidade aberta de automatização de estratégias para  #######
// ######                    negociação de ativos                  #######
// ######                                                          #######
// ######                    www.NeoTraderBot.com                  #######
// #######################################################################
// #######################################################################
// #######################################################################
//
// -----------------------------------------------------------------------
// ---------------------- DADOS DA ESTRATÉGIA ----------------------------
// -----------------------------------------------------------------------
//
// NOME DA ESTRATÉGIA: 
//   DESENVOLVIDA POR: 
//    DATA DE CRIAÇÃO: 
//             VERSÃO: 
//      ATUALIZADA EM: 
// TIPO DE ESTRATÉGIA: (X) Indicador  ( ) Coloração ( ) Execução
//                     ( ) Screening  ( ) Texto     ( ) Alarme
//
// DESCRIÇÃO DA ESTRATÉGIA:
// 
// 
// 
// 
// 
// 
//
// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
//
// ######################### FIM DO CABEÇALHO ############################
//
//
// -----------------------------------------------------------------------
// -------------------------- Constantes ---------------------------------
// OBS: 
// -----------------------------------------------------------------------
const
  cCONSTANTE = 1;
  //
  // ---------------------------------------------------------------------
  // -------------------------- Parâmetros -------------------------------
  // OBS: Segue abaixo a descriação de cada parâmetro
  // 1) parametro1 -> 
  // 2) parametro2 -> 
  // ---------------------------------------------------------------------
input
  pParametro(1);
  // ---------------------------------------------------------------------
  // ---------------------- Variáveis globais ----------------------------
  // OBS:
  // ---------------------------------------------------------------------
var
bStarted, 	bPlotIndicador: boolean;
begin
  // ---------------------------------------------------------------------
  // ----------------- Inicialização da estratégia -----------------------
  // OBS: Inicialização de variáveis a serem utilizadas na estratégia de 
  // execução
  // ---------------------------------------------------------------------
  if Not bStarted then
  begin
    bStarted := True;
    //Colocar aqui ações que serão executadas apenas no primeiro processamento
    //da estratégia. Por exemplo, inicialização de variáveis.
  end;


  // ---------------------------------------------------------------------
  // ------------ Atribuição de variáveis por processamento --------------
  // ---------------------------------------------------------------------



  // ---------------------------------------------------------------------
  // --------------------- Cálculo do indicador  -------------------------
  // OBS: Inserir lógica de cálculo do indicador e caso ele possa ser plo_
  // tado, atribuir em algum momento True para variável bPlotIndicador 
  // ---------------------------------------------------------------------
  bPlotIndicador := false;




  //
  // ---------------------------------------------------------------------
  // ------------------ Plota valores do indicador -----------------------
  // OBS: Atribuir na sessão anterior o valor para variavel bPlotIndicador
  // quando for possível plotar um valor para o indicador no instante atual
  // ---------------------------------------------------------------------
  if bPlotIndicador then
    begin
      Plot(cCONSTANTE);
    end;   

end;









				
			

Modelo de Estratégia de Screening

				
					// #######################################################################
// #######################################################################
// #######################################################################
// ######                            O                             #######
// ######                        ____|____                         #######
// ######                      _|         |_                       #######
// ######                     (_|  O   O  |_)                      #######
// ######                       |_________|                        #######
// ######                                                          #######
// ###### ____        __        ____________           ________    #######
// ###### | | \       | |       | |_________|         /  ____  \   #######
// ###### | |\ \      | |       | |                  /  /    \  \  #######
// ###### | | \ \     | |       | |____             |  |      |  | #######
// ###### | |  \ \    | |       | |____|            |  |      |  | #######
// ###### | |   \ \   | |       | |____|            |  |      |  | #######
// ###### | |    \ \  | |       | |                 |  |      |  | #######
// ###### | |     \ \ | |       | |_________         \  \____/  /  #######
// ###### |_|      \_\|_|       |_|_________|         \________/   #######
// ######                                                          #######
// ###### _______  __          __   ____  __   ___    __  _______  #######
// ######    |    |  \   /\   |  \ |     |  \ |   \  /  \    |     #######
// ######    |    |__/  /__\  |   ||__   |__/ |___/ |    |   |     #######
// ######    |    |\   /    \ |   ||     |\   |   \ |    |   |     #######
// ######    |    | \ /      \|__/ |____ | \  |___/  \__/    |     #######
// ######                                                          #######
// ######  Comunidade aberta de automatização de estratégias para  #######
// ######                    negociação de ativos                  #######
// ######                                                          #######
// ######                    www.NeoTraderBot.com                  #######
// #######################################################################
// #######################################################################
// #######################################################################
//
// -----------------------------------------------------------------------
// ---------------------- DADOS DA ESTRATÉGIA ----------------------------
// -----------------------------------------------------------------------
//
// NOME DA ESTRATÉGIA: 
//   DESENVOLVIDA POR: 
//    DATA DE CRIAÇÃO: 
//             VERSÃO: 
//      ATUALIZADA EM: 
// TIPO DE ESTRATÉGIA: ( ) Indicador  ( ) Coloração ( ) Execução
//                     (X) Screening  ( ) Texto     ( ) Alarme
//
// DESCRIÇÃO DA ESTRATÉGIA:
//     
// 
// 
// 
// 
// 
//
// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
//
// ######################### FIM DO CABEÇALHO ############################
//
//
// -----------------------------------------------------------------------
// -------------------------- Constantes ---------------------------------
// OBS: 
// -----------------------------------------------------------------------
const
  cXXXXXX = true;  
  //
  // ---------------------------------------------------------------------
  // -------------------------- Parâmetros -------------------------------
  // OBS: Segue abaixo a descrição de cada parâmetro
  // 1) pXXXXXX -> 
  // 
  // 2) pYYYYYY -> 
  // 
  // 3) pZZZZZZ -> 
  // ---------------------------------------------------------------------
input
  pXXXXX(5);
  pYYYYY(True);
  pZZZZZ(2.3);

  // ---------------------------------------------------------------------
  // ---------------------- Variáveis globais ----------------------------
  // OBS:
  // ---------------------------------------------------------------------
var
//Estrutura padrão do modelo
bStarted: boolean;


//Variáveis personalizadas
iXXXXX, iZZZZZZ: integer;
fXXXXX, fZZZZZZ: float;


begin
  // ---------------------------------------------------------------------
  // ----------------- Inicialização da estratégia -----------------------
  // OBS: Inicialização de variáveis a serem utilizadas na estratégia de 
  // coloração
  // ---------------------------------------------------------------------
  if Not bStarted then
  begin
    bStarted := True;
    //Colocar aqui ações que serão executadas apenas no primeiro processamento
    //da estratégia. Por exemplo, inicialização de variáveis.
  end;


  // ---------------------------------------------------------------------
  // ------------ Atribuição de variáveis por processamento --------------
  // ---------------------------------------------------------------------
  // Atribuições das variáveis da estratégia



  // ---------------------------------------------------------------------
  // ---------------------- Lógica de coloração  -------------------------
  // OBS: Inserir lógica de cálculo para coloração do gráfico 
  // ---------------------------------------------------------------------
  if (...) then
  begin
    Select()
  end
  else
    if (...) then
    begin
      Select();
    end;

    


end;
































				
			

Snippets para Ordens e Administração de Trade

Esta seção visa apresentar trechos de códigos com exemplos de envio de ordens e administração de trade utilizando técnicas de stoploss (fixo, móvel, breakeven) e take profit.

Você pode acessar os Snippets diretamente pelo menu lateral direito, ou fazendo CRL+F (CTRL+L) para localizar algum texto específico na página, uma vez que o conteúdo tende a crescer ao longo do tempo, dificultando a navegação pelo menu.

Caso tenham sugestões de código para acrescentar à lista, gentileza deixar o código nos comentários com o link para seu perfil em rede social (para devido crédito de autoria).

Snippets

Como rotear ordens a mercado, stop e limitada?

No código abaixo, você encontra um exemplo de estratégia que abre um posição em uma data/horário específicos. Assim, você poderá testar a abertura de posições por ordens a mercado, limitada ou stop.

O código possui parâmetros para quantidade, horario de encerramento da posição e lado da posição (comprado/vendido).

OBS: É importante ressaltar que uma vez apregoada uma ordem, ela permanecerá ativa e aguardando execução até que o usuário cancele. Não há um auto-gerenciamento de execução apenas para próxima barra como em outras plataformas.

				
					using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using Runtime.Script;
using TradeApi;
using TradeApi.History;
using TradeApi.Indicators;
using TradeApi.Instruments;
using TradeApi.ToolBelt;
using TradeApi.Trading;



namespace ExemplosNeoTraderBot
{
    /// <summary>
    /// Strategy1
    /// 
    /// </summary>
    public class NTB_ExemploRoteamentoOrdens : StrategyBuilder
    {
		private BarData dadosBarra;
		
        public NTB_ExemploRoteamentoOrdens()
            : base()
        {
			#region Initialization
            Credentials.Author = "NeoTraderBot";
            Credentials.Company = "NeoTraderBot";
            Credentials.Copyrights = "";
            Credentials.DateOfCreation = new DateTime(2023, 9, 5);
            Credentials.ExpirationDate = DateTime.MinValue;
            Credentials.Version = "";
            Credentials.Password = "66b4a6416f59370e942d353f08a9ae36";
            Credentials.ProjectName = "exemploOrdensBasicas";
            #endregion 


        }
        
        /// <summary>
        /// This function will be called after creating
        /// </summary>
		public override void Init()
		{
			dadosBarra = (HistoryDataSeries as BarData);
		}        
 
        /// <summary>
        /// Entry point. This function is called when new quote comes or new bar created
        /// </summary>
        public override void Update(TickStatus args)
        {
        	if (args == TickStatus.IsBar)
        	{
        		List<Position> listaPosicoes = PositionsManager.GetPositions();

        		//DATA E HORA PARA ABERTURA DE POSIÇÕES
        		DateTime horarioAbertura = new DateTime(2023, 09, 05, 09, 06, 0);
				DateTime horarioEncerramento = horarioAbertura.AddMinutes(10);
				
				//INFORMAÇÃO PARA ABERTURA DE POSIÇÕES
				OrderSide ladoOperacao = OrderSide.Sell;
				int quantidade = 1;
				double precoOrdemStop = 4977.5;
				double precoOrdemLimitada = 4982.5;
        		
				OrderRequest request = null;
				
				//CRIA ORDENS
        		if ((listaPosicoes.Count == 0) && (dadosBarra.GetTimeUtc(0).ToLocalTime() == horarioAbertura))
        		{
					// ORDEM A MERCADO
					//request = new OrderRequest(OrderType.Market, InstrumentsManager.Current, AccountManager.Current, ladoOperacao, quantidade);
            		
					// ORDEM LIMITADA
					//request = new OrderRequest(OrderType.Limit, InstrumentsManager.Current, AccountManager.Current, ladoOperacao, quantidade, precoOrdemLimitada);
        			
        			// ORDEM STOP
        			request = new OrderRequest(OrderType.Stop, InstrumentsManager.Current, AccountManager.Current, ladoOperacao, quantidade, null, precoOrdemStop);

	        		//ENVIA ORDENS PARA BROKER
	        		OrdersManager.Send(request);
        		}

				
				//CRIA ORDEM DE ENCERRAMENO A MERCADO        		
				if ((listaPosicoes.Count != 0) && (dadosBarra.GetTimeUtc(0).ToLocalTime() == horarioEncerramento))
        		{
					request = new OrderRequest(OrderType.Market, InstrumentsManager.Current, AccountManager.Current, (ladoOperacao == OrderSide.Buy) ? OrderSide.Sell : OrderSide.Buy, quantidade);
            		OrdersManager.Send(request);
        		} 

        	}
			
        }
        
        /// <summary>
        /// This function will be called before removing
        /// </summary>
		public override void Complete()
		{
			
		} 
     }
}

				
			

Como enviar uma ordem a mercado?

Para enviar uma ordem a mercado, é necessário criar uma requisição de ordem (OrderRequest) com a parametrização desejada e, em seguida, solicitar ao Gestor de ordens que envie essa ordem.

O envio de ordem pode ser feito de maneira síncrona ou assincrona. Na primeira forma (síncrona), o código fica aguardando o retorno da função Send. Já no envio assíncrono, o código continua sua execução e o programador fornece uma função callback para ser executada quando houver o resultado do envio da ordem.

Seguem abaixo exemplos de envio de ordens a mercado de compra e venda.

Ordem de compra a mercado (Envio síncrono)
				
					orderSize = 1;

OrderRequest request = new OrderRequest(OrderType.Market, 
                                        InstrumentsManager.Current,
                                        AccountManager.Current,
                                        OrderSide.Buy,
                                        orderSize);
OrdersManager.Send(request); 
				
			
Ordem de venda a mercado (Envio síncrono)
				
					orderSize = 1;

OrderRequest request = new OrderRequest(OrderType.Market, 
                                        InstrumentsManager.Current,
                                        AccountManager.Current,
                                        OrderSide.Sell,
                                        orderSize);
OrdersManager.Send(request); 
				
			

Como abrir uma posição com ordens OCO?

Gestão de risco é essencial para negociação de ativos. O exemplo abaixo demonstra como enviar um ordem de compra a mercado para abertura de posição, acompanhada das ordens de stoploss e alvo em termos de ticks. 

Ordem de compra a mercado com RG 3:1 e Stop de 30 ticks (Envio síncrono)
				
					using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using Runtime.Script;
using TradeApi;
using TradeApi.History;
using TradeApi.Indicators;
using TradeApi.Instruments;
using TradeApi.ToolBelt;
using TradeApi.Trading;



namespace ExemplosNeoTraderBot
{
    /// <summary>
    /// Strategy1
    /// 
    /// </summary>
    public class NTB_ExemploOrdemOCO : StrategyBuilder
    {
		private BarData dadosBarra;
		
        public NTB_ExemploOrdemOCO()
            : base()
        {
			#region Initialization
            Credentials.Author = "NeoTraderBot";
            Credentials.Company = "NeoTraderBot";
            Credentials.Copyrights = "";
            Credentials.DateOfCreation = new DateTime(2023, 9, 5);
            Credentials.ExpirationDate = DateTime.MinValue;
            Credentials.Version = "";
            Credentials.Password = "66b4a6416f59370e942d353f08a9ae36";
            Credentials.ProjectName = "exemploOrdensOCO";
            #endregion 


        }
        
        /// <summary>
        /// This function will be called after creating
        /// </summary>
		public override void Init()
		{
			dadosBarra = (HistoryDataSeries as BarData);
		}        
 
        /// <summary>
        /// Entry point. This function is called when new quote comes or new bar created
        /// </summary>
        public override void Update(TickStatus args)
        {
        	if (args == TickStatus.IsBar)
        	{
        		List<Position> listaPosicoes = PositionsManager.GetPositions();

        		//DATA E HORA PARA ABERTURA DE POSIÇÕES
        		DateTime horarioAbertura = new DateTime(2023, 09, 05, 09, 06, 0);
				DateTime horarioEncerramento = new DateTime(2023, 09, 05, 17, 00, 0);
				
				//INFORMAÇÃO PARA ABERTURA DE POSIÇÕES
				TradeResult ordem;				
				OrderSide ladoOperacao = OrderSide.Sell;
				int quantidade = 1;
				double stoplossTicks = 30;
				double takeProfitTicks = stoplossTicks*3;        		
				
				OrderRequest request = null;
				
				//CRIA ORDEM OCO
        		if ((listaPosicoes.Count == 0) && (dadosBarra.GetTimeUtc(0).ToLocalTime() == horarioAbertura))
        		{
					request = new OrderRequest(OrderType.Market,
					                                        InstrumentsManager.Current,
					                                        AccountManager.Current,
					                                        ladoOperacao, quantity: quantidade)
					{
						SLTPPriceType = SLTPPriceType.Ticks,
        				StopLossPrice = stoplossTicks,
						TakeProfitPrice = takeProfitTicks
					};
					
					//ENVIA ORDENS PARA BROKER
					ordem = OrdersManager.Send(request);

        		}

				
				//CRIA ORDEM DE ENCERRAMENO A MERCADO        		
				if ((listaPosicoes.Count != 0) && (dadosBarra.GetTimeUtc(0).ToLocalTime() == horarioEncerramento))
        		{
					request = new OrderRequest(OrderType.Market, InstrumentsManager.Current, AccountManager.Current, (ladoOperacao == OrderSide.Buy) ? OrderSide.Sell : OrderSide.Buy, quantidade);
            		OrdersManager.Send(request);
        		} 

        	}
			
        }
        
        /// <summary>
        /// This function will be called before removing
        /// </summary>
		public override void Complete()
		{
			
		} 
     }
}

				
			

Documentação - IntelliRisk

Esta página visa apresentar uma documentação completa da ferramenta IntelliRisk para fins de referência em caso de dúvidas.

Assim, sugerimos utilizar o menu lateral direito de conteúdo para ir direto nas seções de interesse.

Ressaltamos que as orientações para instalação e ativação da licença contratada foram enviadas por e-mail no momento da contratação.

Objetivo da ferramenta e funcionalidades disponíveis

O objetivo principal da ferramenta IntelliRisk é fornecer as informações adequadas para que o trader possa tomar decisões sobre o risco de suas operações e conta, principalmente, para aqueles que estão participando de testes de mesas proprietárias (tais como Apex, TopStep, Bulenox, entre outras).

 

Veja abaixo as funcionalidades disponíveis na IntelliRisk:

        • Calcula o preço médio da sua posição de acordo com a montagem e realização parcial de sua posição
        • Apresenta o valor financeiro e em ticks em cada ordem de alvo e stop no gráfico, facilitando a sua gestão de risco da operação
        • Calcula o ponto de cobertura da sua conta (Daily Breakven). Uma vez com posição aberta, você saberá qual o nível de preço você ficaria com o resultado da sessão zerado.
        • Plota linha de limite de perda de mesas proprietárias: Trailling drawdown, static drawdown ou end of day. Permite monitorar em tempo real, uma vez posicionado, qual seria o nível de preço de risco máximo da conta.
        • Flexibilidade para escolher quais linhas deseja-se plotar no gráfico: preço médio, ponto de cobertura, limite de risco da conta
        • Ferramenta 100% customizada (cores, texto, plot de linhas, …)
        • Funciona em qualquer ativo, tipo de gráfico, tempo gráfico, janelas com multigráficos e multiabas

Como abrir a IntelliRisk em um gráfico da NinjaTrader

A ferramenta IntelliRisk deve ser adicionada a um gráfico como indicador. Para isso você pode clicar no ícone referente a indicadores na barra superior do gráfico (conforme figura abaixo) ou usar o atalho CTRL+I.

Como manipular gráficos na NT8 (Funcionalidades básicas)

Reproduzir vídeo

Neste video iremos apresentar todas as funcionalidades básicas relacionadas a gráficos na Plataforma NinjaTrader.

Este é um conteúdo informativo sobre NinjaTrader para que os membros da comunidade tenham informações do que é possível realizar em outros ambientes.

Reforço que não estamos realizando nenhuma recomendação para mudança de Plataforma e que a decisão de migrar parte ou todo o processo de desenvolvimento e execução das estratégias automatizadas é muito pessoal e cabe apenas ao trader decidir sobre tal assunto.

Stop Móvel (Trailling stop)

O Stop Móvel (Trailling Stop) consiste em uma gestão de risco da operação na qual uma vez atingido determinado gatilho, o stoploss passa a ser atualizado para ficar sempre uma determinada distância atrás do preço de fechamento da barra, reduzindo assim o prejuízo de um eventual loss ou garantindo uma proteção parcial de ganhos, a depender da posição definida para o gatilho.

Veja a figura abaixo a qual apresenta um exemplo da aplicação individual do Stop Móvel e que será usada como referência para explicar a função de cada parâmetro de configuração.

pStopMovel (boolean)
  THUNDER  

Quando true, este parâmetro irá habilitar a funcionalidade de stop móvel. Observe que o stop móvel pode ser usado individualmente ou em concomitância com o Stop BreakEven e as configuração de RG FIXO.

Assim, o usuário pode utilizar apenas a gestão de risco da operação pelo Stop móvel, o que deixará a operação desprotegida até que o gatilho do stop móvel seja acionado. Ou de maneira mais prudente, com a aplicação de ordens OCO RG Fixo. Ainda pode fazer uma combinação com o Stop BreakEven, gerando assim uma administração completa de risco da operação.

pGatilhoStopMovelNoPrecoFechamento (boolean)
  THUNDER  

Este parâmetro quando true, irá realizar o deslocamento ou posicionamento de stop na posição configurada apenas quando uma barra fechar acima do gatilho de stop móvel no caso de uma posição comprada ou abaixo do gatilho quando a operação for de venda.

Caso o parâmetro seja false, o deslocamento ou posicionamento de stop na posição será realizado se em algum momento a máxima de uma barra fechar acima do gatilho de breakeven no caso de uma posição comprada ou a mínima de uma barra fechar abaixo do gatilho quando a operação for de venda.

É importante ressaltar que devido ao funcionamento do modelo de execução da Nelogica, a atualização ou posicionamento do stop, independente da configuração de pGatilhoNoPrecoFechamento, será realizada apenas após o fechamento da barra na qual a condição de gatilho foi satisfeita.

Observe pela figura acima que apenas após o preço superar a linha de gatilho do stop móvel (linha tracejada em vermelho escuro), o stop foi deslocado para a posição configurada, o que ocorreu no fechamento da barra.

pGatilhoStopMovelEmTicks (integer)
  THUNDER  

Este parâmetro é utilizado para definir quantos ticks uma operação deve andar a favor até que seja ativado o Stoploss móvel.

Se o trader definir o valor zero, isso significa que o stop móvel será habilitado já na abertura da posição.

pAncorarStopMovelXTicksAtras (integer)
  THUNDER  

Este parâmetro é utilizado para, uma vez ativado o stop móvel, definir quantos ticks o stoploss deve ficar atrás do preço de fechamento da barra.

É importante ressaltar que o stop móvel não retrocede o valor do stoploss. Ou seja, uma vez deslocado o stoploss para mais próximo do preço negociado, o stoploss não retroage para uma posição mais distante do preço negociado.

Perguntas Frequentes (FAQ) & Exemplos de Código

Nesta seção vamos apresentar exemplos de códigos e respostas às perguntas frequentes para que você comece a usar a integração com o Telegram de maneira mais rápida possível. Caso tenha alguma dúvida, deixe nos comentários que iremos atualizar esta seção de acordo com a demanda.

Como eu incluo a ferramenta de integração com o telegram no meu código?

O primeiro passo é instalar a ferramenta em sua plataforma TraderEvolution. Para isso, basta seguir o roteiro apresentado neste link.

Uma vez instalada a ferramenta, no seu código fonte você deve referenciar a biblioteca de Integração com Telegram (desenvolvida pela NeoTraderBot) na seção de using. Como segue abaixo:

				
					using NTB_IntegrationServices_TE;
				
			

Em seguida, instancie um objeto no para integraçao com o Telegram, conforme segue abaixo:

				
					TelegramIntegration telegramConn;
				
			

Por fim, no método Init do seu código, você pode utilizar a seguinte estrutura de inicialização da biblioteca de integração com o Telegram.

				
					try
    {
        string botToken = "INSIRA AQUI O TOKEN DO SEU BOT";
        string emailAutenticacao = "seuEmail@teste.com";
        string versaoFerramenta = "PREMIUM";
        telegramConn = TelegramIntegration.GetTelegramConn;
        telegramConn.Authenticate(emailAutenticacao, this.AccountManager.Current, versaoFerramenta);
        
        //Registra o robô, grupos e tópicos com suas IDs
        telegramConn.AddBot("NeoTraderBot", botToken);
        telegramConn.AddGroup("NeoTraderBot", "Meus códigos TraderEvolution", "-1001909578209");
        telegramConn.AddTopic("NeoTraderBot", "Meus códigos TraderEvolution", "Alarme Volatilidade", "124");
        telegramConn.AddTopic("NeoTraderBot", "Meus códigos TraderEvolution", "Carteira de ações", "2");
        telegramConn.AddTopic("NeoTraderBot", "Meus códigos TraderEvolution", "Screening Opening Range", "60");
        telegramConn.AddTopic("NeoTraderBot", "Meus códigos TraderEvolution", "Grid Trading", "57");
    }
    catch (Exception ex)
    {
        Notification.Alert("Não autenticou a ferramenta de integração com telegram: " + ex.Message);
    }
				
			

Pronto! Caso não haja problema na Autenticação do seu usuário no servidor da NeoTraderBot, você já poderá utilizar os métodos para envio de mensagens no seu código.

Ah…eu quero guardar o token do meu bot e ler a partir de um arquivo. Ok! Use o snippet abaixo, o qual fará a leitura do arquivo “meuTokenTelegram.txt” na pasta “Meus Documentos”. O arquivo contém unica e exclusivamente o token do bot.

				
								try
			{
				string botToken = "";
				string logPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "meuTokenTelegram.txt");
	            using (StreamReader inputFile = new StreamReader(logPath))
	            {
	            	botToken = inputFile.ReadLine();
	            }
				
			    string emailAutenticacao = "seuEmail@teste.com";
			    string versaoFerramenta = "FREE";
			    telegramConn = TelegramIntegration.GetTelegramConn;
			    telegramConn.Authenticate(emailAutenticacao, this.AccountManager.Current, versaoFerramenta);
			
			    //Registra o robô, grupos e tópicos com suas IDs
			    telegramConn.AddBot("NeoTraderBot", botToken);
			    telegramConn.AddGroup("NeoTraderBot", "Meus códigos TraderEvolution", "-1001909578209");
			}
			catch (Exception ex)
			{
			    Notification.Alert("Não autenticou a ferramenta de integração com telegram: " + ex.Message);
			}	
				
			

Quais são os métodos para envio de mensagens?

Uma vez instanciado um objeto, conforme instruções da pergunta anterior, você irá utilizar o método SendMessage para enviar mensagens para um grupo do Telegram ou tópicos dentro dos grupos.

Cabe ressaltar que você deve verificar se sua versão contratada possui a funcionalidade desejada. Por exemplo, a versão FREE não permite o envio de mensagens para tópicos específicos de um grupo. Ela permite o envio apenas para o tópico principal.

Assim, existem 2 sobrecargas para o método SendMessage: uma para envio de mensagem para um grupo e outra para envio de mensagem para tópico de um grupo.

OBS: É necessário adicionar as IDs e texto de identificação de grupos e tópicos, antes de enviar as mensagens. Pois os grupos e tópicos serão referenciados pelo texto de identificação fornecido.

Enviando mensagem para um Grupo | SendMessage(string botName, string groupName, string message)

No exemplo abaixo, estamos utilizando o objeto telegramConn para enviar uma mensagem utilizando o bot “NeoTraderBot” para o grupo “Meus códigos TraderEvolution”. A mensagem enviada é: “Teste de envio!”.

				
					telegramConn.SendMessage("NeoTraderBot", "Meus códigos TraderEvolution", 
                         "Teste de envio!");
				
			
Enviando mensagem para um Tópico | SendMessage(string botName, string groupName, string topicName, string message)

No exemplo abaixo, estamos utilizando o objeto telegramConn para enviar uma mensagem utilizando o bot “NeoTraderBot” para o tópico “Carteira de ações” do grupo “Meus códigos TraderEvolution”. A mensagem enviada é: “21/nov/2023 – Valor atual da carteira: R$ 89.780,00”.

				
					telegramConn.SendMessage("NeoTraderBot", "Meus códigos TraderEvolution", 
                         "Carteira de ações", 
                         "21/nov/2023 - Valor atual da carteira: R$ 89.780,00");
				
			

Posso enviar emojis nas mensagens de texto?

Sim, claro! Talvez você queira utilizar elementos visuais em suas mensagens de texto. Você pode utilizar os códigos padronizados de emojis os quais estão disponíveis em diversos sites. 

Você pode utilizar o https://emojipedia.org/ como referencia ou copiar as figuras abaixo e colar nas suas mensagens.

OBS: A renderização do emoji (figura a ser desenhada) depende do ambiente no qual está utilizando (Windows/Mac/Telegram/Facebook/Twitter…).

TEMPO:

⏰  ⏲️  ⏳

PERCEPÇÃO DO MERCADO:

🌡️   🔥   🚀  💣 😱  ❄️ 🛒

TENDÊNCIA:

🔼 🔻 📉  📈

DESTAQUES:

⭐ 👀 🔎

ANÚNCIOS:

📢 🔔

ALERTAS:

⚠️  ⛔  🛑  🟢  🔴  🔵  🟡  🟠

RESULTADO:

💰  🤑  💲 🎉 💀 💩

Eu posso enviar imagens (arquivos jpg, png,...)?

Sim. Assim como o método SendMessage permite enviar mensagens de texto, o método SendPicture permite enviar mensagens contendo imagens e uma legenda.

Também há duas sobrecargas do método SendPicture para diferenciar o envio para grupo e tópicos específicos dentro de um grupo.

Veja o exemplo abaixo no qual é enviada uma mensagem contendo uma figura localizada na máquina local (em C:\\Users\\johna\\OneDrive\\Documents\\bulls_bears.jpg) com a legenda “Aqui você escreve o caption!” para o grupo “Meus códigos TraderEvolution” utilizando o bot “NeoTraderBot”.

				
					telegramConn.SendPicture("NeoTraderBot", "Meus códigos TraderEvolution", 
                         "C:\\Users\\johna\\OneDrive\\Documents\\bulls_bears.jpg", 
                         "Aqui você escreve o caption!");
				
			

Por questões de segurança, não é possível referenciar URLs de imagens na internet para envio de mensagens. Assim, recomendamos que baixe as imagens e salve em um diretório local para referenciar em seus códigos.

Não estou conseguindo enviar mensagens. O que pode estar acontecendo?

Caso ocorra alguma inconsistência no envio de alguma mensagem, a biblioteca de integração com o telegram foi projetada para não lançar exceções a fim de não causar distúrbios na execução dos códigos do usuário. Assim, para identificar o problema precisamos eliminar as causas de maneira gradativa.

1) Problemas relacionados à Autenticação do usuário

A primeira causa para você não conseguir enviar mensagens seria algum problema relacionado ao processo de autenticação da ferramenta vinculado ao e-mail e conta do usuário. Certifique-se que a autenticação está ocorrendo adequadamente.

Caso haja alguma falha de comunicação com o servidor de autenticação ou o usuário não esteja cadastrado, isso irá gerar uma exceção ainda no método Init, antes do código iniciar o processamento.

2) Problemas relacionados ao cadastro de token do Bot

Certifique-se de que você está inserindo o token do seu Bot Telegram por meio do método AddBot com o token correto. Atente-se para as funcionalidades da sua versão contratada, pois pode haver limitação da quantidade de bots a serem utilizados em um único código.

3) Permissões do Bot nos grupos destinatários

É importante verificar se você atribuiu as permissões necessárias ao Bot dentro dos grupos destinatários. Clique aqui para ver um roteiro passo a passo de como atribuir corretamente as permissões nos grupos.

4) Problemas relacionados a vinculação de ID para grupos e tópicos

Certifique-se de que você está inserindo os IDs de grupos e seus respectivos textos de identificação (método AddGroup). Ao enviar mensagens, o destinatário deverá ser referenciado pelo mesmo texto identificador. Clique aqui para ver um roteiro passo a passo de como identificar os IDs de grupos e tópicos.

Somente após cadastrar os grupos é que você deve inserir os tópicos do grupo, utilizando o método AddTopic.

Atente-se para as restrições da sua versão em uso, pois podem haver limitações de envio para mais de um grupo ou tópicos dentro dos grupos.

Por fim, certifique-se que as IDs de grupos e tópicos foram devidamente incluídas nos métodos AddGroup e AddTopic.

Sugestão: Inicie um código simples de indicador e insira apenas o código necessário para instanciar a sua conexão com a ferramenta de integração do Telegram e enviar uma única mensagem para um grupo. Uma vez validado esse funcionamento básico, você pode ir aos poucos incluindo outras tarefas no código e copiar essa estrutura para dentro dos seus códigos que deseja integrar com o Telegram.

Como enviar mensagens apenas quando minha estratégia/robô estiver analisando dados em tempo real?

Este controle de fluxo deve ser implementado pelo próprio usuário, pois a ferramenta foi criada para ser flexivel o suficiente para rodar em dados históricos em casos de inicializações com o mercado já aberto e envio de informações referentes a por exemplo a abertura do mercado.

Você possivelmente sabe que o código é processado algumas vezes para cada barra histórica, iniciando na barra mais antiga de dado disponível. As barras são percorridas sequencialmente até chegarmos a última barra, a qual se o mercado estiver aberto, estará sendo atualizada em tempo real.

Assim, para criar um controle de fluxo, no qual você irá enviar mensagens pelo Telegram apenas na última barra do gráfico, ou seja, na barra em tempo real, precisamos declarar uma variável auxiliar no seu código, conforme segue abaixo:

				
					private bool realTime;
				
			

Em seguida, insira no método Update de seu código a estrutura abaixo. Ela permitirá identificar em que momento seu código passará a processar barras em tempo real. Assim, basta você inserir a ação que deseja executar no fechamento da barra ou a cada nova cotação.

				
					public override void Update(TickStatus args)
{
    if (!realTime && (args == TickStatus.IsBar))
    { realTime = true; }
    else
    {
        if (args == TickStatus.IsQuote)   
        {
            //Insira aqui o que deseja executar sempre que tem nova cotação
        }
        else
        if (args == TickStatus.IsBar)
        {
            //Insira aqui o que deseja executar no fechamento da barra
        }
    }
}
				
			

Como eu posso fazer minha estratégia mandar mensagens pelo Telegram?

O código de estratégia abaixo é meramente ilustrativo, mas você pode copiar e rodar em sua conta de simulação na Trader Evolution. O que ele faz basicamente é a cada timeSpaceMinutes (parâmetro da estratégia) verificar se há uma posição aberta e se não houver a estratégia irá comprar ou vender (aleatoriamente) colocando ordens de stop e alvo em ticks, conforme definido nos parâmetros.

As mensagens enviadas para o telegram, nesse caso, foram realizadas sempre que uma ordem é posicionada e executada, bem como quando uma posição é aberta e encerrada. No exemplo, utilizamos sobrecarga de métodos nos eventos já disponíveis no EvoCode. Mas você pode encaminhar mensagens pelo Telegram nas condições que desejar.

				
					using System;
using Runtime.Script;
using TradeApi;
using TradeApi.History;
using TradeApi.Instruments;
using TradeApi.ToolBelt;
using TradeApi.Trading;
using NTB_IntegrationServices_TE;

namespace NeoTraderBotExemplos
{
    public class TimeSpacedOrdersExample : StrategyBuilder
    {
        [InputParameterAttribute(InputType.Color, "Abrir posição a cada (minutos)", 2)]
        [SimpleNumeric(1D, 2400D)]
        public int timeSpaceMinutes = 2;

        [InputParameterAttribute(InputType.Color, "Tamanho da exposição", 3)]
        [SimpleNumeric(1D, int.MaxValue)]
        public int orderQty = 1;

        [InputParameterAttribute(InputType.Color, "OCO - Stoploss (TICKS)", 4)]
        [SimpleNumeric(1D, int.MaxValue, 0, 1)]
        public int stoplossTicks = 10;

        [InputParameterAttribute(InputType.Color, "OCO - Take profit (TICKS)", 5)]
        [SimpleNumeric(1D, int.MaxValue, 0, 1)]
        public int takeProfitTicks = 10;

        TelegramIntegration telegramConn;

        BarData dadosCandle;
        private bool realTime;
        private double positionSize;
        private Random rndSignal;
        public TimeSpacedOrdersExample()
            : base()
        {
            #region Initialization
            Credentials.Author = "Johnathas Carvalho";
            Credentials.Company = "NeoTraderBot";
            Credentials.Copyrights = "NeoTraderBot";
            Credentials.DateOfCreation = new DateTime(2023, 10, 07);
            Credentials.ExpirationDate = DateTime.MinValue;
            Credentials.Version = "1.0";
            Credentials.Password = "66b4a6416f59370e942d353f08a9ae36";
            Credentials.ProjectName = "Estratégia integrada com Telegram";
            #endregion

            SeparateWindow = false;
        }
        public override void Init()
        {
            try
            {
                string botToken = "INSIRA SEU TOKEN AQUI";
                telegramConn = TelegramIntegration.GetTelegramConn;
                telegramConn.Authenticate("seuEmail@gmail.com", this.AccountManager.Current, "SUA VERSAO CONTRATADA");
                telegramConn.AddBot("NeoTraderBot", botToken);
                telegramConn.AddGroup("NeoTraderBot", "Meus códigos TraderEvolution", "INSIRA O ID DO SEU GRUPO AQUI");
            }
            catch (Exception ex)
            {
                Notification.Alert("Não autenticou a ferramenta de integração com telegram: " + ex.Message);
            }

            dadosCandle = (HistoryDataSeries as BarData);
            realTime = false;

            OrdersManager.OnFill += OnOrderFill;
            OrdersManager.OnPlace += OnOrderPlaced;
            PositionsManager.OnOpen += OnOpenPosition;
            PositionsManager.OnClose += OnClosePosition;

            //Gestão de posição
            positionSize = 0;
            
            //Geração de sinais aleatórios
            rndSignal = new Random();

        }

       public override void Update(TickStatus args)
        {

            if (!realTime && (args == TickStatus.IsBar))
            {
                realTime = true;
            }

            if (realTime)
            {
                if (args == TickStatus.IsQuote)   //Atua sempre que tem nova cotação
                {
                    
                }
                else
                if (args == TickStatus.IsBar)    //Atua no fechamento da barra
                {
                    positionSize = GetPositionSize();

                    if ((positionSize == 0) && ( ((dadosCandle.GetTimeUtc().TimeOfDay.TotalMinutes - 9*60) % timeSpaceMinutes) == 0))
                    {
                        if (rndSignal.Next(0, 2) == 0)
                            BuyAtMarket(orderQty, CalculationMode.TICKS, takeProfitTicks, stoplossTicks);
                        else SellAtMarket(orderQty, CalculationMode.TICKS, takeProfitTicks, stoplossTicks);
                    }
                }
            }
        }

        public override void Complete()
        {
            OrdersManager.OnFill -= OnOrderFill;
            OrdersManager.OnPlace -= OnOrderPlaced;

            PositionsManager.OnOpen -= OnOpenPosition;
            PositionsManager.OnClose -= OnClosePosition;

            telegramConn.SendMessage("NeoTraderBot", "Meus códigos TraderEvolution", "A estratégia exemplo de ordens espaçadas no tempo foi encerrada.");
        }

        private TradeResult BuyAtMarket(int qty, CalculationMode mode, double takeProfitUnits, double stoplossUnits)
        {
            OrderRequest request = null;
            TradeResult order;

            request = new OrderRequest(OrderType.Market,
                InstrumentsManager.Current,
                AccountManager.Current,
                OrderSide.Buy, quantity: qty)
            {
                SLTPPriceType = SLTPPriceType.Ticks,
                StopLossPrice = stoplossUnits,
                TakeProfitPrice = takeProfitUnits
            };

            order = OrdersManager.Send(request);
            return order;
        }

        private TradeResult SellAtMarket(int qty, CalculationMode mode, double takeProfitUnits, double stoplossUnits)
        {
            OrderRequest request = null;
            TradeResult order;

            request = new OrderRequest(OrderType.Market,
                InstrumentsManager.Current,
                AccountManager.Current,
                OrderSide.Sell, quantity: qty)
            {
                SLTPPriceType = SLTPPriceType.Ticks,
                StopLossPrice = stoplossUnits,
                TakeProfitPrice = takeProfitUnits
            };

            order = OrdersManager.Send(request);
            return order;
        }

        private void ClosePositions()
        {
            OrderRequest request = null;

            foreach (Position p in PositionsManager.GetPositions())
            {
                request = new OrderRequest(OrderType.Market, InstrumentsManager.Current, AccountManager.Current, (p.Side == PositionSide.Long) ? OrderSide.Sell : OrderSide.Buy, p.Quantity);
                OrdersManager.Send(request);
            }
        }

        private double GetPositionSize()
        {
            double posSize = 0;
            foreach (Position p in PositionsManager.GetPositions(po => po.Instrument == InstrumentsManager.Current))
            {
                Notification.Alert("Posição é de " + p.Quantity);
                posSize += ((p.Side == PositionSide.Long) ? 1 : -1) * p.Quantity;
            }

            return posSize;
        }


        #region callback for Orders and Position events
        private void OnOrderFill(Order order)
        {
            double price = (AccountManager.Current.Name.ToUpper().Contains("DEMO")) ? order.Price : order.AverageFilledPrice;
            double quantity = (AccountManager.Current.Name.ToUpper().Contains("DEMO")) ? order.Quantity : order.FilledQuantity;

            string msg = "Foi executada uma " + ((order.Side == OrderSide.Buy) ? "compra" : "venda") + $" de {quantity} @ {price}";
            telegramConn.SendMessage("NeoTraderBot", "Meus códigos TraderEvolution", ((order.Side == OrderSide.Buy) ? "🔼" : "🔻") + " " + msg);
        }

        private void OnOrderPlaced(Order order)
        {
            double price = order.Price;
            double quantity = order.Quantity;

            string msg = "Foi apregoada uma ordem de " + ((order.Side == OrderSide.Buy) ? "compra" : "venda") + $" de {quantity} @ {price}";
            telegramConn.SendMessage("NeoTraderBot", "Meus códigos TraderEvolution", "👀" + " " + msg);
        }

        private void OnOpenPosition(Position position)
        {
            string msg = "Foi aberta uma posição " + ((position.Side == PositionSide.Long ? "comprada" : "vendida")) + $" de {position.Quantity} @ {position.OpenPrice}";
            telegramConn.SendMessage("NeoTraderBot", "Meus códigos TraderEvolution", "⚠️" + " " + msg);
        }

        private void OnClosePosition(Position position)
        {
            string msg = "Foi encerrada uma posição " + ((position.Side == PositionSide.Long ? "comprada" : "vendida")) + $" de {position.Quantity} com resultado líquido de {position.NetPnL}";
            telegramConn.SendMessage("NeoTraderBot", "Meus códigos TraderEvolution", ((position.NetPnL >= 0) ? "🟢" : "🔴") + " " + msg);

        }

        #endregion

        private enum CalculationMode
        {
            PRICE,
            TICKS,
            PERCENTAGE,
        }

    }
}
				
			

Aula 05 - Hands-on: Primeiros programas em Pascal

Nesta última aula iremos implementar dois programas de exemplo para consolidar o que vimos no curso básico e preparar o caminho para começarmos a implementação de estratégias automatizadas.

Reproduzir vídeo

1. Por onde "começar"?

Se você assistiu/leu as aulas do curso básico até aqui, deve estar se perguntando: por qual linguagem de programação devo “começar” a estudar e implementar meus primeiros programas/estratégias?

Eu penso que para aprender uma linguagem de programação, é necessário atender a um propósito, a uma finalidade prática, para não corrermos o risco de perder a motivação no meio do caminho. Como nesta comunidade nosso objetivo é compartilhar conhecimento e experiências sobre automatização de estratégias para negociação de ativos, iremos selecionar uma linguagem que facilite alcançar esse objetivo.

Neste contexto, existem duas plataformas com maior capilaridade no mercado: Profit Chart (Empresa Nelogica) e MetaTrader (Empresa MetaQuotes Software), quando se trata de negociação de ativos na B3. Ainda tem outras plataformas disponíveis por aí como TradingView e outras que também podem atuar na B3 quanto em criptoativos.

O Profit Chart baseia-se na linguagem Pascal, enquanto o MetaTrader baseia-se na linguagem C.

Iremos iniciar a construção das bases de conhecimento desta comunidade abordando inicialmente implementações de estratégias no Profit Chart. Por que? Porque eu acredito que seja uma plataforma mais amigável para quem está iniciando e com uma curva de aprendizado menor. Está certo que a plataforma é mais limitada em termos de implementação de estratégias do que o MetaTrader. Mas para quem está iniciando, ainda há muito espaço para aprender, testar seu conhecimento e implementar diversas estratégias.

O caminho natural em um segundo momento será abordarmos também a programação em C visando utilização do MetaTrader, software que apresenta uma interface gráfica menos amigável e uma curva de aprendizado maior, embora tenha uma comunidade mundial ativa desenvolvendo soluções.

Assim, visando reduzir nosso nível de preocupação com o que é essencial utilizaremos para esta aula um console virtual e compilador hospedado na web. Faremos isso para evitar passarmos pelo processo de baixar na internet um compilador de Pascal, instalarmos uma API para programar (nada mais é que um editor de texto específico para escrever código fonte). Pois este processo não será necessário para programar as estratégias no Profit Chart, não agregando informação relevante nesse momento.

Então clique em uma das opções de compiladores online abaixo para abrir em uma nova aba o console e compilador online de Pascal para prosseguirmos com esta aula!

      1. Onlinegdb.com;
      2. JDoodle;
      3. Rextester.com
      4. Tutorialspoint.com

Em todos os compiladores onlines haverá uma seção na página onde você poderá editar o código-fonte, e outra seção que será o terminal de comando no qual você irá visualizar o resultado da execução do seu programa. Cada compilador tem um botão para executar o código que pode estar sinalizado como “Run”, “Run code”, “Execute”, etc…

2. Entendendo a estrutura básica de um programa em Pascal

Ao abrir qualquer um dos links acima, você verá no editor de código fonte, possivelmente, o famoso programa “HelloWorld” que qualquer curso de programação irá ensinar como primeira lição! Vamos entender o que está escrito!?

				
					Program HelloWorld(output);
begin
  writeln('Hello, world!');
end.
				
			

Em Pascal todo programa começa com a declaração do nome do programa: Program HelloWorld. Em parentêses são fornecidos os parâmetros do programa. O parâmetro output é uma variável especial que se refere ao terminal de comando, e que especifica que neste programa os comandos de escrita (writeln, abreviação de write line) serão direcionados para o terminal (tela à direita do compilador virtual).

Entre as linhas 2 e 4 está o corpo do programa HelloWorld, que deve estar entre as palavras reservadas begin  e end. (não esqueça do ponto!).

Este é um programa muito simples! A única coisa que ele faz é escrever em tela a string (sequencia de caracteres) “Hello, world!”.

Clique no botão “Execute” no compilador virtual. Observe que o código do programa Hello World será compilado, e caso não haja nenhum erro de compilação, será executado! Nas últimas linhas do lado direito da tela, você deve visualizar o seguinte resultado, demonstrando que seu código foi compilado e o resultado da execução.

Parabéns! Você acabou de compilar e executar seu primeiro programa na linguagem Pascal! Agora vamos explorar um pouco mais os conceitos que você aprendeu até o momento, implementando alguns programas em Pascal. 

3. Hello, market! Uma versão um pouco mais elaborada...

Entre as linhas 1 e 2 do código fonte que vimos anteriormente, o Pascal nos permite realizar algumas coisas:

  • Declarar bibliotecas que serão utilizadas pelo programa (comando uses);
  • Declarar constantes (comando const);
  • Declarar variáveis globais (comando var);
  • Declarar functions/procedures.

As bibliotecas (library) são um repositório de funções e tipos de dados que permitem facilitar escrever um programa para determinada finalidade. Por exemplo, a biblioteca strings possui algumas funcionalidades para facilitar a manipulação de dados de texto. Toda biblioteca possui uma documentação com descrição de como utilizar os tipos de dados e funções.

As constantes são definições de dados que não podem ter seu valor alterado dentro do programa.

As variáveis globais são variáveis que podem ser utilizadas em qualquer lugar de seu programa principal e, naturalmente, podem ter seu valor modificado durante a execução do programa.

As funções (functions) são pedaços reutilizáveis de código fonte que retornam algum valor, enquanto os procedimentos (procedures) não retornam nenhum valor.

A seguir vamos complicar o código fonte de forma incremental para explorarmos a linguagem Pascal.

3.1 Declarando constantes

Vamos mudar o nome do programa para “HelloMarket” e declarar uma constante chamada “dizerHello” do tipo boolean e que tenha o valor verdadeiro. Vamos escrever “Hello, market” apenas se “dizerHello” for verdadeira. Veja abaixo como fica o código fonte:

				
					Program HelloMarket(output);
const
  dizerHello = true;
  
begin
  if dizerHello = true then
    writeln('Hello, market!');   
end.
				
			

Vamos nos atentar para alguns detalhes:

  • A atribuição de valor às constantes na seção const se dá utilizando o sinal “=”;
  • O operador de igualdade para condição do if também utiliza o sinal “=”, mas não trata de uma atribuição de valor e sim de uma expressão booleana;
  • Quando há apenas um comando a ser executado dentro de um controle de decisão/repetição, não há necessidade de utilizar os delimitadores begin…end;

Ao executar o código acima, você irá verificar que o resultado é o mesmo. Você pode tentar mudar a atribuição da constante “dizerHello” para false e verificar o resultado do programa.

3.2 Utilizando biblioteca sysutils

Vamos utilizar a biblioteca sysutils que possui várias funções interessantes para ajudar a escrever programas em Pascal. Como todo programador, você terá que se acostumar a ler a documentação das bibliotecas para aprender a utilizar as funções e até mesmo ver exemplos de uso. A documentação da biblioteca sysutils pode ser acessada aqui.

Agora vamos declarar uma variável do tipo string, chamada “frase”, contendo o texto que iremos imprimir na tela, na seção var do nosso programa. Também vamos usar a função Concat para concatenar (unir) duas strings: “Hello, ” e “market!”. Em seguida vamos usar a função UpperCase para transformar o resultado da concatenção em letras maiuscúlas e armazenar na variável “frase”. Vamos lá!?

				
					Program HelloMarket(output);
uses sysutils;
const
  dizerHello = true;
var 
  frase : string;
begin
  frase := UpperCase(Concat('Hello, ', 'market!'));
  if dizerHello = true then
    writeln(frase);   
end.
				
			

Você observará que o resultado do programa ainda será o mesmo, exceto que as letras estarão em maiúsculo.

3.3 Imprimindo "Hello, market!" n vezes

Bom, agora vamos utilizar um controle de repetição para imprimir o texto “Hello, market!” quantas vezes desejarmos.

Para isso vamos utilizar o controle for e também precisaremos declarar duas variáveis auxiliares do tipo inteiro, uma para fazer a contagem (variável i) e outra para dizer quantas vezes devemos repetir o texto (n_vezes). Veja como seria o código abaixo.

				
					Program HelloMarket(output);
uses sysutils;
const
  dizerHello = true;
var 
  frase : string;
  i, n_vezes : integer;
begin
  n_vezes := 5;
  frase := UpperCase(Concat('Hello, ', 'market!'));
  if dizerHello = true then
    for i := 1 to n_vezes do
        writeln(i, ') ', frase);   
end.
				
			

O resultado esperado da execução do programa segue abaixo:

3.4 Criando uma procedure

Vamos agora implementar uma procedure que recebe como parâmetro uma string e uma quantidade. Esses parâmetros servirão para dizer o texto que deve ser impresso e quantas vezes isso deve ocorrer.

Iremos implementar uma procedure porque em Pascal é esse nome que se dá a uma “função” que não retorna nenhum resultado para o programa principal. Veja abaixo como implementamos! O resultado esperado deve ser exatamente o mesmo da seção anterior.

				
					Program HelloMarket(output);
uses sysutils;
const
  dizerHello = true;
var 
  frase : string;
  i, n_vezes : integer;
  
procedure printHello(texto: string; t: integer);
begin
    for i:=1 to t do
        writeln(i, ') ', frase);
end;

begin
  n_vezes := 5;
  frase := UpperCase(Concat('Hello, ', 'market!'));
  if dizerHello = true then
    printHello(frase, n_vezes);  
end.
				
			

Note que no corpo principal do programa, existem duas variáveis chamadas n_vezes e frase, as quais são passadas como parâmetro para a procedure printHello. Dentro dessa procedure, os parâmetros podem possuir nomes diferentes, que é exatamente o caso. Dentro de printHello, a variável frase é chamada texto e a variável n_vezes é chamada de t. Qualquer alteração nos valores das variáveis texto e t não refletirão mudança no valor das variáveis frase e n_vezes. Isto deve-se ao fato dos parâmetros serem passados para as funções/procedures como valores.

Caso o programador deseja-se modificar os valores das variáveis fornecidas como parâmetros no escopo que chamou a função, ou seja, passando a referência das variáveis originais, bastaria definir os parâmetros precedidos com o comando var.

Esses mecanismos de passagem de parâmetros como valor ou como referência para funções ocorre em todas as linguagens de programação.

3.5 Obtendo dados do usuário

Obter dados externos é uma tarefa muito comum em programação. Ora o programa pode receber dados via terminal de comando, quando o dado a ser inserido é relativamente simples, ora o programa pode receber dados via arquivo de texto com um padrão definido, quando o volume e complexidade dos dados a serem recebidos justificar.

A última parte desse primeiro exercício de programação, será obtermos do usuário a quantidade de vezes que a frase “Hello, market!” deve ser impressa. Desta forma, vamos programar para que o programa peça esta informação e atue com este dado. Vamos lá!? Veja o código abaixo:

				
					Program HelloMarket(output);
uses strings;

const
  hello = 'Hello, market!';

var
  i, vezes: integer;
  
  dizerHello: boolean;

procedure printHello(print: boolean; t: integer);
begin
    for i:=1 to t do
        if (print = true) then
            writeln(i, ' - ', hello);
end;

begin
  dizerHello := true;
  
  writeln('Digite a quantidade de vezes que deseja dizer ''Hello, market!'':');
  readln(vezes);

  printHello(dizerHello, vezes);
    
end.
				
			

O resultado da execução do programa, inserindo o número 7 (seguido de ENTER) segue abaixo:

4. Implementando Bubble Sort

Este segundo exercício de programação consistirá em entendermos um algoritmo e implementarmos um programa que o execute.

Utilizaremos um algoritmo clássico de ordenação, chamado Bubble sort. Já aviso que não é o algoritmo mais eficiente para realizar tal tarefa, mas foi um dos primeiros desenvolvidos e tem o seu valor didático. Se você se interessar em conhecer algoritmos de ordenação, veja esse vídeo aqui (Bubble sort está no minuto 4:00)!

Veja abaixo o algoritmo Bubble sort (fonte: wikipedia). Tente entender o algoritmo antes de passarmos para implementação.

				
					procedure bubbleSort(A : list of sortable items)
    n := length(A)
    repeat
        newn := 0
        for i := 1 to n - 1 inclusive do
            if A[i - 1] > A[i] then
                swap(A[i - 1], A[i])
                newn := i
            end if
        end for
        n := newn
    until n ≤ 1
end procedure
				
			

Vou tentar lhe dar uma ideia de como funciona o algoritmo Bubble sort. Pense em uma lista “A” de números inteiros aleatórios. O algoritmo irá começar comparando os dois primeiros elementos da lista, A[0] e A[1]. Se A[0] for maior que A[1], esses elementos serão trocados na lista, de tal forma que A[1] ficará na segunda posição e A[0] na primeira posição da lista. Em seguida, o algoritmo compara A[1] com A[2], e troca de posição se A[1] for maior que A[2]. Esse processo irá se repetir até chegar na comparação de A[n-i] e A[n], sendo n a quantidade de elementos da lista.

Perceba que ao iterar de 1 até n, o maior elemento da lista estará ao final desse controle (linhas 5 a 10 do algoritmo) na posição n-1. Mas o restante da lista ainda não está ordenada!

Portanto, repete-se a iteração na lista de 1 até n-1 (linhas 5 a 10), fazendo com que o segundo maior elemento da lista agora ocupe a posição n-2. Essas iterações vão ocorrer sucessivamente, até que a última iteração será apenas para comparar o elemento da primeira posição com o elemento da segunda posição. Essas repetições são controlados pelo comando repeat (linha 3) e sua condição de parada na linha 12.

O nome Bubble sort vem da analogia de um copo com refrigerante, as bolhas vão subindo, asssim como os maiores elementos também vão subindo de posição dentro da lista.

Veja abaixo a implementação do algoritmo e tente entender um pouco cada parte antes de prosseguirmos.

				
					program programaOrdenacao;
uses SysUtils;

type
  IntegerArray = array of Integer;
var 
    listaNaoOrdenada: IntegerArray;
    listaOrdenada: IntegerArray;
    i, tamanhoLista: integer;

procedure swap( var a, b:integer);
var
  temp : integer;
begin
  temp := a;
  a := b;
  b := temp;
end;

function BubbleSort(a: IntegerArray): IntegerArray;
var
  n, newn, i:integer;
begin
  n := high( a );
  repeat
    newn := 0;
    for i := 1 to n   do
      begin
        if a[ i - 1 ] > a[ i ] then
          begin
            swap( a[ i - 1 ], a[ i ]);
            newn := i ;
          end;
      end ;
    n := newn;
  until n = 0;
  
BubbleSort := a;
end;

begin
  Write('Insira o tamanho da lista que deseja ordenar (pressione ENTER):');
  readln(tamanhoLista);

  SetLength(listaNaoOrdenada, tamanhoLista);
  SetLength(listaOrdenada, tamanhoLista);

  writeln('Digite ', tamanhoLista, ' números inteiros separados ENTER:');
  for i:= 0 to tamanhoLista-1 do
    readln(listaNaoOrdenada[i]);

  writeln();
  Write('Lista inserida: ');
  for i:= 0 to tamanhoLista-1 do
    Write(listaNaoOrdenada[i], '   ');
  Write(sLineBreak);
  
  listaOrdenada := BubbleSort(listaNaoOrdenada);
  
  Write('Lista ordenada: ');
  for i:= 0 to tamanhoLista-1 do
    Write(listaOrdenada[i], '   ');
  Write(sLineBreak);
end.


				
			

Perceba que a implementação de um algoritmo simples já começa a apresentar detalhes particulares de implementação. Vamos explorar um pouco o código fonte para explicá-lo.

As linhas 1 e 2 são bem objetivas, nomeia o programa como “programaOrdenacao” e informa que será utilizada a biblioteca SysUtils. A documentação do compilador FreePascal que é utilizado nos links dos compiladores online, bem como a documentação das bibliotecas está disponível no site freepascal.org.

Nas linhas 4 e 5, a gente irá declarar um tipo de dado chamado IntegerArray que será um array de Integer (vimos o que era array na segunda aula!). Essa declaração de tipo é uma exigência da linguagem para utilizarmos este tipo de dados como retorno da função BubbleSort.

Entre as linhas 6 e 9, vamos declarar as variáveis que o programa irá utilizar: uma lista não ordenada que será informada pelo usuário, uma lista ordenada que será o resultado da função BubbleSort, uma variável de iteração i e o tamanho da lista a ser informada pelo usuário.

A procedure swap (entre as linhas 11 e 18) realiza apenas a troca de valores entre dois elementos. Essa procedure foi criada devido à recorrência desse tipo de operação no algoritmo BubbleSort. Note que os parâmetros foram passados como referência, o que permite, portanto, a manipulação de seus valores e reflexo no escopo que chamou a procedure swap, no caso, a função BubbleSort.

Entre as linhas 20 e 39, você verá a função BubbleSort que implementa o algoritmo visto anteriormente A função recebe como parâmetro um array de inteiros por valor, e retorna outro array de inteiros ordenado.

Entre as linhas 41 e 64 está o corpo principal do programa. O programa começa solicitando ao usuário o tamanho da lista que será ordenada. Assim, o usuário deve fornecer um número inteiro positivo ao programa.

Com base nessa informação, as linhas 45 e 46 definem o tamanho dos arrays listaNaoOrdenada e listaOrdenada. Em seguida, nas linhas 48 a 50, o programa pede que o usuário insira cada um dos números da lista de tamanho que ele definiu. Ao tempo que os valores são informados, eles são gravados nas posições do array listaNaoOrdenada (linha 49 e 50).

Entre as linhas 52 e 56, o programa irá imprimir na tela qual foi a lista de valores inseridas pelo usuário.

Na linha 58, é executada a chamada da função BubbleSort e o resultado é armazenado na variável listaOrdenada.

Por fim, a lista ordenada é impressa em tela (linha 60 a 63).

Talvez você cometa o erro de inserir uma letra quando o programa solicitar o tamanho da lista. Você observará que ocorrerá um erro no programa, pois o valor inserido pelo usuário seria do tipo string e o programa está tentando armazenar em uma variável do tipo inteiro.

Esses erros em programação são conhecidos como erros de execução e ocorrem sempre que o usuário realiza uma ação diferente do esperado. Em programação, o programador sempre tenta prever estes casos de “exceção” parar que o programa trate de forma correta. Por exemplo, o programa poderia informar que o valor inserido não é um número inteiro e solicitar novamente a inserção da informação até que ela venha correta. Assim, não haveria erro de execução e o programa continuaria sua execução até o fim. Situação análoga poderia ocorrer no momento de informar os elementos da lista.

Próximos passos

Bom, chegamos ao fim do curso básico de lógica de programação e espero que tenham conseguido entender os principais conceitos e ideias por trás da programação.

Esta última aula, na qual entramos em detalhes específicos da linguagem Pascal demonstra um pouco como é a vida de um programador…Especializar-se em uma linguagem específica leva tempo, exige horas de leitura de documentação, inúmeras pesquisas no google sobre erros de compilação, exemplos de código fonte, etc. É um trabalho de pesquisa e estudo que exige proativdade para achar as soluções para os problemas. As dificuldades em programação sempre vão existir! No início você irá se deparar com dificuldade em tarefas simples que com o tempo se tornarão naturais de se programar, mas surgirão novas dificuldades em tarefas mais complexas.

O importante no final das contas, é manter-se motivado, sentir-se realizado pelas pequenas conquistas e buscar suporte e materiais de qualidade para consulta. A intenção do site Neo traderBot é justamente ter um ambiente colaborativo com materiais de relevância e pessoas interessadas em ajudar umas as outras na busca por soluções.

Espero que tenha gostado do curso, mas se há alguma sugestão ou critíca para que possamos melhorar o conteúdo, não hesite em comentar abaixo.

Muito obrigado e sucesso para você nessa jornada de conhecimento!

Grade de Gráficos na TraderEvolution [Monitorando o mercado]

Reproduzir vídeo

Neste vídeo da séria “Conhecendo a Trader Evolution” vamos explorar a funcionalidade GRADE DE GRÁFICOS, por meio da qual você poderá monitorar o mercado. Esta funcionalidade é análoga a “Visão de Mercado” do Profit Chart e do “Market Watch” da Ninja Trader.

Automatizando SEM programação

Espera aí! É possível automatizar sem programar? Então para que eu vou perder meu tempo aprendendo a programar!? Aposto que você deve ter pensado isso….rsrsrs…Ok! É um argumento bem válido…Mas vou te mostrar alguns pontos que talvez ajudem você a enxergar melhor a médio e longo prazo.

Para regras muito simples de coloração, estratégias de negociação e stoploss, ou um Screening (se não souber do que estou falando…leia o documento sobre Tipo de Estratégias), você pode recorrer a interface gráfica do Profit e criar a sua própria regra sem a necessidade de escrever código.

Se você não sabe programação (AINDA!!!) acho que vale a pena explorar essas funcionalidades! Fizemos vários vídeos explicando as estratégias e automatizações que você pode fazer no Profit Chart sem a necessidade de programar e criamos essa playlist no Youtube!

Mas em pouco tempo, você encontrará dificuldades para criar regras ou pouco mais sofisticadas pela interface gráfica. Além disso, perceberá que não acha lugar nenhum explicando o que gostaria de saber e tampouco conteúdos de qualidade na internet (exceto os materiais da NeoTraderBot…kkkk). Para ser muito sincero, a documentação da Nelogica, que é a empresa que desenvolve e mantém o Profit Chart,  é muito “minimalista” (estou tentando ser político para não falar um português mais claro!).

Além disso, a interface gráfica do Profit também te obriga a descrever suas regras de uma forma que pode dificultar a manutenção e ajustes futuros. E para fazer algumas coisas, você precisa saber exatamente o mesmo comando que precisaria saber se estivesse programando! Ou seja, não há vantagem nessa situação…é melhor programar mesmo!

Então para resumir, recomendamos fortemente que aprenda a programar o quanto antes! Aqui na NeoTraderBot você tem acesso a tudo que precisa para aprender a automatizar suas estratégias, desde o Curso Básico de Lógica de Programação e o passo-a-passo para fazer todas automatizações na plataforma Profit, até exemplos completos da implementação de estratégias de execução (robôs)!

Mas se ainda não sabe nada de programação e tem algumas ideias de coisas simples que pode fazer para te ajudar no seu operacional, então tente implementar pela interface gráfica, enquanto investe parte do seu tempo para também aprender programação. Se você não conseguir fazer pela interface gráfica é porque não é tão simples quanto imaginava!

E o que podemos automatizar no Profit sem escrever código? Segue a lista abaixo e a nossa playlist ensinando como automatizar cada etapa do seu operacional!

  1. Estratégias de negociação: automatização de ordens de ganho, saidas parciais e stoploss na abertura de posições;
  2. Estratégias de stoploss: Autobreakeven (desloca stoploss uma vez atingido um lucro mínimo, evitando assim que o trade resulte em prejuízo em um movimento contrário à posição) e Stop móvel (Trailing stop) que é uma técnica para proteger ganhos já alcançados a medida que o preço do ativo anda a favor da operação;
  3. Screening: filtro de ativos que estejam na condição adequada, de acordo com o seu operacional, para abrir posição, liquidar posição existente, etc…
  4. Regras de alarme: configuração de alarmes sonoros e visuais para alertar o trader sobre um condição específica em um ativo determinado.
  5. Regras de coloração: configuração de coloração de gráficos e barras de acordo com a preferência do trader para indicar situações específicas ou gatilhos para seu setup operacional;
  6. Regras de execução (robôs): em resumo são regras para criação de um robô. Apesar de poder criar robôs sem escrever código eu recomendo criá-los apenas por meio de código fonte.
 
 

No próximo documento vamos abordar as melhores práticas de programação, para que possa evoluir de forma assertiva, em um bom ritmo, escrevendo códigos-fonte organizados legíveis (fáceis de entender para você e para outros…no futuro você vai entender essa frase!) e mantendo uma curadoria adequada de suas estratégias.

Snippets para Implementação de estratégias

Snippets para Implementação de estratégias

Esta seção visa apresentar trechos de códigos com funcionalidades relativas à localização temporal da estratégia. Por exemplo, identificar se a atual barra é a primeira barra do dia para verificar gap diário.

Você pode acessar os Snippets diretamente pelo menu lateral direito, ou fazendo CTRL+F (CTRL+L) para localizar algum texto específico na página, uma vez que o conteúdo tende a crescer ao longo do tempo, dificultando a navegação pelo menu.

Caso tenham sugestões de código para acrescentar à lista, gentileza deixar o código nos comentários com o link para seu perfil em rede social (para devido crédito de autoria).

Snippets

Como identificar gap de abertura do dia?

Veja abaixo um exemplo de como estruturar uma lógica para identificar gap de abertura diário pelo EvoCode.

				
					using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using Runtime.Script;
using TradeApi;
using TradeApi.History;
using TradeApi.Indicators;
using TradeApi.Instruments;
using TradeApi.ToolBelt;


namespace Snippets_NeoTraderBot
{
    /// <summary>
    /// Indicator1
    /// 
    /// </summary>
    public class exemploIdentGapAbertura : IndicatorBuilder 
    {
		private BarData dadosCandle;
    	
        public exemploIdentGapAbertura()
            : base()
        {
			#region Initialization
            Credentials.Author = "NeoTraderBot";
            Credentials.Company = "NeoTraderBot";
            Credentials.Copyrights = "";
            Credentials.DateOfCreation = new DateTime(2023, 9, 4);
            Credentials.ExpirationDate = DateTime.MinValue;
            Credentials.Version = "";
            Credentials.Password = "66b4a6416f59370e942d353f08a9ae36";
            Credentials.ProjectName = "exemploIdentGapAbertura";
            #endregion 
            
            Lines.Set("line1");
			Lines["line1"].Color = Color.Blue;

            SeparateWindow = false;
        }
        
        /// <summary>
        /// This function will be called after creating
        /// </summary>
		public override void Init()
		{
			dadosCandle = (HistoryDataSeries as BarData);
		}        
 
        /// <summary>
        /// Entry point. This function is called when new quote comes or new bar created
        /// </summary>
        public override void Update(TickStatus args)
        {
			if (dadosCandle.Count <= 1)
				return;
        	
			if (args != TickStatus.IsQuote)
			{
				if (dadosCandle.GetTimeUtc(0).ToLocalTime().Date != dadosCandle.GetTimeUtc(1).ToLocalTime().Date)
				{
					double gapDoDia = dadosCandle.GetOpen(0) - dadosCandle.GetClose(1);
					Notification.Print(dadosCandle.GetTimeUtc(0).ToLocalTime().ToString() + ": Mercado abriu em gap de " + gapDoDia);
				}
			}
        }
        
        /// <summary>
        /// This function will be called before removing
        /// </summary>
		public override void Complete()
		{
			
		} 
     }
}

				
			

Documentação - Gain Guardian

Recursos avançados de Subgráficos e Multigráficos na NT8

Reproduzir vídeo

Neste video iremos apresentar as funcionalidades avançadas relacionadas a gráficos na Plataforma NinjaTrader.

Você perceberá como o NinjaTrader possui funcionalidades que não se encontra em outras plataformas, como a capacidade de plotar mais de um ativo no mesmo gráfico, ou de até mesmo plotar tempos gráficos diferentes do mesmo ativo no mesmo gráfico.

Por exemplo, em um mesmo gráfico ver o box de 15 minutos e candles de 1 minuto. A Plataforma permite configurar e personalizar todas formas diferentes de subgráficos e multigráficos que expande bastante a capacidade analítica na leitura de gráficos e permite uma flexibilidade muito grande para plotagem de indicadores customizados.

Este é um conteúdo informativo sobre NinjaTrader para que os membros da comunidade tenham informações do que é possível realizar em outros ambientes.

Reforço que não estamos realizando nenhuma recomendação para mudança de Plataforma e que a decisão de migrar parte ou todo o processo de desenvolvimento e execução das estratégias automatizadas é muito pessoal e cabe apenas ao trader decidir sobre tal assunto.

Ferramentas para EvoCode

Nesta seção vamos apresentar informações sobre as ferramentas de trading desenvolvidas pela NeoTraderBot para Trader Evolution, bem como informações relevantes para instalação e configuração em sua plataforma.

Como instalar/remover ferramentas, indicadores e estratégias da Trader Evolution

Nesse tutorial vamos ver o passo-a-passo para instalação e remoção de ferramentas, estratégias e indicadores na Plataforma Trader Evolution.

Todas as ferramentas, indicadores ou estratégias automatizadas desenvolvidas pela NeoTraderBot, independente de serem pagas ou gratuitas, são autenticadas antes de iniciarem sua execução. Assim é imprescindível que você instale a biblioteca de Autenticação da NeoTraderBot em sua plataforma Trader Evolution.

Instalando o Biblioteca de Autenticação da NeoTraderBot

Este é um procedimento bem simples, basta clicar aqui para baixar a versão mais recente da biblioteca de autenticação da NeoTraderBot. Por se tratar de um arquivo com extensão dll, seu navegador pode alertar para algum risco no download. Certifique-se de que conseguiu baixar o arquivo sem problemas.

Em seguida, mova o arquivo baixado para o diretório principal da TraderEvolution. Sigas os passos abaixo para identificar o diretório principal da plataforma TraderEvolution.

Passo 1: Abra uma janela do Windows Explorer (atalho WINDOWS + E) e na barra de endereço, (no lado esquerdo e superior da tela, logo abaixo do menu), digite “%APPDATA%” e pressione ENTER.

Passo 2: Será aberto um diretório contendo os programas instalados em seu PC, localize a pasta “Trader Evolution Brasil” e acesse-a.

Passo 3: Você está agora dentro do diretório principal da Trader Evolution. A biblioteca de autenticação deve ser copiada para dentro do diretório principal.

OBS: A sua plataforma Trader Evolution deve estar preferencialmente fechada.

Instalando Indicadores e Estratégias na TraderEvolution

A instalação de indicadores e Estratégias consiste basicamente em copiar as estratégias para dentro das pastas apropriadas dentro do diretório TraderEvolution, ou criar um diretório para concentrar códigos e referenciar esta pasta dentro da TraderEvolution.

Abaixo vamos demonstrar as duas maneiras de fazer a TraderEvolution listar os indicadores e estratégias dentro da plataforma.

Forma 1: Incluindo indicadores e estratégias nas pastas nativas da TraderEvolution

Passo 1: Abra uma janela do Windows Explorer (atalho WINDOWS + E) e na barra de endereço, (no lado esquerdo e superior da tela, logo abaixo do menu), digite “%APPDATA%” e pressione ENTER.

Passo 2: Será aberto um diretório contendo os programas instalados em seu PC, localize a pasta “Trader Evolution Brasil” e acesse-a.

Passo 3: Você está agora dentro do diretório principal da Trader Evolution. Acesse a pasta “Scripts”.

Passo 4: Dentro da pasta “Scripts”, você terá a pasta “Indicators” e “Strategies”. Basta copiar os indicadores/estratégias para dentro das respectivas pastas e a TraderEvolution passará a listá-los.

OBS: Esta cópia pode ser feita com a plataforma aberta. No entanto, recomendamos que feche-a antes de substituir arquivos.

Passo 5: Ao clicar sobre um gráfico o botão direito -> “Indicadores” -> “Adicionar Indicador”, você notará que os arquivos acrescentados na pasta “Indicators” são listados adequadamente.

OBS: Os arquivos são listados pelo nome do arquivo do código. Todos os arquivos da NeoTraderBot possuem em seu nome as iniciais NTB, facilitando assim a pesquisa pelo campo de busca. Observe que os novos indicadores não são listados dentro das categorias apresentadas pela plataforma.

Forma 2: Importando os códigos a partir de uma pasta ou arquivos individuais

Iremos demonstrar abaixo o processo para importação de indicadores. O procedimento é análogo no caso de estratégias, sendo a única diferença que o processo de importação de estratégias ocorre dentro do “Strategy Manager” ao tentar adicionar uma estratégia.

Passo 1: Crie uma pasta no local que desejar e copie para dentro dessa pasta os códigos que deseja que sejam listados dentro da plataforma TraderEvolution. Uma boa prática é manter um diretório para indicadores e outro para estratégias.

OBS: No exemplo abaixo, preferimos criar as pastas “NeoTraderBot_Indicators” e “NeoTraderBot_Strategies” dentro da pasta “Scripts” da TraderEvolution (conforme pode ser visto abaixo).

Passo 2: Ao clicar sobre um gráfico da TraderEvolution com o botão direito -> “Indicadores” -> “Adicionar Indicador”, será aberta uma janela para seleção de indicadores. Clique em “Importar”.

Passo 3: Será aberta uma janela de “Importar Script”, a qual você poderá selecionar uma pasta ou arquivos de maneira individual. Escolha uma das opções e localize os arquivos/pasta que deseja importar.

Passo 4: Ao acrescentar os arquivos, eles serão identificados pelo seu respectivo tipo e listados conforme figura abaixo. A coluna “Destino” por padrão seleciona a opção de copiar os arquivos para um diretório da TraderEvolution do usuário da máquina em “Documents\Trader Evolution Brasil\My scripts”.

Selecione a opção desejada na coluna “Destino” e, em seguida, clique em “Importar”.

Passo 5: Os arquivos serão importados e serão listados no grupo “Personalizado” na janela de “Pesquisa de Indicadores”.

Removendo Indicadores e Estratégias na TraderEvolution

A remoção de indicadores e Estratégias consiste basicamente em excluir os indicadores e estratégias das pastas nas quais eles foram copiados ou importados.

Conforme apresentado nos roteiro anteriores, a depender da forma como o usuário importou/copiou as ferramentas, elas podem estar no diretório principal da Trader Evolution (Passo 1 do roteiro de instalação da biblioteca de autenticação), ou na pasta do usuário windows referente ao programa Trader Evolution (em “Documents\TraderEvolution Brasil\My scripts”).

Em “My scripts” o usuário irá localizar tanto os códigos compilados (pasta bin) como código-fonte que foram criados pelo EvoCode localmente (arquivos cs, nas pastas “Indicators” e “Strategies”).

Como liberar o meu acesso às ferramentas NeoTraderBot?

Estamos sempre buscando otimizar código, estratégias e processos, visando gastar nosso tempo com o que realmente agrega valor. Assim, esperamos em breve poder tornar esse processo de obtenção de senha para uso das ferramentas NeoTraderBot mais integrado em um futuro próximo.

No momento, o procedimento para obtenção de senha para liberação de uso individual das ferramentas, indicadores e estratégias, pagas ou gratuitos, consiste em enviar o formulário abaixo.

Nós iremos responder em um prazo máximo de 24 horas (dia útil) com os dados de acesso.

Liberação de uso Ferramentas/ Indicadores/ Estratégias - TraderEvolution
Este formulário visa recepcionar a conta na qual o usuário irá executar as ferramentas e códigos desenvolvidos pela NeoTraderBot, que são comercializados para uso individual (apenas uma conta). Caso o usuário deseje executar em mais de uma conta ao mesmo tempo, deverá adquirir outra licença de uso. Entre em contato conosco para condições diferenciadas a partir da 2a licença do mesmo produto.
No caso de ferramentas pagas, utilize o mesmo e-mail fornecido no momento da compra da ferramenta.
Algumas ferramentas possuem funcionalidades liberadas para traders membros da Comunidade NeoTraderBot e que sinalizam o código da NeoTraderBot na plataforma Trader Evolution.
Clique aqui para ver o passo-a-passo de como se cadastrar como parceiro.
Realize o cadastro antes de enviar esse formulário...só leva 1 minuto!

Recebi um e-mail informando a liberação de uso da ferramenta. O que faço agora?

Caso ainda não tenha instalado a ferramenta na sua plataforma Trader Evolution, sigas os passos do roteiro neste link.

Ao adicionar um indicador ou estratégias, sempre haverá um parâmetro de autenticação: email (conforme figura abaixo). Forneça seu email cadastrado. Caso haja algum problema na autenticação, a ferramenta irá exibir mensagem em tela e o indicador ou ferramenta não será executada.

Caso tenha algum problema nesse processo de autenticação, entre em contato conosco pelo e-mail NeoTraderBot@gmail.com, fornecendo seu número de telefone de contato que iremos fornecer o suporte necessário.

Como me registrar como Parceiro da NeoTraderBot?

Aqui na NeoTraderBot temos o objetivo de criar uma comunidade de traders interessados em utilizar a automação a seu favor no trading, seja 100% por meio de robôs, ou semi-automatizada, delegando a algoritmos e códigos automatizados a execução de algumas tarefas específicas.

Para que você tenha acesso a algumas condições especiais no uso de ferramentas, indicadores e estratégias, pedimos que nos ajude a fazer crescer a Comunidade NeoTraderBot, sinalizando como nosso parceiro dentro da plataforma Trader Evolution.

É muito simples fazer isso! Siga o passo-a-passo abaixo:

Passo 1: Na Plataforma Trader Evolution, clique no item “Ferramentas” no menu superior. Em seguida na opção “Extensões” -> “Indique parceiro”.

Passo 2: Vai abrir uma pequena janela, na qual você irá inserir o código “NEOTRADERBOT” para sinalizar para a plataforma Trader Evolution que você pertence a Comunidade NeoTraderBot.

Pronto! Ao sinalizar que você pertence à Comunidade NeoTraderBot, poderemos pleitear novas funcionalidades, ajustes ou melhorias de maneira centralizada e com mais relevância, uma vez que saberão quantas pessoas estão engajadas na Comunidade NeoTraderBot!

Documentação: Integração com Telegram

Você já pensou em conectar os seus robôs e indicadores que rodam na Trader Evolution ao Telegram? Quer receber mensagens quando uma posição é aberta ou uma operação é encerrada? Acompanhar de onde estiver, por meio de mensagens no Telegram, o resultado das suas operações e de suas estratégias automatizadas é possível com a ferramenta de Integração da NeoTraderBot!

Nesta página você terá acesso a todas as informações necessárias para que suas estratégias lhe enviem mensagens pelo Telegram!

O que é a ferramenta de Integração da NeoTraderBot?

É uma biblioteca que permite qualquer robô/indicador implementado em EvoCode enviar mensagens de texto e fotos pelo Telegram. Assim, as possibilidades de uso são muito amplas, podendo servir, por exemplo, para:

          • Acompanhamento da execução de Estratégias/Robôs próprios;
          • Notificações na abertura ou encerramento de posições com o resultado da operação;
          • Envio de notificações para grupo Telegram baseado em filtro automatizado de ativos (Screenings);
          • Envio de alarmes em condições específicas de mercado;
          • Envio automatizado de informações de mercado (preço de ações, preços de abertura, etc..);
          • Acompanhamento do valor patrimonial de uma carteira de ações;
          • Compartilhamento de ordens geradas/executadas por estratégias.

Temos uma versão FREE para você começar a agora a integrar  o seu trading com o Telegram! Além disso, disponibilizamos outras versões com funcionalidades ampliadas.

Pré-configuração, Tutoriais e Documentação

Uma vez contratada/adquirida a ferramenta de Integração TraderEvolution/Telegram, e após a instalação  básica (roteiro aqui), serão necessárias algumas configurações específicas para integração com o Telegram. 

Siga o passo-a-passo abaixo para realizar as pré-configurações e poder utilizar a integração de Telegram em suas estratégias (cada item contém um vídeo de tutorial).

Pronto! Agora você já pode fazer suas estratégias/robôs enviarem mensagens pelo Telegram! Clique aqui para ver as perguntas mais frequentes e exemplos de códigos para adaptar a sua necessidade.

Como criar seu bot para Telegram

A ferramenta de Integração TraderEvolution / Telegram, desenvolvida pela NeoTraderBot, necessita que você crie um bot no Telegram.

Veja abaixo o passo-a-passo para criar o seu próprio bot no Telegram. O procedimento pode ser realizado tanto no Telegram Web quanto eu seu próprio aplicativo no celular.

Reproduzir vídeo

TUTORIAL - PASSO 1: Como criar seu bot para Telegram

1) Acesse o Telegram Web ou abra o app em seu celular
2) Pesquise por botFather

A pesquisa irá buscar os perfis públicos com este nome. Certifique de que irá selecionar o perfil correto conforme abaixo com a verificação do Telegram.

3) Inicie um chat com o perfil @BotFather
4) Digite o comando /newbot

Isto irá iniciar o processo de geração de um bot para Telegram.

5) Em seguida o @botFather irá lhe perguntar qual é o nome do seu bot. Escolha um nome conforme sua conveniência.

No exemplo abaixo, escolhemos o nome “TesteCriacaoBot”

6) No próximo passo, o @botFather irá lhe perguntar por um username que deve terminar com a palavra bot.

O username (nome de usuário) é uma chave única no Telegram e, portanto, alguns nomes podem estar ocupados.

No exemplo abaixo, tentamos “TesteCricaoBot” e fomos avisados de que esse username já havia sido escolhido. Na segunda tentativa, escolhemos o username testeCriacao1bot.

7) Salve em local seguro o token de acesso do seu bot e inicie um chat com o seu bot

Uma vez que o username seja aceito, o @botFather irá gerar um token de acesso ao bot. Esse token de acesso permite administrar o bot criado e, portanto, você deve guardar essa chave em um lugar seguro.

Em seguida, clique na URL indicada no início da mensagem e encaminhe um texto qualquer ao seu bot, para que o mesmo conste na sua lista de Grupos/Chats do Telegram.

 

Próximo passo...

Ok! Criamos com sucesso o nosso bot de Telegram o qual irá enviar mensagens dentro da estratégias e indicadores da TraderEvolution utilizando a ferramenta da NeoTraderBot.

No próximo passo iremos criar o grupo no qual o bot irá encaminhar mensagens (caso você ainda não tenha) e atribuir permissão de administrador ao seu bot recém-criado.

Atribuindo permissões para o bot

Uma vez criado um bot dentro do Telegram, ou já tendo um bot para finalidade de integração com a TraderEvolution. o próximo passo é atribuir permissão de administrador ao bot nos grupos que receberão mensagens pelas suas estratégias, robôs e indicadores da TraderEvolution.

O procedimento pode ser realizado tanto no Telegram Web quanto eu seu próprio aplicativo no celular.

Reproduzir vídeo

TUTORIAL - PASSO 2: Atribuindo ao bot permissão de Administrador

1) Acesse o Telegram Web ou abra o app em seu celular
2) Crie um novo Grupo

Caso já possua um grupo para o qual suas estratégias encaminharão mensagens, vá para o Passo 3.

Neste primeiro momento, não iremos adicionar nenhum membro ao grupo. Clique no botão avançar no canto inferior direito.

Escolha um nome para o grupo que está criando. Nesse exemplo, utilizamos o nome “Grupo Teste”.

3) Inclusão do bot como membro do grupo

Selecione o grupo na listagem lateral esquerda. Em seguida, clique no cabeçalho superior onde há a informação do nome do grupo e quantidade de membros.

Será exibido um painel no lado direito da tela. Clique sobre o ícone de lápis no canto superior direito para abrir o painel de administração.

Em seguida clique no item “Members”, conforme demonstrado abaixo.

Uma vez exibida a listagem de membros atuais, clique no botão de adicionar novos membros no canto inferior direito.

Busque pelo nome do bot desejado. Como há muitos bots públicos, certifique-se de que está selecionando corretamente o bot que criou.

4) Atribua permissão de administrador ao bot

Agora que o bot já é membro do grupo, volte ao painel de administração e clique em “Administrators”.

Será exibida uma listagem com os atuais membros do grupo. Selecione o bot que acabou de adicionar como membro do grupo.

Em geral, não há necessidade de alterar as permissões já configuradas por padrão. Assim, clique na seta de voltar.

5) Certifique que seu bot é administrador do grupo

Ao voltar, você verá novamente a relação de administradores do grupo, onde deve constar o nome do bot e a observação de que você concedeu a permissão de administrador ao bot.

Próximo passo...

Já temos um bot do Telegram e um grupo para receber as mensagens das nossas estratégias da TraderEvolution.

O próximo passo, será identificar o ID do grupo que criamos, pois precisaremos desse ID para encaminhar as mensagens pela ferramenta de integração da NeoTraderBot.

Como obter IDs de Grupos

 

para enviarmos mensagens a partir de suas estratégias da TraderEvolution para um grupo do Telegram, precisamos identificar qual é o ID do grupo desejado, o qual criamos no passo anterior.

Reproduzir vídeo

TUTORIAL - PASSO 3: Identificando o ID dos grupos do Telegram

1) Acesse o Telegram Web ou abra o app em seu celular
2) Envie uma mensagem qualquer dentro do grupo

Para essa etapa é importante garantir que o seu bot é membro do grupo (fizemos isso no passo 2).

Vamos utilizar essa mensagem para localizar no histórico do bot, a partir de qual grupo (ID) a mensagem foi recebida.

3) Acesse o site www.hoppscotch.io

Este site gratuito nos fornece uma interface gráfica para realizarmos requisições web.

Vamos selecionar uma requisição do tipo POST para a URL: “https://api.telegram.org/bot<TOKEN>/getUpdates”.

Você lembra do token gerado pelo @botFather que pedi para guardar em lugar seguro!? Você deve substituir “<TOKEN>” pelo token do seu bot.

Em seguida, clique em “Mandar” ou “Send”, dependendo do idioma configurado em sua máquina.

4) Verificando o retorno da requisição web

A requisição que enviamos, caso esteja correta, será respondida com um primeiro campo “ok” com o valor “true”. Caso encontre algum erro nessa etapa, verifique a URL, pois possivelmente há algum erro na mesma ou quando colou o TOKEN de seu bot sobre o texto <TOKEN>.

Há um outro campo chamado “result” o que irá apresentar as atualizações de atividade mais recente do seu bot. Você deverá visualizar a mensagem que recebeu por meio do grupo criado.

Procure na resposta da requisição por um campo chamado “chat” (podem haver vários, caso tenham encaminhado mais de uma mensagem no grupo). Dentro desse campo haverá 3 subcampos: id, title e type.

Verifique se o campo title coincide com o nome do grupo que deseja encaminhar mensagens pela TraderEvolution. Caso positivo, o ID desse grupo estará no campo id (geralmente é um valor negativo).

Copie esse o valor do ID e o nome do grupo para um bloco de notas, preferencialmente, no mesmo local onde armazenou o token do seu bot. Vamos precisar dessas informações para configurar as estratégias a enviarem mensagens pelo bot para o grupo desejado.

Próximo passo...

No próximo passo iremos instalar a ferramenta de Integração TraderEvolution-Telegram, desenvolvida pela NeoTraderBot, na sua instalação da plataforma Trader Evolution.

Instalando a ferramenta na TraderEvolution

Nesse último passo de pré-configuração, iremos instalar a ferramenta da NeoTraderBot que permitirá integrar suas estratégias da TraderEvolution com grupos no Telegram.

Reproduzir vídeo

TUTORIAL - PASSO 4: Instalando a ferramenta de integração na TraderEvolution

1) Abra uma janela do Windows Explorer (Tecla de atalho: WINDOWS + E)
2) Acesse a pasta de aplicativos do seu usuário windows

Clique na barra de endereço do Windows Explorer, digite “%APPDATA%” e aperte ENTER.

3) Acesse a pasta da TraderEvolution

No diretório de aplicativos, localize a pasta “TraderEvolution Brasil” e acesse-a.

4) Cole o arquivo da ferramenta de integração dentro da pasta "TraderEvolution Brasil"

Você deverá colar o arquivo “NTB_TE_IntegrationTelegram.dll”, baixado no site da NeoTraderBot para dentro dessa pasta. Trata-se de uma biblioteca compilada da NeoTraderBot contendo os requisitos necessários para permitir a integração da TraderEvolution com Telegram.

Pré-configurações efetuadas!

Agora que já realizamos as pré-configurações, podemos incluir o código necessário dentro de nossas estratégias para realizar o envio de mensagens para o Telegram.

Confira aqui um tutorial com exemplos de código fonte para você incluir em suas estratégias e indicadores da TraderEvolution.

Perguntas Frequentes (FAQ) & Exemplos de Código

Nesta seção vamos apresentar exemplos de códigos e respostas às perguntas frequentes para que você comece a usar a integração com o Telegram de maneira mais rápida possível. Caso tenha alguma dúvida, deixe nos comentários que iremos atualizar esta seção de acordo com a demanda.

Como eu incluo a ferramenta de integração com o telegram no meu código?

O primeiro passo é instalar a ferramenta em sua plataforma TraderEvolution. Para isso, basta seguir o roteiro apresentado neste link.

Uma vez instalada a ferramenta, no seu código fonte você deve referenciar a biblioteca de Integração com Telegram (desenvolvida pela NeoTraderBot) na seção de using. Como segue abaixo:

				
					using NTB_IntegrationServices_TE;
				
			

Em seguida, instancie um objeto no para integraçao com o Telegram, conforme segue abaixo:

				
					TelegramIntegration telegramConn;
				
			

Por fim, no método Init do seu código, você pode utilizar a seguinte estrutura de inicialização da biblioteca de integração com o Telegram.

				
					try
    {
        string botToken = "INSIRA AQUI O TOKEN DO SEU BOT";
        string emailAutenticacao = "seuEmail@teste.com";
        string versaoFerramenta = "PREMIUM";
        telegramConn = TelegramIntegration.GetTelegramConn;
        telegramConn.Authenticate(emailAutenticacao, this.AccountManager.Current, versaoFerramenta);
        
        //Registra o robô, grupos e tópicos com suas IDs
        telegramConn.AddBot("NeoTraderBot", botToken);
        telegramConn.AddGroup("NeoTraderBot", "Meus códigos TraderEvolution", "-1001909578209");
        telegramConn.AddTopic("NeoTraderBot", "Meus códigos TraderEvolution", "Alarme Volatilidade", "124");
        telegramConn.AddTopic("NeoTraderBot", "Meus códigos TraderEvolution", "Carteira de ações", "2");
        telegramConn.AddTopic("NeoTraderBot", "Meus códigos TraderEvolution", "Screening Opening Range", "60");
        telegramConn.AddTopic("NeoTraderBot", "Meus códigos TraderEvolution", "Grid Trading", "57");
    }
    catch (Exception ex)
    {
        Notification.Alert("Não autenticou a ferramenta de integração com telegram: " + ex.Message);
    }
				
			

Pronto! Caso não haja problema na Autenticação do seu usuário no servidor da NeoTraderBot, você já poderá utilizar os métodos para envio de mensagens no seu código.

Ah…eu quero guardar o token do meu bot e ler a partir de um arquivo. Ok! Use o snippet abaixo, o qual fará a leitura do arquivo “meuTokenTelegram.txt” na pasta “Meus Documentos”. O arquivo contém unica e exclusivamente o token do bot.

				
								try
			{
				string botToken = "";
				string logPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "meuTokenTelegram.txt");
	            using (StreamReader inputFile = new StreamReader(logPath))
	            {
	            	botToken = inputFile.ReadLine();
	            }
				
			    string emailAutenticacao = "seuEmail@teste.com";
			    string versaoFerramenta = "FREE";
			    telegramConn = TelegramIntegration.GetTelegramConn;
			    telegramConn.Authenticate(emailAutenticacao, this.AccountManager.Current, versaoFerramenta);
			
			    //Registra o robô, grupos e tópicos com suas IDs
			    telegramConn.AddBot("NeoTraderBot", botToken);
			    telegramConn.AddGroup("NeoTraderBot", "Meus códigos TraderEvolution", "-1001909578209");
			}
			catch (Exception ex)
			{
			    Notification.Alert("Não autenticou a ferramenta de integração com telegram: " + ex.Message);
			}	
				
			

Quais são os métodos para envio de mensagens?

Uma vez instanciado um objeto, conforme instruções da pergunta anterior, você irá utilizar o método SendMessage para enviar mensagens para um grupo do Telegram ou tópicos dentro dos grupos.

Cabe ressaltar que você deve verificar se sua versão contratada possui a funcionalidade desejada. Por exemplo, a versão FREE não permite o envio de mensagens para tópicos específicos de um grupo. Ela permite o envio apenas para o tópico principal.

Assim, existem 2 sobrecargas para o método SendMessage: uma para envio de mensagem para um grupo e outra para envio de mensagem para tópico de um grupo.

OBS: É necessário adicionar as IDs e texto de identificação de grupos e tópicos, antes de enviar as mensagens. Pois os grupos e tópicos serão referenciados pelo texto de identificação fornecido.

Enviando mensagem para um Grupo | SendMessage(string botName, string groupName, string message)

No exemplo abaixo, estamos utilizando o objeto telegramConn para enviar uma mensagem utilizando o bot “NeoTraderBot” para o grupo “Meus códigos TraderEvolution”. A mensagem enviada é: “Teste de envio!”.

				
					telegramConn.SendMessage("NeoTraderBot", "Meus códigos TraderEvolution", 
                         "Teste de envio!");
				
			
Enviando mensagem para um Tópico | SendMessage(string botName, string groupName, string topicName, string message)

No exemplo abaixo, estamos utilizando o objeto telegramConn para enviar uma mensagem utilizando o bot “NeoTraderBot” para o tópico “Carteira de ações” do grupo “Meus códigos TraderEvolution”. A mensagem enviada é: “21/nov/2023 – Valor atual da carteira: R$ 89.780,00”.

				
					telegramConn.SendMessage("NeoTraderBot", "Meus códigos TraderEvolution", 
                         "Carteira de ações", 
                         "21/nov/2023 - Valor atual da carteira: R$ 89.780,00");
				
			

Posso enviar emojis nas mensagens de texto?

Sim, claro! Talvez você queira utilizar elementos visuais em suas mensagens de texto. Você pode utilizar os códigos padronizados de emojis os quais estão disponíveis em diversos sites. 

Você pode utilizar o https://emojipedia.org/ como referencia ou copiar as figuras abaixo e colar nas suas mensagens.

OBS: A renderização do emoji (figura a ser desenhada) depende do ambiente no qual está utilizando (Windows/Mac/Telegram/Facebook/Twitter…).

TEMPO:

⏰  ⏲️  ⏳

PERCEPÇÃO DO MERCADO:

🌡️   🔥   🚀  💣 😱  ❄️ 🛒

TENDÊNCIA:

🔼 🔻 📉  📈

DESTAQUES:

⭐ 👀 🔎

ANÚNCIOS:

📢 🔔

ALERTAS:

⚠️  ⛔  🛑  🟢  🔴  🔵  🟡  🟠

RESULTADO:

💰  🤑  💲 🎉 💀 💩

Eu posso enviar imagens (arquivos jpg, png,...)?

Sim. Assim como o método SendMessage permite enviar mensagens de texto, o método SendPicture permite enviar mensagens contendo imagens e uma legenda.

Também há duas sobrecargas do método SendPicture para diferenciar o envio para grupo e tópicos específicos dentro de um grupo.

Veja o exemplo abaixo no qual é enviada uma mensagem contendo uma figura localizada na máquina local (em C:\\Users\\johna\\OneDrive\\Documents\\bulls_bears.jpg) com a legenda “Aqui você escreve o caption!” para o grupo “Meus códigos TraderEvolution” utilizando o bot “NeoTraderBot”.

				
					telegramConn.SendPicture("NeoTraderBot", "Meus códigos TraderEvolution", 
                         "C:\\Users\\johna\\OneDrive\\Documents\\bulls_bears.jpg", 
                         "Aqui você escreve o caption!");
				
			

Por questões de segurança, não é possível referenciar URLs de imagens na internet para envio de mensagens. Assim, recomendamos que baixe as imagens e salve em um diretório local para referenciar em seus códigos.

Não estou conseguindo enviar mensagens. O que pode estar acontecendo?

Caso ocorra alguma inconsistência no envio de alguma mensagem, a biblioteca de integração com o telegram foi projetada para não lançar exceções a fim de não causar distúrbios na execução dos códigos do usuário. Assim, para identificar o problema precisamos eliminar as causas de maneira gradativa.

1) Problemas relacionados à Autenticação do usuário

A primeira causa para você não conseguir enviar mensagens seria algum problema relacionado ao processo de autenticação da ferramenta vinculado ao e-mail e conta do usuário. Certifique-se que a autenticação está ocorrendo adequadamente.

Caso haja alguma falha de comunicação com o servidor de autenticação ou o usuário não esteja cadastrado, isso irá gerar uma exceção ainda no método Init, antes do código iniciar o processamento.

2) Problemas relacionados ao cadastro de token do Bot

Certifique-se de que você está inserindo o token do seu Bot Telegram por meio do método AddBot com o token correto. Atente-se para as funcionalidades da sua versão contratada, pois pode haver limitação da quantidade de bots a serem utilizados em um único código.

3) Permissões do Bot nos grupos destinatários

É importante verificar se você atribuiu as permissões necessárias ao Bot dentro dos grupos destinatários. Clique aqui para ver um roteiro passo a passo de como atribuir corretamente as permissões nos grupos.

4) Problemas relacionados a vinculação de ID para grupos e tópicos

Certifique-se de que você está inserindo os IDs de grupos e seus respectivos textos de identificação (método AddGroup). Ao enviar mensagens, o destinatário deverá ser referenciado pelo mesmo texto identificador. Clique aqui para ver um roteiro passo a passo de como identificar os IDs de grupos e tópicos.

Somente após cadastrar os grupos é que você deve inserir os tópicos do grupo, utilizando o método AddTopic.

Atente-se para as restrições da sua versão em uso, pois podem haver limitações de envio para mais de um grupo ou tópicos dentro dos grupos.

Por fim, certifique-se que as IDs de grupos e tópicos foram devidamente incluídas nos métodos AddGroup e AddTopic.

Sugestão: Inicie um código simples de indicador e insira apenas o código necessário para instanciar a sua conexão com a ferramenta de integração do Telegram e enviar uma única mensagem para um grupo. Uma vez validado esse funcionamento básico, você pode ir aos poucos incluindo outras tarefas no código e copiar essa estrutura para dentro dos seus códigos que deseja integrar com o Telegram.

Como enviar mensagens apenas quando minha estratégia/robô estiver analisando dados em tempo real?

Este controle de fluxo deve ser implementado pelo próprio usuário, pois a ferramenta foi criada para ser flexivel o suficiente para rodar em dados históricos em casos de inicializações com o mercado já aberto e envio de informações referentes a por exemplo a abertura do mercado.

Você possivelmente sabe que o código é processado algumas vezes para cada barra histórica, iniciando na barra mais antiga de dado disponível. As barras são percorridas sequencialmente até chegarmos a última barra, a qual se o mercado estiver aberto, estará sendo atualizada em tempo real.

Assim, para criar um controle de fluxo, no qual você irá enviar mensagens pelo Telegram apenas na última barra do gráfico, ou seja, na barra em tempo real, precisamos declarar uma variável auxiliar no seu código, conforme segue abaixo:

				
					private bool realTime;
				
			

Em seguida, insira no método Update de seu código a estrutura abaixo. Ela permitirá identificar em que momento seu código passará a processar barras em tempo real. Assim, basta você inserir a ação que deseja executar no fechamento da barra ou a cada nova cotação.

				
					public override void Update(TickStatus args)
{
    if (!realTime && (args == TickStatus.IsBar))
    { realTime = true; }
    else
    {
        if (args == TickStatus.IsQuote)   
        {
            //Insira aqui o que deseja executar sempre que tem nova cotação
        }
        else
        if (args == TickStatus.IsBar)
        {
            //Insira aqui o que deseja executar no fechamento da barra
        }
    }
}
				
			

Como eu posso fazer minha estratégia mandar mensagens pelo Telegram?

O código de estratégia abaixo é meramente ilustrativo, mas você pode copiar e rodar em sua conta de simulação na Trader Evolution. O que ele faz basicamente é a cada timeSpaceMinutes (parâmetro da estratégia) verificar se há uma posição aberta e se não houver a estratégia irá comprar ou vender (aleatoriamente) colocando ordens de stop e alvo em ticks, conforme definido nos parâmetros.

As mensagens enviadas para o telegram, nesse caso, foram realizadas sempre que uma ordem é posicionada e executada, bem como quando uma posição é aberta e encerrada. No exemplo, utilizamos sobrecarga de métodos nos eventos já disponíveis no EvoCode. Mas você pode encaminhar mensagens pelo Telegram nas condições que desejar.

				
					using System;
using Runtime.Script;
using TradeApi;
using TradeApi.History;
using TradeApi.Instruments;
using TradeApi.ToolBelt;
using TradeApi.Trading;
using NTB_IntegrationServices_TE;

namespace NeoTraderBotExemplos
{
    public class TimeSpacedOrdersExample : StrategyBuilder
    {
        [InputParameterAttribute(InputType.Color, "Abrir posição a cada (minutos)", 2)]
        [SimpleNumeric(1D, 2400D)]
        public int timeSpaceMinutes = 2;

        [InputParameterAttribute(InputType.Color, "Tamanho da exposição", 3)]
        [SimpleNumeric(1D, int.MaxValue)]
        public int orderQty = 1;

        [InputParameterAttribute(InputType.Color, "OCO - Stoploss (TICKS)", 4)]
        [SimpleNumeric(1D, int.MaxValue, 0, 1)]
        public int stoplossTicks = 10;

        [InputParameterAttribute(InputType.Color, "OCO - Take profit (TICKS)", 5)]
        [SimpleNumeric(1D, int.MaxValue, 0, 1)]
        public int takeProfitTicks = 10;

        TelegramIntegration telegramConn;

        BarData dadosCandle;
        private bool realTime;
        private double positionSize;
        private Random rndSignal;
        public TimeSpacedOrdersExample()
            : base()
        {
            #region Initialization
            Credentials.Author = "Johnathas Carvalho";
            Credentials.Company = "NeoTraderBot";
            Credentials.Copyrights = "NeoTraderBot";
            Credentials.DateOfCreation = new DateTime(2023, 10, 07);
            Credentials.ExpirationDate = DateTime.MinValue;
            Credentials.Version = "1.0";
            Credentials.Password = "66b4a6416f59370e942d353f08a9ae36";
            Credentials.ProjectName = "Estratégia integrada com Telegram";
            #endregion

            SeparateWindow = false;
        }
        public override void Init()
        {
            try
            {
                string botToken = "INSIRA SEU TOKEN AQUI";
                telegramConn = TelegramIntegration.GetTelegramConn;
                telegramConn.Authenticate("seuEmail@gmail.com", this.AccountManager.Current, "SUA VERSAO CONTRATADA");
                telegramConn.AddBot("NeoTraderBot", botToken);
                telegramConn.AddGroup("NeoTraderBot", "Meus códigos TraderEvolution", "INSIRA O ID DO SEU GRUPO AQUI");
            }
            catch (Exception ex)
            {
                Notification.Alert("Não autenticou a ferramenta de integração com telegram: " + ex.Message);
            }

            dadosCandle = (HistoryDataSeries as BarData);
            realTime = false;

            OrdersManager.OnFill += OnOrderFill;
            OrdersManager.OnPlace += OnOrderPlaced;
            PositionsManager.OnOpen += OnOpenPosition;
            PositionsManager.OnClose += OnClosePosition;

            //Gestão de posição
            positionSize = 0;
            
            //Geração de sinais aleatórios
            rndSignal = new Random();

        }

       public override void Update(TickStatus args)
        {

            if (!realTime && (args == TickStatus.IsBar))
            {
                realTime = true;
            }

            if (realTime)
            {
                if (args == TickStatus.IsQuote)   //Atua sempre que tem nova cotação
                {
                    
                }
                else
                if (args == TickStatus.IsBar)    //Atua no fechamento da barra
                {
                    positionSize = GetPositionSize();

                    if ((positionSize == 0) && ( ((dadosCandle.GetTimeUtc().TimeOfDay.TotalMinutes - 9*60) % timeSpaceMinutes) == 0))
                    {
                        if (rndSignal.Next(0, 2) == 0)
                            BuyAtMarket(orderQty, CalculationMode.TICKS, takeProfitTicks, stoplossTicks);
                        else SellAtMarket(orderQty, CalculationMode.TICKS, takeProfitTicks, stoplossTicks);
                    }
                }
            }
        }

        public override void Complete()
        {
            OrdersManager.OnFill -= OnOrderFill;
            OrdersManager.OnPlace -= OnOrderPlaced;

            PositionsManager.OnOpen -= OnOpenPosition;
            PositionsManager.OnClose -= OnClosePosition;

            telegramConn.SendMessage("NeoTraderBot", "Meus códigos TraderEvolution", "A estratégia exemplo de ordens espaçadas no tempo foi encerrada.");
        }

        private TradeResult BuyAtMarket(int qty, CalculationMode mode, double takeProfitUnits, double stoplossUnits)
        {
            OrderRequest request = null;
            TradeResult order;

            request = new OrderRequest(OrderType.Market,
                InstrumentsManager.Current,
                AccountManager.Current,
                OrderSide.Buy, quantity: qty)
            {
                SLTPPriceType = SLTPPriceType.Ticks,
                StopLossPrice = stoplossUnits,
                TakeProfitPrice = takeProfitUnits
            };

            order = OrdersManager.Send(request);
            return order;
        }

        private TradeResult SellAtMarket(int qty, CalculationMode mode, double takeProfitUnits, double stoplossUnits)
        {
            OrderRequest request = null;
            TradeResult order;

            request = new OrderRequest(OrderType.Market,
                InstrumentsManager.Current,
                AccountManager.Current,
                OrderSide.Sell, quantity: qty)
            {
                SLTPPriceType = SLTPPriceType.Ticks,
                StopLossPrice = stoplossUnits,
                TakeProfitPrice = takeProfitUnits
            };

            order = OrdersManager.Send(request);
            return order;
        }

        private void ClosePositions()
        {
            OrderRequest request = null;

            foreach (Position p in PositionsManager.GetPositions())
            {
                request = new OrderRequest(OrderType.Market, InstrumentsManager.Current, AccountManager.Current, (p.Side == PositionSide.Long) ? OrderSide.Sell : OrderSide.Buy, p.Quantity);
                OrdersManager.Send(request);
            }
        }

        private double GetPositionSize()
        {
            double posSize = 0;
            foreach (Position p in PositionsManager.GetPositions(po => po.Instrument == InstrumentsManager.Current))
            {
                Notification.Alert("Posição é de " + p.Quantity);
                posSize += ((p.Side == PositionSide.Long) ? 1 : -1) * p.Quantity;
            }

            return posSize;
        }


        #region callback for Orders and Position events
        private void OnOrderFill(Order order)
        {
            double price = (AccountManager.Current.Name.ToUpper().Contains("DEMO")) ? order.Price : order.AverageFilledPrice;
            double quantity = (AccountManager.Current.Name.ToUpper().Contains("DEMO")) ? order.Quantity : order.FilledQuantity;

            string msg = "Foi executada uma " + ((order.Side == OrderSide.Buy) ? "compra" : "venda") + $" de {quantity} @ {price}";
            telegramConn.SendMessage("NeoTraderBot", "Meus códigos TraderEvolution", ((order.Side == OrderSide.Buy) ? "🔼" : "🔻") + " " + msg);
        }

        private void OnOrderPlaced(Order order)
        {
            double price = order.Price;
            double quantity = order.Quantity;

            string msg = "Foi apregoada uma ordem de " + ((order.Side == OrderSide.Buy) ? "compra" : "venda") + $" de {quantity} @ {price}";
            telegramConn.SendMessage("NeoTraderBot", "Meus códigos TraderEvolution", "👀" + " " + msg);
        }

        private void OnOpenPosition(Position position)
        {
            string msg = "Foi aberta uma posição " + ((position.Side == PositionSide.Long ? "comprada" : "vendida")) + $" de {position.Quantity} @ {position.OpenPrice}";
            telegramConn.SendMessage("NeoTraderBot", "Meus códigos TraderEvolution", "⚠️" + " " + msg);
        }

        private void OnClosePosition(Position position)
        {
            string msg = "Foi encerrada uma posição " + ((position.Side == PositionSide.Long ? "comprada" : "vendida")) + $" de {position.Quantity} com resultado líquido de {position.NetPnL}";
            telegramConn.SendMessage("NeoTraderBot", "Meus códigos TraderEvolution", ((position.NetPnL >= 0) ? "🟢" : "🔴") + " " + msg);

        }

        #endregion

        private enum CalculationMode
        {
            PRICE,
            TICKS,
            PERCENTAGE,
        }

    }
}
				
			

Como instalar o Pacote de Indicadores GRATUITOS?

Se você está nessa página é porque provavelmente recebeu um e-mail contendo as instruções para instalação do PACOTE DE INDICADORES GRATUITOS para TRADER EVOLUTION desenvolvidos pela NeoTraderBot e RNEC indicadores.

Caso queira baixar o pacote de indicadores, clique no botão abaixo.

Localizando o diretório de instalação da Trader Evolution

1) Acesse o Windows Explorer e digite na barra de navegação %APPDATA% e aperte ENTER. Localize o diretório “Trader Evolution Brasil”.

2) Dentro do diretório “Trader Evolution Brasil” acesse as pastas “Scripts” -> “Indicadores”.

3) Dentro da pasta “Indicators” você irá visualizar os indicadores da Trader Evolution instalados nativamente em seu computador. Devemos extrair o conteúdo do arquivo zip do PACOTE DE INDICADORES para esta pasta.

4) Pronto! Agora os indicadores já podem ser aplicados aos gráficos dentro da Plataforma Trader Evolution!

Indicadores para Trader Evolution

Aqui você irá encontrar informações dos indicadores desenvolvidos pela NeoTraderBot para plataforma TraderEvolution.

Os indicadores são disponibilizados em versões FREE, TRADER ou PREMIUM, nas quais há diferença de funcionalidades conforme apresentado nessa documentação.

Todos os indicadores são contratados por meio de licença individual de uso. As licenças são vinculadas ao login de acesso do usuário à plataforma TraderEvolution.

Os indicadores podem ser contratados no modelo de assinatura por meio de pagamento recorrente mensal ou por meio de uma licença vitalícia de uso, a qual irá garantir ao usuário acesso às atualizações que forem realizadas na versão contratada.

A contratação dos indicadores NÃO CONTEMPLA ACESSO AO CÓDIGO FONTE.

Caso tenha interesse em aprender a programar seus próprios indicadores para Trader Evolution, sugerimos realizar o curso de Programação em EvoCode disponível nesse link.

Janelas de negociação

Nos frameworks é possível configurar uma janela temporal para aplicação das ordens advindas dos sinais do robô-trader. Assim, o usuário pode controlar o período do dia em que as posições podem ser abertas.

Na versão LIGHT o usuário pode configurar apenas 1 janela de negociação, ao passo que na versão THUNDER, o usuário pode configurar até 4 janelas de negociação.

Caso o robô-trader esteja configurado para executar em um tempo gráfico com periodicidade acima da diária, as configurações de janela de negociação não serão aplicáveis, dada a impossibilidade de gerir o funcionamento da estratégia dentro de uma barra em ambiente de backtesting com dados históricos OHLCV de maneira confiável (condições de funcionamento do Editor de Estratégia da Nelogica).

pJanelaNegocIni0X (integer)
  LIGHT       THUNDER  

Este parâmetro recebe um horário no formato HHMM para definir a partir de qual horário uma posição pode ser aberta. O horário utilizado para esta funcionalidade é o retorno da função nativa da ntsl “Time”, a qual retorna o horário de abertura da barra.

pJanelaNegocFim0X (integer)
  LIGHT       THUNDER  

Este parâmetro recebe um horário no formato HHMM para definir até qual horário  uma posição pode ser aberta. O horário utilizado para esta funcionalidade é o retorno da função nativa da ntsl “Time”, a qual retorna o horário de abertura da barra.

Recursos gráficos

Os frameworks possuem a funcionalidade de plotar as linhas de stoploss, alvo, gatilho de breakeven, gatilho de stop móvel e preço médio da posição, bem como aplicar coloração quando os sinais definidos pelo usuário forem satisfeitos e estiverem em condição adequada para que ordens sejam roteada, conforme pode ser observado na figura abaixo.

pPlotarLinhasOCO (boolean)
  LIGHT       THUNDER  

Quando true, este parâmetro irá habilitar o plot das linhas de stoploss (sólida na cor vermelho), alvo da operação (sólida na cor azul), preço médio da posição (sólido na cor branca) e os níveis de preço dos gatilhos de breakeven (tracejada na cor amarelo) e stop móvel (tracejada na cor vermelho escuro), enquanto os mesmos não forem acionados.

pPintarBarrasDeSinal (boolean)
  LIGHT       THUNDER  

Quando true, este parâmetro irá habilitar a funcionalidade de colorir as barras de sinal configuradas pelo usuário e que esteja em condições adequadas para execução:

        • Sinal de compra pintará a barra de verde caso não haja posição aberta;
        • Sinal de venda pintará a barra de vermelho caso não haja posição aberta;
        • Sinal de reversão pintará a barra de amarelo caso haja posição aberta;
        • Sinal de fechamento pintará a barra de azul caso haja posição aberta.

Grid de Cotações na TraderEvolution [Aprenda a criar vinculo com um gráfico]

Reproduzir vídeo

Neste vídeo da séria “Conhecendo a Trader Evolution” vamos explorar a funcionalidade GRID DE COTAÇÕES, por meio da qual você poderá criar uma lista com ativos a serem acompanhados e vincular esta tabela com um gráfico para inspeção rápida.

Construtor de Capital - Liberação de acesso a Ferramentas

Este tutorial visa apresentar o passo a passo para liberação de acesso aos alunos/assinantes das ferramentas desenvolvidas pela NeoTraderBot para Construtor de Capital

Uma vez enviada a MachineID por meio do formulário ao final desta página, a liberação de acesso está condicionada à confirmação de vinculo (aluno) junto à Construtor de Capital e será realizada em até 1 dia útil.

Em caso de dúvidas ou questões relacionadas às ferramentas Construtor de Capital, envie e-mail para contrutordecapital1@gmail.com.

Gerando o seu MachineID

Passo 1: No Control Center, clique em “Help” -> “3rd Party Licensing”.

Passo 2: Na tela que abrir, você deve digitar “NeoTraderBot” no campo “Vendor name” e inserir o seu e-mail no campo “User defined ID”, ou em caso de erro por caracteres especiais, insira o seu nome completo sem espaços ou acentos e em letra minúscula. EM SEGUIDA, CLIQUE EM “SUBMIT” (ENVIAR).

Será gerada uma chave de Machine ID, a qual você deve copiar e enviar para nós, por meio do formulário a seguir. 

ATENÇÃO: Copie a chave completa (ela será composta também pelas informações que você inseriu no campo User defined ID (ID do usuário).

Liberação de Acesso - Ferramentas Construtor de Capital
Este formulário visa recepcionar as chaves dos usuários para liberação de uso das ferramentas e códigos desenvolvidos pela NeoTraderBot para Construtor de Capital

MetaTrader

Esta biblioteca contém material introdutório sobre programação em MQL5 e a plataforma MetaTrader, para que você inicie sua jornada de implementação de estratégias automatizadas de forma objetiva e gradual em uma das melhores plataformas do mercado mundial.

Programando em MQL5

Nesta seção iremos abordar os conceitos básicos e necessários para implementação de programas em MQL5 para plataforma MetaTrader.

Conhecendo a IDE Meta Editor

Reproduzir vídeo

Este vídeo visa apresentar o ambiente de programação MQL5 da MetaTrader: o MetaEditor 5.

O MetaEditor é uma IDE (Integrated Development Environment), um ambiente no qual os usuários podem escrever código fonte e desenvolver robôs, indicadores, scripts, serviços e outros programas em MQL5.

Todos os códigos são escritos em MQL5 (MetaQuotes Language 5), uma linguagem baseada em C++ que suporta orientação a objeto e tratamento de eventos. Recomendamos a leitura da Documentação MQL5 no link  https://www.mql5.com/en/docs.

Caso deseje antecipar seus estudos para os conteúdos dos próximos vídeos, indico a leitura dos itens “MQL5 Programs” e “Program running”, no link a seguir. Caso deseje, alterne o idioma para português. https://www.mql5.com/en/docs/runtime

Tipos de Programas, Fluxo de execução e Eventos Pré-definidos

Reproduzir vídeo

Este vídeo visa apresentar os tipos de programas possíveis da plataforma MetaTrader e como eles são executados.

Os tipos de programas possíveis de codificar em MQL5 são: serviço, script, expert advisor (EA) e indicador. Iremos abordar detalhes relacionados a forma de execução, single thread ou multi-thread, bem como explicar como é o fluxo de execução desses programas.

Explicaremos o conceito de fila de eventos, o seu funcionamento e quais são os eventos pré-definidos na linguagem para o utilização pelos programas.

Saber como um código é processado, suas características e como é o fluxo de execução é fundamental para que um programador e trader possa desenvolver um código fonte de qualidade e alcançar seus objetivos de maneira eficiente na criação de robôs e indicadores.

Sempre recomendamos a leitura da Documentação MQL5, no link abaixo, pois há muita informação relevante sobre a plataforma MetaTrader. https://www.mql5.com/en/docs.

Ferramentas de Trading

Construtor de Capital – Liberação de acesso à Gamma Levels

Este tutorial visa apresentar o passo a passo para configuração e liberação de acesso aos alunos/assinantes das ferramentas desenvolvidas pela NeoTraderBot para Construtor de Capital na plataforma Meta Trader 5 (MT5). 

Uma vez enviadas as informações de e-mail da assinatura do indicador e número da conta da corretora Exness, a liberação de acesso está condicionada à confirmação de vinculo (aluno) junto à Construtor de Capital e será realizada em até 1 dia útil.

Em caso de dúvidas ou questões relacionadas às ferramentas Construtor de Capital, envie e-mail para contrutordecapital1@gmail.com.

Pré-configurações da MetaTrader

Passo 1: Abra o MetaTrader, vá no menu “Ferramentas” -> “Opções”.

Passo 2: Na tela que abrir, vá na aba “Expert Advisors” e em seguida marque a opção “Relacione no quadro abaixo as URL que deseja permitir a função WebRequest”. Insira na tabela a seguinte URL:

https://drive.usercontent.google.com/

Em seguida, clique em “OK”.

Instalação do Gamma Levels

Existem duas formas de instalar o Gamma Levels na MetaTrader. Recomenda-se que tente-se instalar pela forma 1 (mais simples). Caso o usuário tenha  conhecimento mais aprofundado sobre a plataforma MT5 e/ou tenha mais de uma instalação de MT5 na mesma máquina, pode-se instalar seguindo as instruções da Forma 2.

Forma 1: Ao receber o arquivo GammaLevelsCC_VXX.ex5 (onde XX é a versão da ferramenta), basta clicar duas vezes que o indicador será automaticamente instalado na MetaTrader.

Uma vez instalado, acesse a janela “Navegador” do MetaTrader e você verá dentro de “Consultor Expert” a ferramenta GammaLevels.

Forma 2: Abra o Windows Explorer e digite na barra de navegação %APPDATA%. A partir daí navegue até a pasta MetaQuotes -> Terminal -> Selecione a instalação desejada -> MQL5 -> Experts. 

Copie o arquivo GammaLevelsCC_VXX.ex5 (onde XX é a versão da ferramenta), para dentro dessa pasta e a ferramenta GammaLevels estará disponível nessa instalação específica do MT5.

Informações necessárias para ativação do Gamma Levels

Para realizar a ativação da ferramenta Gamma Levels para MT5, o usuário precisa enviar pelo formulário no final dessa página, o e-mail pelo qual realizou a assinatura do indicador e o número da conta da corretora. 

A informação de número da conta é obtida na janela “Navegador” -> Contas do MT5, conforme pode ser visto abaixo.

Inserindo o Gamma Levels em um gráfico

Uma vez, enviada a solicitação de ativação e confirmada a ativação pelo Construtor de Capital no e-mail informado, o usuário deve realizar os seguintes passos para incluir os níveis gamma em um gráfico.

Passo 1: Abra um gráfico no ativo desejado. Clique sobre o GammaLevels na aba Navegador, arraste e solte dentro do gráfico no qual deseja plotar os níveis Gamma.

Passo 2: Será aberta uma janela com informações do GammaLevels. Habilite a a opção “Permitir algotrading” e, em seguida, acesse a aba “Parâmetros de entrada”.

OBS: O GammaLevels não realiza nenhum tipo de operação automatizada.

Passo 3: Na aba de parâmetros, insira no campo apropriado o seu e-mail de assinatura da ferramenta GammaLevels. Nesta tela o usuário poderá configurar diversas propriedades de exibição de níveis, filtro de níveis por opções, agrupamento de níveis próximos e alarmes de cruzamento de níveis.

Recomenda-se que o usuário salve as configurações em um arquivo para reutilizar suas configurações. Assim, não é necessário configurar tudo novamente caso acrescente o indicador em outro gráfico. Para carregar uma pré-configuração de parâmetros do indicador, utilize a opção “Abrir”.

Clique em “OK”.

Passo 4: Uma vez configurado, o usuário poderá ver detalhes da execução da ferramenta na aba “Experts” em “Caixa de Ferramentas”, logo abaixo do gráfico. Caso a autenticação tenha sido efetuada corretamente, os níveis serão plotados no gráfico com o texto no lado direito. No canto superior direito do gráfico, o usuário verificará o texto “GammaLevelsCC” indicando que a ferramenta está aplicada naquele gráfico.

Liberação de Acesso - Ferramentas Construtor de Capital MT5
Este formulário visa recepcionar as chaves dos usuários para liberação de uso das ferramentas e códigos desenvolvidos pela NeoTraderBot para Construtor de Capital na plataforma Meta Trader 5 (MT5)

Outros Snippets

Esta seção visa apresentar outros exemplos de trechos de códigos que não se enquadram nas categorias anteriores.

Você pode acessar os Snippets diretamente pelo menu lateral direito, ou fazendo CRL+F (CTRL+L) para localizar algum texto específico na página, uma vez que o conteúdo tende a crescer ao longo do tempo, dificultando a navegação pelo menu.

Caso tenham sugestões de código para acrescentar à lista, gentileza deixar o código nos comentários com o link para seu perfil em rede social (para devido crédito de autoria).

Snippets

Como escrever log com o horário de abertura da candle/barra para facilitar depuração (debug)?

Gerar log de execução de uma estratégia é a melhor forma de rastrear possíveis problemas de lógica ou de execução quando seu robô já está operando. Segue abaixo um trecho que identifica no texto a ser escrito no log o dia/hora início da barra/candle.

OBS: Uma maneira muito efetiva de depurar problemas no seu NinjaScript é utilizar a depuração no Visual Studio! Esta é a maneira recomendável de se aprofundar no estudo de problemas do seu NinjaScript.

				
					string msg = "Mensagem de Teste;
NinjaTrader.Code.Output.Process(Time[0].ToString() + " - " + msg, PrintTo.OutputTab2);
				
			

Da maneira acima, você pode selecionar em qual aba da janela de saída gostaria de imprimir a mensagem de log. Abaixo tem um forma resumida de escrever na saída 1.

				
					string msg = "Mensagem de Teste;
Print(Time[0].ToString() + " - " + msg);
				
			

Outros Snippets

Esta seção visa apresentar outros exemplos de trechos de códigos que não se enquadram nas categorias anteriores.

Você pode acessar os Snippets diretamente pelo menu lateral direito, ou fazendo CRL+F (CTRL+L) para localizar algum texto específico na página, uma vez que o conteúdo tende a crescer ao longo do tempo, dificultando a navegação pelo menu.

Caso tenham sugestões de código para acrescentar à lista, gentileza deixar o código nos comentários com o link para seu perfil em rede social (para devido crédito de autoria).

Snippets

Como escrever log com o horário de abertura da candle/barra para facilitar depuração (debug)?

Reproduzir vídeo

Gerar log de execução de uma estratégia é a melhor forma de rastrear possíveis problemas de lógica ou de execução. Segue abaixo um trecho que identifica no texto a ser escrito no log o dia/hora início da barra/candle.

				
					DateTime datahora = HistoryDataSeries.GetTimeUtc(0);
datahora = datahora.ToLocalTime();
Notification.Print("[" + datahora.ToString() + "] " + msg);
				
			

Como gerar Alertas durante a execução da sua estratégia?

Outra forma de sinalizar problemas ou situações que mereçam mais atenção é por meio de alertas. Na Trader Evolution, os alertas são apresentados em uma janela próprio e o usuário pode ver o histórico de alertas.

				
					Notification.Alert(msg);
				
			

Como adicionar Indicadores aos gráficos

Reproduzir vídeo

Neste video iremos demonstrar passo-a-passo como incluir indicadores em gráficos na Plataforma NinjaTrader.

Iremos apresentar exemplos de indicadores técnicos disponíveis na versão gratuita. A Plataforma permite configurar e personalizar todas formas diferentes de subgráficos e multigráficos que expande bastante a capacidade analítica na leitura de gráficos e permite uma flexibilidade muito grande para plotagem de indicadores customizados.

Este é um conteúdo informativo sobre NinjaTrader para que os membros da comunidade tenham informações do que é possível realizar em outros ambientes.

Reforço que não estamos realizando nenhuma recomendação para mudança de Plataforma e que a decisão de migrar parte ou todo o processo de desenvolvimento e execução das estratégias automatizadas é muito pessoal e cabe apenas ao trader decidir sobre tal assunto.

TraderEvolution

Conhecendo a Trader Evolution

Conheça a plataforma e suas funcionalidades da Interface gráfica.

Introdução a Plataforma TraderEvolution

Reproduzir vídeo

Neste vídeo vamos iniciar uma série sobre a plataforma TraderEvolution.

Apresentaremos informações básicas sobre a plataforma, como contratar e custo de utilização.

Nos próximos vídeos iremos nos aprofundar nas funcionalidades da plataforma, cobrindo desde configuração de gráficos, Times & Sales, Grade de cotações, etc…O nosso objetivo é entender em profundidade a plataforma para que possamos iniciar nossas implementações de robôs e estratégias em EvoCode (C#).

CHART TRADING - Operando pelo Gráfico na Trader Evolution

Reproduzir vídeo

Neste vídeo da séria “Conhecendo a Trader Evolution” vamos explorar a funcionalidade CHART TRADING, em outras palavras, vamos operar pelo gráfico. Esta é uma funcionalidade bem interessante na plataforma devido à sua facilidade de uso e possiblidade de abrir posições ou enviar ordens com apenas um clique.

Explorando a Interface Gráfica e PRINCIPAIS FUNCIONALIDADES da Trader Evolution

Reproduzir vídeo

Neste segundo vídeo da séria “Conhecendo a Trader Evolution” vamos explorar de maneira geral a interface gráfica da Plataforma, para que tenhamos uma noção de onde encontrar as ferramentas principais.

Sinalize na plataforma o código “NEOTRADERBOT” para indicar que faz parte da Comunidade e podermos verificar benefícios especiais aos membros! (No menu principal, vá em “Mais”, em seguida “Indique parceiro”)

Gráficos na TraderEvolution [PARTE 1- Configuração e Funcionalidades]

Reproduzir vídeo

Neste vídeo da séria “Conhecendo a Trader Evolution” vamos explorar as configurações e funcionalidades básicas de Gráficos. Vamos ver como configurar a série de dados do gráfico, a representação gráfica, o tamanho da janela histórica, como personalizar as cores de barras, fundo e outra propriedades.

Também veremos como incluir o volume das barras, adicionar o Volume Profile e Livro visual no gráfico. Ao final, demonstraremos como salvar um modelo de gráfico para ser reutilizado posteriormente e onde os arquivos de templates ficam armazenados.

Caso queira fazer o download da configuração realizada nesse vídeo, basta baixar o arquivo abaixo e descompactar na pasta indicada no vídeo.

      🤖 https://github.com/johnathas/NeoTrade…

Gráficos na TraderEvolution [PARTE 2- Configuração e Funcionalidades]

Reproduzir vídeo

Neste vídeo da séria “Conhecendo a Trader Evolution” vamos explorar as configurações e funcionalidades básicas de Gráficos.

Nesta segunda parte iremos demonstrar como incluir estudos em gráficos, criar e gerenciar alarmes, inserir indicadores, operar pelo gráfico e exibir os trades realizados no gráfico.

Grade de Gráficos na TraderEvolution [Monitorando o mercado]

Reproduzir vídeo

Neste vídeo da séria “Conhecendo a Trader Evolution” vamos explorar a funcionalidade GRADE DE GRÁFICOS, por meio da qual você poderá monitorar o mercado. Esta funcionalidade é análoga a “Visão de Mercado” do Profit Chart e do “Market Watch” da Ninja Trader.

Grid de Cotações na TraderEvolution [Aprenda a criar vinculo com um gráfico]

Reproduzir vídeo

Neste vídeo da séria “Conhecendo a Trader Evolution” vamos explorar a funcionalidade GRID DE COTAÇÕES, por meio da qual você poderá criar uma lista com ativos a serem acompanhados e vincular esta tabela com um gráfico para inspeção rápida.

CRIE ALERTAS E DISPARE ORDENS AUTOMATICAMENTE na Trader Evolution

Reproduzir vídeo

Neste vídeo da séria “Conhecendo a Trader Evolution” vamos explorar a funcionalidade do GERENCIADOR DE ALARME, o qual nos permite criar alertas de som, pop-up ou até mesmo disparar ordens automaticamente quando o alerta for emitido. Detalhe importante é que a ordem pode ser emitida em outro ativo diferente do ativo que gerou o alerta.

RELATÓRIO DE DESEMPENHO – Acompanhe os resultados das suas operações na Trader Evolution

Reproduzir vídeo

Neste vídeo da séria “Conhecendo a Trader Evolution” vamos explorar o Relatório de Desempenho no qual o trader pode avaliar as operações (trades) realizados na plataforma, de maneira individual (por ativo negociado) e agregada.

COMO CONFIGURAR E OPERAR PELO BOOK DE OFERTAS [Trader Evolution]

Reproduzir vídeo

Neste vídeo da séria “Conhecendo a Trader Evolution” vamos explorar o BOOK DE OFERTAS. Esta ferramenta nos permite ter uma visão do segundo nível do mercado, vendo o interesse de compra e venda por nível de preço ou por participante do mercado. Além disso é possível operar diretamente pelo Book de Ofertas, conforme demonstração realizada nesse vídeo.

Não se esqueça de indicar a Comunidade NeoTraderBot como parceiro na Plataforma TraderEvolution. Vá no menu superior em “Mais” – “Extensões” – “Indique parceiro” e digite o código “NEOTRADERBOT”.

Assim, você reforça sua participação na Comunidade e nos ajuda a pleitear novas funcionalidades e melhorias na plataforma visando o benefício de todos os membros em suas automatizações e desenvolvimento de estratégias.

EXPLORANDO O TIMES & SALES da Trader Evolution [Monitore as negociações do mercado]

Reproduzir vídeo

Neste vídeo da séria “Conhecendo a Trader Evolution” vamos explorar a ferramenta de TIMES & SALES. Esta ferramenta nos permite visualizar as negociações realizadas entre os participantes de mercado. Podemos realizar filtros de quantidade de lotes por negócio de forma a enxergar movimentações maiores e que se observadas na atuação de vários participantes pode sinalizar um interesse predominante do mercado em uma direção.

Não se esqueça de indicar a Comunidade NeoTraderBot como parceiro na Plataforma TraderEvolution. Vá no menu superior em “Mais” – “Extensões” – “Indique parceiro” e digite o código “NEOTRADERBOT”.

Assim, você reforça sua participação na Comunidade e nos ajuda a pleitear novas funcionalidades e melhorias na plataforma visando o benefício de todos os membros em suas automatizações e desenvolvimento de estratégias.

SuperDOM na Trader Evolution [Conheça o mercado em profundidade]

Reproduzir vídeo

Neste vídeo da séria “Conhecendo a Trader Evolution” vamos explorar a ferramenta de SuperDOM. A sigla DOM vem do inglês “Depth of Market”. É uma expressão para os dados de book de ofertas que são os registros de ordens limitadas de compra e venda (o interesse aberto dos participantes do mercado). Pelo SuperDOM é possível realizar operações de abertura e fechamento de posição, bem como administrar uma operação aberta.

Não se esqueça de indicar a Comunidade NeoTraderBot como parceiro na Plataforma TraderEvolution. Vá no menu superior em “Mais” – “Extensões” – “Indique parceiro” e digite o código “NEOTRADERBOT”.

Assim, você reforça sua participação na Comunidade e nos ajuda a pleitear novas funcionalidades e melhorias na plataforma visando o benefício de todos os membros em suas automatizações e desenvolvimento de estratégias.

Boleta e Matrix na Trader Evolution [+1 ferramenta para analisar o nível II do mercado]

Reproduzir vídeo

Neste vídeo da séria “Conhecendo a Trader Evolution” vamos explorar a BOLETA e a ferramenta MATRIX. Pela ferramenta MATRIX, o trader possui mais uma opção para visualizar os dados de Nível II do mercado.

Não se esqueça de indicar a Comunidade NeoTraderBot como parceiro na Plataforma TraderEvolution. Vá no menu superior em “Mais” – “Extensões” – “Indique parceiro” e digite o código “NEOTRADERBOT”.

Assim, você reforça sua participação na Comunidade e nos ajuda a pleitear novas funcionalidades e melhorias na plataforma visando o benefício de todos os membros em suas automatizações e desenvolvimento de estratégias.

Ferramenta SCALPER da Trader Evolution

Reproduzir vídeo

Neste vídeo da séria “Conhecendo a Trader Evolution” vamos explorar a ferramenta de SCALPER.

Não se esqueça de indicar a Comunidade NeoTraderBot como parceiro na Plataforma TraderEvolution. Vá no menu superior em “Mais” – “Extensões” – “Indique parceiro” e digite o código “NEOTRADERBOT”.

Assim, você reforça sua participação na Comunidade e nos ajuda a pleitear novas funcionalidades e melhorias na plataforma visando o benefício de todos os membros em suas automatizações e desenvolvimento de estratégias.

Ferramenta MESTRE DE OPÇÕES da Trader Evolution

Reproduzir vídeo

Neste vídeo da séria “Conhecendo a Trader Evolution” vamos explorar a ferramenta MESTRE DE OPÇÕES.

Não se esqueça de indicar a Comunidade NeoTraderBot como parceiro na Plataforma TraderEvolution. Vá no menu superior em “Mais” – “Extensões” – “Indique parceiro” e digite o código “NEOTRADERBOT”.

Assim, você reforça sua participação na Comunidade e nos ajuda a pleitear novas funcionalidades e melhorias na plataforma visando o benefício de todos os membros em suas automatizações e desenvolvimento de estratégias.

Como configurar ativos sintetizados na Trader Evolution

Reproduzir vídeo

Neste vídeo da séria “Conhecendo a Trader Evolution” vamos explorar a possibilidade de criação de um ativo personalizado: um ativo sintetizado. Com este ativo é possível operar vários papeis ou contratos ao mesmo tempo, operacionar estratégias de LONG & SHORT, operar arbitragem, entre outras possibilidades.

Não se esqueça de indicar a Comunidade NeoTraderBot como parceiro na Plataforma TraderEvolution. Vá no menu superior em “Mais” – “Extensões” – “Indique parceiro” e digite o código “NEOTRADERBOT”.

Assim, você reforça sua participação na Comunidade e nos ajuda a pleitear novas funcionalidades e melhorias na plataforma visando o benefício de todos os membros em suas automatizações e desenvolvimento de estratégias.

Como utilizar o IBOV ONLINE [Cálculo do IBOV em tempo real native na Trader Evolution]

Reproduzir vídeo

Neste vídeo da séria “Conhecendo a Trader Evolution” vamos explorar o cálculo nativo de IBOV online, o qual pode ser incluído em um gráfico para comparação visual do valor calculado como justo para os futuros e o valor de futuros atualmente negociado.

Não se esqueça de indicar a Comunidade NeoTraderBot como parceiro na Plataforma TraderEvolution. Vá no menu superior em “Mais” – “Extensões” – “Indique parceiro” e digite o código “NEOTRADERBOT”.

Assim, você reforça sua participação na Comunidade e nos ajuda a pleitear novas funcionalidades e melhorias na plataforma visando o benefício de todos os membros em suas automatizações e desenvolvimento de estratégias.

Ferramenta Saldo Agressor da Trader Evolution

Reproduzir vídeo

Neste vídeo da séria “Conhecendo a Trader Evolution” vamos explorar a ferramenta de SALDO AGRESSOR para verificação de agressão dos participantes do mercado em determinado ativo.

Não se esqueça de indicar a Comunidade NeoTraderBot como parceiro na Plataforma TraderEvolution. Vá no menu superior em “Mais” – “Extensões” – “Indique parceiro” e digite o código “NEOTRADERBOT”.

Assim, você reforça sua participação na Comunidade e nos ajuda a pleitear novas funcionalidades e melhorias na plataforma visando o benefício de todos os membros em suas automatizações e desenvolvimento de estratégias.

Notícias e RSS na Trader Evolution [MANTENHA-SE INFORMADO DENTRO DA PLATAFORMA]

Reproduzir vídeo

Neste vídeo da séria “Conhecendo a Trader Evolution” vamos explorar a configuração de Notícias e RSS dentro da plataforma.

Não se esqueça de indicar a Comunidade NeoTraderBot como parceiro na Plataforma TraderEvolution. Vá no menu superior em “Mais” – “Extensões” – “Indique parceiro” e digite o código “NEOTRADERBOT”.

Assim, você reforça sua participação na Comunidade e nos ajuda a pleitear novas funcionalidades e melhorias na plataforma visando o benefício de todos os membros em suas automatizações e desenvolvimento de estratégias.

Programando em EvoCode

Como criar robôs e indicadores utilizando EvoCode

EvoCode – Ambiente de desenvolvimento de estratégias da Trader Evolution

Reproduzir vídeo

Neste vídeo da séria “Conhecendo a Trader Evolution” vamos explorar o ambiente de desenvolvimento de estratégias: EvoCode.

Não se esqueça de indicar a Comunidade NeoTraderBot como parceiro na Plataforma TraderEvolution. Vá no menu superior em “Mais” – “Extensões” – “Indique parceiro” e digite o código “NEOTRADERBOT”.

Assim, você reforça sua participação na Comunidade e nos ajuda a pleitear novas funcionalidades e melhorias na plataforma visando o benefício de todos os membros em suas automatizações e desenvolvimento de estratégias.

Como configurar o Visual Studio para Trader Evolution [Desenvolvimento e depuração]

Reproduzir vídeo

Neste vídeo, irei demonstrar o passo-a-passo para configurar o Visual Studio para desenvolver e depurar estratégias e indicadores da TraderEvolution.

Não se esqueça de indicar a Comunidade NeoTraderBot como parceiro na Plataforma TraderEvolution. Vá no menu superior em “Mais” – “Extensões” – “Indique parceiro” e digite o código “NEOTRADERBOT”.

Assim, você reforça sua participação na Comunidade e nos ajuda a pleitear novas funcionalidades e melhorias na plataforma visando o benefício de todos os membros em suas automatizações e desenvolvimento de estratégias.

Como CRIAR DO ZERO um INDICADOR NA TRADER EVOLUTION

Reproduzir vídeo

Neste vídeo, irei demonstrar o passo-a-passo como criar a partir do zero um indicador na plataforma TraderEvolution, escrevendo o código em EVOCODE. Para isso, iremos criar um indicador de volatilidade média.

Você pode fazer o download do indicador com CÓDIGO FONTE ABERTO pelo link abaixo:

        🤖 https://neotraderbot.com/indicador-de…

Não se esqueça de indicar a Comunidade NeoTraderBot como parceiro na Plataforma TraderEvolution. Vá no menu superior em “Mais” – “Extensões” – “Indique parceiro” e digite o código “NEOTRADERBOT”.

Assim, você reforça sua participação na Comunidade e nos ajuda a pleitear novas funcionalidades e melhorias na plataforma visando o benefício de todos os membros em suas automatizações e desenvolvimento de estratégias.

Biblioteca NeoTraderBot

Apresentação

A Biblioteca NeoTraderBot foi desenvolvida com o objetivo de facilitar a implementação de estratégias e indicadores em EvoCode.

Assim, o trader pode dedicar mais tempo ao desenvolvimento de estratégias do que quebrando a cabeça para resolver problemas de código fonte ou tentando descobrir como executar determinadas tarefas.

Neste repositório você irá encontrar a documentação de todas as funções da Biblioteca com exemplos de uso.

Aguarde…em implementação!

 

Snippets e How-to

Aprender a programar envolve esforço, persistência e também colaboração com outros programadores (esse é um dos benefícios de participar de uma Comunidade como a NeoTraderBot!).

Pensando em acelerar a curva de aprendizado e reduzir o tempo que ficamos presos com problemas de programação, organizamos esta área de Snippets e de How-To (tutoriais) para elaboração de estratégias e indicadores na TraderEvolution utilizando EvoCode.

Os Snippets são trechos de códigos independentes criados para executar uma determinada tarefa. Eles podem ser copiados e modificados de acordo com a necessidade do usuário

Navegue abaixo pelas categorias disponíveis e caso tenha alguma sugestão de nova categoria ou tarefa, comente nas áreas apropriadas. Caso tenha colegas que também possam fazer bom uso e contribuir com a Comunidade, compartilhe esta área do site pelos ícones abaixo.

 

Compartilhe essa página!

Share on facebook
Facebook
Share on telegram
Telegram
Share on whatsapp
WhatsApp
Share on email
Email

Tutoriais sobre Estrutura de código

Nesta área você terá acesso a informações relacionadas a estrutura de um código fonte em EvoCode.

Tarefas/Tutoriais disponibilizados:

Snippets para Localização Temporal

Nesta área você terá acesso a pedaços de códigos fontes para localização da estratégia em relação ao tempo.

Tarefas disponibilizadas:

Snippets para Manipulação de Gráficos

Nesta área você terá acesso a pedaços de códigos fontes para manipular plot, cores de plotagem, espessura, tipo de gráfico, etc.

Tarefas disponibilizadas:

 

Snippets para Utilização de Indicadores da Plataforma

Nesta área você terá acesso a pedaços de códigos fontes para utilizar os indicadores disponibilizados por padrão na Plataforma.

Tarefas disponibilizadas:

 

Snippets para Ordens e Administração de Trade

Nesta área você terá acesso a pedaços de códigos fontes para execução de ordens e administração de trade (técnicas de stoploss e takeprofit).

Tarefas disponibilizadas:

Snippets para Implementação de estratégias

Nesta área você terá acesso a pedaços de códigos fontes para subtarefas comuns na implementação de estratégias.

Tarefas disponibilizadas:

 

Outros Snippets

Nesta área você terá acesso a pedaços de códigos fontes para objetivos não abrangidos pelas categorias acima.

Tarefas disponibilizadas:

 

Tutoriais sobre Estrutura do código

Introdução

Esta seção visa apresentar trechos de códigos com funcionalidades relativas à estrutura do código de indicadores e estratégias. Por exemplo, como criar parâmetros de entrada.

Você pode acessar os Snippets/Tutoriais diretamente pelo menu lateral direito, ou fazendo CTRL+F (CTRL+L) para localizar algum texto específico na página, uma vez que o conteúdo tende a crescer ao longo do tempo, dificultando a navegação pelo menu.

Caso tenham sugestões de código para acrescentar à lista, gentileza deixar o código nos comentários com o link para seu perfil em rede social (para devido crédito de autoria).

Snippets/Tutoriais

Como criar parâmetros no meu indicador/estratégia?

Os parâmetros de uma estratégia ou indicador são declarados como atributos da classe.

O que diferencia esses atributos dos demais atributos são as anotações (em C# chama-se Annotations e são contidas entre [ ]) que realizamos imediatamente antes da definição dos atributos. Vamos ver abaixo como criar diferentes tipos de parâmetros, como definir seu valor padrão, qual texto será exibido na interface de configuração da estratégia/indicador e pré-validações.

A primeira anotação que realizamos é invocar a função InputParameter. Esta função recebe 3 parâmetros: Tipo do parâmetro da estratégia, Texto a ser exibido na interface de configuração e a ordem de apresentação.

Os tipos de parâmetros possíveis em EvoCode são: Combobox, Checkbox, Numeric ,Color, Instrument, Account, String, DateTime e TimeSpan. Sendo Numeric e ComboBox os mais utilizados. O texto a ser exibido consiste em uma string de sua livre escolha e a ordem deve ser um inteiro iniciando em zero o qual irá ordenar a exibição dos parâmetros na janela de configuração da estratégia.

Existe também uma sobrecarga da função InputParameter, na qual não é necessário informar o parâmetro de ordem. Ao utilizar essa função, os parâmetros da estratégia terão exatamente a ordem na qual são criados no código-fonte.

A segunda anotação que pode ser utilizada é um validador. O usuário pode ver no dicionário EvoCode que existem uma função de validação para parâmetros numéricos chamada SimpleNumericAttribute. Este método é sobrecarregado, ou seja, possui diferentes combinações de parâmetros que realizam diferentes validações. Nos exemplos abaixo, ficará claro o uso desse método.

A terceira anotação possível é utilizada no caso de parâmetros exibidos no formato de ComboBox, ou seja, caixa de seleção. Nesse caso, podem ser inseridas quantas anotações forem necessárias para cada opção do ComboBox, invocando a função ComboBoxItem e passando como parâmetro a chave e o valor. Entenda chave como a string que será apresentada no combobox e valor como a representação da opção selecionada, que pode ser um número inteiro ou um enum.

Veja a seguir alguns exemplos de definição de parâmetros para estratégia:

Parâmetro Inteiro (Exemplo: Qtde de períodos de uma média móvel)

No código abaixo a tela de configuração da estratégia/indicador apresentará como primeiro parâmetro a ser definido a “Média rápida – Qtde de periodos” que é do tipo numérico e inteiro, variando entre 1 e 9999. Dentro do código esse parâmetro é reconhecido pelo nome fastestPeriod e a caixa de texto da tela de configuração já irá exibir o valor padrão igual a 5, conforme definido no código.

				
					[InputParameter(InputType.Numeric, "Média rápida - Qtde de periodos", 0)]
		[SimpleNumeric(1D,9999D)]
		public int fastestPeriod = 5;
				
			
Parâmetro ComboBox (Exemplo: Tipo da média móvel)

No código abaixo a tela de configuração da estratégia/indicador apresentará como segundo parâmetro a ser definido a “Média rápida – Tipo da média”, que apresentará em um comboBox as seguintes opções: SMA, EMA, SMMA, LWMA. O valor padrão desse parâmetro será a média aritmética. Observe que dentro do código, esse parâmetro de tipo de média utiliza um eNum pré-definido do EvoCode chamado MAMode.

Caso haja até 3 opções de seleção, a renderização desse componente na interface gráfica da plataforma será no formato de RadioBox ou invés de ComboBox (Caixa de seleção).

				
							[InputParameterAttribute(InputType.Combobox, "Média rápida - Tipo da média", 1)]
		[ComboboxItem("Aritmética (SMA)", MAMode.SMA)]
		[ComboboxItem("Exponencial (EMA)", MAMode.EMA)]
		[ComboboxItem("Amortecida (SMMA)", MAMode.SMMA)]		
		[ComboboxItem("Ponderada Linear (LWMA)", MAMode.LWMA)]		
		public MAMode fastestAvgType = MAMode.SMA;
				
			
Parâmetro Percentual

No código abaixo a tela de configuração da estratégia/indicador apresentará como primeiro parâmetro a ser definido a “bandPct”, que apresentará em uma caixa de texto com valor padrão igual a 2. É um parâmetro do tipo double e observe a anotação de validação possui 4 parâmetros, o que validará: valor mínimo (0.0), valor máximo (9999) precisão numérica (1 casa decimal) e incremento mínimo (0.1).

				
					        [InputParameter(InputType.Numeric, "bandPct", 0)]
        [SimpleNumeric(0.0D, 9999D, 1, 0.1)]
        public double bandPct = 2;
				
			
Código de um indicador com TODOS os tipos de parâmetros em EvoCode

No código abaixo você encontrará um exemplo de um indicador com todos os tipos de parâmetros possíveis em EvoCode.

				
					using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using Runtime.Script;
using TradeApi;
using TradeApi.History;
using TradeApi.Indicators;
using TradeApi.Instruments;
using TradeApi.ToolBelt;
using TradeApi.Trading;


namespace NeoTraderBot
{
    /// <summary>
    /// Indicator
    /// 
    /// </summary>
    public class TestingParameters : IndicatorBuilder 
    {
    	//Exemplo de parâmetro numérico inteiro
		[InputParameter(InputType.Numeric, "Periods", 0)]
		[SimpleNumeric(1D,9999D)]
		public int periods = 5;

		//Exemplo de parâmetro numérico percentual		
		[InputParameter(InputType.Numeric, "Percentage band (%)", 1)]
		[SimpleNumeric(0.0D, 9999D, 1, 0.1)]
		public double bandPct = 2.3;		

		//Exemplo de parâmetro ComboBox		
		[InputParameterAttribute(InputType.Combobox, "Average type", 2)]
		[ComboboxItem("Aritmética (SMA)", MAMode.SMA)]
		[ComboboxItem("Exponencial (EMA)", MAMode.EMA)]
		[ComboboxItem("Amortecida (SMMA)", MAMode.SMMA)]
		[ComboboxItem("Ponderada Linear (LWMA)", MAMode.LWMA)]
		public MAMode avgType = MAMode.SMA;
		
		[InputParameterAttribute(InputType.Checkbox, "Daytrade mode", 3)]
		public Boolean dayTradeMode;
		
		[InputParameterAttribute(InputType.String, "Input message", 4)]
		public string msg = "Hello EvoCode!";
		
		[InputParameterAttribute(InputType.Color, "Color", 5)]
		public Color someColor = Color.Orange;
		
		[InputParameterAttribute(InputType.Instrument, "Symbol", 6)]
		public Instrument instrument;		
		
		[InputParameterAttribute(InputType.DateTime, "Trading start on:", 7)]
		public DateTime startDateTime = DateTime.Now.AddDays(-3);
		
		[InputParameterAttribute(InputType.TimeSpan, "Open position after:", 8)]
		public TimeSpan openPosAfter = DateTime.Now.TimeOfDay;
    	
        public TestingParameters()
            : base()
        {
			#region Initialization
            Credentials.Author = "";
            Credentials.Company = "";
            Credentials.Copyrights = "";
            Credentials.DateOfCreation = new DateTime(2023, 7, 21);
            Credentials.ExpirationDate = DateTime.MinValue;
            Credentials.Version = "";
            Credentials.Password = "66b4a6416f59370e942d353f08a9ae36";
            Credentials.ProjectName = "TestingParameters";
            #endregion 
            
            Lines.Set("indicator");
			Lines["indicator"].Color = Color.Blue;

            SeparateWindow = false;
        }
        
        /// <summary>
        /// This function will be called after creating
        /// </summary>
		public override void Init()
		{
			string param = "Parâmetros:\n";
			param += "Periods: " + periods.ToString() + "\n";
			param += "Percentage band (%): " + bandPct.ToString() + "\n";
			param += "Average type: " + avgType.ToString() + "\n";
			param += "Daytrade mode: " + dayTradeMode.ToString() + "\n";
			param += "Input message: " + msg + "\n";
			param += "Color: " + someColor.Name + "\n";
			param += "Symbol: " + instrument.Symbol.ToString() + "\n";
			param += "Trading start on: " + startDateTime.ToLongDateString() + "\n";
			param += "Open position after: " + openPosAfter.ToString() + "\n";
		
			Notification.Comment(param);
			
		}        
 
        /// <summary>
        /// Entry point. This function is called when new quote comes or new bar created
        /// </summary>
        public override void Update(TickStatus args)
        {
			Lines["indicator"].SetValue(HistoryDataSeries.GetValue(PriceType.Close));
        }
        
        /// <summary>
        /// This function will be called before removing
        /// </summary>
		public override void Complete()
		{
			
		} 
     }
}

				
			

O que são as credenciais do meu código?

As credenciais servem para identificar a sua estratégia com os atributos de Autor, Empresa, Direitos Autorais (se for o caso), Data de criação do código, Data de Expiração, Versão do código, Senha e Nome do Projeto (este é o nome que irá aparecer nas listagens dentro da plataforma). 

A utilização de #region não tem nenhum impacto sobre o código, sendo apenas uma funcionalidade .NET para poder expandir ou colapsar blocos de código na IDE (ambiente de desenvolvimento).

OBS: É importante ressaltar que se você configurar a data de expiração para um valor diferente de “DateTime.MinValue”, compilar o seu código e compartilhar ele com alguém, o código executará apenas até a data de expiração.

				
					#region Initialization
Credentials.Author = "Johnathas Carvalho";
Credentials.Company = "Comunidade NeoTraderBot";
Credentials.Copyrights = "";
Credentials.DateOfCreation = new DateTime(2023, 5, 16);
Credentials.ExpirationDate = DateTime.MinValue;
Credentials.Version = "1.0";
Credentials.Password = "66b4a6416f59370e942d353f08a9ae36";
Credentials.ProjectName = "NTB_TripleCrossoverIndicator";
Credentials.Description = "Descrição";
#endregion 
				
			

Como definir texto a ser apresentado no cabeçalho do gráfico o indicador?

A definição do texto a ser apresentado no cabeçalho do gráfico, quando seu indicador for aplicado deve ser realizada no método Init. Conforme exemplo abaixo.

É importante dizer que ScriptShortName é um atributo da Classe IndicatorBuilder e o que estamos fazendo é simplesmente atribuir valor a essa variável com uma string. Utilizou-se também a função de formatação de string que permite colocar placeholders (reserva de espaço) dentro da string e definir seus valores nos próximos parâmetros da função string.Format. A sequencia {0} é um placeholder que irá ser substituída pelo primeiro parâmetro, no caso, fastestAvgType.

 

				
					public override void Init()
{

ScriptShortName = (string.Format("NTB Crossover: {0}({1}) | {2}({3}) | {4}({5})",
                              fastestAvgType, fastestPeriod, fastAvgType, fastPeriod, slowAvgType, slowPeriod));

}  
				
			

Quais são os principais eventos que serão tratados pelo método Update?

As classes de indicador e estratégia (IndicatorBuilder e StrategyBuilder) podem lidar com diferentes tipos de eventos. Não obstante, existem 3 eventos que são comuns nessas duas classes e que exigem a implementação de 3 métodos, a saber: Init, Update e Complete.

O Método Init será executado sempre que um indicador/estratégia for inicializado dentro da plataforma TraderEvolution. Ou seja, quando o indicador for incluído em um gráfico um uma estratégia iniciar sua execução.

De maneira análoga, o método Complete é chamado ao final da execução do indicador ou estratégia.

Assim, resta falar do método Update que podemos dizer se tratar do coração do indicador/estratégia. Todos eventos durante a execução do seu código devem ser tratados no método Update, o qual recebe como parâmetro um objeto do tipo TickStatus chamado args).

O valor de args pode ser um dos três valores possíveis do eNum TickStatus: IsBar, IsQuote e IsHistory. Vamos explicar cada um desses eventos abaixo:

      • isBar: quando uma barra é encerrada, gera-se uma chamada ao método Update com o valor de args igual a isBar. Assim, o programador pode definir o que fazer no fechamento das barras no código dentro de Update. Sempre após um evento isBar, o método Update é chamado com um evento isQuote.
      • isQuote: este evento é sempre disparado para cada negociação recebida pela sua plataforma cliente (seu programa TraderEvolution). Assim, o programador pode definir o que fazer no tick. Nos dados históricos, isQuote é disparado 4 vezes para cada barra.
      • isHistory: este evento é disparado para cada barra enquanto seu código processa os dados históricos. Uma vez em tempo real, esse evento não é mais disparado.

Quais são as informações que consigo obter da conta do usuário logado pelo código?

Todas as estratégias/indicador tem acesso às informações da conta logada por meio da classe AccountManager, a qual pode retornar a conta atual e seus detalhes. O código abaixo demonstra como obter o e-mail do usuário que está executando o código.

Posição do DicionárioPropriedade
[0]Conta
[1]Saldo
[2]Saldo bloqueado
[3]L/P líquido aberto
[4]L/P bruto aberto
[5]Saldo projetado
[6]Nº de ordens
[7]Nº de posições
[8]Margem Inicial
[9]Nível de risco
[10]Nível de alerta de margem
[11]Nível “Stop Out”
[12]Fundos disponíveis
[13]Alerta de margem
[14]Manutenção de Margem
[15]Disponível para Retirada
[16]ID do usuário
[17]Login do usuário
[18]Cliente
[19]E-mail
[20]Bruto de hoje
[21]Taxas de hoje
[22]Líquido de hoje
[23]Volume de hoje
[24]Nº de negociações de hoje
[25]Valor da Ação
[26]Saldo em dinheiro
[27]Número do telefone
[28]Margem inicial
[29]Saldo + Risco total
[30]Situação da negociação
[31]Limite diário de perda
[32]Contagem máxima de ordens por dia
[33]Nº máximo de posições
[34]Nº máximo de ordens pendentes
[35]Capital de ordem máximo
[36]Margem disponível
[37]Valor de crédito
[38]Modo da conta
[39]Ativo
[40]Descrição do Ativo
[41]Tipo de conta
[42]Tipo de Ativo
[43]Taxa de juros
[44]Descontos de hoje
[45]Bloqueado para ‘Ações’
[46]Ganho incerto
[47]Modificar nivel de rebaixamento
[48]Quantidade máxima da posição
[49]Limite de perda semanal
[50]Perda diária
[51]Perda semanal
[52]Ordens de ações
[53]Valor da Opção
[54]Liquidez de Ações
[55]Perda não realizada
[56]Limite de perda não realizado
[57]Objetivo de lucro diário
[58]Limite de volume de ações
[59]Limite de volume futuro
[60]Limite de volume de opções
[61]Procuração
[62]Valor da ordem máximo
[63]Req. de prêmio de opção
[64]Rebaixamento Máximo
[65]Margem isenta
[66]Warn. margin req.
[67]Warn. margin req.%
[68]Margin before warning
Obtendo e-mail do usuário
				
					Dictionary<string, string> detalhesConta = AccountManager.Current.GetAccountDetails();
string email = "";
if (detalhesConta.TryGetValue("E-mail", out email))
{
    Notification.Print(email);
}
				
			

Como identificar se o código está rodando em conta real ou conta demo?

				
					string tipoConta = "";
Boolean contaReal = false;

Dictionary<string, string> detalhesConta = AccountManager.Current.GetAccountDetails();
if (detalhesConta.TryGetValue("Conta", out tipoConta))
{
    if (!tipoConta.Contains("demo"))
    {
        contaReal = true;
    }
}
				
			

Snippets para Manipulação de Gráficos

Esta seção visa apresentar trechos de códigos com funcionalidades relativas à manipulação de gráficos.

Você pode acessar os Snippets diretamente pelo menu lateral direito, ou fazendo CRL+F (CTRL+L) para localizar algum texto específico na página, uma vez que o conteúdo tende a crescer ao longo do tempo, dificultando a navegação pelo menu.

Caso tenham sugestões de código para acrescentar à lista, gentileza deixar o código nos comentários com o link para seu perfil em rede social (para devido crédito de autoria).

Snippets

Como criar e configurar os atributos gerais de um plot?

Os plots, ou Lines como é definida a Classe dentro do EvoCode devem ser instanciados no construtor do indicador. Cada Line recebe um nome por meio do método Set e assim pode ser indexado.

O programador pode configurar a visbilidade o estilo de linha (histograma, linha, escada, etc…), a cor padrão, a espessura, entre outras propriedades. Veja abaixo um exemplo de como criar 2 plots, um histograma e uma linha pontilhada.

				
					public IndicadorXYZ(): base()
{
    //Linha pontilhada
    Lines.Set("Média rápida");
    Lines["Média rápida"].Color = Color.Red;
	Lines["Média rápida"].Style = LineStyle.DotLine;
	Lines["Média rápida"].Width = 1;
	
	//Histograma
	Lines.Set("Histograma");
    Lines["Histograma"].Color = Color.Gray;
	Lines["Histograma"].Style = LineStyle.Histogram;
}
				
			

Eu posso plotar indicadores em uma estratégia?

Sim! Apesar da classe StrategyBuilder não possuir interface com classe Lines, é possível instanciarmos indicadores dentro das estratégias. Assim, os plots e elementos gráficos dos indicadores também serão exibidos no gráfico ao rodar a estratégia. 

Os indicadores devem ser instanciados no método Init e naturalmente também devem ser declarados como atributos da classe.

Veja abaixo alguns exemplos de instanciação de indicadores:

Instanciando uma média móvel (Indicador nativo)
				
					private BuiltInIndicator fastAvg;

public override void Init()
{
	fastAvg = IndicatorsManager.BuildIn.MA(HistoryDataSeries, fastPeriod, fastAvgType, 0, PriceType.Close);
} 
				
			
Instanciando Average True Range (ATR)
				
					private BuiltInIndicator avgTrueRange;

public override void Init()
{
    avgTrueRange = IndicatorsManager.BuildIn.ATR(HistoryDataSeries, 200);
} 
				
			
Instanciando Indicador Próprio chamado "NTB_TripleCrossoverIndicator"

Observe que ao instanciar um indicador próprio com o método custom, fornecemos 3 parâmetros: o nome do indicador (nome da classe), a série de dados, e um array com os valores dos parâmetros.

				
					private BuiltInIndicator NTB_3Cross;

public override void Init()
{
	NTB_3Cross = IndicatorsManager.BuildIn.Custom("NTB_TripleCrossoverIndicator" 
	                                              ,	HistoryDataSeries
	                                              , new Object[]{fastestPeriod,
  			                                              	   fastestAvgType,
  			                                              	   fastPeriod,
  			                                              	   fastAvgType,
  			                                              	   slowPeriod,
  			                                              	   slowAvgType})
} 
				
			

Como mudar a cor do plot em determinada condição?

As cores de um plot podem ser alteradas para qualquer posição a qualquer instante. Basta atribuir a cor desejada ao marcador da Line. Veja no exemplo abaixo um código que atribui cores a um histograma de maneira condicional: se a barra for de alta usa corAlta, senão usa corBaixa.

				
					public override void Update(TickStatus args)
{
	if (args == TickStatus.IsQuote)
	{
		Color corAlta = Color.FromArgb(0, 51, 0);;
		Color corBaixa = Color.FromArgb(153, 0, 0);;
		
		Lines["Volat."].SetValue(rangeAtual);
    	Lines["Volat."].Markers.Set((barData.GetOpen() < barData.GetClose()) ? corAlta : corBaixa, 0);
	}
}
				
			

Como inserir um texto no cabeçalho do gráfico?

Caso esteja trabalhando com indicadores, é possível inserir um texto no cabeçalho do gráfico (Veja na figura abaixo). Com esta funcionalidade, você pode inserir informações que julgue ser úteis de serem exibidas no gráfico.

				
					Notification.Comment("Aqui é onde ficam os comentários!");
				
			

Como garantir que indicador será aplicado apenas ao gráfico principal?

Em alguns casos, é desejável garantir que o indicador esteja sendo aplicado no gráfico principal ou em um gráfico separado. Caso o usuário tenha aplicado o indicador na janela diferente da esperada, pode-se alertar isso por meio de um texto, conforme figura abaixo.

Para se implementar esta funcionalidade, deve-se incluir a biblioteca Runtime.Scripts.Charts no cabeçalho do código fonte, e dentro da classe do indicador sobrescrever o método onPaintChart, conforme código exemplo abaixo.

				
					using Runtime.Script.Charts;

public override void OnPaintChart(object sender, PaintChartEventArgs args)
{
    var graphic = args.Graphics;
    int windowNumber = ChartSource.FindWindow(this);
	Font fonte = new Font("Arial", 24);
	Brush boxBrush = new SolidBrush(Color.LightGray);
	
	//É o número da janela que define se o indicador está no gráfico principal (= 0)
    if (windowNumber != 0)
    {
        using (StringFormat format = new StringFormat())
        {
            format.LineAlignment = StringAlignment.Center;
            format.Alignment = StringAlignment.Center;

            graphic.DrawString("O indicador deve ser aplicado ao gráfico principal", fonte, boxBrush, args.Rectangle, format);
        }

        return;
    }
}		
				
			

Snippets para Utilização de Indicadores da Plataforma

Introdução

Esta seção visa apresentar trechos de códigos com exemplos de utilização dos indicadores disponibilizados na plataforma.

Você pode acessar os Snippets diretamente pelo menu lateral direito, ou fazendo CRL+F (CTRL+L) para localizar algum texto específico na página, uma vez que o conteúdo tende a crescer ao longo do tempo, dificultando a navegação pelo menu.

Caso tenham sugestões de código para acrescentar à lista, gentileza deixar o código nos comentários com o link para seu perfil em rede social (para devido crédito de autoria).

Snippets

Como instanciar uma média móvel nativa?

Reproduzir vídeo

Os indicadores devem ser instanciados no método Init e naturalmente também devem ser declarados como atributos da classe.

				
					private BuiltInIndicator fastAvg;

public override void Init()
{
    fastAvg = IndicatorsManager.BuildIn.MA(HistoryDataSeries, 20, MAMode.SMA, 0, PriceType.Close);
} 
				
			

Como instanciar um indicador criado por você dentro de outra estratégia/indicador?

Reproduzir vídeo

Os indicadores devem ser instanciados no método Init e naturalmente também devem ser declarados como atributos da classe. Veja abaixo um exemplo de instanciação de indicador próprio.

Observe que ao instanciar um indicador próprio com o método custom, fornecemos 3 parâmetros: o nome do indicador (nome da classe), a série de dados, e um array com os valores dos parâmetros.

Instanciando Indicador Próprio chamado "NTB_TripleCrossoverIndicator"
				
					private BuiltInIndicator NTB_3Cross;

public override void Init()
{
	NTB_3Cross = IndicatorsManager.BuildIn.Custom("NTB_TripleCrossoverIndicator" 
	                                              ,	HistoryDataSeries
	                                              , new Object[]{fastestPeriod,
  			                                              	   fastestAvgType,
  			                                              	   fastPeriod,
  			                                              	   fastAvgType,
  			                                              	   slowPeriod,
  			                                              	   slowAvgType})
} 
				
			

Como criar estratégias/indicadores em múltiplos tempos gráficos?

Reproduzir vídeo

O EvoCode permite utilizar séries de dados de diferentes ativos e multiplos tempos gráficos em uma mesma estratégia ou indicador. Segue abaixo um exemplo no qual é implementado um indicador no tempo gráfico primário consistindo em uma média aritmética, bem como uma outra média aritmética utilizando dados de preço do mesmo ativo em um tempo gráfico diferente (5 minutos).

 

Calculando médias em múltiplos tempos gráficos
				
					using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using Runtime.Script;
using TradeApi;
using TradeApi.History;
using TradeApi.Indicators;
using TradeApi.Instruments;
using TradeApi.ToolBelt;
using TradeApi.Trading;
using TradeApi.Quotes;
using NeoTraderBot;

namespace NeoTraderBot
{
    public class MultiTimeFrameIndicator : IndicatorBuilder
    {
        private BuiltInIndicator avg;

        // Secondary timeframe 5 minutes
        private HistoricalData historicalDataSeries2 = null;
        private BuiltInIndicator avg2;

        #region inputs
        [InputParameter(InputType.Numeric, "Primary SMA - Periods", 0)]
        [SimpleNumeric(1D, 9999D)]
        public int periods = 50;

        [InputParameter(InputType.Numeric, "Secondary SMA - Periods", 0)]
        [SimpleNumeric(1D, 9999D)]
        public int periods2 = 10;

        #endregion




        public MultiTimeFrameIndicator()
            : base()
        {
            #region Initialization
            Credentials.Author = "";
            Credentials.Company = "";
            Credentials.Copyrights = "";
            Credentials.DateOfCreation = new DateTime(2023, 7, 18);
            Credentials.ExpirationDate = DateTime.MinValue;
            Credentials.Version = "";
            Credentials.Password = "66b4a6416f59370e942d353f08a9ae36";
            Credentials.ProjectName = "Multi TimeFrame Averages";
            #endregion

            Lines.Set("avg1min");
            Lines["avg1min"].Color = Color.Blue;
            Lines.Set("avg5min");
            Lines["avg5min"].Color = Color.Red;

            SeparateWindow = false;
        }
        public override void Init()
        {
            HistoricalDataManager.OnLoaded += plotHistoryValues;

            InstrumentsManager.Subscribe(InstrumentsManager.Current, QuoteTypes.Trade);
            HistoricalRequest historicalRequest2 = new TimeHistoricalRequest(InstrumentsManager.Current, DataType.Trade, Period.Minute, 5);
            historicalDataSeries2 = HistoricalDataManager.Get(historicalRequest2, new Interval(DateTime.UtcNow.AddDays(-10), DateTime.UtcNow));

            avg = IndicatorsManager.BuildIn.MA(HistoryDataSeries, periods, MAMode.SMA);
            avg2 = IndicatorsManager.BuildIn.MA(historicalDataSeries2, periods2, MAMode.SMA);

            Notification.Comment(  "This is a SNIPPET from NeoTraderBot Community: www.NeoTraderBot.com.\n"
                                 + "In the blue line, we have a SMA of " + periods + " periods in the current timeframe. \n"
                                 + "In the red line, we have a SMA of " + periods2 + " periods in a 5-minutes timeframe on the same symbol.");
        }

       public override void Update(TickStatus args)
        {
            Lines["avg1min"].SetValue(avg.GetValue());
            Lines["avg5min"].SetValue(avg2.GetValue());
        }

        public override void Complete()
        {
            HistoricalDataManager.OnLoaded -= plotHistoryValues;
            InstrumentsManager.UnSubscribe(InstrumentsManager.Current, QuoteTypes.Trade);
        }

        public void plotHistoryValues(HistoricalData hData)
        {
            for (int i = 0; i < HistoryDataSeries.Count; i++)
            {
                int index = historicalDataSeries2.FindInterval(HistoryDataSeries.GetTimeUtc(i));
                Lines["avg5min"].SetValue(avg2.GetValue(index), i);
            }
		}


    }
}


				
			

Snippets para Ordens e Administração de Trade

Esta seção visa apresentar trechos de códigos com exemplos de envio de ordens e administração de trade utilizando técnicas de stoploss (fixo, móvel, breakeven) e take profit.

Você pode acessar os Snippets diretamente pelo menu lateral direito, ou fazendo CRL+F (CTRL+L) para localizar algum texto específico na página, uma vez que o conteúdo tende a crescer ao longo do tempo, dificultando a navegação pelo menu.

Caso tenham sugestões de código para acrescentar à lista, gentileza deixar o código nos comentários com o link para seu perfil em rede social (para devido crédito de autoria).

Snippets

Como rotear ordens a mercado, stop e limitada?

No código abaixo, você encontra um exemplo de estratégia que abre um posição em uma data/horário específicos. Assim, você poderá testar a abertura de posições por ordens a mercado, limitada ou stop.

O código possui parâmetros para quantidade, horario de encerramento da posição e lado da posição (comprado/vendido).

OBS: É importante ressaltar que uma vez apregoada uma ordem, ela permanecerá ativa e aguardando execução até que o usuário cancele. Não há um auto-gerenciamento de execução apenas para próxima barra como em outras plataformas.

				
					using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using Runtime.Script;
using TradeApi;
using TradeApi.History;
using TradeApi.Indicators;
using TradeApi.Instruments;
using TradeApi.ToolBelt;
using TradeApi.Trading;



namespace ExemplosNeoTraderBot
{
    /// <summary>
    /// Strategy1
    /// 
    /// </summary>
    public class NTB_ExemploRoteamentoOrdens : StrategyBuilder
    {
		private BarData dadosBarra;
		
        public NTB_ExemploRoteamentoOrdens()
            : base()
        {
			#region Initialization
            Credentials.Author = "NeoTraderBot";
            Credentials.Company = "NeoTraderBot";
            Credentials.Copyrights = "";
            Credentials.DateOfCreation = new DateTime(2023, 9, 5);
            Credentials.ExpirationDate = DateTime.MinValue;
            Credentials.Version = "";
            Credentials.Password = "66b4a6416f59370e942d353f08a9ae36";
            Credentials.ProjectName = "exemploOrdensBasicas";
            #endregion 


        }
        
        /// <summary>
        /// This function will be called after creating
        /// </summary>
		public override void Init()
		{
			dadosBarra = (HistoryDataSeries as BarData);
		}        
 
        /// <summary>
        /// Entry point. This function is called when new quote comes or new bar created
        /// </summary>
        public override void Update(TickStatus args)
        {
        	if (args == TickStatus.IsBar)
        	{
        		List<Position> listaPosicoes = PositionsManager.GetPositions();

        		//DATA E HORA PARA ABERTURA DE POSIÇÕES
        		DateTime horarioAbertura = new DateTime(2023, 09, 05, 09, 06, 0);
				DateTime horarioEncerramento = horarioAbertura.AddMinutes(10);
				
				//INFORMAÇÃO PARA ABERTURA DE POSIÇÕES
				OrderSide ladoOperacao = OrderSide.Sell;
				int quantidade = 1;
				double precoOrdemStop = 4977.5;
				double precoOrdemLimitada = 4982.5;
        		
				OrderRequest request = null;
				
				//CRIA ORDENS
        		if ((listaPosicoes.Count == 0) && (dadosBarra.GetTimeUtc(0).ToLocalTime() == horarioAbertura))
        		{
					// ORDEM A MERCADO
					//request = new OrderRequest(OrderType.Market, InstrumentsManager.Current, AccountManager.Current, ladoOperacao, quantidade);
            		
					// ORDEM LIMITADA
					//request = new OrderRequest(OrderType.Limit, InstrumentsManager.Current, AccountManager.Current, ladoOperacao, quantidade, precoOrdemLimitada);
        			
        			// ORDEM STOP
        			request = new OrderRequest(OrderType.Stop, InstrumentsManager.Current, AccountManager.Current, ladoOperacao, quantidade, null, precoOrdemStop);

	        		//ENVIA ORDENS PARA BROKER
	        		OrdersManager.Send(request);
        		}

				
				//CRIA ORDEM DE ENCERRAMENO A MERCADO        		
				if ((listaPosicoes.Count != 0) && (dadosBarra.GetTimeUtc(0).ToLocalTime() == horarioEncerramento))
        		{
					request = new OrderRequest(OrderType.Market, InstrumentsManager.Current, AccountManager.Current, (ladoOperacao == OrderSide.Buy) ? OrderSide.Sell : OrderSide.Buy, quantidade);
            		OrdersManager.Send(request);
        		} 

        	}
			
        }
        
        /// <summary>
        /// This function will be called before removing
        /// </summary>
		public override void Complete()
		{
			
		} 
     }
}

				
			

Como enviar uma ordem a mercado?

Para enviar uma ordem a mercado, é necessário criar uma requisição de ordem (OrderRequest) com a parametrização desejada e, em seguida, solicitar ao Gestor de ordens que envie essa ordem.

O envio de ordem pode ser feito de maneira síncrona ou assincrona. Na primeira forma (síncrona), o código fica aguardando o retorno da função Send. Já no envio assíncrono, o código continua sua execução e o programador fornece uma função callback para ser executada quando houver o resultado do envio da ordem.

Seguem abaixo exemplos de envio de ordens a mercado de compra e venda.

Ordem de compra a mercado (Envio síncrono)
				
					orderSize = 1;

OrderRequest request = new OrderRequest(OrderType.Market, 
                                        InstrumentsManager.Current,
                                        AccountManager.Current,
                                        OrderSide.Buy,
                                        orderSize);
OrdersManager.Send(request); 
				
			
Ordem de venda a mercado (Envio síncrono)
				
					orderSize = 1;

OrderRequest request = new OrderRequest(OrderType.Market, 
                                        InstrumentsManager.Current,
                                        AccountManager.Current,
                                        OrderSide.Sell,
                                        orderSize);
OrdersManager.Send(request); 
				
			

Como abrir uma posição com ordens OCO?

Gestão de risco é essencial para negociação de ativos. O exemplo abaixo demonstra como enviar um ordem de compra a mercado para abertura de posição, acompanhada das ordens de stoploss e alvo em termos de ticks. 

Ordem de compra a mercado com RG 3:1 e Stop de 30 ticks (Envio síncrono)
				
					using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using Runtime.Script;
using TradeApi;
using TradeApi.History;
using TradeApi.Indicators;
using TradeApi.Instruments;
using TradeApi.ToolBelt;
using TradeApi.Trading;



namespace ExemplosNeoTraderBot
{
    /// <summary>
    /// Strategy1
    /// 
    /// </summary>
    public class NTB_ExemploOrdemOCO : StrategyBuilder
    {
		private BarData dadosBarra;
		
        public NTB_ExemploOrdemOCO()
            : base()
        {
			#region Initialization
            Credentials.Author = "NeoTraderBot";
            Credentials.Company = "NeoTraderBot";
            Credentials.Copyrights = "";
            Credentials.DateOfCreation = new DateTime(2023, 9, 5);
            Credentials.ExpirationDate = DateTime.MinValue;
            Credentials.Version = "";
            Credentials.Password = "66b4a6416f59370e942d353f08a9ae36";
            Credentials.ProjectName = "exemploOrdensOCO";
            #endregion 


        }
        
        /// <summary>
        /// This function will be called after creating
        /// </summary>
		public override void Init()
		{
			dadosBarra = (HistoryDataSeries as BarData);
		}        
 
        /// <summary>
        /// Entry point. This function is called when new quote comes or new bar created
        /// </summary>
        public override void Update(TickStatus args)
        {
        	if (args == TickStatus.IsBar)
        	{
        		List<Position> listaPosicoes = PositionsManager.GetPositions();

        		//DATA E HORA PARA ABERTURA DE POSIÇÕES
        		DateTime horarioAbertura = new DateTime(2023, 09, 05, 09, 06, 0);
				DateTime horarioEncerramento = new DateTime(2023, 09, 05, 17, 00, 0);
				
				//INFORMAÇÃO PARA ABERTURA DE POSIÇÕES
				TradeResult ordem;				
				OrderSide ladoOperacao = OrderSide.Sell;
				int quantidade = 1;
				double stoplossTicks = 30;
				double takeProfitTicks = stoplossTicks*3;        		
				
				OrderRequest request = null;
				
				//CRIA ORDEM OCO
        		if ((listaPosicoes.Count == 0) && (dadosBarra.GetTimeUtc(0).ToLocalTime() == horarioAbertura))
        		{
					request = new OrderRequest(OrderType.Market,
					                                        InstrumentsManager.Current,
					                                        AccountManager.Current,
					                                        ladoOperacao, quantity: quantidade)
					{
						SLTPPriceType = SLTPPriceType.Ticks,
        				StopLossPrice = stoplossTicks,
						TakeProfitPrice = takeProfitTicks
					};
					
					//ENVIA ORDENS PARA BROKER
					ordem = OrdersManager.Send(request);

        		}

				
				//CRIA ORDEM DE ENCERRAMENO A MERCADO        		
				if ((listaPosicoes.Count != 0) && (dadosBarra.GetTimeUtc(0).ToLocalTime() == horarioEncerramento))
        		{
					request = new OrderRequest(OrderType.Market, InstrumentsManager.Current, AccountManager.Current, (ladoOperacao == OrderSide.Buy) ? OrderSide.Sell : OrderSide.Buy, quantidade);
            		OrdersManager.Send(request);
        		} 

        	}
			
        }
        
        /// <summary>
        /// This function will be called before removing
        /// </summary>
		public override void Complete()
		{
			
		} 
     }
}

				
			

Snippets para Implementação de estratégias

Esta seção visa apresentar trechos de códigos com funcionalidades relativas à localização temporal da estratégia. Por exemplo, identificar se a atual barra é a primeira barra do dia para verificar gap diário.

Você pode acessar os Snippets diretamente pelo menu lateral direito, ou fazendo CTRL+F (CTRL+L) para localizar algum texto específico na página, uma vez que o conteúdo tende a crescer ao longo do tempo, dificultando a navegação pelo menu.

Caso tenham sugestões de código para acrescentar à lista, gentileza deixar o código nos comentários com o link para seu perfil em rede social (para devido crédito de autoria).

Snippets

Como identificar gap de abertura do dia?

Veja abaixo um exemplo de como estruturar uma lógica para identificar gap de abertura diário pelo EvoCode.

				
					using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using Runtime.Script;
using TradeApi;
using TradeApi.History;
using TradeApi.Indicators;
using TradeApi.Instruments;
using TradeApi.ToolBelt;


namespace Snippets_NeoTraderBot
{
    /// <summary>
    /// Indicator1
    /// 
    /// </summary>
    public class exemploIdentGapAbertura : IndicatorBuilder 
    {
		private BarData dadosCandle;
    	
        public exemploIdentGapAbertura()
            : base()
        {
			#region Initialization
            Credentials.Author = "NeoTraderBot";
            Credentials.Company = "NeoTraderBot";
            Credentials.Copyrights = "";
            Credentials.DateOfCreation = new DateTime(2023, 9, 4);
            Credentials.ExpirationDate = DateTime.MinValue;
            Credentials.Version = "";
            Credentials.Password = "66b4a6416f59370e942d353f08a9ae36";
            Credentials.ProjectName = "exemploIdentGapAbertura";
            #endregion 
            
            Lines.Set("line1");
			Lines["line1"].Color = Color.Blue;

            SeparateWindow = false;
        }
        
        /// <summary>
        /// This function will be called after creating
        /// </summary>
		public override void Init()
		{
			dadosCandle = (HistoryDataSeries as BarData);
		}        
 
        /// <summary>
        /// Entry point. This function is called when new quote comes or new bar created
        /// </summary>
        public override void Update(TickStatus args)
        {
			if (dadosCandle.Count <= 1)
				return;
        	
			if (args != TickStatus.IsQuote)
			{
				if (dadosCandle.GetTimeUtc(0).ToLocalTime().Date != dadosCandle.GetTimeUtc(1).ToLocalTime().Date)
				{
					double gapDoDia = dadosCandle.GetOpen(0) - dadosCandle.GetClose(1);
					Notification.Print(dadosCandle.GetTimeUtc(0).ToLocalTime().ToString() + ": Mercado abriu em gap de " + gapDoDia);
				}
			}
        }
        
        /// <summary>
        /// This function will be called before removing
        /// </summary>
		public override void Complete()
		{
			
		} 
     }
}

				
			

Outros Snippets

Esta seção visa apresentar outros exemplos de trechos de códigos que não se enquadram nas categorias anteriores.

Você pode acessar os Snippets diretamente pelo menu lateral direito, ou fazendo CRL+F (CTRL+L) para localizar algum texto específico na página, uma vez que o conteúdo tende a crescer ao longo do tempo, dificultando a navegação pelo menu.

Caso tenham sugestões de código para acrescentar à lista, gentileza deixar o código nos comentários com o link para seu perfil em rede social (para devido crédito de autoria).

Snippets

Como escrever log com o horário de abertura da candle/barra para facilitar depuração (debug)?

Reproduzir vídeo

Gerar log de execução de uma estratégia é a melhor forma de rastrear possíveis problemas de lógica ou de execução. Segue abaixo um trecho que identifica no texto a ser escrito no log o dia/hora início da barra/candle.

				
					DateTime datahora = HistoryDataSeries.GetTimeUtc(0);
datahora = datahora.ToLocalTime();
Notification.Print("[" + datahora.ToString() + "] " + msg);
				
			

Como gerar Alertas durante a execução da sua estratégia?

Outra forma de sinalizar problemas ou situações que mereçam mais atenção é por meio de alertas. Na Trader Evolution, os alertas são apresentados em uma janela próprio e o usuário pode ver o histórico de alertas.

				
					Notification.Alert(msg);
				
			

Snippets para Localização Temporal

Esta seção visa apresentar trechos de códigos com funcionalidades relativas à localização temporal da estratégia. Por exemplo, identificar se a atual barra é a primeira barra do dia para verificar gap diário.

Você pode acessar os Snippets diretamente pelo menu lateral direito, ou fazendo CTRL+F (CTRL+L) para localizar algum texto específico na página, uma vez que o conteúdo tende a crescer ao longo do tempo, dificultando a navegação pelo menu.

Caso tenham sugestões de código para acrescentar à lista, gentileza deixar o código nos comentários com o link para seu perfil em rede social (para devido crédito de autoria).

Snippets

Identificação de primeira barra do dia

Algumas estratégias necessitam da identificação da primeira barra do dia (candle) para executar determinada ação ou calcular o gap em relação ao fechamento do dia anterior. Segue abaixo um trecho de código para identificar a primeira barra de um dia.

				
					public override void Update(TickStatus args)
{
	if (HistoryDataSeries.GetTimeUtc(0).ToLocalTime().Date != HistoryDataSeries.GetTimeUtc(1).ToLocalTime().Date)
	{
		DateTime datahora = HistoryDataSeries.GetTimeUtc(0);
    	datahora = datahora.ToLocalTime();
    	Notification.Print("[" + datahora.ToString() + "] - Está é a primeira barra do dia!");
	}			
}
				
			

Identificação de barra por data e hora específicos

Reproduzir vídeo

Este código localiza a barra (candle ou box) por uma data e hora desejados. Onde a hora é referente ao horário de abertura do candle desejado.

Observe que criamos uma variável contendo a data/hora “11:03:00 15/06/2023” para exemplificação de código, mas poderia ser substituído por outras variáveis. E para todos os ticks dessa barra será impressa uma notificação, pois não realizamos um filtro de eventos no método Update.

				
					public override void Update(TickStatus args)
{
	DateTime barra = new DateTime(2023, 6, 15, 11, 03, 0, DateTimeKind.Local);
	if (barra == HistoryDataSeries.GetTimeUtc(0).ToLocalTime())
	{
		DateTime datahora = HistoryDataSeries.GetTimeUtc(0);
    	datahora = datahora.ToLocalTime();
		Notification.Print("[" + datahora.ToString() + "] - Está é a barra desejada!");
	}
}
				
			

Identificação do primeiro tick de uma barra

Este código identifica o primeiro tick de uma barra. Esta tarefa é bem facilitada em EvoCode, tendo em vista a existência do TickStatus de nova barra (IsBar).

				
					public override void Update(TickStatus args)
{
	if (args == TickStatus.IsBar)
	{
		DateTime datahora = HistoryDataSeries.GetTimeUtc(0);
    	datahora = datahora.ToLocalTime();
		Notification.Print("[" + datahora.ToString() + "] - Este é o primeiro tick da barra!");					
	}
}
				
			

Ferramentas para EvoCode

Nesta seção vamos apresentar informações sobre as ferramentas de trading desenvolvidas pela NeoTraderBot para Trader Evolution, bem como informações relevantes para instalação e configuração em sua plataforma.

Como instalar/remover ferramentas, indicadores e estratégias da Trader Evolution

Nesse tutorial vamos ver o passo-a-passo para instalação e remoção de ferramentas, estratégias e indicadores na Plataforma Trader Evolution.

Todas as ferramentas, indicadores ou estratégias automatizadas desenvolvidas pela NeoTraderBot, independente de serem pagas ou gratuitas, são autenticadas antes de iniciarem sua execução. Assim é imprescindível que você instale a biblioteca de Autenticação da NeoTraderBot em sua plataforma Trader Evolution.

Instalando o Biblioteca de Autenticação da NeoTraderBot

Este é um procedimento bem simples, basta clicar aqui para baixar a versão mais recente da biblioteca de autenticação da NeoTraderBot. Por se tratar de um arquivo com extensão dll, seu navegador pode alertar para algum risco no download. Certifique-se de que conseguiu baixar o arquivo sem problemas.

Em seguida, mova o arquivo baixado para o diretório principal da TraderEvolution. Sigas os passos abaixo para identificar o diretório principal da plataforma TraderEvolution.

Passo 1: Abra uma janela do Windows Explorer (atalho WINDOWS + E) e na barra de endereço, (no lado esquerdo e superior da tela, logo abaixo do menu), digite “%APPDATA%” e pressione ENTER.

Passo 2: Será aberto um diretório contendo os programas instalados em seu PC, localize a pasta “Trader Evolution Brasil” e acesse-a.

Passo 3: Você está agora dentro do diretório principal da Trader Evolution. A biblioteca de autenticação deve ser copiada para dentro do diretório principal.

OBS: A sua plataforma Trader Evolution deve estar preferencialmente fechada.

Instalando Indicadores e Estratégias na TraderEvolution

A instalação de indicadores e Estratégias consiste basicamente em copiar as estratégias para dentro das pastas apropriadas dentro do diretório TraderEvolution, ou criar um diretório para concentrar códigos e referenciar esta pasta dentro da TraderEvolution.

Abaixo vamos demonstrar as duas maneiras de fazer a TraderEvolution listar os indicadores e estratégias dentro da plataforma.

Forma 1: Incluindo indicadores e estratégias nas pastas nativas da TraderEvolution

Passo 1: Abra uma janela do Windows Explorer (atalho WINDOWS + E) e na barra de endereço, (no lado esquerdo e superior da tela, logo abaixo do menu), digite “%APPDATA%” e pressione ENTER.

Passo 2: Será aberto um diretório contendo os programas instalados em seu PC, localize a pasta “Trader Evolution Brasil” e acesse-a.

Passo 3: Você está agora dentro do diretório principal da Trader Evolution. Acesse a pasta “Scripts”.

Passo 4: Dentro da pasta “Scripts”, você terá a pasta “Indicators” e “Strategies”. Basta copiar os indicadores/estratégias para dentro das respectivas pastas e a TraderEvolution passará a listá-los.

OBS: Esta cópia pode ser feita com a plataforma aberta. No entanto, recomendamos que feche-a antes de substituir arquivos.

Passo 5: Ao clicar sobre um gráfico o botão direito -> “Indicadores” -> “Adicionar Indicador”, você notará que os arquivos acrescentados na pasta “Indicators” são listados adequadamente.

OBS: Os arquivos são listados pelo nome do arquivo do código. Todos os arquivos da NeoTraderBot possuem em seu nome as iniciais NTB, facilitando assim a pesquisa pelo campo de busca. Observe que os novos indicadores não são listados dentro das categorias apresentadas pela plataforma.

Forma 2: Importando os códigos a partir de uma pasta ou arquivos individuais

Iremos demonstrar abaixo o processo para importação de indicadores. O procedimento é análogo no caso de estratégias, sendo a única diferença que o processo de importação de estratégias ocorre dentro do “Strategy Manager” ao tentar adicionar uma estratégia.

Passo 1: Crie uma pasta no local que desejar e copie para dentro dessa pasta os códigos que deseja que sejam listados dentro da plataforma TraderEvolution. Uma boa prática é manter um diretório para indicadores e outro para estratégias.

OBS: No exemplo abaixo, preferimos criar as pastas “NeoTraderBot_Indicators” e “NeoTraderBot_Strategies” dentro da pasta “Scripts” da TraderEvolution (conforme pode ser visto abaixo).

Passo 2: Ao clicar sobre um gráfico da TraderEvolution com o botão direito -> “Indicadores” -> “Adicionar Indicador”, será aberta uma janela para seleção de indicadores. Clique em “Importar”.

Passo 3: Será aberta uma janela de “Importar Script”, a qual você poderá selecionar uma pasta ou arquivos de maneira individual. Escolha uma das opções e localize os arquivos/pasta que deseja importar.

Passo 4: Ao acrescentar os arquivos, eles serão identificados pelo seu respectivo tipo e listados conforme figura abaixo. A coluna “Destino” por padrão seleciona a opção de copiar os arquivos para um diretório da TraderEvolution do usuário da máquina em “Documents\Trader Evolution Brasil\My scripts”.

Selecione a opção desejada na coluna “Destino” e, em seguida, clique em “Importar”.

Passo 5: Os arquivos serão importados e serão listados no grupo “Personalizado” na janela de “Pesquisa de Indicadores”.

Removendo Indicadores e Estratégias na TraderEvolution

A remoção de indicadores e Estratégias consiste basicamente em excluir os indicadores e estratégias das pastas nas quais eles foram copiados ou importados.

Conforme apresentado nos roteiro anteriores, a depender da forma como o usuário importou/copiou as ferramentas, elas podem estar no diretório principal da Trader Evolution (Passo 1 do roteiro de instalação da biblioteca de autenticação), ou na pasta do usuário windows referente ao programa Trader Evolution (em “Documents\TraderEvolution Brasil\My scripts”).

Em “My scripts” o usuário irá localizar tanto os códigos compilados (pasta bin) como código-fonte que foram criados pelo EvoCode localmente (arquivos cs, nas pastas “Indicators” e “Strategies”).

Como liberar o meu acesso às ferramentas NeoTraderBot?

Estamos sempre buscando otimizar código, estratégias e processos, visando gastar nosso tempo com o que realmente agrega valor. Assim, esperamos em breve poder tornar esse processo de obtenção de senha para uso das ferramentas NeoTraderBot mais integrado em um futuro próximo.

No momento, o procedimento para obtenção de senha para liberação de uso individual das ferramentas, indicadores e estratégias, pagas ou gratuitos, consiste em enviar o formulário abaixo.

Nós iremos responder em um prazo máximo de 24 horas (dia útil) com os dados de acesso.

Liberação de uso Ferramentas/ Indicadores/ Estratégias - TraderEvolution
Este formulário visa recepcionar a conta na qual o usuário irá executar as ferramentas e códigos desenvolvidos pela NeoTraderBot, que são comercializados para uso individual (apenas uma conta). Caso o usuário deseje executar em mais de uma conta ao mesmo tempo, deverá adquirir outra licença de uso. Entre em contato conosco para condições diferenciadas a partir da 2a licença do mesmo produto.
No caso de ferramentas pagas, utilize o mesmo e-mail fornecido no momento da compra da ferramenta.
Algumas ferramentas possuem funcionalidades liberadas para traders membros da Comunidade NeoTraderBot e que sinalizam o código da NeoTraderBot na plataforma Trader Evolution.
Clique aqui para ver o passo-a-passo de como se cadastrar como parceiro.
Realize o cadastro antes de enviar esse formulário...só leva 1 minuto!

Recebi um e-mail informando a liberação de uso da ferramenta. O que faço agora?

Caso ainda não tenha instalado a ferramenta na sua plataforma Trader Evolution, sigas os passos do roteiro neste link.

Ao adicionar um indicador ou estratégias, sempre haverá um parâmetro de autenticação: email (conforme figura abaixo). Forneça seu email cadastrado. Caso haja algum problema na autenticação, a ferramenta irá exibir mensagem em tela e o indicador ou ferramenta não será executada.

Caso tenha algum problema nesse processo de autenticação, entre em contato conosco pelo e-mail NeoTraderBot@gmail.com, fornecendo seu número de telefone de contato que iremos fornecer o suporte necessário.

Como me registrar como Parceiro da NeoTraderBot?

Aqui na NeoTraderBot temos o objetivo de criar uma comunidade de traders interessados em utilizar a automação a seu favor no trading, seja 100% por meio de robôs, ou semi-automatizada, delegando a algoritmos e códigos automatizados a execução de algumas tarefas específicas.

Para que você tenha acesso a algumas condições especiais no uso de ferramentas, indicadores e estratégias, pedimos que nos ajude a fazer crescer a Comunidade NeoTraderBot, sinalizando como nosso parceiro dentro da plataforma Trader Evolution.

É muito simples fazer isso! Siga o passo-a-passo abaixo:

Passo 1: Na Plataforma Trader Evolution, clique no item “Ferramentas” no menu superior. Em seguida na opção “Extensões” -> “Indique parceiro”.

Passo 2: Vai abrir uma pequena janela, na qual você irá inserir o código “NEOTRADERBOT” para sinalizar para a plataforma Trader Evolution que você pertence a Comunidade NeoTraderBot.

Pronto! Ao sinalizar que você pertence à Comunidade NeoTraderBot, poderemos pleitear novas funcionalidades, ajustes ou melhorias de maneira centralizada e com mais relevância, uma vez que saberão quantas pessoas estão engajadas na Comunidade NeoTraderBot!

Documentação: Integração com Telegram

Você já pensou em conectar os seus robôs e indicadores que rodam na Trader Evolution ao Telegram? Quer receber mensagens quando uma posição é aberta ou uma operação é encerrada? Acompanhar de onde estiver, por meio de mensagens no Telegram, o resultado das suas operações e de suas estratégias automatizadas é possível com a ferramenta de Integração da NeoTraderBot!

Nesta página você terá acesso a todas as informações necessárias para que suas estratégias lhe enviem mensagens pelo Telegram!

O que é a ferramenta de Integração da NeoTraderBot?

É uma biblioteca que permite qualquer robô/indicador implementado em EvoCode enviar mensagens de texto e fotos pelo Telegram. Assim, as possibilidades de uso são muito amplas, podendo servir, por exemplo, para:

          • Acompanhamento da execução de Estratégias/Robôs próprios;
          • Notificações na abertura ou encerramento de posições com o resultado da operação;
          • Envio de notificações para grupo Telegram baseado em filtro automatizado de ativos (Screenings);
          • Envio de alarmes em condições específicas de mercado;
          • Envio automatizado de informações de mercado (preço de ações, preços de abertura, etc..);
          • Acompanhamento do valor patrimonial de uma carteira de ações;
          • Compartilhamento de ordens geradas/executadas por estratégias.

Temos uma versão FREE para você começar a agora a integrar  o seu trading com o Telegram! Além disso, disponibilizamos outras versões com funcionalidades ampliadas.

Pré-configuração, Tutoriais e Documentação

Uma vez contratada/adquirida a ferramenta de Integração TraderEvolution/Telegram, e após a instalação  básica (roteiro aqui), serão necessárias algumas configurações específicas para integração com o Telegram. 

Siga o passo-a-passo abaixo para realizar as pré-configurações e poder utilizar a integração de Telegram em suas estratégias (cada item contém um vídeo de tutorial).

Pronto! Agora você já pode fazer suas estratégias/robôs enviarem mensagens pelo Telegram! Clique aqui para ver as perguntas mais frequentes e exemplos de códigos para adaptar a sua necessidade.

Como instalar o Pacote de Indicadores GRATUITOS?

Se você está nessa página é porque provavelmente recebeu um e-mail contendo as instruções para instalação do PACOTE DE INDICADORES GRATUITOS para TRADER EVOLUTION desenvolvidos pela NeoTraderBot e RNEC indicadores.

Caso queira baixar o pacote de indicadores, clique no botão abaixo.

Localizando o diretório de instalação da Trader Evolution

1) Acesse o Windows Explorer e digite na barra de navegação %APPDATA% e aperte ENTER. Localize o diretório “Trader Evolution Brasil”.

2) Dentro do diretório “Trader Evolution Brasil” acesse as pastas “Scripts” -> “Indicadores”.

3) Dentro da pasta “Indicators” você irá visualizar os indicadores da Trader Evolution instalados nativamente em seu computador. Devemos extrair o conteúdo do arquivo zip do PACOTE DE INDICADORES para esta pasta.

4) Pronto! Agora os indicadores já podem ser aplicados aos gráficos dentro da Plataforma Trader Evolution!

Indicadores para Trader Evolution

Aqui você irá encontrar informações dos indicadores desenvolvidos pela NeoTraderBot para plataforma TraderEvolution.

Os indicadores são disponibilizados em versões FREE, TRADER ou PREMIUM, nas quais há diferença de funcionalidades conforme apresentado nessa documentação.

Todos os indicadores são contratados por meio de licença individual de uso. As licenças são vinculadas ao login de acesso do usuário à plataforma TraderEvolution.

Os indicadores podem ser contratados no modelo de assinatura por meio de pagamento recorrente mensal ou por meio de uma licença vitalícia de uso, a qual irá garantir ao usuário acesso às atualizações que forem realizadas na versão contratada.

A contratação dos indicadores NÃO CONTEMPLA ACESSO AO CÓDIGO FONTE.

Caso tenha interesse em aprender a programar seus próprios indicadores para Trader Evolution, sugerimos realizar o curso de Programação em EvoCode disponível nesse link.

Snippets para Localização Temporal

Esta seção visa apresentar trechos de códigos com funcionalidades relativas à localização temporal da estratégia. Por exemplo, identificar se a atual barra é a primeira barra do dia para verificar gap diário.

Você pode acessar os Snippets diretamente pelo menu lateral direito, ou fazendo CTRL+F (CTRL+L) para localizar algum texto específico na página, uma vez que o conteúdo tende a crescer ao longo do tempo, dificultando a navegação pelo menu.

Caso tenham sugestões de código para acrescentar à lista, gentileza deixar o código nos comentários com o link para seu perfil em rede social (para devido crédito de autoria).

Snippets

Identificação de primeira barra do dia

Algumas estratégias necessitam da identificação da primeira barra do dia (candle) para executar determinada ação ou calcular o gap em relação ao fechamento do dia anterior. Segue abaixo um trecho de código para identificar a primeira barra de um dia.

				
					public override void Update(TickStatus args)
{
	if (HistoryDataSeries.GetTimeUtc(0).ToLocalTime().Date != HistoryDataSeries.GetTimeUtc(1).ToLocalTime().Date)
	{
		DateTime datahora = HistoryDataSeries.GetTimeUtc(0);
    	datahora = datahora.ToLocalTime();
    	Notification.Print("[" + datahora.ToString() + "] - Está é a primeira barra do dia!");
	}			
}
				
			

Identificação de barra por data e hora específicos

Reproduzir vídeo

Este código localiza a barra (candle ou box) por uma data e hora desejados. Onde a hora é referente ao horário de abertura do candle desejado.

Observe que criamos uma variável contendo a data/hora “11:03:00 15/06/2023” para exemplificação de código, mas poderia ser substituído por outras variáveis. E para todos os ticks dessa barra será impressa uma notificação, pois não realizamos um filtro de eventos no método Update.

				
					public override void Update(TickStatus args)
{
	DateTime barra = new DateTime(2023, 6, 15, 11, 03, 0, DateTimeKind.Local);
	if (barra == HistoryDataSeries.GetTimeUtc(0).ToLocalTime())
	{
		DateTime datahora = HistoryDataSeries.GetTimeUtc(0);
    	datahora = datahora.ToLocalTime();
		Notification.Print("[" + datahora.ToString() + "] - Está é a barra desejada!");
	}
}
				
			

Identificação do primeiro tick de uma barra

Este código identifica o primeiro tick de uma barra. Esta tarefa é bem facilitada em EvoCode, tendo em vista a existência do TickStatus de nova barra (IsBar).

				
					public override void Update(TickStatus args)
{
	if (args == TickStatus.IsBar)
	{
		DateTime datahora = HistoryDataSeries.GetTimeUtc(0);
    	datahora = datahora.ToLocalTime();
		Notification.Print("[" + datahora.ToString() + "] - Este é o primeiro tick da barra!");					
	}
}
				
			

CRIE ALERTAS E DISPARE ORDENS AUTOMATICAMENTE na Trader Evolution

Reproduzir vídeo

Neste vídeo da séria “Conhecendo a Trader Evolution” vamos explorar a funcionalidade do GERENCIADOR DE ALARME, o qual nos permite criar alertas de som, pop-up ou até mesmo disparar ordens automaticamente quando o alerta for emitido. Detalhe importante é que a ordem pode ser emitida em outro ativo diferente do ativo que gerou o alerta.

Snippets para Localização Temporal

Esta seção visa apresentar trechos de códigos com funcionalidades relativas à localização temporal da estratégia. Por exemplo, identificar se a atual barra é a primeira barra do dia para verificar gap diário.

Você pode acessar os Snippets diretamente pelo menu lateral direito, ou fazendo CTRL+F (CTRL+L) para localizar algum texto específico na página, uma vez que o conteúdo tende a crescer ao longo do tempo, dificultando a navegação pelo menu.

Caso tenham sugestões de código para acrescentar à lista, gentileza deixar o código nos comentários com o link para seu perfil em rede social (para devido crédito de autoria).

Snippets

Identificação de primeira barra da sessão ou do dia

Algumas estratégias necessitam da identificação da primeira barra do dia ou da primeira barra da sessão de negociação atual para executar determinada ação ou calcular o gap em relação ao fechamento da sessão anterior. Segue abaixo um trecho de código para identificar essas barras.

				
					namespace NinjaTrader.NinjaScript.Indicators
{
	public class NTB_Ex_FirstSessionBar : Indicator
	{
		protected override void OnStateChange()
		{

			if (State == State.SetDefaults)
			{ 
				Description									= @"NeoTraderBot Example: How to locate first bar of Session or Day";
				Name										= "NTB_Ex_FirstSessionBar";
				Calculate									= Calculate.OnBarClose;
				IsOverlay									= false;
				DisplayInDataBox							= true;
				DrawOnPricePanel							= true;
				DrawHorizontalGridLines						= true;
				DrawVerticalGridLines						= true;
				PaintPriceMarkers							= true;
				ScaleJustification							= NinjaTrader.Gui.Chart.ScaleJustification.Right;
				//Disable this property if your indicator requires custom values that cumulate with each new market data event. 
				//See Help Guide for additional information.
				IsSuspendedWhileInactive					= true;
				
            }
		}

		protected override void OnBarUpdate()
		{
            
			// Uncomment line below if you want to locate the first bar of the day
			//if (Time[0].Date != Time[1].Date)
            // Uncomment line below if you want to locate the first bar of the session
			if (Bars.IsFirstBarOfSession)
            {
				DateTime datahora = Time[0];
				NinjaTrader.Code.Output.Process("[" + datahora.ToString() + "] - The bar was located!", PrintTo.OutputTab1);
				BackBrushes[0] = Brushes.Blue;
            }
		}

	}
}
				
			

Identificação do primeiro tick de uma barra

Algumas estratégias podem necessitar de uma atuação mais tempestiva, porém, o programador gostaria de selecionar quais ações seria executadas no tick e quais seriam no fechamento da barra. Para isso, podemos criar um NinjaScript com a propriedade de cálculo configurada em Calculate.OnEachTick, e filtrar nas chamadas ao método OnBarUpdate o primeiro tick da barra, sinalizando o fechamento da barra anterior.

Assim temos liberdade para programar o NinjaScript para executar ações tanto no fechamento da barra quanto durante a formação de uma barra. Veja o código de exemplo abaixo:

				
					namespace NinjaTrader.NinjaScript.Indicators
{
	public class NTB_Ex_FirstTickOfBar : Indicator
	{
		protected override void OnStateChange()
		{

			if (State == State.SetDefaults)
			{ 
				Description									= @"NeoTraderBot Example: How to locate first bar of Session or Day";
				Name										= "NTB_Ex_FirstTickOfBar";
				Calculate									= Calculate.OnEachTick;
				IsOverlay									= false;
				DisplayInDataBox							= true;
				DrawOnPricePanel							= true;
				DrawHorizontalGridLines						= true;
				DrawVerticalGridLines						= true;
				PaintPriceMarkers							= true;
				ScaleJustification							= NinjaTrader.Gui.Chart.ScaleJustification.Right;
				//Disable this property if your indicator requires custom values that cumulate with each new market data event. 
				//See Help Guide for additional information.
				IsSuspendedWhileInactive					= true;
				
            }
		}

		protected override void OnBarUpdate()
		{
			if ( IsFirstTickOfBar)
			{
				Draw.Text(this,"teste","Primeiro Tick!",0,Close[0]);
			}
			else Draw.Text(this,"teste","Outros Ticks!",0,Close[0]);
		}

	}
}
				
			

Identificação de barra por data e hora específicos

Reproduzir vídeo

Este código localiza a barra (candle ou box) por uma data e hora desejados. Onde a hora é referente ao horário de abertura do candle desejado.

Observe que criamos um parâmetro no qual o usuário pode inserir um horário para facilitar os testes. O código pode tanto colorir o fundo da barra no horário especificado no dia atual ou nesse mesmo horário em todos os dias de negociação.

				
					namespace NinjaTrader.NinjaScript.Indicators
{
	public class NTB_Ex_DateTime : Indicator
	{
		public TimeSpan TimeOfDay;

		protected override void OnStateChange()
		{

			if (State == State.SetDefaults)
			{
				Description									= @"NeoTraderBot Example: How to find bars at specific Time or DateTime";
				Name										= "NTB_Ex_DateTime";
				Calculate									= Calculate.OnBarClose;
				IsOverlay									= false;
				DisplayInDataBox							= true;
				DrawOnPricePanel							= true;
				DrawHorizontalGridLines						= true;
				DrawVerticalGridLines						= true;
				PaintPriceMarkers							= true;
				ScaleJustification							= NinjaTrader.Gui.Chart.ScaleJustification.Right;
				//Disable this property if your indicator requires custom values that cumulate with each new market data event.
				//See Help Guide for additional information.
				IsSuspendedWhileInactive					= true;
				DesiredDateTime								= DateTime.Parse("10:31", System.Globalization.CultureInfo.InvariantCulture);

            }
			else if (State == State.Configure)
			{
				TimeOfDay = new TimeSpan(DesiredDateTime.Hour, DesiredDateTime.Minute, 0);
			}
				
		}

		protected override void OnBarUpdate()
		{

			// Uncomment line below if you want to sign the bar at a specific time just for the current date
			//if (Time[0] == DesiredDateTime)
            // Uncomment line below if you want to sign the bar at a specific time each day
			if (Time[0].TimeOfDay == TimeOfDay)
            {
				DateTime datahora = Time[0];
				NinjaTrader.Code.Output.Process("[" + datahora.ToString() + "] - This is the desired bar!", PrintTo.OutputTab1);
				BackBrushes[0] = Brushes.Blue;
            }
		}

		#region Properties
		[NinjaScriptProperty]
		[PropertyEditor("NinjaTrader.Gui.Tools.TimeEditorKey")]
		[Display(Name="DesiredDateTime", Order=1, GroupName="Parameters")]
		public DateTime DesiredDateTime
		{ get; set; }
		#endregion

	}
}
				
			

Como desenhar estudos nos gráficos da NinjaTrader

Reproduzir vídeo

Neste video iremos demonstrar passo-a-passo como incluir estudos ou desenhar elementos nos gráficos na Plataforma NinjaTrader.

A Plataforma permite configurar e personalizar todas formas diferentes de subgráficos e multigráficos que expande bastante a capacidade analítica na leitura de gráficos e permite uma flexibilidade muito grande para plotagem de indicadores customizados.

Este é um conteúdo informativo sobre NinjaTrader para que os membros da comunidade tenham informações do que é possível realizar em outros ambientes. Reforço que não estamos realizando nenhuma recomendação para mudança de Plataforma e que a decisão de migrar parte ou todo o processo de desenvolvimento e execução das estratégias automatizadas é muito pessoal e cabe apenas ao trader decidir sobre tal assunto.

Limitações da Plataforma

Não existe perfeição…e quando falamos de software é difícil acharmos um que não tenha bugs ou pontos de melhoria (que as vezes tem uma análise mais subjetiva…uma melhoria para um usuário pode não ser para outro).

Este documento visa abordar as limitações conhecidas da plataforma Profit Chart referentes a automatização de estratégias e backtesting. Trata-se de uma base de dados em constante evolução, que pode crescer ou diminuir (assim esperamos) a medida que os membros da comunidade apresentarem novos itens, ou se a Nelógica lançar atualizações da plataforma para tratar as questões apresentadas.

Primeiramente, antes de começarmos precisamos fazer justiça e ressaltar que em termos de disponibilização de ferramentas para análise de mercado, a Plataforma Profit Chart entrega muitas funcionalidades interessantes e é uma plataforma muito bem aceita pelos traders! Nosso papel é um pouco cruel, pois vamos ser bem críticos neste documento, mas sem desmerecer a qualidade do software Profit Chart!

Nossos olhares estarão direcionados ao módulo de Editor de Estratégias que vinha recebendo pouca atenção até meados de Agosto/2022, quando a Nelógica começou a lançar atualizações referentes à automação de estratégias.

A primeira atualização do Editor de estratégias que nos chamou a atenção foi a possibilidade de usar dados de preço de múltiplos ativos nas estratégias. Isso era algo desejado há muito tempo e apesar de ainda haver algumas limitações nessa funcionalidade, a atualização já abriu várias oportunidades para elaborar novas estratégias. Se quiser saber mais sobre isso, assista ao vídeo que fizemos sobre estratégia baseada em múltiplos ativos no Youtube da Comunidade.

Recentemente, ainda tivemos a disponibilização da versão 5.2.2.121 na qual foi lançado o módulo de Automação de Estratégias, permitindo rodar Estratégias de Execução (robôs) em conta simulada. Esta também era outra funcionalidade há muito tempo demandada à Nelógica (clique aqui para conhecer o módulo de automação de estratégias), que em breve permitirá rodar os robôs em conta real! Será uma revolução!

Estamos vendo com muito bons olhos o esforço da Nelógica em melhorar as funcionalidades relacionadas à automatização das estratégias! Assim, esperamos que este documento também alcance a equipe de desenvolvimento da Nelógica e que possamos contribuir para o aprimoramento da Plataforma por meio das sugestões apresentadas!

Sem mais delongas, veja abaixo as limitações da Plataforma Profit Chart listadas pela Comunidade NeoTraderBot, bem como observações sobre a evolução da situação de cada item.

Limitações conhecidas da Plataforma Profit Chart

Legenda:

O código fonte desenvolvido para backtesting não pode ser exatamente o mesmo que será executado como robô no Módulo de Automação.

Seria interessante se houvesse compatibilidade entre os dois contextos, evitando assim retrabalhos e erros de tradução de código para que este funcione em áreas distintas dentro do mesmo software.


Sugestões:

  1. Implementar um gestor de ordens em ambiente backtesting para que as ordens sejam tratadas da mesma forma em Backtesting e no Módulo de Automação;
  2. Tratamento das ordens de cobertura no Módulo de Automação, pois não são reconhecidas nesse contexto;
  3. Estratégias com multi-objetivos (coloração, indicador e execução) quando utilizadas no Módulo de Automação ou em gráficos em tempo real são incluídas como diferentes instâncias, que dependendo do objetivo também são processadas de formas diferentes, gerando descasamento de informações.
 

Embora haja dados tick a tick, as ordens são enviadas apenas no fechamento dos Candles e este comportamento não pode ser alterado.


Sugestões:

  1. Refatorar as funções de ordens para que permitam execução no tick ou no fechamento da barra, cabendo essa decisão ao programador.

USERVOICE: CRIAR parâmetro de funções de ROTEAMENTO DE ORDENS para serem executadas NO TICK ou fechamento da Barra [NeoTraderBot]

Para backtesting de estratégias baseadas em renko, não é possível garantir encerramento de posição de daytrade porque as ordens são executadas apenas no fechamento do box.


Sugestões:

  1. Reestruturar o modelo de simulação de renko para que o backtesting permita encerrar posição dentro do box que contiver o horário desejado.

USERVOICE: GARANTIR ENCERRAMENTO DE POSIÇÃO por horário para Gráficos não temporais em Backtesting (ex: Renko) [NeoTraderBot]

Seguem abaixo os pontos observados em relação ao recém lançado Módulo de Automação de Estratégias (lançamento oficial em 29/set/2022)

  1. Velocidade de replay impacta preço de abertura de posição. Se executa replay em 1x, o preço de abertura de uma posição é diferente se fosse executado em 10x, para todas as demais condições de código e simulação iguais. Por que acontece isso em replay?
  2. Estratégias que possuem indicadores são inseridos como uma instância separada da instância que realiza a execução de ordens. Isso gera problemas de consistência entre um plot baseado em preço de posição com o preço efetivamente realizado na instância de execução da estratégia;
  3. Processamento de replay é muito lento. Mesmo em 10x. Seria possível aprimorar isso? Executar o processamento dos dados em maior frequencia do que a renderização (amostrando renderização).
  4. Não há funções NTSL para retornar resultado bruto no momento.

USERVOICE: Velocidade de REPLAY NÃO DEVE IMPACTAR execução de ordens em estratégias/robôs no Módulo de Automação [NeoTraderBot]

O acesso a dados de 1 minutos (por exemplo) é muito limitado . A plataforma consegue recuperar apenas os últimos 3 (três) meses de dados de preço com frequência de 1 minuto. Para desenvolvimento de estratégias de alta frequência, otimização e backtesting, esse é um volume muito pequeno de dados.

Felizmente, à medida que utiliza-se dados com menor frequência (5, 15 60 minutos, 1 dia) é possível obter uma janela maior de dados históricos. Por exemplo, se o usuário demandar dados de 15 minutos, a plataforma recupera 6 anos. O que nesses casos demonstra-se adequado.


Sugestões:

  1. Permitir que o usuário puxe mais dados da base, quando for conveniente;
  2. Permitir carregar série de dados OHLCV (Open, High, Low, Close, Volume) para fins de backtesting.

USERVOICE: PERMITIR IMPORTAÇÃO DE DADOS OHLCV e Tick PARA FINS DE BACKTESTING [NeoTraderBot]

Para desenvolvimento de estratégia o trader/programador não possui acesso à dados de negociação (times & trades) com granularidade suficiente para implementar lógicas que se baseiem na forma como as negociações estão ocorrendo no mercado.

Tampouco, há acesso para a informações do Book de ofertas, quantidade de ordens por nível de preço, volume  das ordens, corretora, etc…Não ter esse tipo de dado disponível também cria limitação na implementação de estratégias que se baseiem em fundamentos diferentes da análise técnica.


Sugestões:

  1. Criar funções no editor de estratégia para obter acesso amplo à negociações realizadas no último tick;
  2. Criar funções no editor de estratégia para obter acesso às informações do book de ofertas.

A plataforma não apresenta funcionalidade para auxiliar a tarefa de otimização de parâmetros de estratégias.

Por exemplo, caso o usuário implemente um robô baseado em cruzamento de média, a plataforma poderia auxilia-lo na definição do número de períodos mais adequado para a média por meio da maximização ou minimização de alguma métrica, tal como maximização do percentual de operações vencedoras, ou minimização do drawdown médio das operações.


Sugestões:

  1. Criar funcionalidade para otimizar “parâmetros” das estratégias em função de uma métrica escolhida pelo usuário.

USERVOICE: CRIAR OTIMIZADOR de Estratégias no Profit [NeoTraderBot]

No Profit, toda estratégia de execução precisa estar vinculada a um gráfico de um ativo. Desta forma, não é possível criar ordens em um ativo baseado em sua posição em outros ativos. Ou seja, não há possibilidade de criar uma estratégia para operar uma correlação entre múltiplos ativos.

Esta limitação do Profit impede, por exemplo, de se criar uma estratégia para gestão de portfolio ou  estratégias de arbitragem, entre outras…


Sugestões:

  1. Alterar funções de Backtesting (IsBought, IsSold, SellPrice, BuyPrice, etc…) para que o usuário informe o código do ativo. Por default, o código seria o ativo no qual a estratégia de execução está rodando;
  2. Permitir executar em conta real estratégias que não estejam vinculadas a nenhum ativo específico;

USERVOICE: PERMITIR CRIAÇÃO DE ESTRATÉGIAS que envie ordens em DIFERENTES ATIVOS [NeoTraderBot]

Antes da versão beta 5.2.2.121 do Profit Chart, o debug do editor de estratégias não possuía opção de “continuar”. Ou seja, uma vez pausado o código em um breakpoint, o usuário tinha que percorrer linha a linha ou terminar de executar tudo de uma vez. Não era possível executar o código de uma vez até o próximo breakpoint.

Outra limitação era o fato de não haver a possibilidade de criação de breakpoint condicional. A atualização mencionada passou a permitir criar breakpoint baseados em timestamp (horário), o que já representou um avanço na ferramenta.


Sugestões:

  1. Permitir criação de breakpoints baseados em valor específico de uma variável;
  2. Permitir inspeção de expressões com base nos valores atuais das variáveis quando o código estiver pausado em um breakpoint;

USERVOICE:MELHORAR poder de Depuração da NTSL – MELHORAR DEBUG [NeoTraderBot]

Segue abaixo uma relação de ítens a serem melhorados no Editor de estratégias. A medida que forem sendo resolvidos pelas atualizações da plataforma, iremos sinalizar com a tag RESOLVIDO (Versão XXX).

    1. Não é possível alterar o valor dos parâmetros da estratégia no modo de exibição misto;
    2. Não é possível utilizar funções de indicadores passando como parâmetro o ativo no qual se deseja calcular o indicador;
    3. No desenvolvimento de indicadores, não é possível via código definir preenchimento e cor de preenchimento entre duas séries de dados. Isto invialibiliza preencher entre séries quando há mais do que 2 séries plotadas;
    4. Não há uma forma sistematizada de inicializar variáveis globais;
    5. Na linguagem NTSL, não há comando “break”   para os controles de repetição (for e while);
    6. Não há constantes definidas para valores máximos e mínimos de integer e float;
    7. Não há função built-in (já implementada) para manipulação básica de arrays, tais como obter valor máximo, valor mínimo, ordenar…etc)
    8. Ao utilizar o depurador estando o mercado aberto, a medida que chega novos dados, ainda que você esteja parado em um breakpoint, os plots se movimentam, dificultando a depuração

Sugestões:

  1. Criar função para preenchimento entre séries;
  2. Refatorar as funções de indicadores para que haja um parâmetro da série do ativo que se deseja calcular o indicador;
  3. Adicionar aba de “Parâmetros” às “Propriedades da Estratégia” para configurar valores dos parâmetros da estratégia no modo de exibição misto;
  4. Padronizar função OnInit para o usuário poder inicializar da forma que desejar as variáveis antes da estratégia começar a rodar;
  5. Incluir comando de break na linguagem NTSL para os controles de repetição;
  6. Definir constantes de valores máximos e mínimos dos tipos de dados Integer e Float;
  7. Criar algumas funções embutidas para manipulação de array, tais como: max, min e sort.

USERVOICE:MELHORIAS DIVERSAS em NTSL [NeoTraderBot]

USERVOICE:AUMENTAR PRECISÃO da função TIME, CURRENTTIME para segundos e CRIAR função de TempoRestante [NeoTraderBot]

USERVOICE:Refatoração de TODOS os indicadores da plataforma para aceitar como parâmetro a série de dados [NeoTraderBot]

USERVOICE:Criação de Bloco de INICIALIZAÇÃO na linguagem NTSL [NeoTraderBot]

USERVOICE: Criar nova ABA de ORDENS na seção de Estatística do Editor de Estratégias [NeoTraderBot]

USERVOICE:Criar função para retornar preço e quantidade de contratos/lotes negociados desde abertura da posição [NeoTraderBot]

USERVOICE: Criar  EXPORTAÇÃO /IMPORTAÇÃO DE ESTRATÉGIA AUTOMATIZADA configurada no MÓDULO DE AUTOMAÇÃO [NeoTraderBot]

Antes da versão beta 5.2.2.121 do Profit Chart, as estratégias de execução (robôs) só podiam ser usados para fins de backtesting, análise de desempenho em dados históricos e visualização nos gráficos de recomendação de operação, cabendo ao trader efetuar as operações sinalizadas pela estratégia.

O novo Módulo de Automação de Estratégias, lançado na versão beta mencionada, passou a permitir a execução de robôs em tempo real nas contas de simulação. Isto foi um grande avanço e que já prepara a plataforma para permitir rodar os robôs em conta real.

Acredito que essa atualização do Profit mais conservadora seja motivada para corrigir eventuais bugs do módulo antes de liberar para contas reais (acho isso bem responsável por parte da Nelógica!).

 


Sugestões:

  1. Permitir execução de robôs programados pelo próprio usuário em contas reais.

Caso tenham verificado outras limitações da plataforma Profit Chart, gentileza escrever nos comentários desse artigo, bem como sua sugestão de melhoria. Iremos, sempre que possível, complementar a lista com as observações dos membros da Comunidade.

RELATÓRIO DE DESEMPENHO – Acompanhe os resultados das suas operações na Trader Evolution

Reproduzir vídeo

Neste vídeo da séria “Conhecendo a Trader Evolution” vamos explorar o Relatório de Desempenho no qual o trader pode avaliar as operações (trades) realizados na plataforma, de maneira individual (por ativo negociado) e agregada.

Monitore o mercado com o Market Analyzer e Market Watch

Reproduzir vídeo

Neste video iremos demonstrar passo-a-passo como analisar o mercado de maneira global utilizando a ferramenta MARKET ANALYZER E MARKET WATCH na NinjaTrader.

Vamos ensinar PASSO-A-PASSO como configurar esta ferramenta poderosa de análise disponível na Ninja Trader e que permite a inclusão de indicadores customizados que poderão agregar muito valor ao seu operacional, permitindo a realização de screenings muito mais sofisticados do que estamos acostumados a criar em plataformas brasileiras.

Este é um conteúdo informativo sobre NinjaTrader para que os membros da comunidade tenham informações do que é possível realizar em outros ambientes.

Reforço que não estamos realizando nenhuma recomendação para mudança de Plataforma e que a decisão de migrar parte ou todo o processo de desenvolvimento e execução das estratégias automatizadas é muito pessoal e cabe apenas ao trader decidir sobre tal assunto.

Otimização

Esta parte da Base de Conhecimento visa trazer informações sobre os processos de otimização e como realizá-los em diferentes plataformas.

Conceitos básicos

Aprenda sobre os métodos de otimização, técnicas para segregação de dados e otimização.

Introdução a Otimização

Reproduzir vídeo

O processo de desenvolvimento de uma estratégia automatizada demanda a execução de algumas etapas importantes visando aumentar a chance de sucesso ou lucratividade de uma estratégia.

Podemos pensar neste processo como um filtro, no qual iniciamos implementando o código fonte dos algoritmos selecionados que vislumbramos ter maior chance de sucesso na exploração de padrões estatísticos na negociação de ativos. Essa implementação é um desafio inicial e os ajustes que realizamos no código fonte visando melhorar a execução do algoritmo, podem acabar gerando graus de liberdade adicionais à estratégia. Por exemplo, além de parâmetros de médias e outros indicadores próprios do setup operacional, podemos incluir outros indicadores para filtrar situações de mercado. Esses novos indicadores precisarão ser ajustados para que a estratégia funcione bem.

Além disso, é recomendável (para não dizer imprescindível) que toda estratégia tenha uma gestão de risco adequada: definição de tipos e parâmetros de stoploss e definição de alvo das operações (caso não seja feito pelas regras da própria estratégia).

E onde entra a otimização nesse processo? Tendo o código fonte da estratégia implementado, a otimização é o processo pelo qual iremos definir os valores mais apropriados para os graus de liberdade da estratégia! A seguir, vamos entender o que é a otimização para que possamos avançar para a realização prática desse processo sobre uma estratégia.

O que é Otimização?

Otimização é uma área da matemática aplicada que busca selecionar a melhor solução para um problema com relação a um determinado critério dentro de um conjunto de alternativas. Percebam que não estamos falando de problemas teóricos que podem ser modelados por expressões matemáticas lineares ou que podem ser resolvidos por cálculos diferenciais. A otimização aplica-se a problemas nos quais não é possível modelar por equações matemáticas ou ainda que tenhamos as equações não conseguimos resolvê-las pelo cálculo, mas apenas por métodos numéricos ou simulações.

Vamos contextualizar a otimização para o universo das estratégias automatizada. Percebam que não temos fórmulas matemáticas para este problema., mas podemos utilizar um simulador com dados históricos que são os registros do funcionamento do mercado, da oscilação de preços ao longo do tempo e volume negociado, no caso do modelo OHLCV. Podemos ter modelos de simulação que consideram dados com maior ou menor frequência, dados de Book de ofertas ou até informações das ordens executadas. O modelo de simulação pode se tornar mais complexo do que um simples OHLCV e o que é que vai ponderar o nível de complexidade do modelo é a disponibilidade de dados e custo computacional!

Vamos agora formalizar alguns conceitos para seguirmos adiante!

Espaço amostral

Espaço amostral ou espaço de busca…se formos estudar o assunto, cada área de conhecimento atribui um nome diferente para a mesma coisa…o que importa é o conceito!

O espaço de busca ou espaço amostral é o conjunto de todas as possibilidades de valores possíveis para cada variável de entrada do modelo, ou seja, dos graus de liberdade do nosso modelo. Para cada conjunto desse, se aplicarmos a nossa estratégia em uma janela histórica teremos um resultado diferente das operações realizadas.

Na figura acima, visualizamos do lado esquerdo exemplos de graus de liberdade de uma estratégia, que podem ser parâmetros de indicadores (quantidade de períodos de médias móveis, tipos de médias, qtde de períodos do MACD, IFR, sensibilidade de um indicador de topos e fundos), pode ser a opção de uso de uma técnica de stop (fixo, móvel) e todos os parâmetros relacionados: tamanho do stop, tamanho do passo de um stop móvel discreto, utilização de breakeven, valor do gatilho do breakeven, tamanho do alvo das operações (isso também pode ser uma variável de entrada do modelo!).

Do lado direito você visualizará o conjunto de métricas do resultado da execução do modelo de simulação para uma dada configuração de variáveis de entrada. Ou seja, temos um mapeamento do conjunto de dados de entrada para um conjunto de métricas de execução.

O modelo de simulação é que realiza o mapeamento das variáveis de entrada para  as métricas de desempenho! É nele e nos dados históricos utilizados que estão contidas as regras de simulação, bem como as restrições de execução.

Tipos de variáveis de entrada

As variáveis do espaço amostral podem ter tipos diferentes…podem ser números inteiros, por exemplo, a quantidade de períodos das médias. Podem ser números reais, tal como a sensibilidade de um indicador de topos e fundos ou tamanho inicial do stop. Podem ser dados categóricos ou booleanos: tipo de stop, com ou sem breakeven.

A importância de compreender o tipo das variáveis de entrada reside na definição do espaço amostral de cada variável de entrada que irá impactar o tamanho total do espaço amostral do problema de otimização e o esforço computacional demandado.

Calculando o tamanho do espaço amostral

Para cada variável de entrada do modelo de simulação, precisamos definir seu espaço amostral. 

No caso de variáveis que são números inteiros ou reais, precisamos definir um valor inicial, um valor final e o passo entre cada amostra. Cada variável sensibiliza o resultado em determinada magnitude, assim não faz sentido variar os valores em uma escala muito pequena. Por exemplo: não tem sentido simular um stop inicial de 1,37525 %…é muita precisão numérica….não faz diferença na otimização porque o preço de uma ação por exemplo vai até a segunda casa decimal (centavos). O que talvez seja mais factível para esta variável é estabelecer um espaço amostral entre 0,3% até 1,5%, variando em 0,1%, ou 0,2%….Isto é você quem vai decidir! Se fossemos varia entre 0,3 e 1,5% a cada 0,1%…isso daria 13 valores possíveis.

Após definir o espaço amostral para cada variável, iremos calcular a permutação de todos valores possíveis para obter o tamanho do espaço amostral….ou seja, basta multiplicarmos a quantidade de possibilidades de cada variável de entrada e realizar a soma quando uma determinada opção de variável de entrada impacte em alterações da quantidade de variáveis de entrada. Neste último caso, possivelmente estaremos trabalhando com códigos fontes distintos.

Vamos fazer um exemplo de cálculo do tamanho do espaço amostral para uma estratégia de cruzamento triplo de média, só para fixar esta parte do conteúdo. Vejas as figuras abaixo com o passo-a-passo do cálculo:

Existem algumas combinações de variáveis de entrada que não fazem sentido na permutação…por exemplo: quantidade de períodos da media rápida maior que media intermediaria. Então a quantidade de conjuntos viáveis é menor que isso…vamos supor para simplificação que seja 50% do teto calculado do tamanho do espaço amostral….estaríamos falando ainda de cerca de 7 milhões e 800 mil simulações aproximadamente.

Ainda é um número bem grande! Quanto tempo leva para rodar cada simulação? 3 segundos? E para armazenar o resultado em uma planilha? Isso é feito manualmente ou automaticamente? Vamos supor que o armazenamento das métricas da execução do modelo seja automatizado e gaste 0 segundos…se fossemos rodar todas as possibilidade seria 7,8 milhoes veze 3 segundos….o que daria: 270 dias de execução direta em uma única máquina…Isto certamente não é viável!

Ainda vamos falar dos métodos de otimização e se é necessário rodar 7,8 milhões de testes ou não em próximos documentos aqui no site…O que eu queria deixar claro aqui é que há restrições computacionais e por isso precisamos ser criteriosos em relação ao tamanho do espaço amostral que iremos mapear…por uma questão de tempo!

Função objetivo

A função objetivo ou função de custo ou função utilidade é apenas uma fórmula a qual tentaremos minimizar ou maximizar. Ou seja, iremos selecionar as configurações das variáveis de entrada do espaço amostral que minimizam ou maximizam determinada métrica de desempenho da estratégia, ou fórmula matemática.

Podemos definir otimizar o lucro líquido da estratégia ou a taxa de acerto (em outras palavras, o percentual de operações lucrativas).  Poderíamos até otimizar a relação de risco ganho da estratégia, que seria o quanto a estratégia tem de lucro médio nas operações vencedoras em relação ao prejuízo médio das operações perdedoras. O objetivo de otimização também poderia ser minimizar o drawdown da estratégia, que é o decaimento máximo de patrimônio.

A relação de métricas mais comuns como objetivo de otimização estão listadas abaixo, bem como sua definição:

Métrica Definição
Lucro bruto/líquido
Refere-se ao somatório do resultado dos trades realizados. Se positivo, significa que a soma do lucro dos trades vencedores superou a soma do prejuízo dos trades perdedores. Se negativo, significa que a soma do prejuízo dos trades perdedores superou a soma do lucro dos trades vencedores. O lucro pode ser em termos brutos (sem considerar custos de operação: taxas e emolumentos) ou líquido quando a plataforma já considera tais custos.
Taxa de acerto
Trata-se da divisão da quantidade de trades vencedores (que obtiveram lucro) pelo número total de trades realizados.
Drawdown
Refere-se ao maior decaimento de patrimônio ocorrido durante a simulação ou seja, a maior diferença entre um topo do valor de patrimônio e o próximo fundo.
Relação Risco/Ganho
É definida como a divisão entre lucro médio dos trades vencedores e prejuízo médio dos trades não vencedores. Uma sutileza do cálculo é que o lucro médio é calculado como o lucro total dos trades vencedores dividido pela quantidade de trades não perdedores, ou seja, inclui os trades que foram zerados. Já o prejuízo médio é a divisão entre o prejuízo total dos trades perdedores e a quantidade de trades perdedores. Este cálculo é mais conservador e recomendável para análise.
Fator de recuperação
É calculado dividindo o lucro final da simulação maior drawdown da simulação. Mede, portanto, a resiliência da estratégia, o quanto ele consegue recuperar de uma sequência de resultados ruins de trades.
Índice de Sharpe
A análise dessa métrica pressupõe que o retorno da estratégia é uma distribuição normal, uma vez que são utilizados apenas os dois primeiros momentos da distribuição, média e desvio padrão. É calculado como (retorno_est - retorno_livre)/desvio_pad. Onde retorno_est é o retorno da estratégia em uma determinada base temporal: anual, mensal, semanal, diária. retorno_livre é a taxa de retorno livre de risco. O usuário pode arbitrar entre usar IBOV ou taxa de juros de título do tesouro, na mesma base temporal. Por fim, desvio_pad refere-se ao desvio padrão da série de retorno da estratégia.

Imagino que você deve estar se perguntando…eu só posso otimizar uma métrica? E se eu quisesse maximizar o lucro líquido e ao mesmo tempo minimizar o Drawdown? É possível?

Sim, claro…é possível! Estamos falando neste caso de uma otimização multiobjetivo e existem algumas formas para se resolver este problema. Eu vou falar de apenas uma forma pois não é foco deste material, mas sinta-se a vontade para pequisar sobre o assunto.

Uma forma de fazer otimização multiobjetivo é criar uma função linear das métricas desejadas, atribuindo pesos para cada métrica. Estes pesos servirão tanto para ponderar as métricas mais importantes quanto para normalizar o valor das métricas que podem ser de escalas diferentes. Por exemplo, Lucro líquido é em unidades monetárias, enquanto Taxa de acerto é percentual (ou seja varia de 0 a 1). O peso atribuído a taxa de acerto deve ser tal que distribua de forma adequada a importância da otimização entre lucro líquido e taxa de acerto.

Recapitulando

Vimos neste documento os conceitos básicos sobre otimização e como eles se aplicam ao universo das estratégias automatizadas. No próximo documento veremos em maior profundidade como funcionam dois métodos de otimização: Grid Search e Algoritmos Genéticos, bem como iremos abordar questões importantes relacionadas aos dados utilizados para otimização.

Algoritmos, Segregação de dados e Overfitting

Reproduzir vídeo

Antes de falarmos sobre algoritmos de otimização, precisamos abordar o tema de segregação de dados dados históricos disponíveis para permitir a adequada realização de otimização e de backtesting.

A separação de dados é fundamental e precisa ser realizada antes de iniciar a otimização. Normalmente, deixamos os dados mais recentes reservados para o backtesting e um intervalo de tempo que permita uma quantidade suficiente de operações para analisar o resultado do backtesting com significância estatística. Ainda abordaremos aspectos a backtesting em outros materiais…por enquanto, é preciso entender que backtesting é um processo de validação executado após a otimização.

Não existe uma fórmula mágica ou um percentual específico dos dados para separar para backtesting. Na literatura, vemos sugestão de percentuais entre 15% a 30%…isso geralmente depende de vários fatores e também da quantidade de dados históricos que se tem disponível. Por exemplo, se uma estratégia opera daytrade, seria recomendável ter, no mínimo, 100 dias de operação no backtesting. Para que haja uma significância estatística na validação, ou seja para que a estratégia tenha a oportunidade de  experimentar situações distintas de alta, baixa, correção, lateralização… Se o intervalo médio entre as operações de uma estratégia é de 2 dias…então é preciso, no mínimo, 200 dias. Observe que no primeiro caso, haverá possivelmente mais operações do que no segundo caso. Quanto maior a amostra de operações no backtesting melhor, o problema é que há uma limitação de tamanho dos dados de backtesting e, geralmente,  precisamos de mais dados para a otimização do que para backtesting.

O conjunto de dados que separamos para backtesting nós vamos esquecer que existe enquanto estivermos fazendo a otimização e vamos chamar de OUT OF SAMPLE… a razão disso vai ficar mais clara no decorrer da explicação sobre otimização. Os dados que iremos utilizar para otimizar vamos chamar de IN SAMPLE.

Vamos agora falar sobre dois algoritmos muito empregados na otimização de estratégias.

Grid Search

O primeiro algoritmo que vamos tratar se chama Grid Search. Isto é só um nome bonito para um processo de exploração do espaço de busca por força bruta! Ou seja, este algoritmo simula todas as possibilidades de combinação dos parâmetros da estratégia. Você viu no exemplo do vídeo anterior que uma estratégia de cruzamento triplo de média, com 7 graus de liberdade gerou aproximadamente 7 milhões de possibilidades.

É coisa pra caramba! Não dá pra simular isso tudo…fica muito caro! Imagina a quantidade de tempo, o custo de máquinas ou de aluguel de cloud computing para se obter os parâmetros otimizados de uma estratégia que pode no final resultar em uma estratégia não lucrativa.

A primeira lição é ponderar sobre os recursos que se tem a disposição para realizar a otimização. Você vai fazer a simulação e tabelamento dos resultados de forma automática, sem intervenção humana….tudo bem…você pode simular mais possibilidades. Se você vai fazer na mão o processo de otimização com Grid Search, você vai ter que reduzir o espaço de busca.

Vou te dar um exemplo básico de Grid Search. Suponha que iremos otimizar apenas 2 variáveis da nossa estratégia, sendo 5 possibilidades para a primeira variável X e 5 para a segunda variável Y. Têm-se então 25 pontos que representam as combinações dos valores das variáveis X e Y. O Grid Search consiste em rodar a estratégia para cada um desses 25 pontos. Mas em qual ordem? Como iremos testar tudo de qualquer  forma, achar a solução na força bruta, então tanto faz! Mas nada impede também de rodar e coletar o resultado em uma planilha ou aplicativo web em uma ordem que julgar mais interessante.

O Profit Chart, na versão de hoje (12/12/2022), não oferece nenhum funcionalidade de suporte ao processo de otimização. Ou seja, se você só usar o Profit, só poderá fazer uma otimização bem limitada com um espaço de busca pequeno. Para ampliar o espaço de busca e automatizar o processo você precisará utilizar outra plataforma ou framework.

A próxima pergunta que você deve estar fazendo é se existem formas mais elaboradas de se otimizar uma estratégia do que simular na força bruta cada possibilidade? Sim! E uma resposta é algoritmo genético!

Algoritmo Genético

Os algoritmos genéticos baseiam-se nos processos de evolução genética e seleção natural que observamos na natureza e consistem em uma forma de percorrer o espaço de busca.

Em uma explicação com termos bem simples….o algoritmo inicia com uma população de indivíduos gerados aleatoriamente que é a primeira geração. Cada individuo possui em seu DNA uma codificação de alguma possibilidade das variáveis de entrada. Cada individuo terá um resultado associado na simulação. Essa população irá reproduzir, escolhendo aleatoriamente casais, que devido à combinação genética dos pais, irão gerar filhos que terão em seu DNA uma codificação que é uma mistura do DNA de seus pais, consistindo em uma outra possibilidade de variáveis de entrada. Os filhos também terão um resultado associado na simulação, sendo a segunda geração do algoritmo. Daí, como acontece na vida, podem haver mutações nos indivíduos que nascerem, consistindo em pequenas alterações aleatórias e alguns indivíduos irão “morrer”, não passando para futuras gerações seu código genético, que são os indivíduos com pior resultado.

Ou seja, parte da população da geração atual vai permanecer, parte não irá prosseguir para futuras gerações, novos indivíduos serão gerados por combinação dos pais, alguns dos novos indivíduos sofrerão mutações permitindo maior variabilidade genética. Na próxima etapa, os filhos já irão reproduzir, e esse processo irá ocorrer de forma iterativa, regido pela seleção natural daqueles que apresentarem melhores resultados, até que uma condição de parada seja atingida, por exemplo, não tenha surgido nenhum individuo nas últimas 5 gerações com resultado melhor do que o melhor resultado já encontrado.

Qual é o benefício almejado pelos algoritmos genéticos? Reduzir o esforço computacional exigido na força bruta, reduzindo a probabilidade de ter que calcular todas as possibilidades do espaço de busca, pois o algoritmo genético irá percorrer o espaço de forma mais eficiente! Uma vez encontrado a solução ótima, é improvável que haja uma solução melhor do que aquela, no espaço de busca não explorado.

Explicados os dois algoritmos mais utilizados para otimização de estratégias, vamos falar enfim do principal risco da otimização: Overfitting.

Overfitting

Como o nome diz overfitting é um ajuste excessivo ou sobre-ajuste. No caso da otimização é a obtenção de variáveis de entrada da estratégia que funcionam muito bem para os dados IN SAMPLE, mas quando executado o backtesting a estratégia apresenta uma deterioração muito significativa do resultado. Ou seja, o ajuste do modelo encontrado possui baixa capacidade de generalização.

Este é o maior risco da otimização: deterioração de desempenho com dados novos. E quais são as possíveis causas de overfitting? Excesso de graus de liberdade e dados com viés. Vamos entender isso melhor:

Quanto mais variáveis de entrada a otimização estiver calculando, mais graus de liberdade você estamos dando para que a otimização ajuste a estratégia aos dados apresentados. Isto significa que podemos estar otimizando um modelo muito específico que utilize mais indicadores do que precisa ou colocando na otimização muitas variáveis. As configurações que apresentarem os melhores resultados em otimização podem ter chance grande de estarem com overfitting. Algumas pessoas recomendam descartar os melhores resultados, mas é recomendável rodar todas eles em backtesting para certificar se realmente houve ou não overfitting.

Outra forma de incorrer em overfitting é fazer a otimização em um conjunto de dados muito específico, ou seja, dados que tenham, por exemplo, apenas uma tendência de alta no plano mais macro e baixa volatilidade. A otimização vai gerar a melhor configuração para esta situação. Se o backtesting tiver dados, por exemplo, de uma tendência de baixa ou maior volatilidade, é bem provável que o modelo não terá bom desempenho porque a otimização não presenciou esse tipo de situação no ajuste das variáveis.

É bom ressaltar a diferença entre overfitting e otimização focada em situação de mercado. Haverá situações em que desejamos que uma estratégia tenha desempenho equilibrado tanto em mercado de alta como de baixa ou lateralizado. E pra isso precisamos garantir que os dados in sample contenham essa diversidade de cenários.

Mas também podem haver situações, em que queremos fazer a otimização apenas com dados de mercado em alta, por exemplo. Porque iremos colocar para rodar o robô apenas nesta situação. Então é interessante fazer a otimização focada neste cenário, mas sem incorrer em overfitting. O overfitting nesse caso seria ter um desempenho ruim, mesmo quando o backtesting é aplicado em cenário semelhante aos dados de otimização. Isto significa que a otimização fez um sobreajuste para a situação de mercado de alta dos dados de treino, apresentando pouca capacidade de generalização.

É importante observar que a identificação de overfitting é feita no backtesting com dados OUT OF SAMPLE, ou seja, não utilizados na otimização. E por isto a importância de separarmos os dados no início do processo!

O problema do overfitting é que quando ele não é percebido, o elaborador da estratégia cria a falsa expectativa de desempenho da estratégia baseado em resultados de otimização que não vão se repetir com dados novos, o que pode representar prejuízos financeiros que apenas cessarão quando decidir-se parar de rodar a estratégia. E talvez a causa desse prejuízo nem seja corretamente identificada pelo elaborador da estratégia.

Conclusão

Muito bem! Vimos assuntos importantes tais como algoritmos de otimização, cuidados devidos a segregação de dados e o problema mais temido da otimização: overfitting.

Vamos lançar uma pergunta para motivar o próximo texto sobre otimização. Uma vez que tenhamos econtrado uma configuração ótima para a estratégia sem overfitting. Até quando esta configuração deve ser utilizada De quanto em quanto tempo devemos reavaliar a configuração dos parâmetros da estratégia?

Veja o próximo material de otimização para aprender mais sobre robustez no processo de otimização por meio de técnicas de validação cruzada.

Técnicas de Otimização robusta

Reproduzir vídeo

Introdução

Até o presente documento vimos os conceitos básicos de otimização. Abordamos dois algoritmos bastante utilizados para otimizar estratégias baseadas em indicadores técnicos: Grid Search e Algoritmo Genético – e abordamos sobre segregação de dados e overfitting.

Aqui vamos avançar um pouco mais e falaremos sobre técnicas de otimização robusta. Tais técnicas consistem em realizar a otimização e verificar o quão sensível é o desempenho de uma dada estratégia a diferentes situações de mercado e variações dos parâmetros ótimos.

O domínio de técnicas de otimização robusta é fundamental para execução de um processo de otimização de estratégias de maneira mais consistente, fornecendo mais informações para análise do possível desempenho e identificação de estratégia com maior potencial de serem lucrativas quando submetidas a dados novos.

A técnica de otimização robusta mais difundida é denominada Walk Forward Optimization.

Walk Forward Optimization (WFO)

A técnica de Walk Forward Optimization (WFO) foi apresentada inicialmente por Robert Pardo em seu livro “The Evaluation and Optimization of Trading Strategies” de janeiro/2008. Pra quem entende de aprendizado de máquina, é bastante claro que se trata de uma técnica baseada em validações cruzadas (como um k-fold).

A técnica WFO consiste em utilizar os dados históricos e simular como se a estratégia estivesse fazendo trading real. Ou seja, os dados históricos são fatiados em períodos de duração fixa, onde uma parte será utilizada para otimização (dados in sample) e outra parte para realização de backtesting (dados out of sample).

Iniciando pelos dados mais antigos, realizamos uma otimização simples (da maneira tradicional) e obtemos os parâmetros ótimos para avaliar o desempenho da estratégias nos dados out of sample do primeiro período.

Daí simulamos que o tempo passou e obtemos mais dados históricos. Isso equivale a arrastar a janela de dados pela mesma duração do backtesting em direção aos dados mais recentes. Esta nova configuração de dados da janela deslizante será o Período 2, o qual terá uma interseção dos dados in sample do período 1. No entanto, não terá interseção entre os dados de backtesting dos períodos 1 e 2.

A duração (fixa) dos dados de backtesting de cada período e a duração total dos dados históricos irão permitir calcular quantas janelas distintas de otimização poderão ser executadas nos dados históricos. A figura abaixo ilustra o conceito das janelas deslizantes.

Observe que, ao invés de procedermos uma única otimização nos dados históricos disponíveis, a técnica WFO visa realizar múltiplas otimizações para que seja possível realizar uma análise do desempenho da estratégia otimizada de maneira geral levando em consideração o desempenho em cada janela de backtesting. A esse processo de análise se dá o nome de Walk Forward Analysis (WFA).

Walk Forward Analysis (WFA)

Espero que tenha ficado claro na seção anterior que a estratégia é reotimizada para cada período de dados. A análise, portanto, consiste em comparar o desempenho da estratégia reotimizada no dados de backtesting do período atual, com o desempenho nesses mesmos dados utilizando a estratégia otimizada no período anterior, e portanto, não reotimizada para o período atual de dados.

A pergunta a ser respondida pela WFA é: vale a pena reotimizar a estratégia periodicamente? Em outras palavras, é possível um resultado final melhor do que não reotimizar a estratégia?

Intuitivamente, ao reotimizarmos uma estratégia utilizando uma janela deslizante estamos focando a otimização apenas nos dados mais recentes, que podem representar recortes distintos da dinâmica de negociação do ativo. Pode ser que um período seja marcado por uma tendência de alta, enquanto o próximo período terá um comportamento de retração (correção de preço), seguido pelo próximo período de consolidação…e assim por diante.

Perceba que a ideia de utilizar janelas deslizantes é permitir a obtenção de parâmetros ótimos mais adequados a situação recente dando possibilidade a estratégia de se ajustar as diferentes dinâmicas. Diferentemente de uma otimização simples sobre todos os dados históricos que buscaria uma configuração média que seria ótima globalmente, mas que não poderia ser ótima para diferentes subconjuntos desses dados históricos.

O que nos permitirá comparar o desempenho de duas configurações diferentes da estratégias em dados de backtesting (reotimizada e não reotimizada) é a Eficiência da estratégia, que definiremos a seguir.

Cálculo de Eficiência

A Eficiência consiste na razão entre o desempenho da estratégia nos dados out of sample (backtesting) e o desempenho nos dados in sample. O desempenho deve ser medido, preferencialmente, utilizando a mesma métrica utilizada como função objetivo da otimização, a fim de manter a consistência do processo.

Vale ressaltar que a janela de dados de backtesting é bem menor (geralmente) que a janela de dados in sample, e por isso, para tecer uma comparação de desempenho justa, torna-se necessário normalizar a medida de desempenho.

A normalização sempre será necessária quando os valores possíveis para a métrica de desempenho puderem ter limites mínimos e máximos diferentes dependendo do tamanho da janela de dados (ex: lucro líquido). A normalização não é necessária, por exemplo, se a métrica for taxa de acerto, pois o seu valor estará sempre entre 0 e 100%, independentemente do tamanho da janela de dados.

Veja na figura abaixo, um exemplo de cálculo de normalização de lucro líquido e eficiência em diferentes períodos de otimização de uma estratégia.

Estas perguntas nos levam a próxima técnica conhecida como Walk Forward Matix (WFM).

Observa-se que no Período 2 e 3, a estratégia reotimizada apresentou melhor eficiência do que a estratégia não reotimizada. Ao passo que no Período 4, a estratégia não reotimizada é que apresentou melhor eficiência.

A técnica de WFA consiste exatamente em verificar se há predominância de melhor eficiência nas estratégias reotimizadas para concluir se vale a pena reotimizar períodicamente a estratégia.

Caso identifique-se que não é interessante reotimizar a estratégia periodicamente, esse achado não é conclusivo. Pois poderíamos realizar a seguinte pergunta: será que se utilizassemos uma janela de otimização diferente com uma janela de backtesting menor poderíamos obter um resultado melhor em relação à reotimização de estratégias? Ou mesmo se concluíssemos que para o tamanho da janela atual é interessante reotimizar periodicamente, será que esta periodicidade é a periodicidade ótima?

Walk Forward Matrix (WFM)

A técnica WFM nada mais é do que rodar o processo de WFA para diferentes possibilidades de tamanho da janela de dados e percentual de dados out of sample desta janela, utilizando o algoritmo de já vimos de grid search.

Em outras palavras, consiste em realizar a otimização da técnica WFA. É importante ressaltar que a execução de WFM é bastante cara computacionalmente e, portanto, recomenda-se não gerar muitas possibilidades no processo. Além disso, a automatização do processo de WFM é praticamente um pré-requisito, são tantos dados que precisam ser armazenados para se realizar a adequada análise dos resultados, que torna-se fundamental ter um fluxo automatizado para execução do WFM.

Ao final das contas, queremos verificar se a estratégia é robusta a diferentes janelas de otimização e backtesting, bem como identificar o tamanho ótimo da janela de dados de otimização e periodicidade de reotimização.

Conclusão

Neste documento exploramos os conceitos e ideias por trás das técnicas de otimização robusta: WFA e WFM, a qual estão cobertas pelo conceito de Walk Forward Optimization.

Como sugestão, recomenda-se sempre iniciar de maneira simples e complicar a medida que for necessário. Assim, não é recomendável já iniciarmos a otimização de uma estratégia com WFM, pois seria como dar um tiro de canhão em uma mosca.

Comece realizando um otimização simples e verificando se a estratégia é lucrativa em backtesting. Em seguida, pode-se verificar pela aplicação da técnica WFA se há benefício em reotimizar a estratégia períodicamente em uma janela que o trader julgar pertinente. Caso seja observado um potencial de melhoria na otimização da janela de dados e de backtesting, aí sim, deve-se proceder com a técnica WFM.

Espero que este conteúdo tenha sido esclarecedor para o leitor e tenha contribuído para ampliar o conhecimento a respeito do tema otimização de estratégias.

Acompanhe a publicação de vídeos no Canal do Youtube da Comunidade, pois nos próximos conteúdos nós iremos aplicar passo a passo cada técnica apresentada na prática e otimizar estratégias utilizando diferentes plataformas e soluções.

COMO CONFIGURAR E OPERAR PELO BOOK DE OFERTAS [Trader Evolution]

Reproduzir vídeo

Neste vídeo da séria “Conhecendo a Trader Evolution” vamos explorar o BOOK DE OFERTAS. Esta ferramenta nos permite ter uma visão do segundo nível do mercado, vendo o interesse de compra e venda por nível de preço ou por participante do mercado. Além disso é possível operar diretamente pelo Book de Ofertas, conforme demonstração realizada nesse vídeo.

Não se esqueça de indicar a Comunidade NeoTraderBot como parceiro na Plataforma TraderEvolution. Vá no menu superior em “Mais” – “Extensões” – “Indique parceiro” e digite o código “NEOTRADERBOT”.

Assim, você reforça sua participação na Comunidade e nos ajuda a pleitear novas funcionalidades e melhorias na plataforma visando o benefício de todos os membros em suas automatizações e desenvolvimento de estratégias.

Manipulação de Gráficos

Introdução

Esta seção visa apresentar trechos de códigos com funcionalidades relativas à manipulação de gráficos e coloração.

Você pode acessar os Snippets diretamente pelo menu lateral direito, ou fazendo CRL+F (CTRL+L) para localizar algum texto específico na página, uma vez que o conteúdo tende a crescer ao longo do tempo, dificultando a navegação pelo menu.

Caso tenham sugestões de código para acrescentar à lista, gentileza deixar o código nos comentários com o link para seu perfil em rede social (para devido crédito de autoria).

Snippets

Como plotar mais de uma série de dados e Personalizar plot

Este código plota duas séries de valores constantes a fim de demonstrar como personalizar os atributos gráficos dos plots.

OBS: O preenchimento entre séries só pode ser configurado via interface gráfica. Verificar as constantes para tipos de gráficos e estilos de linhas.

				
					const
  cSerieA = 3;
  cSerieB = 2;
begin
  SetPlotColor(1,clGreen);
  SetPlotWidth(1,2);
  SetPlotStyle(1,psDashDot);
  SetPlotType(1,igLine);
  plotN(1,cSerieA);
  
  SetPlotColor(2,clRed);
  SetPlotStyle(2,psDashDot);
  SetPlotType(2,igHistogram);
  plotN(2,cSerieB);
end;
				
			

Como agrupar gráficos/janelas e utilizar Crosshair

Reproduzir vídeo

Neste video iremos demonstrar passo-a-passo como agilizar a sua navegação entre gráficos na NinjaTrader.

Vamos ensinar PASSO-A-PASSO como configurar o Market Analyzer para ao selecionar um ativo, modificar a exibição em múltiplas janelas ao mesmo tempo, permitindo mais velocidade ao analisar o mercado.

Também demonstraremos como vincular janelas diferentes a um mesmo ativo, ou até mesmo como vincular gráficos de ativos diferentes a um mesmo tempo gráfico, de tal forma que uma alteração em um gráfico reflita nas demais janelas.

Por fim, iremos apresentar a funcionalidade de CROSSHAIR a qual permite realizar inspeção gráfico em diferentes janelas de ativos de maneira muito prática, inclusive em gráficos com séries de dados distintas, ex: entre um gráfico de renko e outro de candle.

Estas funcionalidades disponíveis na NinjaTrader são um diferencial em termos de uso e navegação pelo sistema, que não estão disponíveis com este potencial em outras plataformas.

Este é um conteúdo informativo sobre NinjaTrader para que os membros da comunidade tenham informações do que é possível realizar em outros ambientes.

Reforço que não estamos realizando nenhuma recomendação para mudança de Plataforma e que a decisão de migrar parte ou todo o processo de desenvolvimento e execução das estratégias automatizadas é muito pessoal e cabe apenas ao trader decidir sobre tal assunto.

Códigos de exemplo? Tome Snippets!

Aprender a programar envolve esforço, persistência e também colaboração com outros programadores (esse é um dos benefícios de participar de uma Comunidade como a NeoTraderBot!).

Pensando em acelerar a curva de aprendizado e reduzir o tempo que ficamos presos com problemas de programação, organizamos esta área de Snippets para elaboração de estratégias no Profit Chart.

Os Snippets são trechos de códigos independentes, autocontidos e funcionais. Ou seja, cada Snippet pode ser executado sem erros, é autocontido porque executa de início ao fim uma determinada tarefa, sendo assim funcional. Eles podem ser copiados e modificados de acordo com a necessidade do usuário

Navegue abaixo pelas categorias disponíveis e caso tenha alguma sugestão de nova categoria ou tarefa, comente nas áreas apropriadas. Caso tenha colegas que também possam fazer bom uso e contribuir com a Comunidade, compartilhe esta área do site pelos ícones abaixo.

 

Compartilhe essa página!

Share on facebook
Facebook
Share on telegram
Telegram
Share on whatsapp
WhatsApp
Share on email
Email

Snippets para Localização Temporal

Nesta área você terá acesso a pedaços de códigos fontes para localização da estratégia em relação ao tempo.

Tarefas disponibilizadas:

Snippets para Manipulação de Gráficos

Nesta área você terá acesso a pedaços de códigos fontes para manipular plot, cores de plotagem, espessura, tipo de gráfico, etc.

Tarefas disponibilizadas:

 

Snippets para Utilização de Indicadores da Plataforma

Nesta área você terá acesso a pedaços de códigos fontes para utilizar os indicadores disponibilizados por padrão na Plataforma.

Tarefas disponibilizadas:

 

Snippets para Localização Temporal

Introdução

Esta seção visa apresentar trechos de códigos com funcionalidades relativas à localização temporal da estratégia. Por exemplo, identificar se a atual barra é a primeira barra do dia para verificar gap diário.

Você pode acessar os Snippets diretamente pelo menu lateral direito, ou fazendo CTRL+F (CTRL+L) para localizar algum texto específico na página, uma vez que o conteúdo tende a crescer ao longo do tempo, dificultando a navegação pelo menu.

Caso tenham sugestões de código para acrescentar à lista, gentileza deixar o código nos comentários com o link para seu perfil em rede social (para devido crédito de autoria).

Snippets

Identificação do primeiro candle de cada dia

Reproduzir vídeo

Algumas estratégias necessitam da identificação da primeira barra do dia (candle) para executar determinada ação ou calcular o gap em relação ao fechamento do dia anterior.

				
					var
  bPrimeiraBarraDoDia : boolean;
  iDataAtual          : integer;
begin
  if (Date() <> iDataAtual) then
    begin
      iDataAtual := Date();
      bPrimeiraBarraDoDia := true;
    end;
  if bPrimeiraBarraDoDia then
    begin
      bPrimeiraBarraDoDia := false;
      //Faz alguma coisa na primeira barra do dia
      paintBar(clGreen);
    end;
end;
				
			

Identificação de barra por data e hora específicos

Este código localiza a barra (candle ou box) por uma data e hora desejados. Onde a hora é referente ao horário de abertura do candle desejado. Observa-se que existe uma parte do código comentada para utilização em backtesting de gráficos de renko.

OBS: As variáveis pDataDesejada e pHorarioDesejado não foram declaradas como parâmetros para facilitar o teste do Snippet, uma vez que não é possível alterar parâmetro dentro do Editor de Estratégias.

				
					var
  bBarraDesejada                 : boolean;
  pDataDesejada,pHorarioDesejado : integer;
begin
  pDataDesejada := 20220928;
  pHorarioDesejado := 1200;
  if (Date() = ELDate_Consol(pDataDesejada)) And (Time() = pHorarioDesejado) then
    begin
      bBarraDesejada := true;
      //Faz alguma coisa na barra identificada
      paintBar(clGreen);
    end
  else 
    bBarraDesejada := false;
end;
				
			

Identificação do primeiro tick de uma barra

Reproduzir vídeo

Este código identifica o primeiro tick de uma barra. Este Snippet tem aplicação apenas quando a estratégia é utlizada em tempo real.

OBS: É importante ressaltar que em backtesting com dados históricos não há dados tick a tick. Desta forma, este Snippet não possui aplicação em backtesting com dados de barra a barra.

				
					var
  bPrimeiroTickDaBarra : boolean;
  iBarraAtual          : integer;
begin
  if LastBarOnChart then
    if (CurrentBar <> iBarraAtual) then
      begin
        iBarraAtual := CurrentBar;
        bPrimeiroTickDaBarra := true;
      end
  else 
    bPrimeiroTickDaBarra := false;
  if bPrimeiroTickDaBarra then
    begin
      //Faz alguma coisa no primeiro tick da barra
      //Aplicável apenas em execução de tempo real
      paintBar(clGreen);
    end
  else 
    begin
      //Faz alguma coisa nos demais ticks da barra atual
      //Aplicável apenas em execução de tempo real
      paintBar(clYellow);
    end;
end;
				
			

Contador de Candles do dia

Este código realiza a contagem de barras dentro de um mesmo dia.

				
					var
  bPrimeiraBarraDoDia : boolean;
  iDataAtual          : integer;
  iCurrentBarIntraday, iFirstBarOfDay : integer;
begin
  if (Date() <> iDataAtual) then
    begin
      iDataAtual := Date();
      bPrimeiraBarraDoDia := true;
      iFirstBarOfDay := CurrentBar;
    end;
  if bPrimeiraBarraDoDia then
    begin
      bPrimeiraBarraDoDia := false;
      //Faz alguma coisa na primeira barra do dia
      paintBar(clGreen);
    end;

    iCurrentBarIntraday := CurrentBar - iFirstBarOfDay + 1;
    plotText(iCurrentBarIntraday, clWhite,0, 12);

end;
				
			

Manipulação de Gráficos

Introdução

Esta seção visa apresentar trechos de códigos com funcionalidades relativas à manipulação de gráficos e coloração.

Você pode acessar os Snippets diretamente pelo menu lateral direito, ou fazendo CRL+F (CTRL+L) para localizar algum texto específico na página, uma vez que o conteúdo tende a crescer ao longo do tempo, dificultando a navegação pelo menu.

Caso tenham sugestões de código para acrescentar à lista, gentileza deixar o código nos comentários com o link para seu perfil em rede social (para devido crédito de autoria).

Snippets

Como plotar mais de uma série de dados e Personalizar plot

Este código plota duas séries de valores constantes a fim de demonstrar como personalizar os atributos gráficos dos plots.

OBS: O preenchimento entre séries só pode ser configurado via interface gráfica. Verificar as constantes para tipos de gráficos e estilos de linhas.

				
					const
  cSerieA = 3;
  cSerieB = 2;
begin
  SetPlotColor(1,clGreen);
  SetPlotWidth(1,2);
  SetPlotStyle(1,psDashDot);
  SetPlotType(1,igLine);
  plotN(1,cSerieA);
  
  SetPlotColor(2,clRed);
  SetPlotStyle(2,psDashDot);
  SetPlotType(2,igHistogram);
  plotN(2,cSerieB);
end;
				
			

Utilização de Indicadores da Plataforma

Introdução

Esta seção visa apresentar trechos de códigos com exemplos de utilização dos indicadores disponibilizados na plataforma.

Você pode acessar os Snippets diretamente pelo menu lateral direito, ou fazendo CRL+F (CTRL+L) para localizar algum texto específico na página, uma vez que o conteúdo tende a crescer ao longo do tempo, dificultando a navegação pelo menu.

Caso tenham sugestões de código para acrescentar à lista, gentileza deixar o código nos comentários com o link para seu perfil em rede social (para devido crédito de autoria).

Snippets

Sugira um primeiro Snippet nos comentários!!!

				
					...
				
			

Ordens e Administração de Trade

Introdução

Esta seção visa apresentar trechos de códigos com exemplos de envio de ordens e administração de trade utilizando técnicas de stoploss (fixo, móvel, breakeven) e take profit.

Você pode acessar os Snippets diretamente pelo menu lateral direito, ou fazendo CRL+F (CTRL+L) para localizar algum texto específico na página, uma vez que o conteúdo tende a crescer ao longo do tempo, dificultando a navegação pelo menu.

Caso tenham sugestões de código para acrescentar à lista, gentileza deixar o código nos comentários com o link para seu perfil em rede social (para devido crédito de autoria).

Snippets

Como limitar a quantidade de trades por dia

Reproduzir vídeo

O código abaixo apresenta a funcionalidade em código fonte para limitar a quantidade de trades realizados pela sua estratégia/ robô (constante cQtdeMaxOperacoesNoDia).

Apesar do Módulo de Automação possui um limite de perda e ganho diário, ele não possui esta funcionalidade. Idealmente, a Nelogica deveria disponbilizar funções para verificação do resultado bruto alcançado até o momento para permitir outras forma de gestão de risco em código fonte.

				
					const
  // Mude aqui a qtde maxima de trades por dia 
  cQtdeMaxOperacoesNoDia = 5;

var 
  iQtdeOperacoesNoDia: integer;
  iDataAtual: integer;
  bJaContouOperacao: boolean;
  fMedia: float;

begin
  // Inicialização do contador de ordens do dia  
  if Date <> iDataAtual then
  begin
    iDataAtual := Date;
    iQtdeOperacoesNoDia := 0;
    bJaContouOperacao := false;
  end;
  
  // Setup de cruzamento de Media movel só para gerar operações
  fMedia := Media(3,Close);

  // Realiza abertura de posições apenas se número maximo de operação
  // não tiver sido atingido
  if iQtdeOperacoesNoDia < cQtdeMaxOperacoesNoDia then
  begin
    // COMPRA se fechamento cruzar media para cima e
    // VENDE se fechamento cruzar media pra baixo
    if (Close > fMedia) and (Close[1] <= fMedia[1]) and Not HasPosition then BuyAtMarket;       
    if (Close < fMedia) and (Close[1] >= fMedia[1]) and Not HasPosition then SellShortAtMarket;
  end;
  
  // Contabiliza a abertura da posição como mais uma operação no dia   
  if (isBought or isSold) and Not bJaContouOperacao then
  begin
    iQtdeOperacoesNoDia := iQtdeOperacoesNoDia + 1;
    bJaContouOperacao := true;  
  end;

  // Posiciona ordens para gestão do trade
  if isBought then
  begin
    SellShortStop(buyPrice - 5*MinPriceIncrement);
    SellShortLimit(buyPrice + 15*MinPriceIncrement);
  end;

  // Posiciona ordens para gestão do trade
  if isSold then
  begin
    BuyStop(sellPrice + 5*MinPriceIncrement);
    BuyLimit(sellPrice - 15*MinPriceIncrement);
  end;
  
  // Encerra posicao no mesmo dia
  if (Time >= 1645) and hasPosition then ClosePosition;

  // Se posição for encerrada ativa novamente o contador
  if Not IsBought and Not isSold and bJaContouOperacao then bJaContouOperacao := false;  

  // Apenas para inspeção gráfica do sinal
  Plot(fMedia);
  
end
				
			

Como limitar trades por objetivo de ganho ou limite de perda

Reproduzir vídeo

O código abaixo apresenta a funcionalidade em código fonte para limitar a realização de trades baseado no resultado do dia.

Caso o resultado das operações da estratégia atinja o objetivo de ganho ou o limite de perda, fornecidos em valores absolutos e unidade financeira pelos parâmetros pLimitePerdaDiaria e pObjetivoGanhoDiario, a estratégia não realiza mais operações e encerra posições abertas.

O parâmetro pPlotarResultado pode receber os valores “FECHADO”, “ABERTO” e “TOTAL”, para se referir ao resultado de trades fechados, resultado do trade em aberto e resultado total do dia (FECHADO + ABERTO), respectivamente.

				
					input
  pPlotarResultado("ABERTO");
  pLimitePerdaDiaria(200.00);
  pObjetivoGanhoDiario(600.00);

var
  fResultado: float;
  fResultadoDiario: float;
  iDataTeste: integer;
  iHora: integer;
begin
  //-----------------------------------------------------------
  //Plots podem ser excluídos...servem apenas para demonstração

  // Resultado fechado do dia
  If pPlotarResultado = "FECHADO" then
  begin
    fResultado := DailyResult(false);
    plot(fResultado);
    SetPlotStyle(1,psSolid);
    SetPlotColor(1,clWhite);
  end;

  // Resultado até o momento no dia (fechado + aberto)
  If pPlotarResultado = "TOTAL" then
  begin
    fResultado := DailyResult(true);
    plot2(fResultado);
    SetPlotStyle(2,psDash);
    SetPlotColor(2,clRed);
  end;

  // Resultado do trade aberto
  If pPlotarResultado = "ABERTO" then
  begin
    fResultado := DailyResult(true) - DailyResult(false); 
    if fResultado <> 0 then
      plot3(fResultado);
    SetPlotStyle(3,psDash);
    if fResultado >= 0  then SetPlotColor(3,clGreen)
    else SetPlotColor(3,clRed);
    SetPlotType(3, igHistogram);
  end;
  //-----------------------------------------------------------


  // Estratégias apenas opera se resultado do dia não 
  // tiver atingido objetivo de ganho ou limite de perda
  iDataTeste := ELDate(2023,2,10);
  fResultadoDiario := DailyResult(true);
  
  if (fResultadoDiario > -1*pLimitePerdaDiaria)
  and (fResultadoDiario < pObjetivoGanhoDiario) then
  begin
    // SIMULAÇÃO DE ORDENS PARA FINS DE EXEMPLO
    for iHora := 0 to 8 do
    begin
      if (Date = iDataTeste) and (Time = (0900 + iHora*100)) then
        if random(2) = 0 then BuyAtMarket else SellShortAtMarket;
  
      if (Date = iDataTeste) and (Time = (0930 + iHora*100)) then
        ClosePosition;
    end;

  end
  //Se resultado excedeu objetivo de ganho ou limite de perda
  //e houver posição aberta, então encerra a posição.
  else if hasPosition then ClosePosition;
                
            
end;
				
			

Limite de horário para encerramento de posição

Reproduzir vídeo

O código abaixo apresenta a funcionalidade em código fonte para encerramento de posição a partir de um determinado horário. É um exemplo útil para quem opera daytrade e não deseja/não pode correr o risco de carregar operação para o dia seguinte.

				
					var
  bBarraDesejada                 : boolean;
  pDataDesejada,pHorarioDesejado : integer;
  //Util apenas para Backtesting em Gráfico de Renko  
  pMargemMinutos: integer;  
begin
  pHorarioDesejado := 1645;
  pMargemMinutos := 15;
  //Para Gráficos de Candle/Renko executados em tempo real
  //if Time > pHorarioDesejado then

  //Para Gráficos de Renko, em backtesting, utiliza-se uma margem de tempo em torno do horário desejado
  if  (Time >= CalcTIme(pHorarioDesejado, -pMargemMinutos)) then
    begin
      bBarraDesejada := true;
      //Encerra posição caso esteja comprado/vendido
      if isBought or isSold then ClosePosition;
    end
  else
    bBarraDesejada := false;
end;
				
			

Stoploss simples (fixo)

Reproduzir vídeo

O código abaixo apresenta um exemplo de stoploss fixo e take profit (alvo de lucro da operação), para uma relação de risco/ganho de 3:1 em função de quantidade de ticks, aplicado a uma estratégia de posicionamento. O código tem um limite de horário para abertura e fechamento de posição, o qual pode ser alterado pelos parâmetros.

OBS 1: A versão é compatível com o Editor de Estratégias e Módulo de Automação de Estratégias. Devido a um bug do Profit, é necessário ter um comando ClosePosition, pois do contrário a ferramenta informa equivocadamente que não existem ordens para encerrar posição.

				
					const
 //Relação risco/ganho de 3:1
 cStopEmTicks = 10;
 cAlvoEmTicks = 30;
 cStopOffsetEmTicks = 50;

input
  bGestaoDeRiscoPelaEstrategia(true);
  iHorarioInicioAberturaPosicao(0905);
  iHorarioFimAberturaPosicao(1630);
  iHorarioEncerramentoDaytrade(1645);

var
  iCaraCoroa: integer;
  bSinalCompra, bSinalVenda, bPosicionado: boolean;
  fPrecoStop, fPrecoAlvo, fPrecoStopOffset: float;
  bConfigurouRisco: boolean;

begin

  bSinalCompra := false;
  bSinalVenda := false;
  bPosicionado := hasPosition;

  //ESTRATÉGIA CARA OU COROA!
  //Gera um numero aleatorio de 0 a 9. Se for menor igual a 4, gera
  //sinal de compra, se for maior que 4 geral sinal de venda
  if Not bPosicionado
  and (Time >= iHorarioInicioAberturaPosicao)
  and (Time <= iHorarioFimAberturaPosicao)
  then
  begin
    //Número aleatório foi substituido por minuto par ou impar para permitir depurar
    //melhor o robô quando a estratégia é inserida multiplas vezes: como indicador  e como execução
    //iCaraCoroa := Random(10);
    iCaraCoroa := mod(Time,2);
    if iCaraCoroa = 0 then bSinalCompra := true
    else bSinalVenda := true;
  end;


  //Gera ordem de compra a mercado quando há um Sinal de COMPRA
  //e define ordem stoploss e take profit
  if bSinalCompra then BuyAtMarket;

  //Gera ordem de venda a mercado quando há um Sinal de VENDA
  //e define ordem stoploss e take profit
  if bSinalVenda then SellShortAtMarket;

  if bGestaoDeRiscoPelaEstrategia then
  begin
    //POSIÇÃO COMPRADA
    //Código responsável pela manutenção das ordens de stoploss e take profit
    if isBought then
    begin
      if not bConfigurouRisco then
      begin
        fPrecoStop := BuyPrice - cStopEmTicks*MinPriceIncrement;
        fPrecoAlvo := BuyPrice + cAlvoEmTicks*MinPriceIncrement;
        fPrecoStopOffset := fPrecoStop - cStopOffsetEmTicks*MinPriceIncrement;
        bConfigurouRisco := true;
      end;

      SellToCoverStop(fPrecoStop,fPrecoStopOffset);
       SellToCoverLimit(fPrecoAlvo);
    end;

    //POSIÇÃO VENDIDA
    //Código responsável pela manutenção das ordens de stoploss e take profit
    if isSold then
    begin
      if not bConfigurouRisco then
      begin
        fPrecoStop := SellPrice + cStopEmTicks*MinPriceIncrement;
        fPrecoAlvo := SellPrice - cAlvoEmTicks*MinPriceIncrement;
        fPrecoStopOffset := fPrecoStop + cStopOffsetEmTicks*MinPriceIncrement;
        bConfigurouRisco := true;
      end;

      BuyToCoverStop(fPrecoStop,fPrecoStopOffset);
      BuyToCoverLimit(fPrecoAlvo);

    end;

    //Encerra posicao
    if (Time >= iHorarioEncerramentoDaytrade)
    and HasPosition
    then ClosePosition;

    if Not HasPosition then bConfigurouRisco := false;

  end;

  // Plot de Stop e Alvo para inspeção visual do código
  bPosicionado := hasPosition;
  if bPosicionado or bPosicionado[1] or bPosicionado[2] then
  begin
    PlotN(1,fPrecoStop);
    PlotN(2,fPrecoStopOffset);
    PlotN(3,fPrecoAlvo);
    SetPlotColor(1,clRed);
    SetPlotColor(2,clRed);
    SetPlotColor(3,clGreen);
    SetPlotStyle(1,psDash);
    SetPlotStyle(2,psDash);
    SetPlotStyle(3,psDash);
    SetPlotWidth(1,2);
    SetPlotWidth(2,2);
    SetPlotWidth(3,2);

end;


end;
				
			

Stoploss com Breakeven

Reproduzir vídeo

O código abaixo apresenta um exemplo de Stoploss fixo + Breakeven (alvo de lucro da operação), para uma relação de risco/ganho de 3:1 em função de quantidade de ticks, aplicado a uma estratégia de posicionamento aleatório com uma operação por dia.

OBS 1: A versão é compatível com o Editor de Estratégias e Módulo de Automação de Estratégias. Devido a um bug do Profit, é necessário ter um comando ClosePosition, pois do contrário a ferramenta informa equivocadamente que não existem ordens para encerrar posição.

				
					const
 //Relação risco/ganho de 3:1
 cStopEmTicks = 30;
 cStopOffsetEmTicks = 20;
 cBreakevenEmTicks = 30;
 cAlvoEmTIcks = 90;

input
  bGestaoDeRiscoPelaEstrategia(true);
  iHorarioInicioAberturaPosicao(0905);
  iHorarioFimAberturaPosicao(1630);
  iHorarioEncerramentoDaytrade(1645);

var
  iCaraCoroa: integer;
  bSinalCompra, bSinalVenda, bPosicionado: boolean;
  fPrecoStop, fPrecoAlvo, fPrecoStopOffset: float;
  bConfigurouRiscoInicial: boolean;
begin

  bSinalCompra := false;
  bSinalVenda := false;
  bPosicionado := hasPosition;

  //ESTRATÉGIA CARA OU COROA!
  //Gera um numero aleatorio de 0 a 9. Se for menor igual a 4, gera
  //sinal de compra, se for maior que 4 geral sinal de venda
  if Not bPosicionado
  and (Time >= iHorarioInicioAberturaPosicao)
  and (Time <= iHorarioFimAberturaPosicao)
  then
  begin
    //Número aleatório foi substituido por minuto par ou impar para permitir depurar
    //melhor o robô quando a estratégia é inserida multiplas vezes: como indicador  e como execução
    //iCaraCoroa := Random(10);
    iCaraCoroa := mod(Time,2);
    if iCaraCoroa = 0 then bSinalCompra := true
    else bSinalVenda := true;
  end;

  //Gera ordem de compra a mercado quando há um Sinal de COMPRA
  //e define ordem stoploss e take profit
  if bSinalCompra then BuyAtMarket;

  //Gera ordem de venda a mercado quando há um Sinal de VENDA
  //e define ordem stoploss e take profit
  if bSinalVenda then SellShortAtMarket;

  if bGestaoDeRiscoPelaEstrategia then
  begin
    //Código responsável pela manutenção das ordens de stoploss e take profit
    if isBought then
    begin
      if Not bConfigurouRiscoInicial then
      begin
        fPrecoStop := BuyPrice - cStopEmTicks*MinPriceIncrement;
        fPrecoAlvo := BuyPrice + cAlvoEmTicks*MinPriceIncrement;
        fPrecoStopOffset := fPrecoStop - cStopOffsetEmTicks*MinPriceIncrement;
        bConfigurouRiscoInicial := true;
      end;

      if Close >= (BuyPrice + cBreakevenEmTicks*MinPriceIncrement) then
      begin
        fPrecoStop := BuyPrice;
        fPrecoStopOffset := fPrecoStop-cStopOffsetEmTicks*MinPriceIncrement;
      end;

      SellToCoverStop(fPrecoStop,fPrecoStopOffset);
      SellToCoverLimit(fPrecoAlvo);
    end;

    //Código responsável pela manutenção das ordens de stoploss e take profit
    if isSold then
    begin
      if Not bConfigurouRiscoInicial then
      begin
        fPrecoStop := SellPrice + cStopEmTicks*MinPriceIncrement;
        fPrecoAlvo := SellPrice - cAlvoEmTicks*MinPriceIncrement;
        fPrecoStopOffset := fPrecoStop + cStopOffsetEmTicks*MinPriceIncrement;
        bConfigurouRiscoInicial := true;
      end;

      if Close <= (SellPrice - cBreakevenEmTicks*MinPriceIncrement) then
      begin
        fPrecoStop := SellPrice;
        fPrecoStopOffset := fPrecoStop+cStopOffsetEmTicks*MinPriceIncrement;
      end;

      BuyToCoverStop(fPrecoStop,fPrecoStopOffset);
      BuyToCoverLimit(fPrecoAlvo);

    end;


    //Encerra posicao
    if (Time >= iHorarioEncerramentoDaytrade)
    and HasPosition
    then ClosePosition;

    if Not hasPosition and bConfigurouRiscoInicial then bConfigurouRiscoInicial := false;


  end;

  bPosicionado := hasPosition;

  // Plot de Stop e Alvo para inspeção visual do código
  if bPosicionado or bPosicionado[1] or bPosicionado[2] then
  begin
    PlotN(1,fPrecoStop);
    PlotN(2,fPrecoStopOffset);
    PlotN(3,fPrecoAlvo);
    SetPlotColor(1,clRed);
    SetPlotColor(2,clRed);
    SetPlotColor(3,clGreen);
    SetPlotStyle(1,psDash);
    SetPlotStyle(2,psDash);
    SetPlotStyle(3,psDash);
    SetPlotWidth(1,2);
    SetPlotWidth(2,2);
    SetPlotWidth(3,2);
  end;

end;
				
			

Stoploss móvel (Versão contínua)

Reproduzir vídeo

O código abaixo apresenta um exemplo de stoploss móvel (Versão contínua), ou seja, valor de stop é atualizado a cada fechamento de candle. Só não é atualizado a cada tick por uma limitação do Profit.

O stop será alterado para cOffsetStopEmTicks em relação ao preço de fechamento do candle, não podendo o valor do stop retroceder. O código pode ser alterado para calcular o stop móvel em relação ao valor máximo do candle.

O exemplo também conta com ordem take profit (alvo de lucro da operação) para uma relação de risco/ganho de 3:1 em função de quantidade de ticks, aplicado a uma estratégia de posicionamento aleatório com uma operação por dia.

OBS 1: A versão é compatível com o Editor de Estratégias e Módulo de Automação de Estratégias. Devido a um bug do Profit, é necessário ter um comando ClosePosition, pois do contrário a ferramenta informa equivocadamente que não existem ordens para encerrar posição.

				
					const
 //Relação risco/ganho de 3:1
 cStopEmTicks = 15;
 cAlvoEmTicks = 45;
 cTraillingStopTrigger = 20;
 cTrailingStopOffset = 10;
 cStopOffsetEmTicks = 50;

input
  bGestaoDeRiscoPelaEstrategia(true);
  iHorarioInicioAberturaPosicao(0905);
  iHorarioFimAberturaPosicao(1630);
  iHorarioEncerramentoDaytrade(1645);

var
  iCaraCoroa: integer;
  bSinalCompra, bSinalVenda, bPosicionado: boolean;
  fPrecoStop, fPrecoAlvo, fPrecoStopOffset: float;
  bConfigurouRiscoInicial: boolean;
  bTrailingStopAtivado: boolean;
begin

  bSinalCompra := false;
  bSinalVenda := false;
  bPosicionado := hasPosition;

  //ESTRATÉGIA CARA OU COROA!
  //Gera um numero aleatorio de 0 a 9. Se for menor igual a 4, gera
  //sinal de compra, se for maior que 4 geral sinal de venda
  if Not bPosicionado
  and (Time >= iHorarioInicioAberturaPosicao)
  and (Time <= iHorarioFimAberturaPosicao)
  then
  begin
    //Número aleatório foi substituido por minuto par ou impar para permitir depurar
    //melhor o robô quando a estratégia é inserida multiplas vezes: como indicador  e como execução
    //iCaraCoroa := Random(10);
    iCaraCoroa := mod(Time,2);
    if iCaraCoroa = 0 then bSinalCompra := true
    else bSinalVenda := true;
  end;


  //Gera ordem de compra a mercado quando há um Sinal de COMPRA
  //e define ordem stoploss e take profit
  if bSinalCompra then BuyAtMarket;

  //Gera ordem de venda a mercado quando há um Sinal de VENDA
  //e define ordem stoploss e take profit
  if bSinalVenda then SellShortAtMarket;

  if bGestaoDeRiscoPelaEstrategia then
  begin

    //POSIÇÃO COMPRADA
    //Código responsável pela manutenção das ordens de stoploss e take profit
    if isBought then
    begin
      if Not bConfigurouRiscoInicial then
      begin
        fPrecoStop := BuyPrice - cStopEmTicks*MinPriceIncrement;
        fPrecoAlvo := BuyPrice + cAlvoEmTicks*MinPriceIncrement;
        fPrecoStopOffset := fPrecoStop - cStopOffsetEmTicks*MinPriceIncrement;
        bConfigurouRiscoInicial := true;
      end;

      if ((Close >= (BuyPrice + cTraillingStopTrigger*MinPriceIncrement))
          or (cTraillingStopTrigger = 0))
      and (not bTrailingStopAtivado) then bTrailingStopAtivado := true;

      if ((Close - cTrailingStopOffset*MinPriceIncrement) >= fPrecoStop)
      and (bTrailingStopAtivado) then
      begin
        fPrecoStop := Close - cTrailingStopOffset*MinPriceIncrement;
        fPrecoStopOffset := fPrecoStop - cStopOffsetEmTicks*MinPriceIncrement;
      end;

      SellToCoverStop(fPrecoStop,fPrecoStopOffset);
      SellToCoverLimit(fPrecoAlvo);

    end;


    //POSIÇÃO VENDIDA
    //Código responsável pela manutenção das ordens de stoploss e take profit
    if isSold then
    begin
      if Not bConfigurouRiscoInicial then
      begin
        fPrecoStop := SellPrice + cStopEmTicks*MinPriceIncrement;
        fPrecoAlvo := SellPrice - cAlvoEmTicks*MinPriceIncrement;
        fPrecoStopOffset := fPrecoStop + cStopOffsetEmTicks*MinPriceIncrement;
        bConfigurouRiscoInicial := true;
      end;

      if ((Close <= (SellPrice - cTraillingStopTrigger*MinPriceIncrement))
          or (cTraillingStopTrigger = 0))
      and (not bTrailingStopAtivado) then bTrailingStopAtivado := true;

      if ((Close + cTrailingStopOffset*MinPriceIncrement) <= fPrecoStop)
      and (bTrailingStopAtivado) then
      begin
        fPrecoStop := Close + cTrailingStopOffset*MinPriceIncrement;
        fPrecoStopOffset := fPrecoStop + cStopOffsetEmTicks*MinPriceIncrement;
      end;

      BuyToCoverStop(fPrecoStop,fPrecoStopOffset);
      BuyToCoverLimit(fPrecoAlvo);

    end;

    //Encerra posicao comprada no horario limite
    if (Time >= iHorarioEncerramentoDaytrade)
    and HasPosition
    then ClosePosition;

    if Not hasPosition and bConfigurouRiscoInicial then
    begin
      bConfigurouRiscoInicial := false;
      bTrailingStopAtivado := false;
    end;


  end;

  // Plot de Stop e Alvo para inspeção visual do código
  bPosicionado := hasPosition;
  if bPosicionado or bPosicionado[1] or bPosicionado[2] then
  begin
    PlotN(1,fPrecoStop);
    PlotN(2,fPrecoStopOffset);
    PlotN(3,fPrecoAlvo);
    SetPlotColor(1,clRed);
    SetPlotColor(2,clRed);
    SetPlotColor(3,clGreen);
    SetPlotStyle(1,psDash);
    SetPlotStyle(2,psDash);
    SetPlotStyle(3,psDash);
    SetPlotWidth(1,2);
    SetPlotWidth(2,2);
    SetPlotWidth(3,2);
  end;

end;
				
			

Stoploss móvel (Versão baseada em passos)

Reproduzir vídeo

O código abaixo apresenta um exemplo de stoploss móvel (Versão discreta, baseada em passos), ou seja, valor de stop é atualizado cada vez que o preço de fechamento do candle supera o passo definido em cTrailingStepEmTicks. Só não é atualizado a cada tick por uma limitação do Profit.

O stop será alterado para cOffsetStop em relação ao preço do último passo alcançado, não podendo o valor do stop retroceder. O código pode ser alterado para calcular o stop móvel em relação ao valor máximo do candle.

O exemplo também conta com ordem take profit (alvo de lucro da operação) em posições compradas, para uma relação de risco/ganho de 3:1. O raciocínio para posições vendidas é análogo.

OBS 1: A versão é compatível com o Editor de Estratégias e Módulo de Automação de Estratégias. Devido a um bug do Profit, é necessário ter um comando ClosePosition, pois do contrário a ferramenta informa equivocadamente que não existem ordens para encerrar posição.

				
					const
 //Relação risco/ganho de 3:1
 cStopEmTicks = 15;
 cAlvoEmTicks = 45;
 cTraillingStopTrigger = 0;
 cTrailingStopOffset = 8;
 cTrailingStepEmTicks = 10;
 cStopOffsetEmTicks = 10;

input
  bGestaoDeRiscoPelaEstrategia(true);
  iHorarioInicioAberturaPosicao(1000);
  iHorarioFimAberturaPosicao(1630);
  iHorarioEncerramentoDaytrade(1645);

var
  iCaraCoroa: integer;
  bSinalCompra, bSinalVenda, bPosicionado: boolean;
  fPrecoStop, fPrecoAlvo, fPrecoStopOffset: float;
  fFloorTraillingStop : float;
  bConfigurouRiscoInicial: boolean;
  bTrailingStopAtivado: boolean;

begin

  bSinalCompra := false;
  bSinalVenda := false;
  bPosicionado := hasPosition;

  //ESTRATÉGIA CARA OU COROA!
  //Gera um numero aleatorio de 0 a 9. Se for menor igual a 4, gera
  //sinal de compra, se for maior que 4 geral sinal de venda
  if Not bPosicionado
  and (Time >= iHorarioInicioAberturaPosicao)
  and (Time <= iHorarioFimAberturaPosicao)
  then
  begin
    //Número aleatório foi substituido por minuto par ou impar para permitir depurar
    //melhor o robô quando a estratégia é inserida multiplas vezes: como indicador  e como execução
    //iCaraCoroa := Random(10);
    iCaraCoroa := mod(Time,2);
    if iCaraCoroa = 0 then bSinalCompra := true
    else bSinalVenda := true;
  end;


  //Gera ordem de compra a mercado quando há um Sinal de COMPRA
  //e define ordem stoploss e take profit
  if bSinalCompra then BuyAtMarket;

  //Gera ordem de venda a mercado quando há um Sinal de VENDA
  //e define ordem stoploss e take profit
  if bSinalVenda then SellShortAtMarket;


  if bGestaoDeRiscoPelaEstrategia then
  begin
    //POSIÇÃO COMPRADA
    //Código responsável pela manutenção das ordens de stoploss e take profit
    if isBought then
    begin
      if Not bConfigurouRiscoInicial then
      begin
        fPrecoStop := BuyPrice - cStopEmTicks*MinPriceIncrement;
        fPrecoAlvo := BuyPrice + cAlvoEmTicks*MinPriceIncrement;
        fPrecoStopOffset := fPrecoStop - cStopOffsetEmTicks*MinPriceIncrement;
        bConfigurouRiscoInicial := true;
      end;

      if ((Close >= (BuyPrice + cTraillingStopTrigger*MinPriceIncrement))
         or (cTraillingStopTrigger = 0))
      and (not bTrailingStopAtivado) then bTrailingStopAtivado := true;

      fFloorTraillingStop := BuyPrice
          + floor((Close - BuyPrice)/(cTrailingStepEmTicks*MinPriceIncrement))
          *cTrailingStepEmTicks*MinPriceIncrement;

      if ((fFloorTraillingStop-cTrailingStopOffset*MinPriceIncrement) >= fPrecoStop)
      and bTrailingStopAtivado then
        fPrecoStop := fFloorTraillingStop - cTrailingStopOffset*MinPriceIncrement;


      SellToCoverStop(fPrecoStop,fPrecoStopOffset);
      SellToCoverLimit(fPrecoAlvo);
    end;

    //POSIÇÃO VENDIDA
    //Código responsável pela manutenção das ordens de stoploss e take profit
    if isSold Then
    begin
      if Not bConfigurouRiscoInicial then
      begin
        fPrecoStop := SellPrice + cStopEmTicks*MinPriceIncrement;
        fPrecoAlvo := SellPrice - cAlvoEmTicks*MinPriceIncrement;
        fPrecoStopOffset := fPrecoStop + cStopOffsetEmTicks*MinPriceIncrement;
        bConfigurouRiscoInicial := true;
      end;

      if ((Close <= (SellPrice - cTraillingStopTrigger*MinPriceIncrement))
          or (cTraillingStopTrigger = 0))
      and (not bTrailingStopAtivado) then bTrailingStopAtivado := true;

      if Close <= SellPrice then
        fFloorTraillingStop := SellPrice
            - floor((SellPrice - Close)/(cTrailingStepEmTicks*MinPriceIncrement))
            *cTrailingStepEmTicks*MinPriceIncrement;

      if ((fFloorTraillingStop+cTrailingStopOffset*MinPriceIncrement) <= fPrecoStop)
      and bTrailingStopAtivado then
        fPrecoStop := fFloorTraillingStop + cTrailingStopOffset*MinPriceIncrement;


      BuyToCoverStop(fPrecoStop,fPrecoStopOffset);
      BuyToCoverLimit(fPrecoAlvo);
    end;

    //Encerra posicao
    if (Time >= iHorarioEncerramentoDaytrade)
    and HasPosition
    then ClosePosition;

    if Not hasPosition and bConfigurouRiscoInicial then
    begin
      bConfigurouRiscoInicial := false;
      bTrailingStopAtivado := false;
    end;

  end;

  // Plot de Stop e Alvo para inspeção visual do código
  bPosicionado := hasPosition;
  if bPosicionado or bPosicionado[1] or bPosicionado[2] then
  begin
    PlotN(1,fPrecoStop);
    PlotN(2,fPrecoStopOffset);
    PlotN(3,fPrecoAlvo);
    SetPlotColor(1,clRed);
    SetPlotColor(2,clRed);
    SetPlotColor(3,clGreen);
    SetPlotStyle(1,psDash);
    SetPlotStyle(2,psDash);
    SetPlotStyle(3,psDash);
    SetPlotWidth(1,2);
    SetPlotWidth(2,2);
    SetPlotWidth(3,2);
  end;



end;
				
			

Stoploss móvel (Versão contínua) + Breakeven

Reproduzir vídeo

O código abaixo apresenta um exemplo avançado de stoploss móvel com Breakeven na versão contínua, ou seja, valor de stop é atualizado para cada valor de fechamento de candle encerrado. Só não é atualizado a cada tick por uma limitação do Profit.

O stop será alterado para cOffsetStop em relação ao maior preço de fechamento alcançado desde a abertura da posição. O código pode ser alterado para calcular o stop móvel em relação ao valor máximo do candle.

O exemplo também conta com ordem take profit (alvo de lucro da operação) em posições compradas, para uma relação de risco/ganho de 3:1. O raciocínio para posições vendidas é análogo.

OBS 1: A versão é compatível com o Editor de Estratégias e Módulo de Automação de Estratégias. Devido a um bug do Profit, é necessário ter um comando ClosePosition, pois do contrário a ferramenta informa equivocadamente que não existem ordens para encerrar posição.

				
					const
 //Relação risco/ganho de 3:1
 cStopEmTicks = 30;
 cStopOffsetEmTicks = 10;
 cTrailingStopOffset = 15;
 cBreakevenEmTicks = 10;
 cTraillingStopTrigger = 20;
 cAlvoEmTicks = 90;


input
  bGestaoDeRiscoPelaEstrategia(true);
  iHorarioInicioAberturaPosicao(0905);
  iHorarioFimAberturaPosicao(1630);
  iHorarioEncerramentoDaytrade(1645);

var
  iCaraCoroa: integer;
  bSinalCompra, bSinalVenda, bPosicionado: boolean;
  fPrecoStop, fPrecoAlvo, fPrecoStopOffset: float;
  bBreakevenAtivado: boolean;
  bConfigurouRiscoInicial: boolean;
  bTrailingStopAtivado: boolean;

begin

  bSinalCompra := false;
  bSinalVenda := false;
  bPosicionado := hasPosition;

  //ESTRATÉGIA CARA OU COROA!
  //Gera um numero aleatorio de 0 a 9. Se for menor igual a 4, gera
  //sinal de compra, se for maior que 4 geral sinal de venda
  if Not bPosicionado
  and (Time >= iHorarioInicioAberturaPosicao)
  and (Time <= iHorarioFimAberturaPosicao)
  then
  begin
    //Número aleatório foi substituido por minuto par ou impar para permitir depurar
    //melhor o robô quando a estratégia é inserida multiplas vezes: como indicador  e como execução
    //iCaraCoroa := Random(10);
    iCaraCoroa := mod(Time,2);
    if iCaraCoroa = 0 then bSinalCompra := true
    else bSinalVenda := true;
  end;

  //Gera ordem de compra a mercado quando há um Sinal de COMPRA
  //e define ordem stoploss e take profit
  if bSinalCompra then BuyAtMarket;

  //Gera ordem de venda a mercado quando há um Sinal de VENDA
  //e define ordem stoploss e take profit
  if bSinalVenda then SellShortAtMarket;

  if bGestaoDeRiscoPelaEstrategia then
  begin
    //Código responsável pela manutenção das ordens de stoploss e take profit
    if isBought then
    begin
      if Not bConfigurouRiscoInicial then
      begin
        fPrecoStop := BuyPrice - cStopEmTicks*MinPriceIncrement;
        fPrecoAlvo := BuyPrice + cAlvoEmTicks*MinPriceIncrement;
        fPrecoStopOffset := fPrecoStop - cStopOffsetEmTicks*MinPriceIncrement;
        bConfigurouRiscoInicial := true;
      end;

      if ((Close >= (BuyPrice + cTraillingStopTrigger*MinPriceIncrement))
          or (cTraillingStopTrigger = 0))
      and (not bTrailingStopAtivado) then bTrailingStopAtivado := true;

      if ((Close - cTrailingStopOffset*MinPriceIncrement) >= fPrecoStop)
      and bTrailingStopAtivado then
          fPrecoStop := Close - cTrailingStopOffset*MinPriceIncrement;

      if (Close >= (BuyPrice + cBreakevenEmTicks*MinPriceIncrement))
      and (not bBreakevenAtivado) then
      begin
        bBreakevenAtivado := true;
        if fPrecoStop < BuyPrice then fPrecoStop := BuyPrice;
      end;


      fPrecoStopOffset := fPrecoStop-cStopOffsetEmTicks*MinPriceIncrement;
      SellToCoverStop(fPrecoStop,fPrecoStopOffset);
      SellToCoverLimit(fPrecoAlvo);
    end;


    //Código responsável pela manutenção das ordens de stoploss e take profit
    if isSold then
    begin
      if Not bConfigurouRiscoInicial then
      begin
        fPrecoStop := SellPrice + cStopEmTicks*MinPriceIncrement;
        fPrecoAlvo := SellPrice - cAlvoEmTicks*MinPriceIncrement;
        fPrecoStopOffset := fPrecoStop + cStopOffsetEmTicks*MinPriceIncrement;
        bConfigurouRiscoInicial := true;
      end;

      if ((Close <= (SellPrice - cTraillingStopTrigger*MinPriceIncrement))
          or (cTraillingStopTrigger = 0))
      and (not bTrailingStopAtivado) then bTrailingStopAtivado := true;

      if ((Close + cTrailingStopOffset*MinPriceIncrement) <= fPrecoStop)
      and bTrailingStopAtivado then
          fPrecoStop := Close + cTrailingStopOffset*MinPriceIncrement;

      if (Close <= (SellPrice - cBreakevenEmTicks*MinPriceIncrement))
      and (not bBreakevenAtivado) then
      begin
        bBreakevenAtivado := true;
        if fPrecoStop > SellPrice then fPrecoStop := SellPrice;
      end;


      fPrecoStopOffset := fPrecoStop + cStopOffsetEmTicks*MinPriceIncrement;
      BuyToCoverStop(fPrecoStop,fPrecoStopOffset);
      BuyToCoverLimit(fPrecoAlvo);
    end;


    //Encerra posicao
    if (Time >= iHorarioEncerramentoDaytrade)
    and HasPosition
    then ClosePosition;

    if Not hasPosition and bConfigurouRiscoInicial then
    begin
      bConfigurouRiscoInicial := false;
      bBreakevenAtivado := false;
      bTrailingStopAtivado := false;
    end;

  end;

  // Plot de Stop e Alvo para inspeção visual do código
  bPosicionado := hasPosition;
  if bPosicionado or bPosicionado[1] or bPosicionado[2] then
  begin
    PlotN(1,fPrecoStop);
    PlotN(2,fPrecoStopOffset);
    PlotN(3,fPrecoAlvo);
    SetPlotColor(1,clRed);
    SetPlotColor(2,clRed);
    SetPlotColor(3,clGreen);
    SetPlotStyle(1,psDash);
    SetPlotStyle(2,psDash);
    SetPlotStyle(3,psDash);
    SetPlotWidth(1,2);
    SetPlotWidth(2,2);
    SetPlotWidth(3,2);
  end
  else
  begin
    NoPlot(1);
    NoPlot(2);
    NoPlot(3);
  end;


end;
				
			

Stoploss móvel (Versão baseada em passos) + Breakeven

O código abaixo apresenta um exemplo avançado de stoploss móvel com Breakeven na versão discreta (baseada em passos), ou seja, valor de stop é atualizado para cada valor de fechamento que supera o passo definido (cTrailingStepEmTicks). Só não é atualizado a cada tick por uma limitação do Profit.

O stop será alterado para cOffsetStop em relação ao último passo alcançado pelo maior preço de fechamento de candle desde a abertura da posição. O código pode ser alterado para calcular o stop móvel em relação ao valor máximo do candle.

O exemplo também conta com ordem take profit (alvo de lucro da operação) em posições compradas, para uma relação de risco/ganho de 3:1. O raciocínio para posições vendidas é análogo.

OBS 1: A versão é compatível com o Editor de Estratégias e Módulo de Automação de Estratégias. Devido a um bug do Profit, é necessário ter um comando ClosePosition, pois do contrário a ferramenta informa equivocadamente que não existem ordens para encerrar posição.

				
					const
 //Relação risco/ganho de 3:1
 cStopEmTicks = 30;
 cBreakevenEmTicks = 10;
 cTraillingStopTrigger = 20;
 cTrailingStepEmTicks = 20;
 cTrailingStopOffset = 10;
 cStopOffsetEmTicks = 10;
 cAlvoEmTIcks = 90;

input
  bGestaoDeRiscoPelaEstrategia(true);
  iHorarioInicioAberturaPosicao(0905);
  iHorarioFimAberturaPosicao(1630);
  iHorarioEncerramentoDaytrade(1645);

var
  iCaraCoroa: integer;
  bSinalCompra, bSinalVenda, bPosicionado: boolean;
  fPrecoStop, fPrecoAlvo, fPrecoStopOffset: float;
  fFloorTraillingStop: float;
  bBreakevenAtivado: boolean;
  bConfigurouRiscoInicial: boolean;
  bTrailingStopAtivado: boolean;

begin

  bSinalCompra := false;
  bSinalVenda := false;
  bPosicionado := hasPosition;

  //ESTRATÉGIA CARA OU COROA!
  //Gera um numero aleatorio de 0 a 9. Se for menor igual a 4, gera
  //sinal de compra, se for maior que 4 geral sinal de venda
  if Not bPosicionado
  and (Time >= iHorarioInicioAberturaPosicao)
  and (Time <= iHorarioFimAberturaPosicao)
  then
  begin
    //Número aleatório foi substituido por minuto par ou impar para permitir depurar
    //melhor o robô quando a estratégia é inserida multiplas vezes: como indicador  e como execução
    //iCaraCoroa := Random(10);
    iCaraCoroa := mod(Time,2);
    if iCaraCoroa = 0 then bSinalCompra := true
    else bSinalVenda := true;
  end;

  //Gera ordem de compra a mercado quando há um Sinal de COMPRA
  //e define ordem stoploss e take profit
  if bSinalCompra then BuyAtMarket;

  //Gera ordem de venda a mercado quando há um Sinal de VENDA
  //e define ordem stoploss e take profit
  if bSinalVenda then SellShortAtMarket;

  if bGestaoDeRiscoPelaEstrategia then
  begin
    //Código responsável pela manutenção das ordens de stoploss e take profit
    if isBought then
    begin
      if Not bConfigurouRiscoInicial then
      begin
        fPrecoStop := BuyPrice - cStopEmTicks*MinPriceIncrement;
        fPrecoAlvo := BuyPrice + cAlvoEmTicks*MinPriceIncrement;
        fPrecoStopOffset := fPrecoStop - cStopOffsetEmTicks*MinPriceIncrement;
        bConfigurouRiscoInicial := true;
      end;

      if ((Close >= (BuyPrice + cTraillingStopTrigger*MinPriceIncrement))
          or (cTraillingStopTrigger = 0))
      and (not bTrailingStopAtivado) then bTrailingStopAtivado := true;

      fFloorTraillingStop := BuyPrice
          + floor((Close - BuyPrice)/(cTrailingStepEmTicks*MinPriceIncrement))
          *cTrailingStepEmTicks*MinPriceIncrement;

      if ((fFloorTraillingStop-cTrailingStopOffset*MinPriceIncrement) >= fPrecoStop)
      and (Close >= BuyPrice+cTrailingStepEmTicks*MinPriceIncrement)
      and bTrailingStopAtivado then
        fPrecoStop := fFloorTraillingStop - cTrailingStopOffset*MinPriceIncrement;

      if (Close >= (BuyPrice + cBreakevenEmTicks*MinPriceIncrement))
      and (not bBreakevenAtivado) then
      begin
        bBreakevenAtivado := true;
        if fPrecoStop < BuyPrice then fPrecoStop := BuyPrice;
      end;

      fPrecoStopOffset := fPrecoStop-cStopOffsetEmTicks*MinPriceIncrement;

      SellToCoverStop(fPrecoStop,fPrecoStopOffset);
      SellToCoverLimit(fPrecoAlvo);
    end;


    //Código responsável pela manutenção das ordens de stoploss e take profit
    if isSold then
    begin
      if Not bConfigurouRiscoInicial then
      begin
        fPrecoStop := SellPrice + cStopEmTicks*MinPriceIncrement;
        fPrecoAlvo := SellPrice - cAlvoEmTicks*MinPriceIncrement;
        fPrecoStopOffset := fPrecoStop + cStopOffsetEmTicks*MinPriceIncrement;
        bConfigurouRiscoInicial := true;
      end;

      if ((Close <= (SellPrice - cTraillingStopTrigger*MinPriceIncrement))
          or (cTraillingStopTrigger = 0))
      and (not bTrailingStopAtivado) then bTrailingStopAtivado := true;

      if Close <= SellPrice then
        fFloorTraillingStop := SellPrice
            - floor((SellPrice - Close)/(cTrailingStepEmTicks*MinPriceIncrement))
            *cTrailingStepEmTicks*MinPriceIncrement;


      if ((fFloorTraillingStop+cTrailingStopOffset*MinPriceIncrement) <= fPrecoStop)
      and (Close <= SellPrice - cTrailingStepEmTicks*MinPriceIncrement)
      and bTrailingStopAtivado then
        fPrecoStop := fFloorTraillingStop + cTrailingStopOffset*MinPriceIncrement;


      if (Close <= (SellPrice - cBreakevenEmTicks*MinPriceIncrement))
      and (not bBreakevenAtivado) then
      begin
        bBreakevenAtivado := true;
        if fPrecoStop > SellPrice then fPrecoStop := SellPrice;
      end;


      fPrecoStopOffset := fPrecoStop + cStopOffsetEmTicks*MinPriceIncrement;

      BuyToCoverStop(fPrecoStop,fPrecoStopOffset);
      BuyToCoverLimit(fPrecoAlvo);

    end;


    //Encerra posicao
    if (Time >= iHorarioEncerramentoDaytrade)
    and HasPosition
    then ClosePosition;

    if Not hasPosition and bConfigurouRiscoInicial then
    begin
      bConfigurouRiscoInicial := false;
      bBreakevenAtivado := false;
      bTrailingStopAtivado := false;
    end;

  end;

  // Plot de Stop e Alvo para inspeção visual do código
  bPosicionado := hasPosition;
  if bPosicionado or bPosicionado[1] or bPosicionado[2] then
  begin
    PlotN(1,fPrecoStop);
    PlotN(2,fPrecoStopOffset);
    PlotN(3,fPrecoAlvo);
    SetPlotColor(1,clRed);
    SetPlotColor(2,clRed);
    SetPlotColor(3,clGreen);
    SetPlotStyle(1,psDash);
    SetPlotStyle(2,psDash);
    SetPlotStyle(3,psDash);
    SetPlotWidth(1,2);
    SetPlotWidth(2,2);
    SetPlotWidth(3,2);
  end
  else
  begin
    NoPlot(1);
    NoPlot(2);
    NoPlot(3);
  end;




end;
				
			

Confirmação de ordens por múltiplos sinais

O código abaixo apresenta um exemplo para o conceito de confirmação de compra por meio de dois sinais distintos: um sinal baseado em IFR e outro baseado em cruzamento de média.

Os sinais podem ser adaptados para quaisquer condições que se deseje. O importante deste exemplo é entender a lógica por trás de duplas confirmações ou múltiplas confirmações com janela de timeout para abertura de posição.

OBS 1: Como o foco do snippet é a confirmação de ordens com múltiplos sinais, a gestão de risco foi implementada da forma mais simples possível apenas para tornar o código funcional. Percebe-se que há um stop e alvo fixos na relação 3:1, onde o stop está 30 ticks atrás do preço de compra e o alvo a 90 ticks acima do preço de compra.

OBS 2: A parametrização dos indicadores, bem como a seleção dos indicadores deste exemplo não representam nenhuma recomendação de setup, sendo apenas um exemplo didático.

				
					const
  // Determina a qtde de candles a se aguardar a confirmação
  // de sinal de compra 
  iTimeoutConfirmacao = 12;
  // Limite para considerar sobrevenda no IFR
  iLimiteSobreVendaIFR = 35;

input
  iQtdePeriodosMedia(16);
  iQtdePeriodosIFR(16);
  //Compatibilidade com Módulo de Automação de Estratégias
  bModuloAutomacao(false);
var
  bSinalCompraIFR, bSinalCompraCruzMedia: boolean;
  fIFR, fMedia: float;

  iInteradorTimeout: integer;
  bSinalCompraConfirmada: boolean;
  bSinalCompraIFRativou, bSinalCompraCruzMediaAtivou: boolean;
  
  bComprado: boolean;
  bConfigurouRiscoOperacao: boolean;
  fPrecoAlvo, fPrecoStop, fStopOffset: float;
begin
  // Indicadores técnicos utilizados para sinais
  bComprado := isBought;
  fIFR := RSI(iQtdePeriodosIFR,0);
  fMedia := Media(iQtdePeriodosMedia,Close);
  bSinalCompraConfirmada := false;  

  //Sinais de compra individuais para indicadores
  bSinalCompraCruzMedia := (Close > fMedia) and (Close[1] <= fMedia[1]);
  bSinalCompraIFR := (fIFR > iLimiteSobreVendaIFR) and (fIFR[1] <= iLimiteSobreVendaIFR);

  // Auxilio visual de sinais individuais
  if bSinalCompraCruzMedia and Not bComprado then PlotText("S1", clBlue,-1,9);
  if bSinalCompraIFR and Not bComprado then PlotText("S2", clYellow,0,9);

  // Lógica para multiplas confirmações
  // Se Timeout for zero a dupla confirmação de compra deve ocorrer
  // no mesmo candle/box
  if Not bComprado then
  begin
    if (iTimeoutConfirmacao = 0) and bSinalCompraCruzMedia and bSinalCompraIFR then
      bSinalCompraConfirmada := true
    else
    if (iTimeoutConfirmacao > 0) then
    begin
      bSinalCompraConfirmada := false;
      bSinalCompraIFRativou := false;
      bSinalCompraCruzMediaAtivou := false;
  
      for iInteradorTimeout := 0 to iTimeoutConfirmacao do
      begin
        if bSinalCompraCruzMedia[iInteradorTimeout] = true then bSinalCompraCruzMediaAtivou := true;
        if bSinalCompraIFR[iInteradorTimeout] = true then bSinalCompraIFRativou := true;
        if bSinalCompraCruzMediaAtivou and bSinalCompraIFRativou then bSinalCompraConfirmada := true;
      end;
    end;
  end;

  // Se houver multipla confirmação, executa ordem a mercado
  if bSinalCompraConfirmada and Not bComprado then 
  begin
    BuyAtMarket;
    bConfigurouRiscoOperacao := false;
  end;
  bComprado := isBought;

  // Configura risco da operação no Módulo de Automação (Ordem OCO)
  // Para outras configurações de STOPLOSS, consulte os snippets no site
  if bModuloAutomacao then
  begin
    if bComprado and Not bConfigurouRiscoOperacao then
    begin
      fPrecoAlvo := buyPrice + 450*MinPriceIncrement;
      fPrecoStop := buyPrice - 150*MinPriceIncrement;
      fStopOffset := fPrecoStop - 100*MinPriceIncrement;

      SellShortStop(fPrecoStop, fStopOffset);
      SellShortLimit(fPrecoAlvo);
    end
    else
    //Proteção de pulo da ordem stop devido à gaps 
    if isBought and (Close < fStopOffset) then closePosition;

  end
  // Configura alvo e stoploss para Backtesting
  else
  begin
    if bComprado then
    begin
      fPrecoAlvo := buyPrice + 450*MinPriceIncrement;
      fPrecoStop := buyPrice - 150*MinPriceIncrement;
      fStopOffset := fPrecoStop - 60*MinPriceIncrement;

      SellToCoverStop(fPrecoStop, fStopOffset);
      //Proteção de pulo da ordem stop devido à gaps
      if isBought and (Close < fStopOffset) then closePosition;
      if isBought then SellToCoverLimit(fPrecoAlvo);
    end;
  end;


end.

				
			

Gestão de Risco diária e Proteção de Ganhos

Reproduzir vídeo

O código abaixo apresenta um exemplo de programação para fazer a gestão de risco do resultado diário de um robô.

Inicialmente, são estabelecidos para a estratégia o limite de perda (pLimitePerdaDiaria) e objetivo de ganho diário (pObjetivoGanhoDiario), bem como a proteção de ganho desejada (pProtecaoGanho), tudo em valor financeiro.

A medida que o robô faz as operações, caso o resultado atinja o limite de perda inicial, a estratégia para de operar durante o resto do dia.

Caso o objetivo de ganho seja atingido, a gestão de risco do código protege parte do ganho (pProtecaoGanho) e o robô continua a operar. Caso atinja novamente o objetivo de ganho, a partir do último patamar de ganho planejado, o lucro é novamente protegido.

				
					input
  pLimitePerdaDiaria(100.00);
  pObjetivoGanhoDiario(300.00);
  pProtecaoGanho(200.00);
  pTempoReal(false);
var
  fResultado: float;
  fResultadoDiario: float;
  iHora: integer;

  fObjetivoAtualGanho, fLimiteAtualPerda: float;
  fNovaReferencia: float;

  bPrimeiraBarraDoDia : boolean;
  iDataAtual          : integer;
  bPrimeiroTickDaBarra : boolean;
  iBarraAtual          : integer;
begin
  // Configura a gestão de risco no primeiro tick da primeira
  // barra do dia. Necessário agora que tem roteamento no tick
  // SNIPPET de "Identificação do primeiro candle de cada dia"
  // +
  // SNIPPET de "Identificação do primeiro tick de uma barra"
  if (Date() <> iDataAtual) then
    begin
      iDataAtual := Date();
      bPrimeiraBarraDoDia := true;
    end;
  if bPrimeiraBarraDoDia then
    begin
      bPrimeiraBarraDoDia := false;

      if (pTempoReal and LastBarOnChart) or not pTempoReal then
      if (CurrentBar <> iBarraAtual) then
        begin
          iBarraAtual := CurrentBar;
          bPrimeiroTickDaBarra := true;
        end
      else
        bPrimeiroTickDaBarra := false;

      if bPrimeiroTickDaBarra then
        begin
          //Faz alguma coisa no primeiro tick da barra
          //Aplicável apenas em execução de tempo real
          fObjetivoAtualGanho := pObjetivoGanhoDiario;
          fLimiteAtualPerda := pLimitePerdaDiaria;
          fNovaReferencia := 0;
        end;

    end;


  //-----------------------------------------------------------
  // SNIPPET de "Como limitar trades por objetivo de ganho ou limite de perda"
  // Resultado até o momento no dia (fechado + aberto)
    fResultado := DailyResult(true);
    plot(fResultado);
    SetPlotStyle(1,psDash);
    SetPlotColor(1,clGray);
    SetPlotType(1,igHistogram);

    plot2(fNovaReferencia - fLimiteAtualPerda);
    SetPlotStyle(2,psSolid);
    SetPlotColor(2,clRed);
    SetPlotWidth(2,3);

  // Estratégia qualquer de operação!!!
  // Estratégias apenas opera se resultado do dia não
  // tiver atingido objetivo de ganho ou limite de perda
  fResultadoDiario := DailyResult(true) - fNovaReferencia;

  if (fResultadoDiario > -1*fLimiteAtualPerda)
  and (fResultadoDiario < fObjetivoAtualGanho) then
  begin
    // SIMULAÇÃO DE ORDENS PARA FINS DE EXEMPLO
    for iHora := 0 to 8 do
    begin
      if (Time = (0900 + iHora*100)) or (Time = (0930 + iHora*100)) then
        if random(2) = 0 then BuyAtMarket else SellShortAtMarket;

      if (Time = (0920 + iHora*100)) Or (Time = (0950 + iHora*100)) then
        ClosePosition;
    end;

  end
  //Se resultado excedeu objetivo de ganho cria-se novos limites
  //Se atingiu limite de perda ou proteção de ganho então para de operar
  else 
  begin
    if fResultadoDiario <= -1*pLimitePerdaDiaria then
    begin
      if hasPosition then ClosePosition;
    end
    else
    if fResultadoDiario >= pObjetivoGanhoDiario then
    begin
       fNovaReferencia := fNovaReferencia + pObjetivoGanhoDiario;
       fLimiteAtualPerda := (pObjetivoGanhoDiario - pProtecaoGanho);
    end;

  end;

end;
				
			

Identificando resultado da última operação

Reproduzir vídeo

O código abaixo apresenta um exemplo de programação para identificar o resultado da última operação realizada. Assim, o trader pode realizar outras lógicas de limitação de sequência de trades com prejuízo, lucro e outras que desejar.

				
					var
  bHasPosition: boolean;
  iDia: integer;
  fResultadoFechadoDia, fResultadoTotalDia: float;
  fResultadoUltimoTrade, fResultadoAberto: float;
begin
  if (Date <> iDia) then
  begin
    iDia := Date;
    fResultadoUltimoTrade := 0;
  end;

  // ARMAZENAMENTO DE VARIÁVEIS (FACILITA A DEPURAÇÃO)
  bHasPosition := HasPosition;
  fResultadoTotalDia := DailyResult(true);
  fResultadoFechadoDia := DailyResult(false);

  // CALCULA O RESULTADO ABERTO
  if bHasPosition 
  then fResultadoAberto := fResultadoTotalDia - fResultadoFechadoDia
  else fResultadoAberto := 0;

  // CALCULA O RESULTADO DO ÚLTIMO TRADE
  if not bHasPosition and bHasPosition[1]
  then fResultadoUltimoTrade := fResultadoAberto[1];
 
  // PLOTA GRÁFICO PARA INSPEÇÃO VISUAL
  plot(fResultadoAberto);
  SetPlotType(1,igHistogram);
  if fResultadoAberto > 0 then SetPlotColor(1,clGreen)
  else if fResultadoAberto < 0 then SetPlotColor(1,clRed)
       else SetPlotColor(1,clGray);

  plot2(fResultadoUltimoTrade);
  SetPlotColor(2,clWhite);
  SetPlotStyle(2,psDash);
  SetPlotWidth(2,2);


  //ROTEAMENTO DE ORDENS
  if (Time = 0905) then BuyAtMarket;
  if (Time >= 0915) then ClosePosition;

end;
				
			

Como obter o preço médio executado durante montagem e realização parcial

É tarefa comum quando você está com um setup de montagem e realizações parciais querer estabelecer ordens de alvo e stop de acordo com o preço executado da última ordem e não do preço médio da posição.

É possível obter esse valor pelo código abaixo. No entanto, é importante ressaltar que devido às limitações da linguagem NTSL, caso haja várias execuções de ordens na mesma barra, o preço calculado de execução será o preço médio das ordens executadas na barra tendo em vista a diferença da posição.

				
					var
  iPosicao: integer;
  fPrecoMedio: float;
  fPrecoExecutado: float;

// ----------------------------------------------------------------------------------------
function getAvgFilledOrderPrice(previousPos: integer; previousPrice: Float; 
                                currentPos:integer; currentPrice: Float): float;
begin
  if  (currentPos <> 0) and (previousPos <> 0) 
  and (currentPos <> previousPos) then
  begin
    Result := (currentPos*currentPrice - previousPos*previousPrice)/(currentPos - previousPos);
  end
  else
    Result := 0;   
end;
// ----------------------------------------------------------------------------------------


begin
  // Como calcular preço médio de execução de ordens na barra
  iPosicao := Position;
  fPrecoMedio := Price;
  fPrecoExecutado := getAvgFilledOrderPrice(iPosicao[1], fPrecoMedio[1], iPosicao, fPrecoMedio);

  plot2(fPrecoExecutado);
  SetPlotType(2,igHistogram);
  // ---------------------------------------------------------

  if (Date = LastCalcDate) and (Time = 1500) then
      SellShortAtMarket(2);

  if (Date = LastCalcDate) and (Time = 1505) then
      BuyAtMarket(1);

  if (Date = LastCalcDate) and (Time = 1515) then
    SellShortAtMarket(2);

  if (Date = LastCalcDate) and (Time = 1530) then
    SellShortAtMarket(2);

  if (Time >= 1630) and hasPosition then ClosePosition;

  if hasPosition then Plot(Price);
  SetPlotColor(1, clWhite);
  SetPlotStyle(1, psDash);

end;
				
			

Implementação de estratégias

Introdução

Esta seção visa apresentar trechos de códigos com exemplos de tarefas comuns para implementação de estratégias.

Você pode acessar os Snippets diretamente pelo menu lateral direito, ou fazendo CRL+F (CTRL+L) para localizar algum texto específico na página, uma vez que o conteúdo tende a crescer ao longo do tempo, dificultando a navegação pelo menu.

Caso tenham sugestões de código para acrescentar à lista, gentileza deixar o código nos comentários com o link para seu perfil em rede social (para devido crédito de autoria).

Snippets

Cruzamento simples entre 2 séries

Reproduzir vídeo

O exemplo abaixo visa identificar quando há um cruzamento simples entre duas séries, considerando apenas o instante atual e anterior.

				
					var
  fMedia1, fMedia2: float;
  iCruzamento: integer;


function NTB_ArredondarFloat(Value: float; nCasas: integer):float;
var
    fValor: float;
    fParteInteira: float;
    fParteDecimal: float;
begin
  fValor := Value;
  fParteInteira := IntPortion(fValor);
  fParteDecimal := Round((fValor - fParteInteira)*Power(10,nCasas));

  Result := fParteInteira + fParteDecimal/Power(10,nCasas);
end;


begin
  iCruzamento := 0;
  fMedia1 := NTB_ArredondarFloat(Media(10,Close),2);
  fMedia2 := NTB_ArredondarFloat(Media(20,Close),2);

  if  (fMedia1 > fMedia2)
  and (fMedia1[1] <= fMedia2[1]) then
    iCruzamento := 1;

  if (fMedia1 < fMedia2)
  and (fMedia1[1] >= fMedia2[1]) then
    iCruzamento := -1;

  if iCruzamento = 1 then
  begin
    // O que fazer quando houver cruzamento para cima?
    PlotText("Cruzou acima", clGreen, -1,12);
  end;

  if iCruzamento = -1 then
  begin
    // O que fazer quando houver cruzamento para baixo?
    PlotText("Cruzou abaixo", clRed, -1,12);
  end;

  //Plot apenas para visualizar graficamente o funcionamento
  //do código
  Plot(fMedia1);
  Plot2(fMedia2);
  SetPlotColor(1,clRed);
  SetPlotWidth(1,2);  
  SetPlotColor(2,clWhite);
  SetPlotStyle(2,psDash);  
  SetPlotWidth(2,2);  

end;
				
			

Cruzamento simples entre 2 séries com percentual de cruzamento

O exemplo abaixo visa identificar quando há um cruzamento simples entre duas séries, considerando apenas o instante atual e anterior, e desde que o cruzamento seja superior a um determinado valor percentual.

				
					const
  //Constante fornecida em percentual. Ex: 0.1 significa 0.1%
  fPercCruzamento = 0.1;
var
  fMedia1, fMedia2: float;
  iCruzamento: integer;

begin
  iCruzamento := 0;
  fMedia1 := Media(10,Close);
  fMedia2 := Media(20,Close);    

  //Plot apenas para visualizar graficamente o funcionamento
  //do código
  Plot(fMedia1);
  Plot2(fMedia2); 

  if (fMedia1 <> 0) and (fMedia2 <> 0) then
  begin

    if  (fMedia1 > fMedia2)
    and (fMedia1[1] <= fMedia2[1])
    and (((fMedia1-fMedia2)/fMedia1*100) >= fPercCruzamento)
    then iCruzamento := 1;
  
    if  (fMedia1 < fMedia2)
    and (fMedia1[1] >= fMedia2[1]) 
    and ((Abs((fMedia2-fMedia1)/fMedia1*100)) >= fPercCruzamento)
    then iCruzamento := -1;
  
    if iCruzamento = 1 then 
    begin
      // O que fazer quando houver cruzamento para cima?
      PlotText("Cruzou pra cima", clGreen, -1,12);
    end;
  
    if iCruzamento = -1 then 
    begin
      // O que fazer quando houver cruzamento para baixo?
      PlotText("Cruzou pra baixo", clRed, -1,12);    
    end;
  end;

end;
				
			

Cruzamento entre 2 séries nos últimos N períodos

O exemplo abaixo visa identificar qual cruzamento houve entre duas séries nos últimos N períodos (constante cJanelaCruzamento).

				
					const
  cJanelaCruzamento = 5;
var
  fMedia1,fMedia2 : float;
  iCruzamento : integer;
  iUltimoCruzamentoJanela : integer;
  iPeriodo, iPeriodoJanela : integer;
begin
  iCruzamento := 0;
  fMedia1 := Media(10,Close);
  fMedia2 := Media(20,Close);

  //Plot apenas para visualizar graficamente o funcionamento
  //do código
  Plot(fMedia1);
  Plot2(fMedia2);

  if (fMedia1 > fMedia2) and (fMedia1[1] <= fMedia2[1]) then
    iCruzamento := 1;
  if (fMedia1 < fMedia2) and (fMedia1[1] >= fMedia2[1]) then
    iCruzamento := - 1;
  
  if iCruzamento = 1 then
    begin
      // O que fazer quando houver cruzamento para cima?
      PlotText("Cruzou pra cima",clGreen, - 1,12);
    end;
  
  if iCruzamento = - 1 then
    begin
      // O que fazer quando houver cruzamento para baixo?
      PlotText("Cruzou pra baixo",clRed, - 1,12);
    end;


  // Código para proteção do início da série em backtesting
  if MaxBarsBack < cJanelaCruzamento then
    iPeriodoJanela := MaxBarsBack
  else iPeriodoJanela := cJanelaCruzamento;
  
  // Identificação do último cruzamento
  if iPeriodoJanela >= 1 then
  begin  
    iUltimoCruzamentoJanela := iCruzamento;
    iPeriodo := 1;
    while iPeriodo <= iPeriodoJanela do
    begin
      if iCruzamento[iPeriodo] <> 0 then
      begin
         iUltimoCruzamentoJanela := iCruzamento[iPeriodo];
         iPeriodo := iPeriodoJanela + 1;
      end;
      iPeriodo := iPeriodo + 1;
    end;
  
    // Escreve no gráfico qual cruzamento houve nos últimos
    // cJanelaCruzamento periodos
    if (iCruzamento = 0) and (iUltimoCruzamentoJanela <> 0) then
      if iUltimoCruzamentoJanela = 1 then
        PlotText("Cruz p/ cima",clWhite, - 1,8)
      else
        PlotText("Cruz p/ baixo",clWhite, - 1,8);
  end;

end;
				
			

Toque na média utilizando percentual de proximidade

Reproduzir vídeo

O exemplo abaixo visa identificar quando ocorre o toque do preço em uma média, utilizando como parâmetro o percentual de proximidade.

OBS: Neste exemplo foi introduzido também uma função customizada para arredondar um valor float de acordo com a quantidade de casas decimais desejada (NTB_ArredondarFloat)). Este tipo de função não tem de forma nativa no Profit (o que é uma pena!);

				
					const
  // Define o percentual que caracteriza o toque
  // Se for igual a zero, a barra tem conter a média
  // Ex: se cPercProximidade = 0.5, define como toque se
  // preço chegar a 0.5% ou menos de distância da média
  cPercProximidade = 0.0;
var
  fMedia: float;
  bTocouMedia: boolean;


function NTB_ArredondarFloat(Value: float; nCasas: integer):float;
var
    fValor: float;
    fParteInteira: float;
    fParteDecimal: float;
begin
  fValor := Value;
  fParteInteira := IntPortion(fValor);
  fParteDecimal := Round((fValor - fParteInteira)*Power(10,nCasas));

  Result := fParteInteira + fParteDecimal/Power(10,nCasas);

end;

begin
  bTocouMedia := false;
  fMedia :=  NTB_ArredondarFloat(Media(20,Close),2);

  //Plot apenas para visualizar graficamente o funcionamento
  //do código
  Plot(fMedia);
  SetPlotColor(1,clRed);
  SetPlotWidth(1,2);
  if (cPercProximidade <> 0) then
  begin
    Plot2(NTB_ArredondarFloat(fMedia*(1 + cPercProximidade/100),2));
    Plot3(NTB_ArredondarFloat(fMedia*(1 - cPercProximidade/100),2));
    SetPlotColor(2, clGray);
    SetPlotColor(3, clGray);
  end;


  //Proteção para os primeiros períodos de backtesting
  //Quando pode ocorrer divisão por zero
  if fMedia <> 0 then
  begin

    // Situação em que a media está no meio da barra
    if (fMedia >= Low) and (fMedia <= High)
    then bTocouMedia := True;

    // Situação em que a media está abaixo do preço
    // negociado e este chegou a cPercProximidade da
    // média
    if (fMedia < Low)
    and (((Low - fMedia)/fMedia*100) <= cPercProximidade)
    then
    begin
      bTocouMedia := True;
    end;

    // Situação em que a media está abaixo do preço
    // negociado e este chegou a cPercProximidade da
    // média
    if (fMedia > High)
    and (((fMedia - High)/High*100) <= cPercProximidade)
    then
    begin
    bTocouMedia := True;
    end;

   if bTocouMedia then
     PlotText("Tocou",clWhite, - 1,8);

  end;

end;
				
			

Toque na média utilizando quantidade de ticks de proximidade

Reproduzir vídeo

O exemplo abaixo visa identificar quando ocorre o toque do preço em uma média, utilizando como parâmetro a quantidade de ticks do ativo.

OBS: Neste exemplo foi introduzido também uma função customizada para arredondar um valor float de acordo com a quantidade de casas decimais desejada (NTB_ArredondarFloat)). Este tipo de função não tem de forma nativa no Profit (o que é uma pena!);

				
					const
  // Define o percentual que caracteriza o toque
  // Se for igual a zero, a barra tem conter a média
  // Ex: se cPercProximidade = 0.5, define como toque se
  // preço chegar a 0.5% ou menos de distância da média
  cTicksProximidade = 0;
var
  fMedia: float;
  bTocouMedia: boolean;


function NTB_ArredondarFloat(Value: float; nCasas: integer):float;
var
    fValor: float;
    fParteInteira: float;
    fParteDecimal: float;
begin
  fValor := Value;
  fParteInteira := IntPortion(fValor);
  fParteDecimal := Round((fValor - fParteInteira)*Power(10,nCasas));

  Result := fParteInteira + fParteDecimal/Power(10,nCasas);

end;

begin
  bTocouMedia := false;
  fMedia :=  NTB_ArredondarFloat(Media(20,Close),2);

  //Plot apenas para visualizar graficamente o funcionamento
  //do código
  Plot(fMedia);
  SetPlotColor(1,clRed);
  SetPlotWidth(1,2);
  if (cTicksProximidade <> 0) then
  begin
    Plot2(fMedia + cTicksProximidade*MinPriceIncrement);
    Plot3(fMedia - cTicksProximidade*MinPriceIncrement);
    SetPlotColor(2,clGray);
    SetPlotColor(3,clGray);
  end;

  //Proteção para os primeiros períodos de backtesting
  //Quando pode ocorrer divisão por zero
  if fMedia <> 0 then
  begin

    // Situação em que a media está no meio da barra
    if (fMedia >= Low) and (fMedia <= High)
    then bTocouMedia := True;

    // Situação em que a media está abaixo do preço
    // negociado e este chegou a cPercProximidade da
    // média
    if (fMedia < Low)
    and (((Low - fMedia)/MinPriceIncrement) <= cTicksProximidade)
    then
    begin
      bTocouMedia := True;
    end;

    // Situação em que a media está abaixo do preço
    // negociado e este chegou a cPercProximidade da
    // média
    if (fMedia > High)
    and (((fMedia - High)/MinPriceIncrement) <= cTicksProximidade)
    then
    begin
    bTocouMedia := True;
    end;

   if bTocouMedia then
     PlotText("Tocou",clWhite, - 1,8);

  end;

end;
				
			

Como acessar o Book de Ofertas em NTSL por nível de preço

Reproduzir vídeo

O exemplo abaixo demonstra como armazenar em um array os próximos N níveis de preço do book e obter as quantidades apregoadas para estes níveis no lado da compra e da venda.

OBS: Este código funciona apenas quando o mercado está aberto, não sendo possível fazer backtesting de estratégias baseadas em leitura de book. Isso é algo comum às demais plataformas de trading.

				
					const
  cQtdeNiveis = 4;

input
  cAtivo("CASH3", feedBovespa);

var
  i: integer;
  fBookSell, fBookBuy: array[0..cQtdeNiveis] of float;
  fBookSellSum, fBookBuySum: float;

begin

  for i:= 0 to cQtdeNiveis do
  begin
    fBookSellSum := TotalSellQtd(cAtivo,i+1);
    fBookBuySum :=  TotalBuyQtd(cAtivo,i+1);
    
    if i <> 0 then
    begin
      fBookSell[i] := fBookSellSum - TotalSellQtd(cAtivo,i);    
      fBookBuy[i] := fBookBuySum - TotalBuyQtd(cAtivo,i);
    end
    else
    begin
      fBookSell[i] := fBookSellSum;
      fBookBuy[i] := fBookBuySum;  
    end; 
  end;

  
  {
  // Comparando retorno das funções (Ask/Bid)Size com Total(Sell/Buy)Qtd
  plot(fBookSell[0]);
  plot2(fBookBuy[0]);
  SetPlotColor(1,clRed);
  SetPlotColor(2,clRed);

  plot3(AskSize);
  plot4(BidSize);
  SetPlotColor(3,clYellow);   
  SetPlotColor(4,clYellow);
  }

  // Comparando os 5 primeiros níveis do lado da compra
  plot(fBookBuy[0]);
  plot2(fBookBuy[1]);
  plot3(fBookBuy[2]);
  plot4(fBookBuy[3]);
  plot5(fBookBuy[4]);

  SetPlotColor(1,clRed);
  SetPlotColor(2,clRed);
  SetPlotColor(3,clRed);   
  SetPlotColor(4,clRed);
  SetPlotColor(5,clRed);
  


end
				
			

Outros Snippets

Introdução

Esta seção visa apresentar outros exemplos de trechos de códigos que não se enquadram nas categorias anteriores.

Você pode acessar os Snippets diretamente pelo menu lateral direito, ou fazendo CRL+F (CTRL+L) para localizar algum texto específico na página, uma vez que o conteúdo tende a crescer ao longo do tempo, dificultando a navegação pelo menu.

Caso tenham sugestões de código para acrescentar à lista, gentileza deixar o código nos comentários com o link para seu perfil em rede social (para devido crédito de autoria).

Snippets

Escrevendo no Console com Timestamp para facilitar Debug

A partir da versão beta 215, tornou-se possível no Backtesting escrever texto no Console, o que facilita a depuração de estratégias.

Segue abaixo um snippet no qual há uma função que retorna o timestamp da barra. O corpo principal da estratégia apenas gera na aba “Compilação” o log com mensagem “Teste” precedido do timestamp no formato “DD/MM/AAAA HH:MM”.

				
					var
  horario: integer;
  timestamp : string;


//---------------------------------------------------
function getTimestamp: string;
var
  dia, mes_ano, hora: string;
begin

  if Month(Date) < 10 then 
    mes_ano := "0" + Month(Date) + "/" + Year(Date)
  else
    mes_ano := Month(Date) + "/" + Year(Date);    

  if DayofMonth(Date) < 10 then
    dia := "0" + DayofMonth(Date) + "/" + mes_ano
  else 
    dia := DayofMonth(Date) + "/" + mes_ano;

  if Floor(Time/100) < 10 then
    hora := "0" + Floor(Time/100)
  else
    hora := Floor(Time/100);

  if Mod(Time,100) < 10 then
    hora := hora + ":" + "0" + Mod(Time,100)
  else
    hora := hora + ":" + Mod(Time,100);    

  Result :=  dia + " " + hora + " - ";
end;
//---------------------------------------------------

begin
  if horario <> Time then
  begin
    timestamp := getTimestamp;
    ConsoleLog(getTimestamp() + "Teste", clBlue);
    horario := Time;
  end;
  
end;





				
			

Arrendondamento de valores para N casas decimais

Reproduzir vídeo

Como o Profit não tem nativamente uma função para arrendondar um float para uma determinada quantidade de casas decimais (N), a função abaixo foi implementada com esta finalidade.

				
					var
  fValorOriginal: float;
  fValorArred: float;

function NTB_ArredondarFloat(Value: float; nCasas: integer):float;
var
    fValor: float;
    fParteInteira: float;
    fParteDecimal: float;
begin
  fValor := Value;
  fParteInteira := IntPortion(fValor);
  fParteDecimal := Round((fValor - fParteInteira)*Power(10,nCasas));

  Result := fParteInteira + fParteDecimal/Power(10,nCasas);

end;

begin
  fValorOriginal := 12.345819;
  fValorArred :=  NTB_ArredondarFloat(fValorOriginal,2);

  if LastBarOnChart then
    PlotText(fValorArred,clWhite, - 1,8);
end;
				
			

Restrição de estratégia pelo código do ativo

O código abaixo visa identificar o código do ativo no qual a estratégia ou robô está sendo aplicado. A estratégia apenas é executada se o ticker do ativo for igual a constante “cAtivoEstrategia”.

Isto evita que as estratégias sejam rodadas de forma equivocada em ativos para os quais os parâmetros da estratégia não foram otimizados.

				
					const
  cAtivoEstrategia = "PETR4";
begin
  if GetAsset = cAtivoEstrategia then
  begin
    //TODO CÓDIGO FONTE DA SUA ESTRATÉGIA DEVE ESTAR AQUI DENTRO
    PaintBar(clGreen);
  end
  else
    if LastBarOnChart then
      plotText("Usar em " + cAtivoEstrategia,clWhite,-1,12);
end
				
			

Restrição de estratégia pelo tipo/frequência do gráfico

Reproduzir vídeo

O código abaixo visa identificar o tipo de gráfico no qual a estratégia ou robô está sendo aplicado. Caso não corresponda ao tipo de gráfico para o qual a estratégia foi otimizada, é exibida mensagem com informação sobre o tipo de gráfico adequado.

Isto evita que as estratégias sejam rodadas de forma equivocada para tipos de gráficos e frequências temporais diferentes daquelas para as quais foi validada.

				
					var
  bStarted, bGraficoOK: boolean;
  iTipoGrafico: integer;
  strMensagemErro: string;
begin
  if Not bStarted then
  begin
    bStarted := true;
    iTipoGrafico := GraphicInterval;

    //Verificação de Renko 3R
    if (iTipoGrafico = itRenko) and (GraphicOffset = 3) then bGraficoOK := true
    else strMensagemErro := "Estratégia para 3R"; 
    
    //Verificação de Gráfico de 5 minutos    
    //if (iTipoGrafico = itMinute) and (GraphicOffset = 5) then bGraficoOK := true
    //else strMensagemErro := "Estratégia para 5 Minutos";
         
  end;

  // Robô/Estratégia só irá ser executada se o gráfico estiver configurado
  // adequadamente
  if bGraficoOK then
  begin


  end
  // Se gráfico não estiver na configuração adequada, pinta todas as barras de vermelho
  // e exibe texto na última barra
  else
  begin
  paintBar(clRed);
  if LastBarOnChart then
    plotText(strMensagemErro,clWhite,-1,9);
  end;

end
				
			

Ignorar boxes de Gap em gráficos de Renko

Reproduzir vídeo

É bastante comum, principalmente na operação de contratos futuros, a ocorrência de gaps na abertura. Quando se está em um gráfico de Renko, o código da estratégia é processado para cada box incluído no gráfico devido ao gap.

Este código apresenta uma forma simples de não executar lógica sobre boxes referentes à gap. Os boxes de gap possuem duração igual a zero. Para realizar a verificação da duração temporal em minutos de um box, basta utilizar o comando BarDurationF.

				
					var
  bLocalizouBoxesGap : boolean;
  iDataUltimoBox, iUltimoBoxDiaAnterior, iBoxDeGAP: integer;
begin
  
  // Código é aplicável apenas à gráficos do tipo Renko
  if GraphicInterval = itRenko then
  begin  
    // Identificação de Box relacionados a GAP
    if Date <> iDataUltimoBox then
    begin
      iUltimoBoxDiaAnterior := CurrentBar - 1;
      iBoxDeGAP := CurrentBar;
      bLocalizouBoxesGap := false;
    end;
  
   iDataUltimoBox := Date;
   
   if Not bLocalizouBoxesGap then
    if BarDurationF = 0 then 
    begin
      iBoxDeGAP := CurrentBar;
      PaintBar(clRed);
    end
    else
    begin
      //Aqui foi identificado o primeiro box que não é de GAP
      bLocalizouBoxesGAP := true;
    end;


    //Aqui executa a estratégia em boxes que não são devido à
    //gap de abertura
    if bLocalizouBoxesGAP then
    begin
      PaintBar(clGreen);
    end;



  end
  // O Gráfico não é do tipo Renko!
  else
    if LastBarOnChart then PlotText("Aplicável apenas a Renko",clWhite,-1,10);

end
				
			

Cálculo de Gap em gráficos de Renko em termos de boxes

É bastante comum, principalmente na operação de contratos futuros, a ocorrência de gaps na abertura. Este código visa calcular o tamanho do gap nos gráficos de Renko em termos da quantidade de boxes.

OBS: É importante ressaltar que devido à própria natureza do gráfico de Renko, o cálculo de gap não é preciso quanto o cálculo de gap pelo gráfico de Candle.

OBS2: Os comandos OpenD(0) e CloseD(1) também podem ser utilizados em gráficos de renko, reduzindo o código abaixo a gap := (OpenD(0) – CloseD(1))/((GraphicOffset-1)*MinPriceIncrement). No entanto, os valores encontrados divergem em alguns dias de gap por 1 box. Pela minha apuração, o código abaixo apresenta os resultados corretos.

				
					var
  bLocalizouBoxesGap : boolean;
  fTamanhoBox : float;
  iDataUltimoBox, iUltimoBoxDiaAnterior, iBoxDeGAP: integer;
  fGAPdoDiaBox, fAberturaBox, fFechamentoDiaAnteriorBox: float;
begin
  
  // Código é aplicável apenas à gráficos do tipo Renko
  if GraphicInterval = itRenko then
  begin  
    fTamanhoBox := (GraphicOffset-1)*MinPriceIncrement;
    
    // Identificação de Box relacionados a GAP
    if Date <> iDataUltimoBox then
    begin
      iUltimoBoxDiaAnterior := CurrentBar - 1;
      iBoxDeGAP := CurrentBar;
      bLocalizouBoxesGap := false;
    end;
  
   iDataUltimoBox := Date;
   
   if Not bLocalizouBoxesGap then
    if BarDurationF = 0 then iBoxDeGAP := CurrentBar
    else
    begin
      //Aqui foi identificado o primeiro box que não é de GAP
      bLocalizouBoxesGAP := true;
  
      //Coloque abaixo o que deseja fazer no primero box do dia que não é GAP
      // --------------------------------------------------------------------
      if (Open < Close[1]) Or (Open > Close[1]) then fAberturaBox := Open[1]
      else fAberturaBox := Close[1];
      fFechamentoDiaAnteriorBox := Close[CurrentBar - iUltimoBoxDiaAnterior];
       
      fGAPdoDiaBox := (fAberturaBox -  fFechamentoDiaAnteriorBox)/fTamanhoBox;
  
      if fGAPdoDiaBox <> 0 then 
      begin
        if fGAPdoDiaBox > 0 then
          PlotText("GAP:" + Floor(fGAPdoDiaBox) + " Box",clGreen,-1,9)
        else
          PlotText("GAP:" + Floor(fGAPdoDiaBox) + " Box",clRed,-1,9);
        PaintBar(clRed);
      end;
      // --------------------------------------------------------------------
    end;
  end
  // O Gráfico não é do tipo Renko!
  else
    if LastBarOnChart then PlotText("Aplicável apenas a Renko",clWhite,-1,10);

end
				
			

Execução de estratégia em frequência superamostrada

Reproduzir vídeo

É de conhecimento de quem opera gráficos com tempo gráfico maior os impactos de se executar ordens apenas no fechamento dos candles/boxes.

Este Snippet visa tornar as ordens mais tempestivas, exemplificando uma forma de executar uma estratégia/robô em um tempo gráfico menor do que o original. Naturalmente que isso exige um código fonte mais complexo para tratar de forma adequada os cálculos de indicadores utilizados na estratégia.

O código de exemplo abaixo, demonstra como utilizar uma média móvel em um tempo gráfico superamostrado equivalente ao tempo gráfico original da estratégia (e com valor superior). Bem como também demonstra como seria o cálculo para obter a média de fechamento em tempos gráficos superiores ao gráfico supermostrado.

OBS: Embora não seja um requisito, sugere-se que o tempo gráfico original seja um múltiplo do tempo gráfico superamostrado.

				
					//LIMITAÇÃO IMPORTANTE: Não dá para fazer em escala de segundos
//devido a função time não retornar segundos
const
  // Estratégia originalmente rodava em gráfico de 15 min
  cTempoGraficoOriginal = 15;
  //Qtde de periodos no tempo gráfico original
  cQtdePeriodosMedia = 20;
  //Horario inicial de negociação do ativo
  //0900 para futuros, 1000 para mercado a vista
  cHoraInicioNegociacao = 0900;
var
  bStarted: boolean;

  iTempoGraficoAtual: integer;
  iQtdePeriodosEquivalente: integer;
  fMediaSuperAmostradaEquivalente: float;

  fInicializacaoMedia: float;
  fMediaTempoGraficoOriginal: float;
  iQtdePeriodosCalculados: integer;

  iHorarioEmMinutos: integer;
  iHorarioGrafSuperior: integer;
  bCalculouTempoGrafSuperior: boolean;

begin
  //1a opção: Dar preferencia sempre que possível
  // Identifica tempo gráfico utilizado e qtde de periodos equivalente para média superamostrada
  iTempoGraficoAtual := GraphicOffset;
  iQtdePeriodosEquivalente := Floor(cTempoGraficoOriginal/iTempoGraficoAtual)*cQtdePeriodosMedia;

  // Obtem média superamostrada equivalente
  fMediaSuperAmostradaEquivalente := Media(iQtdePeriodosEquivalente,Close);

  //Plot da série para inspeção
  PlotN(1,fMediaSuperAmostradaEquivalente);
  SetPlotColor(1, clWhite);
  SetPlotWidth(1,2);
  SetPlotStyle(1, psDash);



  //2a opção: Exige mais linhas de código para gerenciar execução
  //Amostrando apenas os valores de fechamento do Tempo gráfico original
  iHorarioEmMinutos := Floor(Time/100)*60+Mod(Time,100)
                     - (Floor(cHoraInicioNegociacao/100)*60+Mod(cHoraInicioNegociacao,100));
  
  if Not bStarted then
  begin
    iHorarioGrafSuperior := CalcTime(Time,-Mod(iHorarioEmMinutos, cTempoGraficoOriginal));
    bStarted := true;
  end;

  // Bloco para criar mecanismo de calcular apenas uma vez para o gráfico superior
  if (CalcTime(Time,-Mod(iHorarioEmMinutos, cTempoGraficoOriginal)) <> iHorarioGrafSuperior) then
  begin
    iHorarioGrafSuperior := CalcTime(Time,-Mod(iHorarioEmMinutos, cTempoGraficoOriginal));
    bCalculouTempoGrafSuperior := false;
  end;


  // Cálculo da média no tempo gráfico original
  if (Mod(iHorarioEmMinutos, cTempoGraficoOriginal) = 0) and Not bCalculouTempoGrafSuperior then
  begin
    bCalculouTempoGrafSuperior := true;
    if (iQtdePeriodosCalculados < cQtdePeriodosMedia) then 
    begin
      iQtdePeriodosCalculados := iQtdePeriodosCalculados + 1;
      fInicializacaoMedia := fInicializacaoMedia + Close[1];
    end
    else
      if (iQtdePeriodosCalculados = cQtdePeriodosMedia) then
      begin
        fMediaTempoGraficoOriginal := fInicializacaoMedia/iQtdePeriodosCalculados;
        iQtdePeriodosCalculados := iQtdePeriodosCalculados + 1;
      end
      else
        fMediaTempoGraficoOriginal := (fMediaTempoGraficoOriginal*cQtdePeriodosMedia
                                     - Close[1+cQtdePeriodosMedia*Floor(cTempoGraficoOriginal/iTempoGraficoAtual)]
                                     + Close[1])/cQtdePeriodosMedia;
  end;


  //Plot da série para inspeção
  PlotN(2,fMediaTempoGraficoOriginal);
  SetPlotColor(2, clRed);
  SetPlotWidth(2,2);
  SetPlotStyle(2, psSolid);

end
				
			

Como utilizar dados de preço de outros ativos

O código abaixo apenas exemplifica como obter os dados OHLCV de outras ativos em uma estratégia, o que pode ser feito via parâmetro ou constante. Caso o ativo desejado seja uma ação, deve-se atentar para modificar o feedBMF para feedBovespa.

				
					const
  cAtivo1 = Asset("INDFUT",feedBMF);
input
  pAtivo2("WINFUT",feedBMF);
  pQtdePeriodos(50);
var
  fMediaAtivo1, fMediaAtivo2: float;
begin
  fMediaAtivo1 := Media(pQtdePeriodos,cAtivo1.Close);
  fMediaAtivo2 := Media(Floor(pQtdePeriodos*1/3),pAtivo2.Close);
  plot(fMediaAtivo1);
  plot2(fMediaAtivo2);

end;
				
			

EXPLORANDO O TIMES & SALES da Trader Evolution [Monitore as negociações do mercado]

Reproduzir vídeo

Neste vídeo da séria “Conhecendo a Trader Evolution” vamos explorar a ferramenta de TIMES & SALES. Esta ferramenta nos permite visualizar as negociações realizadas entre os participantes de mercado. Podemos realizar filtros de quantidade de lotes por negócio de forma a enxergar movimentações maiores e que se observadas na atuação de vários participantes pode sinalizar um interesse predominante do mercado em uma direção.

Não se esqueça de indicar a Comunidade NeoTraderBot como parceiro na Plataforma TraderEvolution. Vá no menu superior em “Mais” – “Extensões” – “Indique parceiro” e digite o código “NEOTRADERBOT”.

Assim, você reforça sua participação na Comunidade e nos ajuda a pleitear novas funcionalidades e melhorias na plataforma visando o benefício de todos os membros em suas automatizações e desenvolvimento de estratégias.

Alertas e Serviços de Compartilhamento (Envio de E-mail)

Reproduzir vídeo

Neste video iremos demonstrar DIVERSAS FORMAS de CRIAR ALERTAS na NinjaTrader, sejam pop-ups, avisos sonoros, envio de e-mail, publicação de post no Twitter ou envio de ordens.

Começaremos apresentando formas de gerar alertas no Market Analyzer. O que permite criar alertas para ativos individuais ou para toda uma carteira de ativos.

Com os alertas também é possível criar screenings sofisticados com a utilização de indicadores, principalmente customizados.

Em seguida apresentarei os recursos avançados de criação de alertas sobre figuras e elementos de estudos inseridos em gráficos. Iremos demonstrar também como enviar e-mails quando um alerta for acionado.

Por fim, será apresentada a tela de Log de Alertas que reúne todos os alertas sinalizados pela plataforma com informações de ativo, origem, criticidade, data e hora.

A utilização de alertas na plataforma NinjaTrader é bastante abrangente e integrado com serviços de e-mails e redes sociais, o que permitirá ao trader criar mecanismos sofisticados para monitoramento e sinalização de situações de mercado em múltiplos ativos e com indicadores complexos.

Este é um conteúdo informativo sobre NinjaTrader para que os membros da comunidade tenham informações do que é possível realizar em outros ambientes.

Reforço que não estamos realizando nenhuma recomendação para mudança de Plataforma e que a decisão de migrar parte ou todo o processo de desenvolvimento e execução das estratégias automatizadas é muito pessoal e cabe apenas ao trader decidir sobre tal assunto.

SuperDOM na Trader Evolution [Conheça o mercado em profundidade]

Reproduzir vídeo

Neste vídeo da séria “Conhecendo a Trader Evolution” vamos explorar a ferramenta de SuperDOM. A sigla DOM vem do inglês “Depth of Market”. É uma expressão para os dados de book de ofertas que são os registros de ordens limitadas de compra e venda (o interesse aberto dos participantes do mercado). Pelo SuperDOM é possível realizar operações de abertura e fechamento de posição, bem como administrar uma operação aberta.

Não se esqueça de indicar a Comunidade NeoTraderBot como parceiro na Plataforma TraderEvolution. Vá no menu superior em “Mais” – “Extensões” – “Indique parceiro” e digite o código “NEOTRADERBOT”.

Assim, você reforça sua participação na Comunidade e nos ajuda a pleitear novas funcionalidades e melhorias na plataforma visando o benefício de todos os membros em suas automatizações e desenvolvimento de estratégias.

Como importar dados históricos para NT8 (OHLCV 1 min e Ticks)

Reproduzir vídeo

Neste video irei demonstrar como IMPORTAR DADOS HISTÓRICOS OHLCV (1 MIN) e de TICKS para plataforma NINJATRADER.

No decorrer do vídeo farei a conversão dos dados exportados a partir da MetaTrader para o formato aceito para importação na plataforma NinjaTrader. Você perceberá que é possível fazer os ajustes necessários tanto com excel e um bloco de notas ou automatizando a conversão por um código em Python, caso a quantidade de arquivos a ser importada seja muito grande.

O benefício de ter mais dados históricos é poder realizar o BACKTESTING de sua estratégia ou robô em uma janela histórica mais longa, permitindo maior significância estatística nos resultados encontrados.

Reforço que não estamos realizando nenhuma recomendação para mudança de Plataforma e que a decisão de migrar parte ou todo o processo de desenvolvimento e execução das estratégias automatizadas é muito pessoal e cabe apenas ao trader decidir sobre tal assunto.

Boleta e Matrix na Trader Evolution [+1 ferramenta para analisar o nível II do mercado]

Reproduzir vídeo

Neste vídeo da séria “Conhecendo a Trader Evolution” vamos explorar a BOLETA e a ferramenta MATRIX. Pela ferramenta MATRIX, o trader possui mais uma opção para visualizar os dados de Nível II do mercado.

Não se esqueça de indicar a Comunidade NeoTraderBot como parceiro na Plataforma TraderEvolution. Vá no menu superior em “Mais” – “Extensões” – “Indique parceiro” e digite o código “NEOTRADERBOT”.

Assim, você reforça sua participação na Comunidade e nos ajuda a pleitear novas funcionalidades e melhorias na plataforma visando o benefício de todos os membros em suas automatizações e desenvolvimento de estratégias.

Rodando e gravando dados de Replay de Mercado

Reproduzir vídeo

Neste video irei demonstrar como HABILITAR A GRAVAÇÃO de DADOS DE MERCADO em seu computador utilizando a plataforma NINJATRADER.

Com a gravação de dados habilitada, você poderá criar uma base de dados de replay de mercado contendo informação de Book de Oferta.

Outra opção disponível na plataforma é solicitar o download de MARKET REPLAY do seu provedor de MARKET DATA.

Por fim, também demonstrarei como executar um REPLAY DE MERCADO com os dados históricos de tick na sua base da NinjaTrader. Estes dados podem inclusive terem sido importados para dentro da plataforma.

Ferramenta SCALPER da Trader Evolution

Reproduzir vídeo

Neste vídeo da séria “Conhecendo a Trader Evolution” vamos explorar a ferramenta de SCALPER.

Não se esqueça de indicar a Comunidade NeoTraderBot como parceiro na Plataforma TraderEvolution. Vá no menu superior em “Mais” – “Extensões” – “Indique parceiro” e digite o código “NEOTRADERBOT”.

Assim, você reforça sua participação na Comunidade e nos ajuda a pleitear novas funcionalidades e melhorias na plataforma visando o benefício de todos os membros em suas automatizações e desenvolvimento de estratégias.

Como criar robô/estratégia do ZERO com o Strategy Builder

Reproduzir vídeo

Neste vídeo irei demonstrar como CRIAR um ROBÔ ou ESTRATÉGIA do ZERO, e sem programar nenhuma linha de código, com a ferramenta STRATEGY BUILDER da plataforma NINJATRADER (em português: Construtor de Estratégia).

Você perceberá que mesmo sendo uma ferramenta gráfica NO CODE, o usuário tem muita flexibilidade para configurar e definir a estratégia a ser criada.

Há muita liberdade para configurar indicadores, funções prontas pra verificar cruzamento de séries no instante atual ou passado recente, lucro/prejuízo realizado pela estratégia ou em aberto, configuração de cálculo da estratégia (fechamento de barra, tick ou mudança de preço) e etc.

Além disso, é possível utilizar séries de dados de outros ativos ou até o mesmo ativo em outra escala de tempo ou tipo de série.

A estratégia pode disparar a criação todos os objetos de estudo dentro dos gráficos, rotear ordens, enviar e-mails, criar alertas visuais sonoros e muito mais.

Ferramenta MESTRE DE OPÇÕES da Trader Evolution

Reproduzir vídeo

Neste vídeo da séria “Conhecendo a Trader Evolution” vamos explorar a ferramenta MESTRE DE OPÇÕES.

Não se esqueça de indicar a Comunidade NeoTraderBot como parceiro na Plataforma TraderEvolution. Vá no menu superior em “Mais” – “Extensões” – “Indique parceiro” e digite o código “NEOTRADERBOT”.

Assim, você reforça sua participação na Comunidade e nos ajuda a pleitear novas funcionalidades e melhorias na plataforma visando o benefício de todos os membros em suas automatizações e desenvolvimento de estratégias.

Como rodar backtesting na NinjaTrader

Reproduzir vídeo

Neste video irei demonstrar como rodar BACKTESTING de ESTRATÉGIAS e ROBÔS na plataforma NINJATRADER.

Você verá a riqueza de funcionalidades, métricas e personalização do ambiente de backtesting da NinjaTrader. O que demonstra o cuidado do desenolvimento da plataforma para usuários que desejam automatizar seus setups operacionais.

Por fim, demonstrarei a vantagem de poder carregar dados históricos para plataforma e poder realizar backtesting em uma janela adequada de dados.

Como configurar ativos sintetizados na Trader Evolution

Reproduzir vídeo

Neste vídeo da séria “Conhecendo a Trader Evolution” vamos explorar a possibilidade de criação de um ativo personalizado: um ativo sintetizado. Com este ativo é possível operar vários papeis ou contratos ao mesmo tempo, operacionar estratégias de LONG & SHORT, operar arbitragem, entre outras possibilidades.

Não se esqueça de indicar a Comunidade NeoTraderBot como parceiro na Plataforma TraderEvolution. Vá no menu superior em “Mais” – “Extensões” – “Indique parceiro” e digite o código “NEOTRADERBOT”.

Assim, você reforça sua participação na Comunidade e nos ajuda a pleitear novas funcionalidades e melhorias na plataforma visando o benefício de todos os membros em suas automatizações e desenvolvimento de estratégias.

Como utilizar o IBOV ONLINE [Cálculo do IBOV em tempo real native na Trader Evolution]

Reproduzir vídeo

Neste vídeo da séria “Conhecendo a Trader Evolution” vamos explorar o cálculo nativo de IBOV online, o qual pode ser incluído em um gráfico para comparação visual do valor calculado como justo para os futuros e o valor de futuros atualmente negociado.

Não se esqueça de indicar a Comunidade NeoTraderBot como parceiro na Plataforma TraderEvolution. Vá no menu superior em “Mais” – “Extensões” – “Indique parceiro” e digite o código “NEOTRADERBOT”.

Assim, você reforça sua participação na Comunidade e nos ajuda a pleitear novas funcionalidades e melhorias na plataforma visando o benefício de todos os membros em suas automatizações e desenvolvimento de estratégias.

Ferramenta Saldo Agressor da Trader Evolution

Reproduzir vídeo

Neste vídeo da séria “Conhecendo a Trader Evolution” vamos explorar a ferramenta de SALDO AGRESSOR para verificação de agressão dos participantes do mercado em determinado ativo.

Não se esqueça de indicar a Comunidade NeoTraderBot como parceiro na Plataforma TraderEvolution. Vá no menu superior em “Mais” – “Extensões” – “Indique parceiro” e digite o código “NEOTRADERBOT”.

Assim, você reforça sua participação na Comunidade e nos ajuda a pleitear novas funcionalidades e melhorias na plataforma visando o benefício de todos os membros em suas automatizações e desenvolvimento de estratégias.

Notícias e RSS na Trader Evolution [MANTENHA-SE INFORMADO DENTRO DA PLATAFORMA]

Reproduzir vídeo

Neste vídeo da séria “Conhecendo a Trader Evolution” vamos explorar a configuração de Notícias e RSS dentro da plataforma.

Não se esqueça de indicar a Comunidade NeoTraderBot como parceiro na Plataforma TraderEvolution. Vá no menu superior em “Mais” – “Extensões” – “Indique parceiro” e digite o código “NEOTRADERBOT”.

Assim, você reforça sua participação na Comunidade e nos ajuda a pleitear novas funcionalidades e melhorias na plataforma visando o benefício de todos os membros em suas automatizações e desenvolvimento de estratégias.

Utilização de Indicadores da Plataforma

Introdução

Esta seção visa apresentar trechos de códigos com exemplos de utilização dos indicadores disponibilizados na plataforma.

Você pode acessar os Snippets diretamente pelo menu lateral direito, ou fazendo CRL+F (CTRL+L) para localizar algum texto específico na página, uma vez que o conteúdo tende a crescer ao longo do tempo, dificultando a navegação pelo menu.

Caso tenham sugestões de código para acrescentar à lista, gentileza deixar o código nos comentários com o link para seu perfil em rede social (para devido crédito de autoria).

Snippets

Sugira um primeiro Snippet nos comentários!!!

				
					...
				
			

Ordens e Administração de Trade

Introdução

Esta seção visa apresentar trechos de códigos com exemplos de envio de ordens e administração de trade utilizando técnicas de stoploss (fixo, móvel, breakeven) e take profit.

Você pode acessar os Snippets diretamente pelo menu lateral direito, ou fazendo CRL+F (CTRL+L) para localizar algum texto específico na página, uma vez que o conteúdo tende a crescer ao longo do tempo, dificultando a navegação pelo menu.

Caso tenham sugestões de código para acrescentar à lista, gentileza deixar o código nos comentários com o link para seu perfil em rede social (para devido crédito de autoria).

Snippets

Como limitar a quantidade de trades por dia

Reproduzir vídeo

O código abaixo apresenta a funcionalidade em código fonte para limitar a quantidade de trades realizados pela sua estratégia/ robô (constante cQtdeMaxOperacoesNoDia).

Apesar do Módulo de Automação possui um limite de perda e ganho diário, ele não possui esta funcionalidade. Idealmente, a Nelogica deveria disponbilizar funções para verificação do resultado bruto alcançado até o momento para permitir outras forma de gestão de risco em código fonte.

				
					const
  // Mude aqui a qtde maxima de trades por dia 
  cQtdeMaxOperacoesNoDia = 5;

var 
  iQtdeOperacoesNoDia: integer;
  iDataAtual: integer;
  bJaContouOperacao: boolean;
  fMedia: float;

begin
  // Inicialização do contador de ordens do dia  
  if Date <> iDataAtual then
  begin
    iDataAtual := Date;
    iQtdeOperacoesNoDia := 0;
    bJaContouOperacao := false;
  end;
  
  // Setup de cruzamento de Media movel só para gerar operações
  fMedia := Media(3,Close);

  // Realiza abertura de posições apenas se número maximo de operação
  // não tiver sido atingido
  if iQtdeOperacoesNoDia < cQtdeMaxOperacoesNoDia then
  begin
    // COMPRA se fechamento cruzar media para cima e
    // VENDE se fechamento cruzar media pra baixo
    if (Close > fMedia) and (Close[1] <= fMedia[1]) and Not HasPosition then BuyAtMarket;       
    if (Close < fMedia) and (Close[1] >= fMedia[1]) and Not HasPosition then SellShortAtMarket;
  end;
  
  // Contabiliza a abertura da posição como mais uma operação no dia   
  if (isBought or isSold) and Not bJaContouOperacao then
  begin
    iQtdeOperacoesNoDia := iQtdeOperacoesNoDia + 1;
    bJaContouOperacao := true;  
  end;

  // Posiciona ordens para gestão do trade
  if isBought then
  begin
    SellShortStop(buyPrice - 5*MinPriceIncrement);
    SellShortLimit(buyPrice + 15*MinPriceIncrement);
  end;

  // Posiciona ordens para gestão do trade
  if isSold then
  begin
    BuyStop(sellPrice + 5*MinPriceIncrement);
    BuyLimit(sellPrice - 15*MinPriceIncrement);
  end;
  
  // Encerra posicao no mesmo dia
  if (Time >= 1645) and hasPosition then ClosePosition;

  // Se posição for encerrada ativa novamente o contador
  if Not IsBought and Not isSold and bJaContouOperacao then bJaContouOperacao := false;  

  // Apenas para inspeção gráfica do sinal
  Plot(fMedia);
  
end
				
			

Como limitar trades por objetivo de ganho ou limite de perda

Reproduzir vídeo

O código abaixo apresenta a funcionalidade em código fonte para limitar a realização de trades baseado no resultado do dia.

Caso o resultado das operações da estratégia atinja o objetivo de ganho ou o limite de perda, fornecidos em valores absolutos e unidade financeira pelos parâmetros pLimitePerdaDiaria e pObjetivoGanhoDiario, a estratégia não realiza mais operações e encerra posições abertas.

O parâmetro pPlotarResultado pode receber os valores “FECHADO”, “ABERTO” e “TOTAL”, para se referir ao resultado de trades fechados, resultado do trade em aberto e resultado total do dia (FECHADO + ABERTO), respectivamente.

				
					input
  pPlotarResultado("ABERTO");
  pLimitePerdaDiaria(200.00);
  pObjetivoGanhoDiario(600.00);

var
  fResultado: float;
  fResultadoDiario: float;
  iDataTeste: integer;
  iHora: integer;
begin
  //-----------------------------------------------------------
  //Plots podem ser excluídos...servem apenas para demonstração

  // Resultado fechado do dia
  If pPlotarResultado = "FECHADO" then
  begin
    fResultado := DailyResult(false);
    plot(fResultado);
    SetPlotStyle(1,psSolid);
    SetPlotColor(1,clWhite);
  end;

  // Resultado até o momento no dia (fechado + aberto)
  If pPlotarResultado = "TOTAL" then
  begin
    fResultado := DailyResult(true);
    plot2(fResultado);
    SetPlotStyle(2,psDash);
    SetPlotColor(2,clRed);
  end;

  // Resultado do trade aberto
  If pPlotarResultado = "ABERTO" then
  begin
    fResultado := DailyResult(true) - DailyResult(false); 
    if fResultado <> 0 then
      plot3(fResultado);
    SetPlotStyle(3,psDash);
    if fResultado >= 0  then SetPlotColor(3,clGreen)
    else SetPlotColor(3,clRed);
    SetPlotType(3, igHistogram);
  end;
  //-----------------------------------------------------------


  // Estratégias apenas opera se resultado do dia não 
  // tiver atingido objetivo de ganho ou limite de perda
  iDataTeste := ELDate(2023,2,10);
  fResultadoDiario := DailyResult(true);
  
  if (fResultadoDiario > -1*pLimitePerdaDiaria)
  and (fResultadoDiario < pObjetivoGanhoDiario) then
  begin
    // SIMULAÇÃO DE ORDENS PARA FINS DE EXEMPLO
    for iHora := 0 to 8 do
    begin
      if (Date = iDataTeste) and (Time = (0900 + iHora*100)) then
        if random(2) = 0 then BuyAtMarket else SellShortAtMarket;
  
      if (Date = iDataTeste) and (Time = (0930 + iHora*100)) then
        ClosePosition;
    end;

  end
  //Se resultado excedeu objetivo de ganho ou limite de perda
  //e houver posição aberta, então encerra a posição.
  else if hasPosition then ClosePosition;
                
            
end;
				
			

Limite de horário para encerramento de posição

Reproduzir vídeo

O código abaixo apresenta a funcionalidade em código fonte para encerramento de posição a partir de um determinado horário. É um exemplo útil para quem opera daytrade e não deseja/não pode correr o risco de carregar operação para o dia seguinte.

				
					var
  bBarraDesejada                 : boolean;
  pDataDesejada,pHorarioDesejado : integer;
  //Util apenas para Backtesting em Gráfico de Renko  
  pMargemMinutos: integer;  
begin
  pHorarioDesejado := 1645;
  pMargemMinutos := 15;
  //Para Gráficos de Candle/Renko executados em tempo real
  //if Time > pHorarioDesejado then

  //Para Gráficos de Renko, em backtesting, utiliza-se uma margem de tempo em torno do horário desejado
  if  (Time >= CalcTIme(pHorarioDesejado, -pMargemMinutos)) then
    begin
      bBarraDesejada := true;
      //Encerra posição caso esteja comprado/vendido
      if isBought or isSold then ClosePosition;
    end
  else
    bBarraDesejada := false;
end;
				
			

Stoploss simples (fixo)

Reproduzir vídeo

O código abaixo apresenta um exemplo de stoploss fixo e take profit (alvo de lucro da operação), para uma relação de risco/ganho de 3:1 em função de quantidade de ticks, aplicado a uma estratégia de posicionamento. O código tem um limite de horário para abertura e fechamento de posição, o qual pode ser alterado pelos parâmetros.

OBS 1: A versão é compatível com o Editor de Estratégias e Módulo de Automação de Estratégias. Devido a um bug do Profit, é necessário ter um comando ClosePosition, pois do contrário a ferramenta informa equivocadamente que não existem ordens para encerrar posição.

				
					const
 //Relação risco/ganho de 3:1
 cStopEmTicks = 10;
 cAlvoEmTicks = 30;
 cStopOffsetEmTicks = 50;

input
  bGestaoDeRiscoPelaEstrategia(true);
  iHorarioInicioAberturaPosicao(0905);
  iHorarioFimAberturaPosicao(1630);
  iHorarioEncerramentoDaytrade(1645);

var
  iCaraCoroa: integer;
  bSinalCompra, bSinalVenda, bPosicionado: boolean;
  fPrecoStop, fPrecoAlvo, fPrecoStopOffset: float;
  bConfigurouRisco: boolean;

begin

  bSinalCompra := false;
  bSinalVenda := false;
  bPosicionado := hasPosition;

  //ESTRATÉGIA CARA OU COROA!
  //Gera um numero aleatorio de 0 a 9. Se for menor igual a 4, gera
  //sinal de compra, se for maior que 4 geral sinal de venda
  if Not bPosicionado
  and (Time >= iHorarioInicioAberturaPosicao)
  and (Time <= iHorarioFimAberturaPosicao)
  then
  begin
    //Número aleatório foi substituido por minuto par ou impar para permitir depurar
    //melhor o robô quando a estratégia é inserida multiplas vezes: como indicador  e como execução
    //iCaraCoroa := Random(10);
    iCaraCoroa := mod(Time,2);
    if iCaraCoroa = 0 then bSinalCompra := true
    else bSinalVenda := true;
  end;


  //Gera ordem de compra a mercado quando há um Sinal de COMPRA
  //e define ordem stoploss e take profit
  if bSinalCompra then BuyAtMarket;

  //Gera ordem de venda a mercado quando há um Sinal de VENDA
  //e define ordem stoploss e take profit
  if bSinalVenda then SellShortAtMarket;

  if bGestaoDeRiscoPelaEstrategia then
  begin
    //POSIÇÃO COMPRADA
    //Código responsável pela manutenção das ordens de stoploss e take profit
    if isBought then
    begin
      if not bConfigurouRisco then
      begin
        fPrecoStop := BuyPrice - cStopEmTicks*MinPriceIncrement;
        fPrecoAlvo := BuyPrice + cAlvoEmTicks*MinPriceIncrement;
        fPrecoStopOffset := fPrecoStop - cStopOffsetEmTicks*MinPriceIncrement;
        bConfigurouRisco := true;
      end;

      SellToCoverStop(fPrecoStop,fPrecoStopOffset);
       SellToCoverLimit(fPrecoAlvo);
    end;

    //POSIÇÃO VENDIDA
    //Código responsável pela manutenção das ordens de stoploss e take profit
    if isSold then
    begin
      if not bConfigurouRisco then
      begin
        fPrecoStop := SellPrice + cStopEmTicks*MinPriceIncrement;
        fPrecoAlvo := SellPrice - cAlvoEmTicks*MinPriceIncrement;
        fPrecoStopOffset := fPrecoStop + cStopOffsetEmTicks*MinPriceIncrement;
        bConfigurouRisco := true;
      end;

      BuyToCoverStop(fPrecoStop,fPrecoStopOffset);
      BuyToCoverLimit(fPrecoAlvo);

    end;

    //Encerra posicao
    if (Time >= iHorarioEncerramentoDaytrade)
    and HasPosition
    then ClosePosition;

    if Not HasPosition then bConfigurouRisco := false;

  end;

  // Plot de Stop e Alvo para inspeção visual do código
  bPosicionado := hasPosition;
  if bPosicionado or bPosicionado[1] or bPosicionado[2] then
  begin
    PlotN(1,fPrecoStop);
    PlotN(2,fPrecoStopOffset);
    PlotN(3,fPrecoAlvo);
    SetPlotColor(1,clRed);
    SetPlotColor(2,clRed);
    SetPlotColor(3,clGreen);
    SetPlotStyle(1,psDash);
    SetPlotStyle(2,psDash);
    SetPlotStyle(3,psDash);
    SetPlotWidth(1,2);
    SetPlotWidth(2,2);
    SetPlotWidth(3,2);

end;


end;
				
			

Stoploss com Breakeven

Reproduzir vídeo

O código abaixo apresenta um exemplo de Stoploss fixo + Breakeven (alvo de lucro da operação), para uma relação de risco/ganho de 3:1 em função de quantidade de ticks, aplicado a uma estratégia de posicionamento aleatório com uma operação por dia.

OBS 1: A versão é compatível com o Editor de Estratégias e Módulo de Automação de Estratégias. Devido a um bug do Profit, é necessário ter um comando ClosePosition, pois do contrário a ferramenta informa equivocadamente que não existem ordens para encerrar posição.

				
					const
 //Relação risco/ganho de 3:1
 cStopEmTicks = 30;
 cStopOffsetEmTicks = 20;
 cBreakevenEmTicks = 30;
 cAlvoEmTIcks = 90;

input
  bGestaoDeRiscoPelaEstrategia(true);
  iHorarioInicioAberturaPosicao(0905);
  iHorarioFimAberturaPosicao(1630);
  iHorarioEncerramentoDaytrade(1645);

var
  iCaraCoroa: integer;
  bSinalCompra, bSinalVenda, bPosicionado: boolean;
  fPrecoStop, fPrecoAlvo, fPrecoStopOffset: float;
  bConfigurouRiscoInicial: boolean;
begin

  bSinalCompra := false;
  bSinalVenda := false;
  bPosicionado := hasPosition;

  //ESTRATÉGIA CARA OU COROA!
  //Gera um numero aleatorio de 0 a 9. Se for menor igual a 4, gera
  //sinal de compra, se for maior que 4 geral sinal de venda
  if Not bPosicionado
  and (Time >= iHorarioInicioAberturaPosicao)
  and (Time <= iHorarioFimAberturaPosicao)
  then
  begin
    //Número aleatório foi substituido por minuto par ou impar para permitir depurar
    //melhor o robô quando a estratégia é inserida multiplas vezes: como indicador  e como execução
    //iCaraCoroa := Random(10);
    iCaraCoroa := mod(Time,2);
    if iCaraCoroa = 0 then bSinalCompra := true
    else bSinalVenda := true;
  end;

  //Gera ordem de compra a mercado quando há um Sinal de COMPRA
  //e define ordem stoploss e take profit
  if bSinalCompra then BuyAtMarket;

  //Gera ordem de venda a mercado quando há um Sinal de VENDA
  //e define ordem stoploss e take profit
  if bSinalVenda then SellShortAtMarket;

  if bGestaoDeRiscoPelaEstrategia then
  begin
    //Código responsável pela manutenção das ordens de stoploss e take profit
    if isBought then
    begin
      if Not bConfigurouRiscoInicial then
      begin
        fPrecoStop := BuyPrice - cStopEmTicks*MinPriceIncrement;
        fPrecoAlvo := BuyPrice + cAlvoEmTicks*MinPriceIncrement;
        fPrecoStopOffset := fPrecoStop - cStopOffsetEmTicks*MinPriceIncrement;
        bConfigurouRiscoInicial := true;
      end;

      if Close >= (BuyPrice + cBreakevenEmTicks*MinPriceIncrement) then
      begin
        fPrecoStop := BuyPrice;
        fPrecoStopOffset := fPrecoStop-cStopOffsetEmTicks*MinPriceIncrement;
      end;

      SellToCoverStop(fPrecoStop,fPrecoStopOffset);
      SellToCoverLimit(fPrecoAlvo);
    end;

    //Código responsável pela manutenção das ordens de stoploss e take profit
    if isSold then
    begin
      if Not bConfigurouRiscoInicial then
      begin
        fPrecoStop := SellPrice + cStopEmTicks*MinPriceIncrement;
        fPrecoAlvo := SellPrice - cAlvoEmTicks*MinPriceIncrement;
        fPrecoStopOffset := fPrecoStop + cStopOffsetEmTicks*MinPriceIncrement;
        bConfigurouRiscoInicial := true;
      end;

      if Close <= (SellPrice - cBreakevenEmTicks*MinPriceIncrement) then
      begin
        fPrecoStop := SellPrice;
        fPrecoStopOffset := fPrecoStop+cStopOffsetEmTicks*MinPriceIncrement;
      end;

      BuyToCoverStop(fPrecoStop,fPrecoStopOffset);
      BuyToCoverLimit(fPrecoAlvo);

    end;


    //Encerra posicao
    if (Time >= iHorarioEncerramentoDaytrade)
    and HasPosition
    then ClosePosition;

    if Not hasPosition and bConfigurouRiscoInicial then bConfigurouRiscoInicial := false;


  end;

  bPosicionado := hasPosition;

  // Plot de Stop e Alvo para inspeção visual do código
  if bPosicionado or bPosicionado[1] or bPosicionado[2] then
  begin
    PlotN(1,fPrecoStop);
    PlotN(2,fPrecoStopOffset);
    PlotN(3,fPrecoAlvo);
    SetPlotColor(1,clRed);
    SetPlotColor(2,clRed);
    SetPlotColor(3,clGreen);
    SetPlotStyle(1,psDash);
    SetPlotStyle(2,psDash);
    SetPlotStyle(3,psDash);
    SetPlotWidth(1,2);
    SetPlotWidth(2,2);
    SetPlotWidth(3,2);
  end;

end;
				
			

Stoploss móvel (Versão contínua)

Reproduzir vídeo

O código abaixo apresenta um exemplo de stoploss móvel (Versão contínua), ou seja, valor de stop é atualizado a cada fechamento de candle. Só não é atualizado a cada tick por uma limitação do Profit.

O stop será alterado para cOffsetStopEmTicks em relação ao preço de fechamento do candle, não podendo o valor do stop retroceder. O código pode ser alterado para calcular o stop móvel em relação ao valor máximo do candle.

O exemplo também conta com ordem take profit (alvo de lucro da operação) para uma relação de risco/ganho de 3:1 em função de quantidade de ticks, aplicado a uma estratégia de posicionamento aleatório com uma operação por dia.

OBS 1: A versão é compatível com o Editor de Estratégias e Módulo de Automação de Estratégias. Devido a um bug do Profit, é necessário ter um comando ClosePosition, pois do contrário a ferramenta informa equivocadamente que não existem ordens para encerrar posição.

				
					const
 //Relação risco/ganho de 3:1
 cStopEmTicks = 15;
 cAlvoEmTicks = 45;
 cTraillingStopTrigger = 20;
 cTrailingStopOffset = 10;
 cStopOffsetEmTicks = 50;

input
  bGestaoDeRiscoPelaEstrategia(true);
  iHorarioInicioAberturaPosicao(0905);
  iHorarioFimAberturaPosicao(1630);
  iHorarioEncerramentoDaytrade(1645);

var
  iCaraCoroa: integer;
  bSinalCompra, bSinalVenda, bPosicionado: boolean;
  fPrecoStop, fPrecoAlvo, fPrecoStopOffset: float;
  bConfigurouRiscoInicial: boolean;
  bTrailingStopAtivado: boolean;
begin

  bSinalCompra := false;
  bSinalVenda := false;
  bPosicionado := hasPosition;

  //ESTRATÉGIA CARA OU COROA!
  //Gera um numero aleatorio de 0 a 9. Se for menor igual a 4, gera
  //sinal de compra, se for maior que 4 geral sinal de venda
  if Not bPosicionado
  and (Time >= iHorarioInicioAberturaPosicao)
  and (Time <= iHorarioFimAberturaPosicao)
  then
  begin
    //Número aleatório foi substituido por minuto par ou impar para permitir depurar
    //melhor o robô quando a estratégia é inserida multiplas vezes: como indicador  e como execução
    //iCaraCoroa := Random(10);
    iCaraCoroa := mod(Time,2);
    if iCaraCoroa = 0 then bSinalCompra := true
    else bSinalVenda := true;
  end;


  //Gera ordem de compra a mercado quando há um Sinal de COMPRA
  //e define ordem stoploss e take profit
  if bSinalCompra then BuyAtMarket;

  //Gera ordem de venda a mercado quando há um Sinal de VENDA
  //e define ordem stoploss e take profit
  if bSinalVenda then SellShortAtMarket;

  if bGestaoDeRiscoPelaEstrategia then
  begin

    //POSIÇÃO COMPRADA
    //Código responsável pela manutenção das ordens de stoploss e take profit
    if isBought then
    begin
      if Not bConfigurouRiscoInicial then
      begin
        fPrecoStop := BuyPrice - cStopEmTicks*MinPriceIncrement;
        fPrecoAlvo := BuyPrice + cAlvoEmTicks*MinPriceIncrement;
        fPrecoStopOffset := fPrecoStop - cStopOffsetEmTicks*MinPriceIncrement;
        bConfigurouRiscoInicial := true;
      end;

      if ((Close >= (BuyPrice + cTraillingStopTrigger*MinPriceIncrement))
          or (cTraillingStopTrigger = 0))
      and (not bTrailingStopAtivado) then bTrailingStopAtivado := true;

      if ((Close - cTrailingStopOffset*MinPriceIncrement) >= fPrecoStop)
      and (bTrailingStopAtivado) then
      begin
        fPrecoStop := Close - cTrailingStopOffset*MinPriceIncrement;
        fPrecoStopOffset := fPrecoStop - cStopOffsetEmTicks*MinPriceIncrement;
      end;

      SellToCoverStop(fPrecoStop,fPrecoStopOffset);
      SellToCoverLimit(fPrecoAlvo);

    end;


    //POSIÇÃO VENDIDA
    //Código responsável pela manutenção das ordens de stoploss e take profit
    if isSold then
    begin
      if Not bConfigurouRiscoInicial then
      begin
        fPrecoStop := SellPrice + cStopEmTicks*MinPriceIncrement;
        fPrecoAlvo := SellPrice - cAlvoEmTicks*MinPriceIncrement;
        fPrecoStopOffset := fPrecoStop + cStopOffsetEmTicks*MinPriceIncrement;
        bConfigurouRiscoInicial := true;
      end;

      if ((Close <= (SellPrice - cTraillingStopTrigger*MinPriceIncrement))
          or (cTraillingStopTrigger = 0))
      and (not bTrailingStopAtivado) then bTrailingStopAtivado := true;

      if ((Close + cTrailingStopOffset*MinPriceIncrement) <= fPrecoStop)
      and (bTrailingStopAtivado) then
      begin
        fPrecoStop := Close + cTrailingStopOffset*MinPriceIncrement;
        fPrecoStopOffset := fPrecoStop + cStopOffsetEmTicks*MinPriceIncrement;
      end;

      BuyToCoverStop(fPrecoStop,fPrecoStopOffset);
      BuyToCoverLimit(fPrecoAlvo);

    end;

    //Encerra posicao comprada no horario limite
    if (Time >= iHorarioEncerramentoDaytrade)
    and HasPosition
    then ClosePosition;

    if Not hasPosition and bConfigurouRiscoInicial then
    begin
      bConfigurouRiscoInicial := false;
      bTrailingStopAtivado := false;
    end;


  end;

  // Plot de Stop e Alvo para inspeção visual do código
  bPosicionado := hasPosition;
  if bPosicionado or bPosicionado[1] or bPosicionado[2] then
  begin
    PlotN(1,fPrecoStop);
    PlotN(2,fPrecoStopOffset);
    PlotN(3,fPrecoAlvo);
    SetPlotColor(1,clRed);
    SetPlotColor(2,clRed);
    SetPlotColor(3,clGreen);
    SetPlotStyle(1,psDash);
    SetPlotStyle(2,psDash);
    SetPlotStyle(3,psDash);
    SetPlotWidth(1,2);
    SetPlotWidth(2,2);
    SetPlotWidth(3,2);
  end;

end;
				
			

Stoploss móvel (Versão baseada em passos)

Reproduzir vídeo

O código abaixo apresenta um exemplo de stoploss móvel (Versão discreta, baseada em passos), ou seja, valor de stop é atualizado cada vez que o preço de fechamento do candle supera o passo definido em cTrailingStepEmTicks. Só não é atualizado a cada tick por uma limitação do Profit.

O stop será alterado para cOffsetStop em relação ao preço do último passo alcançado, não podendo o valor do stop retroceder. O código pode ser alterado para calcular o stop móvel em relação ao valor máximo do candle.

O exemplo também conta com ordem take profit (alvo de lucro da operação) em posições compradas, para uma relação de risco/ganho de 3:1. O raciocínio para posições vendidas é análogo.

OBS 1: A versão é compatível com o Editor de Estratégias e Módulo de Automação de Estratégias. Devido a um bug do Profit, é necessário ter um comando ClosePosition, pois do contrário a ferramenta informa equivocadamente que não existem ordens para encerrar posição.

				
					const
 //Relação risco/ganho de 3:1
 cStopEmTicks = 15;
 cAlvoEmTicks = 45;
 cTraillingStopTrigger = 0;
 cTrailingStopOffset = 8;
 cTrailingStepEmTicks = 10;
 cStopOffsetEmTicks = 10;

input
  bGestaoDeRiscoPelaEstrategia(true);
  iHorarioInicioAberturaPosicao(1000);
  iHorarioFimAberturaPosicao(1630);
  iHorarioEncerramentoDaytrade(1645);

var
  iCaraCoroa: integer;
  bSinalCompra, bSinalVenda, bPosicionado: boolean;
  fPrecoStop, fPrecoAlvo, fPrecoStopOffset: float;
  fFloorTraillingStop : float;
  bConfigurouRiscoInicial: boolean;
  bTrailingStopAtivado: boolean;

begin

  bSinalCompra := false;
  bSinalVenda := false;
  bPosicionado := hasPosition;

  //ESTRATÉGIA CARA OU COROA!
  //Gera um numero aleatorio de 0 a 9. Se for menor igual a 4, gera
  //sinal de compra, se for maior que 4 geral sinal de venda
  if Not bPosicionado
  and (Time >= iHorarioInicioAberturaPosicao)
  and (Time <= iHorarioFimAberturaPosicao)
  then
  begin
    //Número aleatório foi substituido por minuto par ou impar para permitir depurar
    //melhor o robô quando a estratégia é inserida multiplas vezes: como indicador  e como execução
    //iCaraCoroa := Random(10);
    iCaraCoroa := mod(Time,2);
    if iCaraCoroa = 0 then bSinalCompra := true
    else bSinalVenda := true;
  end;


  //Gera ordem de compra a mercado quando há um Sinal de COMPRA
  //e define ordem stoploss e take profit
  if bSinalCompra then BuyAtMarket;

  //Gera ordem de venda a mercado quando há um Sinal de VENDA
  //e define ordem stoploss e take profit
  if bSinalVenda then SellShortAtMarket;


  if bGestaoDeRiscoPelaEstrategia then
  begin
    //POSIÇÃO COMPRADA
    //Código responsável pela manutenção das ordens de stoploss e take profit
    if isBought then
    begin
      if Not bConfigurouRiscoInicial then
      begin
        fPrecoStop := BuyPrice - cStopEmTicks*MinPriceIncrement;
        fPrecoAlvo := BuyPrice + cAlvoEmTicks*MinPriceIncrement;
        fPrecoStopOffset := fPrecoStop - cStopOffsetEmTicks*MinPriceIncrement;
        bConfigurouRiscoInicial := true;
      end;

      if ((Close >= (BuyPrice + cTraillingStopTrigger*MinPriceIncrement))
         or (cTraillingStopTrigger = 0))
      and (not bTrailingStopAtivado) then bTrailingStopAtivado := true;

      fFloorTraillingStop := BuyPrice
          + floor((Close - BuyPrice)/(cTrailingStepEmTicks*MinPriceIncrement))
          *cTrailingStepEmTicks*MinPriceIncrement;

      if ((fFloorTraillingStop-cTrailingStopOffset*MinPriceIncrement) >= fPrecoStop)
      and bTrailingStopAtivado then
        fPrecoStop := fFloorTraillingStop - cTrailingStopOffset*MinPriceIncrement;


      SellToCoverStop(fPrecoStop,fPrecoStopOffset);
      SellToCoverLimit(fPrecoAlvo);
    end;

    //POSIÇÃO VENDIDA
    //Código responsável pela manutenção das ordens de stoploss e take profit
    if isSold Then
    begin
      if Not bConfigurouRiscoInicial then
      begin
        fPrecoStop := SellPrice + cStopEmTicks*MinPriceIncrement;
        fPrecoAlvo := SellPrice - cAlvoEmTicks*MinPriceIncrement;
        fPrecoStopOffset := fPrecoStop + cStopOffsetEmTicks*MinPriceIncrement;
        bConfigurouRiscoInicial := true;
      end;

      if ((Close <= (SellPrice - cTraillingStopTrigger*MinPriceIncrement))
          or (cTraillingStopTrigger = 0))
      and (not bTrailingStopAtivado) then bTrailingStopAtivado := true;

      if Close <= SellPrice then
        fFloorTraillingStop := SellPrice
            - floor((SellPrice - Close)/(cTrailingStepEmTicks*MinPriceIncrement))
            *cTrailingStepEmTicks*MinPriceIncrement;

      if ((fFloorTraillingStop+cTrailingStopOffset*MinPriceIncrement) <= fPrecoStop)
      and bTrailingStopAtivado then
        fPrecoStop := fFloorTraillingStop + cTrailingStopOffset*MinPriceIncrement;


      BuyToCoverStop(fPrecoStop,fPrecoStopOffset);
      BuyToCoverLimit(fPrecoAlvo);
    end;

    //Encerra posicao
    if (Time >= iHorarioEncerramentoDaytrade)
    and HasPosition
    then ClosePosition;

    if Not hasPosition and bConfigurouRiscoInicial then
    begin
      bConfigurouRiscoInicial := false;
      bTrailingStopAtivado := false;
    end;

  end;

  // Plot de Stop e Alvo para inspeção visual do código
  bPosicionado := hasPosition;
  if bPosicionado or bPosicionado[1] or bPosicionado[2] then
  begin
    PlotN(1,fPrecoStop);
    PlotN(2,fPrecoStopOffset);
    PlotN(3,fPrecoAlvo);
    SetPlotColor(1,clRed);
    SetPlotColor(2,clRed);
    SetPlotColor(3,clGreen);
    SetPlotStyle(1,psDash);
    SetPlotStyle(2,psDash);
    SetPlotStyle(3,psDash);
    SetPlotWidth(1,2);
    SetPlotWidth(2,2);
    SetPlotWidth(3,2);
  end;



end;
				
			

Stoploss móvel (Versão contínua) + Breakeven

Reproduzir vídeo

O código abaixo apresenta um exemplo avançado de stoploss móvel com Breakeven na versão contínua, ou seja, valor de stop é atualizado para cada valor de fechamento de candle encerrado. Só não é atualizado a cada tick por uma limitação do Profit.

O stop será alterado para cOffsetStop em relação ao maior preço de fechamento alcançado desde a abertura da posição. O código pode ser alterado para calcular o stop móvel em relação ao valor máximo do candle.

O exemplo também conta com ordem take profit (alvo de lucro da operação) em posições compradas, para uma relação de risco/ganho de 3:1. O raciocínio para posições vendidas é análogo.

OBS 1: A versão é compatível com o Editor de Estratégias e Módulo de Automação de Estratégias. Devido a um bug do Profit, é necessário ter um comando ClosePosition, pois do contrário a ferramenta informa equivocadamente que não existem ordens para encerrar posição.

				
					const
 //Relação risco/ganho de 3:1
 cStopEmTicks = 30;
 cStopOffsetEmTicks = 10;
 cTrailingStopOffset = 15;
 cBreakevenEmTicks = 10;
 cTraillingStopTrigger = 20;
 cAlvoEmTicks = 90;


input
  bGestaoDeRiscoPelaEstrategia(true);
  iHorarioInicioAberturaPosicao(0905);
  iHorarioFimAberturaPosicao(1630);
  iHorarioEncerramentoDaytrade(1645);

var
  iCaraCoroa: integer;
  bSinalCompra, bSinalVenda, bPosicionado: boolean;
  fPrecoStop, fPrecoAlvo, fPrecoStopOffset: float;
  bBreakevenAtivado: boolean;
  bConfigurouRiscoInicial: boolean;
  bTrailingStopAtivado: boolean;

begin

  bSinalCompra := false;
  bSinalVenda := false;
  bPosicionado := hasPosition;

  //ESTRATÉGIA CARA OU COROA!
  //Gera um numero aleatorio de 0 a 9. Se for menor igual a 4, gera
  //sinal de compra, se for maior que 4 geral sinal de venda
  if Not bPosicionado
  and (Time >= iHorarioInicioAberturaPosicao)
  and (Time <= iHorarioFimAberturaPosicao)
  then
  begin
    //Número aleatório foi substituido por minuto par ou impar para permitir depurar
    //melhor o robô quando a estratégia é inserida multiplas vezes: como indicador  e como execução
    //iCaraCoroa := Random(10);
    iCaraCoroa := mod(Time,2);
    if iCaraCoroa = 0 then bSinalCompra := true
    else bSinalVenda := true;
  end;

  //Gera ordem de compra a mercado quando há um Sinal de COMPRA
  //e define ordem stoploss e take profit
  if bSinalCompra then BuyAtMarket;

  //Gera ordem de venda a mercado quando há um Sinal de VENDA
  //e define ordem stoploss e take profit
  if bSinalVenda then SellShortAtMarket;

  if bGestaoDeRiscoPelaEstrategia then
  begin
    //Código responsável pela manutenção das ordens de stoploss e take profit
    if isBought then
    begin
      if Not bConfigurouRiscoInicial then
      begin
        fPrecoStop := BuyPrice - cStopEmTicks*MinPriceIncrement;
        fPrecoAlvo := BuyPrice + cAlvoEmTicks*MinPriceIncrement;
        fPrecoStopOffset := fPrecoStop - cStopOffsetEmTicks*MinPriceIncrement;
        bConfigurouRiscoInicial := true;
      end;

      if ((Close >= (BuyPrice + cTraillingStopTrigger*MinPriceIncrement))
          or (cTraillingStopTrigger = 0))
      and (not bTrailingStopAtivado) then bTrailingStopAtivado := true;

      if ((Close - cTrailingStopOffset*MinPriceIncrement) >= fPrecoStop)
      and bTrailingStopAtivado then
          fPrecoStop := Close - cTrailingStopOffset*MinPriceIncrement;

      if (Close >= (BuyPrice + cBreakevenEmTicks*MinPriceIncrement))
      and (not bBreakevenAtivado) then
      begin
        bBreakevenAtivado := true;
        if fPrecoStop < BuyPrice then fPrecoStop := BuyPrice;
      end;


      fPrecoStopOffset := fPrecoStop-cStopOffsetEmTicks*MinPriceIncrement;
      SellToCoverStop(fPrecoStop,fPrecoStopOffset);
      SellToCoverLimit(fPrecoAlvo);
    end;


    //Código responsável pela manutenção das ordens de stoploss e take profit
    if isSold then
    begin
      if Not bConfigurouRiscoInicial then
      begin
        fPrecoStop := SellPrice + cStopEmTicks*MinPriceIncrement;
        fPrecoAlvo := SellPrice - cAlvoEmTicks*MinPriceIncrement;
        fPrecoStopOffset := fPrecoStop + cStopOffsetEmTicks*MinPriceIncrement;
        bConfigurouRiscoInicial := true;
      end;

      if ((Close <= (SellPrice - cTraillingStopTrigger*MinPriceIncrement))
          or (cTraillingStopTrigger = 0))
      and (not bTrailingStopAtivado) then bTrailingStopAtivado := true;

      if ((Close + cTrailingStopOffset*MinPriceIncrement) <= fPrecoStop)
      and bTrailingStopAtivado then
          fPrecoStop := Close + cTrailingStopOffset*MinPriceIncrement;

      if (Close <= (SellPrice - cBreakevenEmTicks*MinPriceIncrement))
      and (not bBreakevenAtivado) then
      begin
        bBreakevenAtivado := true;
        if fPrecoStop > SellPrice then fPrecoStop := SellPrice;
      end;


      fPrecoStopOffset := fPrecoStop + cStopOffsetEmTicks*MinPriceIncrement;
      BuyToCoverStop(fPrecoStop,fPrecoStopOffset);
      BuyToCoverLimit(fPrecoAlvo);
    end;


    //Encerra posicao
    if (Time >= iHorarioEncerramentoDaytrade)
    and HasPosition
    then ClosePosition;

    if Not hasPosition and bConfigurouRiscoInicial then
    begin
      bConfigurouRiscoInicial := false;
      bBreakevenAtivado := false;
      bTrailingStopAtivado := false;
    end;

  end;

  // Plot de Stop e Alvo para inspeção visual do código
  bPosicionado := hasPosition;
  if bPosicionado or bPosicionado[1] or bPosicionado[2] then
  begin
    PlotN(1,fPrecoStop);
    PlotN(2,fPrecoStopOffset);
    PlotN(3,fPrecoAlvo);
    SetPlotColor(1,clRed);
    SetPlotColor(2,clRed);
    SetPlotColor(3,clGreen);
    SetPlotStyle(1,psDash);
    SetPlotStyle(2,psDash);
    SetPlotStyle(3,psDash);
    SetPlotWidth(1,2);
    SetPlotWidth(2,2);
    SetPlotWidth(3,2);
  end
  else
  begin
    NoPlot(1);
    NoPlot(2);
    NoPlot(3);
  end;


end;
				
			

Stoploss móvel (Versão baseada em passos) + Breakeven

O código abaixo apresenta um exemplo avançado de stoploss móvel com Breakeven na versão discreta (baseada em passos), ou seja, valor de stop é atualizado para cada valor de fechamento que supera o passo definido (cTrailingStepEmTicks). Só não é atualizado a cada tick por uma limitação do Profit.

O stop será alterado para cOffsetStop em relação ao último passo alcançado pelo maior preço de fechamento de candle desde a abertura da posição. O código pode ser alterado para calcular o stop móvel em relação ao valor máximo do candle.

O exemplo também conta com ordem take profit (alvo de lucro da operação) em posições compradas, para uma relação de risco/ganho de 3:1. O raciocínio para posições vendidas é análogo.

OBS 1: A versão é compatível com o Editor de Estratégias e Módulo de Automação de Estratégias. Devido a um bug do Profit, é necessário ter um comando ClosePosition, pois do contrário a ferramenta informa equivocadamente que não existem ordens para encerrar posição.

				
					const
 //Relação risco/ganho de 3:1
 cStopEmTicks = 30;
 cBreakevenEmTicks = 10;
 cTraillingStopTrigger = 20;
 cTrailingStepEmTicks = 20;
 cTrailingStopOffset = 10;
 cStopOffsetEmTicks = 10;
 cAlvoEmTIcks = 90;

input
  bGestaoDeRiscoPelaEstrategia(true);
  iHorarioInicioAberturaPosicao(0905);
  iHorarioFimAberturaPosicao(1630);
  iHorarioEncerramentoDaytrade(1645);

var
  iCaraCoroa: integer;
  bSinalCompra, bSinalVenda, bPosicionado: boolean;
  fPrecoStop, fPrecoAlvo, fPrecoStopOffset: float;
  fFloorTraillingStop: float;
  bBreakevenAtivado: boolean;
  bConfigurouRiscoInicial: boolean;
  bTrailingStopAtivado: boolean;

begin

  bSinalCompra := false;
  bSinalVenda := false;
  bPosicionado := hasPosition;

  //ESTRATÉGIA CARA OU COROA!
  //Gera um numero aleatorio de 0 a 9. Se for menor igual a 4, gera
  //sinal de compra, se for maior que 4 geral sinal de venda
  if Not bPosicionado
  and (Time >= iHorarioInicioAberturaPosicao)
  and (Time <= iHorarioFimAberturaPosicao)
  then
  begin
    //Número aleatório foi substituido por minuto par ou impar para permitir depurar
    //melhor o robô quando a estratégia é inserida multiplas vezes: como indicador  e como execução
    //iCaraCoroa := Random(10);
    iCaraCoroa := mod(Time,2);
    if iCaraCoroa = 0 then bSinalCompra := true
    else bSinalVenda := true;
  end;

  //Gera ordem de compra a mercado quando há um Sinal de COMPRA
  //e define ordem stoploss e take profit
  if bSinalCompra then BuyAtMarket;

  //Gera ordem de venda a mercado quando há um Sinal de VENDA
  //e define ordem stoploss e take profit
  if bSinalVenda then SellShortAtMarket;

  if bGestaoDeRiscoPelaEstrategia then
  begin
    //Código responsável pela manutenção das ordens de stoploss e take profit
    if isBought then
    begin
      if Not bConfigurouRiscoInicial then
      begin
        fPrecoStop := BuyPrice - cStopEmTicks*MinPriceIncrement;
        fPrecoAlvo := BuyPrice + cAlvoEmTicks*MinPriceIncrement;
        fPrecoStopOffset := fPrecoStop - cStopOffsetEmTicks*MinPriceIncrement;
        bConfigurouRiscoInicial := true;
      end;

      if ((Close >= (BuyPrice + cTraillingStopTrigger*MinPriceIncrement))
          or (cTraillingStopTrigger = 0))
      and (not bTrailingStopAtivado) then bTrailingStopAtivado := true;

      fFloorTraillingStop := BuyPrice
          + floor((Close - BuyPrice)/(cTrailingStepEmTicks*MinPriceIncrement))
          *cTrailingStepEmTicks*MinPriceIncrement;

      if ((fFloorTraillingStop-cTrailingStopOffset*MinPriceIncrement) >= fPrecoStop)
      and (Close >= BuyPrice+cTrailingStepEmTicks*MinPriceIncrement)
      and bTrailingStopAtivado then
        fPrecoStop := fFloorTraillingStop - cTrailingStopOffset*MinPriceIncrement;

      if (Close >= (BuyPrice + cBreakevenEmTicks*MinPriceIncrement))
      and (not bBreakevenAtivado) then
      begin
        bBreakevenAtivado := true;
        if fPrecoStop < BuyPrice then fPrecoStop := BuyPrice;
      end;

      fPrecoStopOffset := fPrecoStop-cStopOffsetEmTicks*MinPriceIncrement;

      SellToCoverStop(fPrecoStop,fPrecoStopOffset);
      SellToCoverLimit(fPrecoAlvo);
    end;


    //Código responsável pela manutenção das ordens de stoploss e take profit
    if isSold then
    begin
      if Not bConfigurouRiscoInicial then
      begin
        fPrecoStop := SellPrice + cStopEmTicks*MinPriceIncrement;
        fPrecoAlvo := SellPrice - cAlvoEmTicks*MinPriceIncrement;
        fPrecoStopOffset := fPrecoStop + cStopOffsetEmTicks*MinPriceIncrement;
        bConfigurouRiscoInicial := true;
      end;

      if ((Close <= (SellPrice - cTraillingStopTrigger*MinPriceIncrement))
          or (cTraillingStopTrigger = 0))
      and (not bTrailingStopAtivado) then bTrailingStopAtivado := true;

      if Close <= SellPrice then
        fFloorTraillingStop := SellPrice
            - floor((SellPrice - Close)/(cTrailingStepEmTicks*MinPriceIncrement))
            *cTrailingStepEmTicks*MinPriceIncrement;


      if ((fFloorTraillingStop+cTrailingStopOffset*MinPriceIncrement) <= fPrecoStop)
      and (Close <= SellPrice - cTrailingStepEmTicks*MinPriceIncrement)
      and bTrailingStopAtivado then
        fPrecoStop := fFloorTraillingStop + cTrailingStopOffset*MinPriceIncrement;


      if (Close <= (SellPrice - cBreakevenEmTicks*MinPriceIncrement))
      and (not bBreakevenAtivado) then
      begin
        bBreakevenAtivado := true;
        if fPrecoStop > SellPrice then fPrecoStop := SellPrice;
      end;


      fPrecoStopOffset := fPrecoStop + cStopOffsetEmTicks*MinPriceIncrement;

      BuyToCoverStop(fPrecoStop,fPrecoStopOffset);
      BuyToCoverLimit(fPrecoAlvo);

    end;


    //Encerra posicao
    if (Time >= iHorarioEncerramentoDaytrade)
    and HasPosition
    then ClosePosition;

    if Not hasPosition and bConfigurouRiscoInicial then
    begin
      bConfigurouRiscoInicial := false;
      bBreakevenAtivado := false;
      bTrailingStopAtivado := false;
    end;

  end;

  // Plot de Stop e Alvo para inspeção visual do código
  bPosicionado := hasPosition;
  if bPosicionado or bPosicionado[1] or bPosicionado[2] then
  begin
    PlotN(1,fPrecoStop);
    PlotN(2,fPrecoStopOffset);
    PlotN(3,fPrecoAlvo);
    SetPlotColor(1,clRed);
    SetPlotColor(2,clRed);
    SetPlotColor(3,clGreen);
    SetPlotStyle(1,psDash);
    SetPlotStyle(2,psDash);
    SetPlotStyle(3,psDash);
    SetPlotWidth(1,2);
    SetPlotWidth(2,2);
    SetPlotWidth(3,2);
  end
  else
  begin
    NoPlot(1);
    NoPlot(2);
    NoPlot(3);
  end;




end;
				
			

Confirmação de ordens por múltiplos sinais

O código abaixo apresenta um exemplo para o conceito de confirmação de compra por meio de dois sinais distintos: um sinal baseado em IFR e outro baseado em cruzamento de média.

Os sinais podem ser adaptados para quaisquer condições que se deseje. O importante deste exemplo é entender a lógica por trás de duplas confirmações ou múltiplas confirmações com janela de timeout para abertura de posição.

OBS 1: Como o foco do snippet é a confirmação de ordens com múltiplos sinais, a gestão de risco foi implementada da forma mais simples possível apenas para tornar o código funcional. Percebe-se que há um stop e alvo fixos na relação 3:1, onde o stop está 30 ticks atrás do preço de compra e o alvo a 90 ticks acima do preço de compra.

OBS 2: A parametrização dos indicadores, bem como a seleção dos indicadores deste exemplo não representam nenhuma recomendação de setup, sendo apenas um exemplo didático.

				
					const
  // Determina a qtde de candles a se aguardar a confirmação
  // de sinal de compra 
  iTimeoutConfirmacao = 12;
  // Limite para considerar sobrevenda no IFR
  iLimiteSobreVendaIFR = 35;

input
  iQtdePeriodosMedia(16);
  iQtdePeriodosIFR(16);
  //Compatibilidade com Módulo de Automação de Estratégias
  bModuloAutomacao(false);
var
  bSinalCompraIFR, bSinalCompraCruzMedia: boolean;
  fIFR, fMedia: float;

  iInteradorTimeout: integer;
  bSinalCompraConfirmada: boolean;
  bSinalCompraIFRativou, bSinalCompraCruzMediaAtivou: boolean;
  
  bComprado: boolean;
  bConfigurouRiscoOperacao: boolean;
  fPrecoAlvo, fPrecoStop, fStopOffset: float;
begin
  // Indicadores técnicos utilizados para sinais
  bComprado := isBought;
  fIFR := RSI(iQtdePeriodosIFR,0);
  fMedia := Media(iQtdePeriodosMedia,Close);
  bSinalCompraConfirmada := false;  

  //Sinais de compra individuais para indicadores
  bSinalCompraCruzMedia := (Close > fMedia) and (Close[1] <= fMedia[1]);
  bSinalCompraIFR := (fIFR > iLimiteSobreVendaIFR) and (fIFR[1] <= iLimiteSobreVendaIFR);

  // Auxilio visual de sinais individuais
  if bSinalCompraCruzMedia and Not bComprado then PlotText("S1", clBlue,-1,9);
  if bSinalCompraIFR and Not bComprado then PlotText("S2", clYellow,0,9);

  // Lógica para multiplas confirmações
  // Se Timeout for zero a dupla confirmação de compra deve ocorrer
  // no mesmo candle/box
  if Not bComprado then
  begin
    if (iTimeoutConfirmacao = 0) and bSinalCompraCruzMedia and bSinalCompraIFR then
      bSinalCompraConfirmada := true
    else
    if (iTimeoutConfirmacao > 0) then
    begin
      bSinalCompraConfirmada := false;
      bSinalCompraIFRativou := false;
      bSinalCompraCruzMediaAtivou := false;
  
      for iInteradorTimeout := 0 to iTimeoutConfirmacao do
      begin
        if bSinalCompraCruzMedia[iInteradorTimeout] = true then bSinalCompraCruzMediaAtivou := true;
        if bSinalCompraIFR[iInteradorTimeout] = true then bSinalCompraIFRativou := true;
        if bSinalCompraCruzMediaAtivou and bSinalCompraIFRativou then bSinalCompraConfirmada := true;
      end;
    end;
  end;

  // Se houver multipla confirmação, executa ordem a mercado
  if bSinalCompraConfirmada and Not bComprado then 
  begin
    BuyAtMarket;
    bConfigurouRiscoOperacao := false;
  end;
  bComprado := isBought;

  // Configura risco da operação no Módulo de Automação (Ordem OCO)
  // Para outras configurações de STOPLOSS, consulte os snippets no site
  if bModuloAutomacao then
  begin
    if bComprado and Not bConfigurouRiscoOperacao then
    begin
      fPrecoAlvo := buyPrice + 450*MinPriceIncrement;
      fPrecoStop := buyPrice - 150*MinPriceIncrement;
      fStopOffset := fPrecoStop - 100*MinPriceIncrement;

      SellShortStop(fPrecoStop, fStopOffset);
      SellShortLimit(fPrecoAlvo);
    end
    else
    //Proteção de pulo da ordem stop devido à gaps 
    if isBought and (Close < fStopOffset) then closePosition;

  end
  // Configura alvo e stoploss para Backtesting
  else
  begin
    if bComprado then
    begin
      fPrecoAlvo := buyPrice + 450*MinPriceIncrement;
      fPrecoStop := buyPrice - 150*MinPriceIncrement;
      fStopOffset := fPrecoStop - 60*MinPriceIncrement;

      SellToCoverStop(fPrecoStop, fStopOffset);
      //Proteção de pulo da ordem stop devido à gaps
      if isBought and (Close < fStopOffset) then closePosition;
      if isBought then SellToCoverLimit(fPrecoAlvo);
    end;
  end;


end.

				
			

Gestão de Risco diária e Proteção de Ganhos

Reproduzir vídeo

O código abaixo apresenta um exemplo de programação para fazer a gestão de risco do resultado diário de um robô.

Inicialmente, são estabelecidos para a estratégia o limite de perda (pLimitePerdaDiaria) e objetivo de ganho diário (pObjetivoGanhoDiario), bem como a proteção de ganho desejada (pProtecaoGanho), tudo em valor financeiro.

A medida que o robô faz as operações, caso o resultado atinja o limite de perda inicial, a estratégia para de operar durante o resto do dia.

Caso o objetivo de ganho seja atingido, a gestão de risco do código protege parte do ganho (pProtecaoGanho) e o robô continua a operar. Caso atinja novamente o objetivo de ganho, a partir do último patamar de ganho planejado, o lucro é novamente protegido.

				
					input
  pLimitePerdaDiaria(100.00);
  pObjetivoGanhoDiario(300.00);
  pProtecaoGanho(200.00);
  pTempoReal(false);
var
  fResultado: float;
  fResultadoDiario: float;
  iHora: integer;

  fObjetivoAtualGanho, fLimiteAtualPerda: float;
  fNovaReferencia: float;

  bPrimeiraBarraDoDia : boolean;
  iDataAtual          : integer;
  bPrimeiroTickDaBarra : boolean;
  iBarraAtual          : integer;
begin
  // Configura a gestão de risco no primeiro tick da primeira
  // barra do dia. Necessário agora que tem roteamento no tick
  // SNIPPET de "Identificação do primeiro candle de cada dia"
  // +
  // SNIPPET de "Identificação do primeiro tick de uma barra"
  if (Date() <> iDataAtual) then
    begin
      iDataAtual := Date();
      bPrimeiraBarraDoDia := true;
    end;
  if bPrimeiraBarraDoDia then
    begin
      bPrimeiraBarraDoDia := false;

      if (pTempoReal and LastBarOnChart) or not pTempoReal then
      if (CurrentBar <> iBarraAtual) then
        begin
          iBarraAtual := CurrentBar;
          bPrimeiroTickDaBarra := true;
        end
      else
        bPrimeiroTickDaBarra := false;

      if bPrimeiroTickDaBarra then
        begin
          //Faz alguma coisa no primeiro tick da barra
          //Aplicável apenas em execução de tempo real
          fObjetivoAtualGanho := pObjetivoGanhoDiario;
          fLimiteAtualPerda := pLimitePerdaDiaria;
          fNovaReferencia := 0;
        end;

    end;


  //-----------------------------------------------------------
  // SNIPPET de "Como limitar trades por objetivo de ganho ou limite de perda"
  // Resultado até o momento no dia (fechado + aberto)
    fResultado := DailyResult(true);
    plot(fResultado);
    SetPlotStyle(1,psDash);
    SetPlotColor(1,clGray);
    SetPlotType(1,igHistogram);

    plot2(fNovaReferencia - fLimiteAtualPerda);
    SetPlotStyle(2,psSolid);
    SetPlotColor(2,clRed);
    SetPlotWidth(2,3);

  // Estratégia qualquer de operação!!!
  // Estratégias apenas opera se resultado do dia não
  // tiver atingido objetivo de ganho ou limite de perda
  fResultadoDiario := DailyResult(true) - fNovaReferencia;

  if (fResultadoDiario > -1*fLimiteAtualPerda)
  and (fResultadoDiario < fObjetivoAtualGanho) then
  begin
    // SIMULAÇÃO DE ORDENS PARA FINS DE EXEMPLO
    for iHora := 0 to 8 do
    begin
      if (Time = (0900 + iHora*100)) or (Time = (0930 + iHora*100)) then
        if random(2) = 0 then BuyAtMarket else SellShortAtMarket;

      if (Time = (0920 + iHora*100)) Or (Time = (0950 + iHora*100)) then
        ClosePosition;
    end;

  end
  //Se resultado excedeu objetivo de ganho cria-se novos limites
  //Se atingiu limite de perda ou proteção de ganho então para de operar
  else 
  begin
    if fResultadoDiario <= -1*pLimitePerdaDiaria then
    begin
      if hasPosition then ClosePosition;
    end
    else
    if fResultadoDiario >= pObjetivoGanhoDiario then
    begin
       fNovaReferencia := fNovaReferencia + pObjetivoGanhoDiario;
       fLimiteAtualPerda := (pObjetivoGanhoDiario - pProtecaoGanho);
    end;

  end;

end;
				
			

Identificando resultado da última operação

Reproduzir vídeo

O código abaixo apresenta um exemplo de programação para identificar o resultado da última operação realizada. Assim, o trader pode realizar outras lógicas de limitação de sequência de trades com prejuízo, lucro e outras que desejar.

				
					var
  bHasPosition: boolean;
  iDia: integer;
  fResultadoFechadoDia, fResultadoTotalDia: float;
  fResultadoUltimoTrade, fResultadoAberto: float;
begin
  if (Date <> iDia) then
  begin
    iDia := Date;
    fResultadoUltimoTrade := 0;
  end;

  // ARMAZENAMENTO DE VARIÁVEIS (FACILITA A DEPURAÇÃO)
  bHasPosition := HasPosition;
  fResultadoTotalDia := DailyResult(true);
  fResultadoFechadoDia := DailyResult(false);

  // CALCULA O RESULTADO ABERTO
  if bHasPosition 
  then fResultadoAberto := fResultadoTotalDia - fResultadoFechadoDia
  else fResultadoAberto := 0;

  // CALCULA O RESULTADO DO ÚLTIMO TRADE
  if not bHasPosition and bHasPosition[1]
  then fResultadoUltimoTrade := fResultadoAberto[1];
 
  // PLOTA GRÁFICO PARA INSPEÇÃO VISUAL
  plot(fResultadoAberto);
  SetPlotType(1,igHistogram);
  if fResultadoAberto > 0 then SetPlotColor(1,clGreen)
  else if fResultadoAberto < 0 then SetPlotColor(1,clRed)
       else SetPlotColor(1,clGray);

  plot2(fResultadoUltimoTrade);
  SetPlotColor(2,clWhite);
  SetPlotStyle(2,psDash);
  SetPlotWidth(2,2);


  //ROTEAMENTO DE ORDENS
  if (Time = 0905) then BuyAtMarket;
  if (Time >= 0915) then ClosePosition;

end;
				
			

Como obter o preço médio executado durante montagem e realização parcial

É tarefa comum quando você está com um setup de montagem e realizações parciais querer estabelecer ordens de alvo e stop de acordo com o preço executado da última ordem e não do preço médio da posição.

É possível obter esse valor pelo código abaixo. No entanto, é importante ressaltar que devido às limitações da linguagem NTSL, caso haja várias execuções de ordens na mesma barra, o preço calculado de execução será o preço médio das ordens executadas na barra tendo em vista a diferença da posição.

				
					var
  iPosicao: integer;
  fPrecoMedio: float;
  fPrecoExecutado: float;

// ----------------------------------------------------------------------------------------
function getAvgFilledOrderPrice(previousPos: integer; previousPrice: Float; 
                                currentPos:integer; currentPrice: Float): float;
begin
  if  (currentPos <> 0) and (previousPos <> 0) 
  and (currentPos <> previousPos) then
  begin
    Result := (currentPos*currentPrice - previousPos*previousPrice)/(currentPos - previousPos);
  end
  else
    Result := 0;   
end;
// ----------------------------------------------------------------------------------------


begin
  // Como calcular preço médio de execução de ordens na barra
  iPosicao := Position;
  fPrecoMedio := Price;
  fPrecoExecutado := getAvgFilledOrderPrice(iPosicao[1], fPrecoMedio[1], iPosicao, fPrecoMedio);

  plot2(fPrecoExecutado);
  SetPlotType(2,igHistogram);
  // ---------------------------------------------------------

  if (Date = LastCalcDate) and (Time = 1500) then
      SellShortAtMarket(2);

  if (Date = LastCalcDate) and (Time = 1505) then
      BuyAtMarket(1);

  if (Date = LastCalcDate) and (Time = 1515) then
    SellShortAtMarket(2);

  if (Date = LastCalcDate) and (Time = 1530) then
    SellShortAtMarket(2);

  if (Time >= 1630) and hasPosition then ClosePosition;

  if hasPosition then Plot(Price);
  SetPlotColor(1, clWhite);
  SetPlotStyle(1, psDash);

end;
				
			

Implementação de estratégias

Introdução

Esta seção visa apresentar trechos de códigos com exemplos de tarefas comuns para implementação de estratégias.

Você pode acessar os Snippets diretamente pelo menu lateral direito, ou fazendo CRL+F (CTRL+L) para localizar algum texto específico na página, uma vez que o conteúdo tende a crescer ao longo do tempo, dificultando a navegação pelo menu.

Caso tenham sugestões de código para acrescentar à lista, gentileza deixar o código nos comentários com o link para seu perfil em rede social (para devido crédito de autoria).

Snippets

Cruzamento simples entre 2 séries

Reproduzir vídeo

O exemplo abaixo visa identificar quando há um cruzamento simples entre duas séries, considerando apenas o instante atual e anterior.

				
					var
  fMedia1, fMedia2: float;
  iCruzamento: integer;


function NTB_ArredondarFloat(Value: float; nCasas: integer):float;
var
    fValor: float;
    fParteInteira: float;
    fParteDecimal: float;
begin
  fValor := Value;
  fParteInteira := IntPortion(fValor);
  fParteDecimal := Round((fValor - fParteInteira)*Power(10,nCasas));

  Result := fParteInteira + fParteDecimal/Power(10,nCasas);
end;


begin
  iCruzamento := 0;
  fMedia1 := NTB_ArredondarFloat(Media(10,Close),2);
  fMedia2 := NTB_ArredondarFloat(Media(20,Close),2);

  if  (fMedia1 > fMedia2)
  and (fMedia1[1] <= fMedia2[1]) then
    iCruzamento := 1;

  if (fMedia1 < fMedia2)
  and (fMedia1[1] >= fMedia2[1]) then
    iCruzamento := -1;

  if iCruzamento = 1 then
  begin
    // O que fazer quando houver cruzamento para cima?
    PlotText("Cruzou acima", clGreen, -1,12);
  end;

  if iCruzamento = -1 then
  begin
    // O que fazer quando houver cruzamento para baixo?
    PlotText("Cruzou abaixo", clRed, -1,12);
  end;

  //Plot apenas para visualizar graficamente o funcionamento
  //do código
  Plot(fMedia1);
  Plot2(fMedia2);
  SetPlotColor(1,clRed);
  SetPlotWidth(1,2);  
  SetPlotColor(2,clWhite);
  SetPlotStyle(2,psDash);  
  SetPlotWidth(2,2);  

end;
				
			

Cruzamento simples entre 2 séries com percentual de cruzamento

O exemplo abaixo visa identificar quando há um cruzamento simples entre duas séries, considerando apenas o instante atual e anterior, e desde que o cruzamento seja superior a um determinado valor percentual.

				
					const
  //Constante fornecida em percentual. Ex: 0.1 significa 0.1%
  fPercCruzamento = 0.1;
var
  fMedia1, fMedia2: float;
  iCruzamento: integer;

begin
  iCruzamento := 0;
  fMedia1 := Media(10,Close);
  fMedia2 := Media(20,Close);    

  //Plot apenas para visualizar graficamente o funcionamento
  //do código
  Plot(fMedia1);
  Plot2(fMedia2); 

  if (fMedia1 <> 0) and (fMedia2 <> 0) then
  begin

    if  (fMedia1 > fMedia2)
    and (fMedia1[1] <= fMedia2[1])
    and (((fMedia1-fMedia2)/fMedia1*100) >= fPercCruzamento)
    then iCruzamento := 1;
  
    if  (fMedia1 < fMedia2)
    and (fMedia1[1] >= fMedia2[1]) 
    and ((Abs((fMedia2-fMedia1)/fMedia1*100)) >= fPercCruzamento)
    then iCruzamento := -1;
  
    if iCruzamento = 1 then 
    begin
      // O que fazer quando houver cruzamento para cima?
      PlotText("Cruzou pra cima", clGreen, -1,12);
    end;
  
    if iCruzamento = -1 then 
    begin
      // O que fazer quando houver cruzamento para baixo?
      PlotText("Cruzou pra baixo", clRed, -1,12);    
    end;
  end;

end;
				
			

Cruzamento entre 2 séries nos últimos N períodos

O exemplo abaixo visa identificar qual cruzamento houve entre duas séries nos últimos N períodos (constante cJanelaCruzamento).

				
					const
  cJanelaCruzamento = 5;
var
  fMedia1,fMedia2 : float;
  iCruzamento : integer;
  iUltimoCruzamentoJanela : integer;
  iPeriodo, iPeriodoJanela : integer;
begin
  iCruzamento := 0;
  fMedia1 := Media(10,Close);
  fMedia2 := Media(20,Close);

  //Plot apenas para visualizar graficamente o funcionamento
  //do código
  Plot(fMedia1);
  Plot2(fMedia2);

  if (fMedia1 > fMedia2) and (fMedia1[1] <= fMedia2[1]) then
    iCruzamento := 1;
  if (fMedia1 < fMedia2) and (fMedia1[1] >= fMedia2[1]) then
    iCruzamento := - 1;
  
  if iCruzamento = 1 then
    begin
      // O que fazer quando houver cruzamento para cima?
      PlotText("Cruzou pra cima",clGreen, - 1,12);
    end;
  
  if iCruzamento = - 1 then
    begin
      // O que fazer quando houver cruzamento para baixo?
      PlotText("Cruzou pra baixo",clRed, - 1,12);
    end;


  // Código para proteção do início da série em backtesting
  if MaxBarsBack < cJanelaCruzamento then
    iPeriodoJanela := MaxBarsBack
  else iPeriodoJanela := cJanelaCruzamento;
  
  // Identificação do último cruzamento
  if iPeriodoJanela >= 1 then
  begin  
    iUltimoCruzamentoJanela := iCruzamento;
    iPeriodo := 1;
    while iPeriodo <= iPeriodoJanela do
    begin
      if iCruzamento[iPeriodo] <> 0 then
      begin
         iUltimoCruzamentoJanela := iCruzamento[iPeriodo];
         iPeriodo := iPeriodoJanela + 1;
      end;
      iPeriodo := iPeriodo + 1;
    end;
  
    // Escreve no gráfico qual cruzamento houve nos últimos
    // cJanelaCruzamento periodos
    if (iCruzamento = 0) and (iUltimoCruzamentoJanela <> 0) then
      if iUltimoCruzamentoJanela = 1 then
        PlotText("Cruz p/ cima",clWhite, - 1,8)
      else
        PlotText("Cruz p/ baixo",clWhite, - 1,8);
  end;

end;
				
			

Toque na média utilizando percentual de proximidade

Reproduzir vídeo

O exemplo abaixo visa identificar quando ocorre o toque do preço em uma média, utilizando como parâmetro o percentual de proximidade.

OBS: Neste exemplo foi introduzido também uma função customizada para arredondar um valor float de acordo com a quantidade de casas decimais desejada (NTB_ArredondarFloat)). Este tipo de função não tem de forma nativa no Profit (o que é uma pena!);

				
					const
  // Define o percentual que caracteriza o toque
  // Se for igual a zero, a barra tem conter a média
  // Ex: se cPercProximidade = 0.5, define como toque se
  // preço chegar a 0.5% ou menos de distância da média
  cPercProximidade = 0.0;
var
  fMedia: float;
  bTocouMedia: boolean;


function NTB_ArredondarFloat(Value: float; nCasas: integer):float;
var
    fValor: float;
    fParteInteira: float;
    fParteDecimal: float;
begin
  fValor := Value;
  fParteInteira := IntPortion(fValor);
  fParteDecimal := Round((fValor - fParteInteira)*Power(10,nCasas));

  Result := fParteInteira + fParteDecimal/Power(10,nCasas);

end;

begin
  bTocouMedia := false;
  fMedia :=  NTB_ArredondarFloat(Media(20,Close),2);

  //Plot apenas para visualizar graficamente o funcionamento
  //do código
  Plot(fMedia);
  SetPlotColor(1,clRed);
  SetPlotWidth(1,2);
  if (cPercProximidade <> 0) then
  begin
    Plot2(NTB_ArredondarFloat(fMedia*(1 + cPercProximidade/100),2));
    Plot3(NTB_ArredondarFloat(fMedia*(1 - cPercProximidade/100),2));
    SetPlotColor(2, clGray);
    SetPlotColor(3, clGray);
  end;


  //Proteção para os primeiros períodos de backtesting
  //Quando pode ocorrer divisão por zero
  if fMedia <> 0 then
  begin

    // Situação em que a media está no meio da barra
    if (fMedia >= Low) and (fMedia <= High)
    then bTocouMedia := True;

    // Situação em que a media está abaixo do preço
    // negociado e este chegou a cPercProximidade da
    // média
    if (fMedia < Low)
    and (((Low - fMedia)/fMedia*100) <= cPercProximidade)
    then
    begin
      bTocouMedia := True;
    end;

    // Situação em que a media está abaixo do preço
    // negociado e este chegou a cPercProximidade da
    // média
    if (fMedia > High)
    and (((fMedia - High)/High*100) <= cPercProximidade)
    then
    begin
    bTocouMedia := True;
    end;

   if bTocouMedia then
     PlotText("Tocou",clWhite, - 1,8);

  end;

end;
				
			

Toque na média utilizando quantidade de ticks de proximidade

Reproduzir vídeo

O exemplo abaixo visa identificar quando ocorre o toque do preço em uma média, utilizando como parâmetro a quantidade de ticks do ativo.

OBS: Neste exemplo foi introduzido também uma função customizada para arredondar um valor float de acordo com a quantidade de casas decimais desejada (NTB_ArredondarFloat)). Este tipo de função não tem de forma nativa no Profit (o que é uma pena!);

				
					const
  // Define o percentual que caracteriza o toque
  // Se for igual a zero, a barra tem conter a média
  // Ex: se cPercProximidade = 0.5, define como toque se
  // preço chegar a 0.5% ou menos de distância da média
  cTicksProximidade = 0;
var
  fMedia: float;
  bTocouMedia: boolean;


function NTB_ArredondarFloat(Value: float; nCasas: integer):float;
var
    fValor: float;
    fParteInteira: float;
    fParteDecimal: float;
begin
  fValor := Value;
  fParteInteira := IntPortion(fValor);
  fParteDecimal := Round((fValor - fParteInteira)*Power(10,nCasas));

  Result := fParteInteira + fParteDecimal/Power(10,nCasas);

end;

begin
  bTocouMedia := false;
  fMedia :=  NTB_ArredondarFloat(Media(20,Close),2);

  //Plot apenas para visualizar graficamente o funcionamento
  //do código
  Plot(fMedia);
  SetPlotColor(1,clRed);
  SetPlotWidth(1,2);
  if (cTicksProximidade <> 0) then
  begin
    Plot2(fMedia + cTicksProximidade*MinPriceIncrement);
    Plot3(fMedia - cTicksProximidade*MinPriceIncrement);
    SetPlotColor(2,clGray);
    SetPlotColor(3,clGray);
  end;

  //Proteção para os primeiros períodos de backtesting
  //Quando pode ocorrer divisão por zero
  if fMedia <> 0 then
  begin

    // Situação em que a media está no meio da barra
    if (fMedia >= Low) and (fMedia <= High)
    then bTocouMedia := True;

    // Situação em que a media está abaixo do preço
    // negociado e este chegou a cPercProximidade da
    // média
    if (fMedia < Low)
    and (((Low - fMedia)/MinPriceIncrement) <= cTicksProximidade)
    then
    begin
      bTocouMedia := True;
    end;

    // Situação em que a media está abaixo do preço
    // negociado e este chegou a cPercProximidade da
    // média
    if (fMedia > High)
    and (((fMedia - High)/MinPriceIncrement) <= cTicksProximidade)
    then
    begin
    bTocouMedia := True;
    end;

   if bTocouMedia then
     PlotText("Tocou",clWhite, - 1,8);

  end;

end;
				
			

Como acessar o Book de Ofertas em NTSL por nível de preço

Reproduzir vídeo

O exemplo abaixo demonstra como armazenar em um array os próximos N níveis de preço do book e obter as quantidades apregoadas para estes níveis no lado da compra e da venda.

OBS: Este código funciona apenas quando o mercado está aberto, não sendo possível fazer backtesting de estratégias baseadas em leitura de book. Isso é algo comum às demais plataformas de trading.

				
					const
  cQtdeNiveis = 4;

input
  cAtivo("CASH3", feedBovespa);

var
  i: integer;
  fBookSell, fBookBuy: array[0..cQtdeNiveis] of float;
  fBookSellSum, fBookBuySum: float;

begin

  for i:= 0 to cQtdeNiveis do
  begin
    fBookSellSum := TotalSellQtd(cAtivo,i+1);
    fBookBuySum :=  TotalBuyQtd(cAtivo,i+1);
    
    if i <> 0 then
    begin
      fBookSell[i] := fBookSellSum - TotalSellQtd(cAtivo,i);    
      fBookBuy[i] := fBookBuySum - TotalBuyQtd(cAtivo,i);
    end
    else
    begin
      fBookSell[i] := fBookSellSum;
      fBookBuy[i] := fBookBuySum;  
    end; 
  end;

  
  {
  // Comparando retorno das funções (Ask/Bid)Size com Total(Sell/Buy)Qtd
  plot(fBookSell[0]);
  plot2(fBookBuy[0]);
  SetPlotColor(1,clRed);
  SetPlotColor(2,clRed);

  plot3(AskSize);
  plot4(BidSize);
  SetPlotColor(3,clYellow);   
  SetPlotColor(4,clYellow);
  }

  // Comparando os 5 primeiros níveis do lado da compra
  plot(fBookBuy[0]);
  plot2(fBookBuy[1]);
  plot3(fBookBuy[2]);
  plot4(fBookBuy[3]);
  plot5(fBookBuy[4]);

  SetPlotColor(1,clRed);
  SetPlotColor(2,clRed);
  SetPlotColor(3,clRed);   
  SetPlotColor(4,clRed);
  SetPlotColor(5,clRed);
  


end
				
			

Criando o seu primeiro ROBÔ - V1

Reproduzir vídeo

Introdução

Neste documento vamos ver passo a passo de como criar o seu primeiro robô no Profit Chart DO ZERO…Você verá que com metodologia, organização e boas referências, programar um robô é uma tarefa relativamente fácil! Os verdadeiros desafios estão em outras partes do processo, e que abordaremos em outras oportunidades.

Eu já te prometo, desde já, que eu não vou te passar nenhum setup milagroso para te fazer rico. O objetivo deste documento não é te vender ilusões ou qualquer curso que seja. Eu quero te apresentar como eu vejo o processo de criação de um robô, que metodologia eu utilizo e você terá a real noção das dificuldades que enfrentará para desenvolver o seu próprio setup automatizado e, que se tudo der certo, um setup lucrativo!

Desde que o mundo é mundo, os vendedores sempre utilizaram a técnica de complicar as coisas para te vender facilidades, isso não é diferente nos dias de hoje…Então eu vou começar simplificando…Vou começar pelo começo! Eu criei o fluxograma abaixo para estabelecer uma linha guia de estrutura do nosso raciocínio.

Metodologia de Desenvolvimento de um Robô

A figura abaixo apresenta o fluxograma da metodologia aplicada no desenvolvimento de um robô. Vamos fazer uma passagem geral sobre a metodologia antes de aprofundar em cada etapa.

Tudo começa pela definição de um algoritmo. É daí que vem o termo algotrading….operações baseadas em algoritmos. No jargão popular, a gente chama de robô…e a Nelógica chama de “Estratégia de execução”…É tudo a mesma coisa!

E como é que achamos um algoritmo? Algoritmos, os bons algoritmos, não são achados por aí pela internet em vídeos de Youtube ou páginas sobre análise técnica. O máximo que você vai encontrar na internet são pessoas falando exatamente a mesma coisa, que são setups baseados em indicadores… quais são os sinais de entrada e sáida de cada setup. 

Apesar de haver muito chão a percorrer em termos de teste, validação, otimização e backtesting para pegar setups primários baseados em indicadores e transformá-los em algoritmos com alguma chance de sucesso, frequentemente você verá pessoas “vendendo” esses setups, ou até vendendo cursos, dizendo se tratar de estratégias infalíveis ou com alta taxa de acerto! Quem dera fosse fácil assim!

Quando o negócio é muito bom… Desconfie! Principalmente, se não puder ver o código fonte da estratégia que lhe está sendo recomendada! A verdade é que você pode até começar uma ideia por algum setup básico de análise técnica, mas terá que desenvolver por conta própria adaptações para chegar a um algoritmo capaz de rodar em conta real. E minha dica é: COMECE SIMPLES! 

Comece um algoritmo o mais simples possível. Rode as três etapas da metodologia e vá melhorando esse algoritmo em iterações sucessivas. Não tente abraçar o mundo logo na primeira implementação.

Uma vez que você tenha um algoritmo inicial, o próximo passo é escrever o código fonte. Esta etapa tem suas dificuldade técnicas de programação, mas você verá com o tempo que não se tratam das maiores dificuldades que encontrará no meio do caminho para desenvolver o seu robô!

Clique aqui para acessar os Modelos de estratégias, ou aqui para acessar a seção de Snippets!

Uma vez escrito o código fonte do algoritmo, sem erros de sintaxe. A gente vai rodar o robô com os dados disponíveis para verificar a aderência da execução do robô ao que havia sido planejado. Nesta terceira etapa, vamos procurar por erros e falhas no código e, se encontradas, vamos voltar à etapa anterior e ajustar a programação.

Agora que já tivemos uma visão geral das etapas, eu devo salientar que a metodologia de desenvolvimento de um robô não é tão linear como na figura apresentada anteriormente. Você verá que teremos muitas iterações entre as etapas, rodando vários ciclos de adaptações e  melhorias até chegar a uma versão de robô madura o suficiente para realizarmos a otimização de parâmetros e backtesting, visando verificar a sua viabilidade de execução em conta real. Mas isso é assunto para outra oportunidade. Por ora, vamos aprofundar em cada etapa nas seções abaixo.

Definindo o seu Algoritmo

Nesta primeira etapa precisamos definir com clareza (até onde podemos) como o robô deverá funcionar. Eu recomendo você abrir um bloco de anotações, físico ou virtual, e anotar suas respostas para as seguintes perguntas:

  1. Qual ativo pretendo operar?
  2. Meu robô vai operar comprado, vendido ou nos dois lados?
  3. Em que frequência gráfica ele vai operar? Ou vai operar de acordo com volatilidade em gráficos do tipo Renko?
  4. Quais indicadores técnicos vou utilizar?
  5. Quando ele deve abrir uma posição comprada? Em termos mais técnicos…qual é o sinal de compra? Faça a mesma pergunta para posição vendida! Desenvolva a resposta em termos de condições objetivas!
  6. Ele vai atuar apenas liquidando a posição ou vai permitir reversão de posição? Quais serão os sinais para cada situação?
  7. Meu robô vai segurar posição para swing trade ou só vai operar daytrade?
  8. Se não tiver sinal para liquidar ou reverter posição, como será definido o alvo da operação?
  9. Como será a administração das operações e a gestão de risco delas? Que técnicas de stoploss serão aplicadas? Vou utilizar stop com breakeven? Stop fixo? Stop móvel (Trailing stop)?

Eu sei que são muitas perguntas! Provavelmente você não tem resposta para todas as perguntas e algumas respostas poderão ser obtidas no processo de otimização da estratégia! O objetivo dessas perguntas é que você faça um brainstorming inicial!

Como a evolução natural nos ensina, a gente precisa se desenvolver de forma incremental! Primeiro a gente faz o simples funcionar e depois vamos aperfeiçoando e ajustando aos poucos…Aliás, essa é a filosofia de muitas diferentes metodologias de desenvolvimento de software… Então, não adianta começarmos pensando no mais complexo! Temos que simplificar ao máximo e escrever o código do nosso robô de forma iterativa, começando pela versão mais simples possível!

Escrevendo o Código-fonte

Esta é uma etapa bem “mão na massa”! Como já mencionei anteriormente, você poderá ganhar bastante tempo se aproveitar da experiência e informações compartilhadas pela Comunidade por meio dos Modelos de Estratégias e Snippets (exemplos de código fonte).

Minha recomendação é que comece o seu código fonte com organização desde o começo. Isso vai lhe ajudar a estruturar melhor, entender mais facilmente quando revisitar seu código ou até para que outra pessoa entenda seu código quando você o compartilhar.

Conte com a Comunidade e os fóruns disponíveis no site para te ajudar nessa etapa! 

Verificando a aderência do seu robô

Rodar um robô (estratégia de execução) em dados históricos, é bem fácil no Profit. Basta clicar no botão “Executar” e pronto! Mas fácil não quer dizerque seja  bom….tem muita coisa pra melhorar no editor de estratégias! Mas é o que temos por hoje temos que extrair o máximo que dá!

A primeira coisa que fazemos depois de rodar a primeira versão do robô (V1) é fazer uma inspeção visual para identificar erros grotescos de implementação! Por exemplo, você pode abrir o gráfico e não ter nenhuma sinalização de ordem. Ou ter apenas uma… Provavelmente, o seu código estaria com algum problema lógico.

Caso encontrasse algum problema, você teria que voltar ao código e tentar corrigir o problema, utilizando até o debug, que apesar de suas limitações é a ferramenta que dispomos para depurar o código fonte das estratégias.

O segundo filtro para identificar possíveis problemas é acessar a aba “Operações” ou “Gráfico de Operações” do modo “Estatísticas”, e inspecionar por problemas óbvios….Operações com lucros ou prejuízos muito grandes, ou operações com duração muito longa, características das operações que você não esperaria encontrar de acordo com os critérios do seu robô.

Caso encontrasse algum problema, você voltaria ao gráfico de simulação e verificaria a operação problemática, analisando o que pode ter ocorrido de diferente do previsto, inclusive depurando por meio de breakpoints.

Um ponto muito importante nessa etapa é tomar o cuidado para utilizar apenas os 70% dos dados históricos disponíveis e mais antigos. E por que disso? Porque os 30% restante dos dados, que são mais recentes serão utilizados para etapa de backtesting. 

É muito importante testar, validar e otimizar seu robô em uma janela de dados distinta da janela de dados de backtesting! A razão é meio óbvia, se você otimizar sua estratégia para todos os dados disponíveis, você pode estar ajustando o robô para as situações específicas daqueles dados e terá por consequência (ou ao menos se espera) que você encontre bons resultados! 

O que queremos no backtesting é verificar se o robô é capaz de generalizar bem com outros dados. Então não se esqueça de limitar sua análise nesta etapa de teste apenas aos dados que não serão usados no backtesting!

Colocando o Robô para rodar em conta real!

Executei as etapas 1, 2 e 3! Já posso colocar meu robô para rodar em conta real? Muito provavelmente a resposta é NÃO!

Lembra-se que eu disse que o processo de desenvolvimento de um robô é iterativo? Veja a figura abaixo para entender o que eu quis dizer com isso!

Dificilmente você conseguirá em uma única iteração do processo, chegar a um bom robô! Até pode…mas isso é altamente improvável.

Uma vez desenvolvido o código fonte da primeira versão do robô, vamos analisar o desempenho dele por meio de métricas objetivas, tais como taxa de acerto, relação risco ganho, lucro líquido, máximo drawdown.

Em seguida vamos postular ajustes que poderiam ser feitos para melhorar a métrica desejada. Geralmente, você irá buscar identificar aspectos relacionados à: ponto de abertura das operações, administração dos trades e gestão de risco, ponto de encerramento das operações.

Vamos fazer isso de forma iterativa até que cheguemos a uma situação de desempenho aceitável. É importante ter um diário do que está sendo alterado de uma versão para outra, guardar as principais métricas em uma planilha, bem como salvar o código fonte intermediário para não se perder no meio das iterações. Lembre-se, organização é muito importante para não perder o foco e gastar tempo desnecessário tentando entender o que você fez!

 

Exemplo de desenvolvimento de um robô

Para dar um exemplo prático e tornar mais tangível o processo de criação de um robô, eu utilizei um caso clássico de setup da literatura de indicadores técnicos para seguir tendência, em inglês, trend following system. Apesar de clássico, ou seja, existe há mais de 1 século, muita gente tira da cartola essa ideia todo ano, como se fosse inovadora.

A primeira versão do setup que iremos trabalhar ao longo deste documento e dos próximos, que vou chamar originalmente de Cruzamento triplo de médias móveis terá as seguintes definições:

  • Vai operar no mercado de ações permitindo swing trade;
  • Só vai operar comprado;
  • Vai utilizar 3 três médias móveis exponenciais de 10 (média rápida), 50 (média intermediária) e 200 (média lenta) períodos;
  • Vai operar em gráfico candle 15 minutos
  • Sinal de compra será o cruzamento da média intermediaria para cima da média lenta, estando a média rápida acima da média intermediária
  • Sinal de liquidação será média rápida cruzando para baixo a média intermediária;
  • Na primeira versão não será utilizado stoploss.

Pessoal, só para reforçar…este é um exemplo… não estou preocupado se é uma estratégia lucrativa ou não…Se funciona nos dias atuais ou não…Aliás já adianto que a taxa de acerto de setups básicos de cruzamento de médias é baixíssima…Isso é bom para fins didáticos. Vamos ter muito espaço para explorar!

Assista ao vídeo do Youtube que fizemos sobre a metodologia de criação de um robô e execução da primeira iteração do processo resultando na versão 1 (V1), conforme código fonte abaixo.

No próximo documento iremos realizar, na prática, sucessivas iterações a fim de melhorar o desempenho do algoritmo inicialmente proposto.

Nos vemos lá!

Robô de Cruzamento triplo de média móvel (V1)

Segue abaixo o código fonte gerado para primeira versão do robô de Cruzamento triplo de média móvel.

				
					// #######################################################################
// #######################################################################
// #######################################################################
// ######                            O                             #######
// ######                        ____|____                         #######
// ######                      _|         |_                       #######
// ######                     (_|  O   O  |_)                      #######
// ######                       |_________|                        #######
// ######                                                          #######
// ###### ____        __        ____________           ________    #######
// ###### | | \       | |       | |_________|         /  ____  \   #######
// ###### | |\ \      | |       | |                  /  /    \  \  #######
// ###### | | \ \     | |       | |____             |  |      |  | #######
// ###### | |  \ \    | |       | |____|            |  |      |  | #######
// ###### | |   \ \   | |       | |____|            |  |      |  | #######
// ###### | |    \ \  | |       | |                 |  |      |  | #######
// ###### | |     \ \ | |       | |_________         \  \____/  /  #######
// ###### |_|      \_\|_|       |_|_________|         \________/   #######
// ######                                                          #######
// ###### _______  __          __   ____  __   ___    __  _______  #######
// ######    |    |  \   /\   |  \ |     |  \ |   \  /  \    |     #######
// ######    |    |__/  /__\  |   ||__   |__/ |___/ |    |   |     #######
// ######    |    |\   /    \ |   ||     |\   |   \ |    |   |     #######
// ######    |    | \ /      \|__/ |____ | \  |___/  \__/    |     #######
// ######                                                          #######
// ######  Comunidade aberta de automatização de estratégias para  #######
// ######                    negociação de ativos                  #######
// ######                                                          #######
// ######                    www.NeoTraderBot.com                  #######
// #######################################################################
// #######################################################################
// #######################################################################
//
// -----------------------------------------------------------------------
// ---------------------- DADOS DA ESTRATÉGIA ----------------------------
// -----------------------------------------------------------------------
//
// NOME DA ESTRATÉGIA: _NBT_EXE_3CROSS
//   DESENVOLVIDA POR: Johnathas Carvalho
//    DATA DE CRIAÇÃO: 02/10/2022
//             VERSÃO: 1.0
//      ATUALIZADA EM: 02/10/2022
// TIPO DE ESTRATÉGIA: ( ) Indicador  ( ) Coloração (X) Execução
//                     ( ) Screening  ( ) Texto     ( ) Alarme
//
// DESCRIÇÃO DA ESTRATÉGIA:
// Estratégia baseada em cruzmaento triplo de média móvel
//
//
// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
//
// ######################### FIM DO CABEÇALHO ############################
//
//
// -----------------------------------------------------------------------
// -------------------------- Constantes ---------------------------------
// OBS:
// -----------------------------------------------------------------------
const
  cPlotarIndicadores = true;
  //
  // ---------------------------------------------------------------------
  // -------------------------- Parâmetros -------------------------------
  // OBS: Segue abaixo a descriação de cada parâmetro
  // 1) pLimiteSobreComprado -> Limite no qual considera-se que o cruzamento
  // para baixo gere uma operação de venda
  // 2) pLimiteSobreVendido -> Limite no qual considera-se que o cruzamento
  // para cima gere uma operação de compra
  // 3) pTamanhoPosicao -> Tamanho da exposição ao ativo
  // ---------------------------------------------------------------------
//input
//  pMediaRapida(10);
//  pMediaIntermediaria(50);
//  pMediaLenta(200);
//  pTamanhoPosicao(100);
  // ---------------------------------------------------------------------
  // ---------------------- Variáveis globais ----------------------------
  // OBS:
  // ---------------------------------------------------------------------
var
  bStarted                                     : boolean;
  bSinalCompra,bSinalVenda,bSinalLiquida       : boolean;
  bComprado,bVendido                           : boolean;
  fMediaRapida,fMediaIntermediaria,fMediaLenta : float;

  //Parametros
  pMediaRapida: integer;
  pMediaIntermediaria: integer;
  pMediaLenta: integer;
  pTamanhoPosicao: integer;

begin
  pMediaRapida := 10;
  pMediaIntermediaria := 50;
  pMediaLenta := 200;
  pTamanhoPosicao := 100;

  // ---------------------------------------------------------------------
  // ----------------- Inicialização da estratégia -----------------------
  // OBS: Inicialização de variáveis a serem utilizadas na estratégia de
  // execuçaõ
  // ---------------------------------------------------------------------
  if Not bStarted then
    begin
      bStarted := True;
    end;
  // ---------------------------------------------------------------------
  // ------------------ Inicialização de variáveis -----------------------
  // OBS: Inicialização de variáveis p/ cada tick/barra
  // Nem todas as variáveis são inicializadas aqui porque se não houver
  // dados suficientes não faz sentido inicializar algumas variáveis
  // ---------------------------------------------------------------------
  bSinalCompra := False;
  bSinalVenda := False;
  bSinalLiquida := False;
  bComprado := isBought();
  bVendido := isSold();

  fMediaRapida := Media(pMediaRapida,Close);
  fMediaIntermediaria := Media(pMediaIntermediaria,Close);
  fMediaLenta := Media(pMediaLenta,Close);


  //BUG: Se não tiver algum plot antes dos comandos de backtesting, não funciona!
  if cPlotarIndicadores then
    begin
      SetPlotColor(1,clRed);
      SetPlotWidth(1,2);
      SetPlotStyle(1,psDash);
      SetPlotColor(2,clOlive);
      SetPlotWidth(2,2);
      SetPlotColor(3,clWhite);
      SetPlotWidth(3,2);
      Plot(fMediaRapida);
      Plot2(fMediaIntermediaria);
      Plot3(fMediaLenta);
    end;

  // ---------------------------------------------------------------------
  // ----------------------- Cálculo dos sinais  -------------------------
  // OBS: Inserir lógica de cálculo dos sinais de compra/venda
  // ---------------------------------------------------------------------
  if (fMediaLenta <> 0) then
  begin
    if  (fMediaRapida >= fMediaIntermediaria)
    and (fMediaIntermediaria > fMediaLenta) 
    and (fMediaIntermediaria[1] <= fMediaLenta[1]) then
        bSinalCompra := True;
    
    if  bComprado 
    and (fMediaRapida < fMediaIntermediaria) 
    and (fMediaRapida[1] >= fMediaIntermediaria[1]) then
        bSinalLiquida := True;
  end;
  // ---------------------------------------------------------------------
  // ------------------- Envia ordens de compra/venda --------------------
  // OBS: Baseando-se nos sinais e na atual posição, cria as ordens de
  // compra e venda de acordo com o setup desejado
  // ---------------------------------------------------------------------
  // Abre posição comprada
  if Not (bComprado Or bVendido) and bSinalCompra then BuyAtMarket(pTamanhoPosicao);

  // Encerra posição comprada
  if (bComprado and bSinalLiquida) then SellToCoverAtMarket(pTamanhoPosicao);


end;
				
			

Melhorando o desempenho do seu robô

Reproduzir vídeo

No documento anterior, vimos o processo de criação de um robô, passo a passo, por meio de um exemplo de setup baseado no cruzamento de três média. Um setup clássico da análise técnica. Se você ainda não viu esse conteúdo, clique aqui antes de prosseguir com a leitura.

Nosso objetivo neste documento é ajustar e melhorar a implementação do nosso algoritmo. Pense nele como um diamante que precisamos lapidar. Iremos de forma iterativa, ou seja, em etapas graduais, trazer o brilho do nosso algoritmo bruto. Explorar o máximo possível da ideia originária e aumentar o seu potencial para as etapas subsequentes de otimização e backtesting.

Para isso, precisamos seguir uma linha de raciocínio, uma metodologia do que verificar na execução do código fonte da nossa estratégia, em que sequência e o que fazer.

Não existe uma fórmula fechada para isso, poderíamos começar por caminhos diferentes, trocar a ordem de alguns passos…isso vai depender dos resultados obtidos no teste e como você pretende priorizar os ajustes! O objetivo final é obter um algoritmo mais refinado do que a versão bruta original. Em outras palavras, um algoritmo com maior chance de ser lucrativo.

Isso quer dizer que o sucesso é garantido? Não! Haverá casos, e estes serão a maioria deles, em que por mais que trabalhemos em ajustes do código, o desempenho refinado do algoritmo não será bom! Isso faz parte do processo de elaboração de robôs…acostume-se! Nem todas ideias que a primeira vista parecem ser muito boas, vão se confirmar durante o processo. O que importa é o quanto você vai aprender cada vez que tentar criar um novo robô…pois isto permitirá acelerar o processo cada vez que executa-lo novamente.

Dito isso, vou apresentar a seguir um diagrama das etapas percorridas para melhorar o código fonte de uma estratégia/robô, representando uma metodologia para você seguir quando estiver trabalhando em suas próprias estratégias.

Metodologia

Antes de apresentarmos o diagrama das etapas metodológicas e explicar cada uma delas, precisamos esclarecer alguns pontos iniciais:

  • Ajustar código fonte não é otimizar estratégia;
  • Estabeleça uma configuração inicial de parâmetros para os indicadores da estratégia e mantenha esses valores fixos até o fim do processo;
  • A configuração dos parâmetros deve ser escolhida de forma a refletir uma condição razoável do setup, a qual permita que ajustes no código fonte tenham reflexos na métricas que iremos monitorar;
  • Recomenda-se incorporar a gestão de risco das operações no processo de otimização da estratégia;
  • Se sua estratégia não tiver uma regra para encerramento de posição, estabeleça uma relação de risco/retorno entre 2:1 e 3:1, apenas para proceder o processo de ajuste do código fonte. Utilize valores razoáveis de stop e alvo em função da volatilidade média do ativo;
  • Os ajustes do código fonte devem ser realizados em fluxos distintos para posições compradas e vendidas, visando aprimorar o código fonte para cada posição de forma independente. A decisão sobre quais posições a estratégia deve abrir dependerá do processo de otimização junto aos resultados obtidos em backtesting.

Feitas essas ressalvas, veja o diagrama abaixo das etapas sequências que iremos executar para ajustar o código fonte da nossa estratégia. As etapas de “Restrições primárias de operação” e “Definição de baseline” são fundamentais e serão executadas necessariamente nessa ordem. No entanto, as demais etapas são intercambiáveis e sua ordem de execução pode ser alterada/suprimida a depender do objetivo do programador.

Vamos ver nas próximas seções maiores detalhes sobre cada etapa.

1) Restrições primárias de operação

Neste primeiro passo, vamos identificar se a estratégia/ robô está operando conforme planejado em termos de duração e quantidade de papéis para cada posição.

Se for um robô de daytrading, temos que garantir que ele não está carregando posições de um dia para outro. E temos que verificar se as quantidades negociadas de papéis ou contratos estão conforme estabelecido pela nossa estratégia.

Se nossa estratégia operar em gráficos de Renko, temos que certificar que operações não estão sendo executadas em boxes de gaps (o que não é possível na prática!).

Enfim, nesta etapa iremos verificar e proceder ajustes a fim de garantir que as futuras alterações no código sejam avaliadas sob as mesmas bases e de forma correta.

2) Definição de baseline

Primeiramente, precisamos definir um intervalo fixo de datas para execução de testes e futuramente, otimização da estratégia. Precisamos fixar também a quantidade de papéis ou contratos que serão negociados, o ativo e o tempo gráfico a ser usado. Estas configurações devem se manter constante até o fim do processo, bem como os parâmetros dos indicadores utilizados.

Usualmente iremos separar da janela histórica de dados da seguinte forma, 50% dos dados mais antigos para ajustes da estratégia e otimização, os 30% dos próximos dados para realização de backtesting, e os últimos 20% para simular a operação do robô em uma execução em tempo real. Estes não são percentuais fixos, cabendo ao programador arbitrar uma divisão que seja melhor para cada caso.

O importante dessa segregação de dados é garantir que não haverá interseção da janela de dados utilizada para testes e otimização do código fonte, backtesting e avaliação com dados novos.

Para dar suporte a todo o processo de ajustes, recomendamos que o programador crie um diretório em seu computador para a estratégia ora em ajuste a armazene todos os artefatos do processo: versões do código fonte sempre que for feita uma alteração que gere uma versão intermediária (em formato txt) e relatório de trades realizados do Profit. Se você é membro da Comunidade, baixe a ferramenta ANALISADOR DE TRADES para realizar este processo de forma eficiente e estruturada..

Uma vez executado o código fonte original na janela de dados históricos definida, iremos monitorar e considerar os valores das métricas Taxa de acerto (%), Relação risco/ganho, quantidade de trades e resultado líquido como base de referência para o próximo ajuste no código fonte.

3) Refinamento dos sinais de entrada

Nesta etapa iremos analisar a relação de trades realizados pelo código original e verificar no gráfico os motivos que levaram as operações a dar prejuízo em termos dos sinais criados. Em outras palavras, queremos reduzir a probabilidade de falsos positivos. Queremos refinar nossos sinais de entrada das operações, para não incorrer em abertura de posição em situações com alta probabilidade de fracasso. Queremos, portanto, melhorar a nossa taxa de acerto e, possivelmente, a relação risco/ganho.

É importante ressaltar que não estamos otimizando o código ainda. Não vamos durante o ajuste do nosso código ficar alterando a quantidade de períodos de médias e parâmetros de indicadores. Esse não é o objetivo….isso ficará para outra etapa, que é a otimização do algoritmo, quando ele já estiver com a lógica refinada.

Nesta etapa, assim como nas subsequentes, as alterações serão incrementais. Ou seja, faremos um ajuste de cada vez, avaliaremos as métricas e, em seguida, iremos acrescentar outro ajuste ao código. Desta forma, cada versão do código fonte terá as alterações realizadas até o momento. Daí, a importância de manter um controle organizado das versões do código fonte e o adequado arquivamento dos trades realizados por cada versão para o cálculo das métricas de cada versão.

4) Filtro de operações de acordo com condição de mercado

Neste momento, vamos focar nossa atenção nas operações que ainda estão gerando prejuízo e vamos ver se existe um padrão entre as operações. Ou seja, se há uma situação de mercado comum que aumenta a chance de operações não serem bem sucedidas. Estaremos procurando coisas do tipo…todas operações com prejuízo tiveram abertura antes de X horas, ou ocorreram quando o mercado estava lateralizado, ou quando o plano de fundo do mercado era um movimento altista, baixista, etc…

Observe que não somos obrigados a fazer um ajuste em cada etapa só porque a etapa existe. Vamos fazer ajustes apenas se estes fizerem sentido e os manteremos no código apenas se o resultado melhorar. Caso alguma alteração retroceda um bom resultado de uma versão anterior, iremos sempre levar a frente nas próximas etapas a melhor versão até o momento.

5) Verificação de oportunidades perdidas

Analisar uma lista fechada de trades e buscar padrões é relativamente “fácil”…Mas nessa etapa teremos que  procurar pelo invisível…tentaremos identificar no gráfico aquilo que não vemos na lista de trades!

Teremos que voltar ao gráfico e realizar uma inspeção visual minuciosa do início do intervalo de teste até o fim, procurando não aquilo que foi feito…mas o que não foi feito e que se tivesse feito poderia ter gerado lucro. É claro, vamos olhar com as lentes do nosso algoritmo original….sem ficar criando novas regras. Podemos trabalhar no relaxamento do sinal de entrada, permitindo uma flexibilidade temporal em relação ao atendimento das condições para abertura de posição, por exemplo.

6) Refinamento do fechamento de posições

Neste passo vamos analisar se o encerramento de posição está ocorrendo em momento adequado, ou se há algum atraso neste encerramento que esteja  reduzindo o lucro das operações.

Podemos tentar utilizar de projeções para antecipar um encerramento de posição em momento mais vantajoso. Observe que não estamos tratando da gestão de risco das operações, como definição de alvo e stoploss…isto iremos fazer numa etapa posterior do processo de criação do robô, quando formos realizar a otimização da estratégia.

No entanto, caso a sua estratégia não tenha uma regra para liquidação de posição, você deve arbitrar um relação fixa de stop e alvo para que possamos avaliar o impacto das alterações do código fonte nas métricas de desempenho da estratégia. Esta relação deve ser razoável e deveria ter sido realizada no momento de geração do baseline. Caso isto não tenha sido feito, você precisará voltar na etapa de definição de baseline e rodar o código fonte de cada alteração com esta relação de encerramento de posição.

Caso neste momento, você identifique uma regra fixa para encerramento de posição no seu algoritmo, então o recomendável é atualizar o seu algoritmo e reiniciar o processo de ajustes do código fonte.

7) Melhorando a tempestividade das ordens

Esse passo se aplica às ordens à mercado utilizadas para abrir posições. É de conhecimento geral que, até o presente momento, o envio de ordens à mercado ocorre apenas no fechamento do Candle ou box, o que pode gerar um atraso muito grande na abertura da posição, dependendo do tempo gráfico utilizado pela estratégia.

Assim, uma possível solução para esta questão é executar o robô em uma frequência superamostrada realizando os ajustes necessários para manter o comportamento coerente a um tempo gráfico original. O nível de complexidade, bem como a viabilidade desses ajustes depende dos indicadores utilizados.

Aumentar a tempestividade das ordens não garante necessariamente resultados melhores. Assim, o programador deve avaliar se é justificável testar a estratégia em frequência superamostrada.

Um ponto importante é referente à disponibilidade de dados dados históricos. Quanto mais se aumentar a frequência, menor será a quantidade de dados disponíveis para teste, impedindo um comparação com as versões anteriores do código na mesma janela de dados. É importante verificar se a quantidade de trades realizados garante uma amostra com confiabilidade estatística adequada.

Conclusão

Apresentamos neste documento uma metodologia para guiar o processo de ajustes e refinamentos do código fonte de sua estratégia/robô.

A importância de seguir uma metodologia e organização do processo é aumentar a chance de obter ao fim do processo um resultado de desempenho do robô dentro dos critérios de aceitação do programador.

Nem sempre conseguiremos obter uma estratégia com desempenho aceitável, o que pode justificar não levar para a fase de otimização tal estratégia. No entanto, para cada insucesso, fica o acúmulo de experiência do programador, que terá cada vez mais facilidade e ferramentas para realizar o processo com estratégias futuras.

Observe que até o momento não falamos de Gestão de risco da estratégia. Pois eu defendo que a gestão de risco fará parte do processo de otimização, o qual será tema em outros documentos desta Base de Conhecimento!

Por fim, no melhor caso, o programador irá finalizar as etapas acima mencionadas com uma versão refinada do código fonte, que não necessariamente será última versão testada (pode ser uma intermediária), que irá avançar para a fase de otimização da estratégia.

Espero que este conteúdo seja útil para o leitor e contribua para o seu processo de desenvolvimento de estratégias.

Versão final do Código fonte para otimização

Para baixar todos os artefatos gerados pelo processo executado no vídeo (código fonte das versões, csv de trades e Analisador de trades), clique aqui.

OBS: A restrição de tipo de gráfico e tempo gráfico está comentada devido a um bug do Profit para execução da estratégia em backtesting.

				
					// #######################################################################
// #######################################################################
// #######################################################################
// ######                            O                             #######
// ######                        ____|____                         #######
// ######                      _|         |_                       #######
// ######                     (_|  O   O  |_)                      #######
// ######                       |_________|                        #######
// ######                                                          #######
// ###### ____        __        ____________           ________    #######
// ###### | | \       | |       | |_________|         /  ____  \   #######
// ###### | |\ \      | |       | |                  /  /    \  \  #######
// ###### | | \ \     | |       | |____             |  |      |  | #######
// ###### | |  \ \    | |       | |____|            |  |      |  | #######
// ###### | |   \ \   | |       | |____|            |  |      |  | #######
// ###### | |    \ \  | |       | |                 |  |      |  | #######
// ###### | |     \ \ | |       | |_________         \  \____/  /  #######
// ###### |_|      \_\|_|       |_|_________|         \________/   #######
// ######                                                          #######
// ###### _______  __          __   ____  __   ___    __  _______  #######
// ######    |    |  \   /\   |  \ |     |  \ |   \  /  \    |     #######
// ######    |    |__/  /__\  |   ||__   |__/ |___/ |    |   |     #######
// ######    |    |\   /    \ |   ||     |\   |   \ |    |   |     #######
// ######    |    | \ /      \|__/ |____ | \  |___/  \__/    |     #######
// ######                                                          #######
// ######  Comunidade aberta de automatização de estratégias para  #######
// ######                    negociação de ativos                  #######
// ######                                                          #######
// ######                    www.NeoTraderBot.com                  #######
// #######################################################################
// #######################################################################
// #######################################################################
//
// -----------------------------------------------------------------------
// ---------------------- DADOS DA ESTRATÉGIA ----------------------------
// -----------------------------------------------------------------------
//
// NOME DA ESTRATÉGIA: _NBT_EXE_3CROSS
//   DESENVOLVIDA POR: Johnathas Araujo de Carvalho
//    DATA DE CRIAÇÃO: 16/09/2022
//             VERSÃO: 3.0
//      ATUALIZADA EM: 12/11/2022
// TIPO DE ESTRATÉGIA: ( ) Indicador  ( ) Coloração (X) Execução
//                     ( ) Screening  ( ) Texto     ( ) Alarme
//
// DESCRIÇÃO DA ESTRATÉGIA:
//      Esta estratégia visa realizar compras mediante o cruzamento triplo
// de médias móveis exponenciais.
//
// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
//
// ######################### FIM DO CABEÇALHO ############################
//
//
// -----------------------------------------------------------------------
// -------------------------- Constantes ---------------------------------
// OBS:
// -----------------------------------------------------------------------
const
  cPlotarIndicadores = true;
  cProtecaoGap = 101.5;
    
  //
  // ---------------------------------------------------------------------
  // -------------------------- Parâmetros -------------------------------
  // OBS: Segue abaixo a descriação de cada parâmetro
  // 1) pLimiteSobreComprado -> Limite no qual considera-se que o cruzamento
  // para baixo gere uma operação de venda
  // 2) pLimiteSobreVendido -> Limite no qual considera-se que o cruzamento
  // para cima gere uma operação de compra
  // 3) pTamanhoPosicao -> Tamanho da exposição ao ativo
  // ---------------------------------------------------------------------
//input
//  pMediaRapida(10);
//  pMediaIntermediaria(50);
//  pMediaLenta(200);
//  pTamanhoPosicao(100);
  // ---------------------------------------------------------------------
  // ---------------------- Variáveis globais ----------------------------
  // OBS:
  // ---------------------------------------------------------------------
var
  bStarted                                     : boolean;
  bSinalCompra,bSinalVenda,bSinalLiquida       : boolean;
  bComprado,bVendido                           : boolean;
  fMediaRapida,fMediaIntermediaria,fMediaLenta : float;

  //Parametros
  pMediaRapida: integer;
  pMediaIntermediaria: integer;
  pMediaLenta: integer;
  pTamanhoPosicao: integer;
  fTBDetector, fUltimoTopo, fUltimoFundo: float;

begin
  pMediaRapida := 10;
  pMediaIntermediaria := 30;
  pMediaLenta := 50;
  pTamanhoPosicao := 100;

  // ---------------------------------------------------------------------
  // ----------------- Inicialização da estratégia -----------------------
  // OBS: Inicialização de variáveis a serem utilizadas na estratégia de
  // execuçaõ
  // ---------------------------------------------------------------------
  if Not bStarted then
    begin
      bStarted := True;
    end;

  //if (GraphicInterval <> itMinute) or (GraphicOffset <> 15) then
  //  if LastBarOnChart then plotText("Mudar para 15 min!", clWhite, -1, 12)
  //else
  //begin 
    // ---------------------------------------------------------------------
    // ------------------ Inicialização de variáveis -----------------------
    // OBS: Inicialização de variáveis p/ cada tick/barra
    // Nem todas as variáveis são inicializadas aqui porque se não houver
    // dados suficientes não faz sentido inicializar algumas variáveis
    // ---------------------------------------------------------------------
    bSinalCompra := False;
    bSinalVenda := False;
    bSinalLiquida := False;
    bComprado := isBought();
    bVendido := isSold();
  
    fMediaRapida := MediaExp(pMediaRapida,Close);
    fMediaIntermediaria := MediaExp(pMediaIntermediaria,Close);
    fMediaLenta := MediaExp(pMediaLenta,Close);
    fTBDetector := TopBottomDetector(4);

    if (fTBDetector <> 0) and (fTBDetector >= Close) then fUltimoTopo := fTBDetector;
    if (fTBDetector <> 0) and (fTBDetector <= Close) then fUltimoFundo := fTBDetector;


    if cPlotarIndicadores then
      begin
        SetPlotColor(1,clRed);
        SetPlotWidth(1,2);
        SetPlotStyle(1,psDash);
        SetPlotColor(2,clOlive);
        SetPlotWidth(2,2);
        SetPlotColor(3,clWhite);
        SetPlotWidth(3,2);
        Plot(fMediaRapida);
        Plot2(fMediaIntermediaria);
        Plot3(fMediaLenta);
      end;
  
    

    // ---------------------------------------------------------------------
    // ----------------------- Cálculo dos sinais  -------------------------
    // OBS: Inserir lógica de cálculo dos sinais de compra/venda
    // ---------------------------------------------------------------------
    if (fMediaLenta <> 0) then
    begin
      if  (fMediaRapida >= fMediaIntermediaria)
      and (fMediaIntermediaria > fMediaLenta) 
      and (fMediaIntermediaria[1] <= fMediaLenta[1])  then
      begin
        if (fMediaRapida/fMediaLenta*100 <= cProtecaoGap) then
        if  (fMediaLenta > fMediaLenta[1])
        and (fMediaLenta[1] > fMediaLenta[2]) then
        if  (fMediaRapida > fMediaRapida[1]) 
        and (fMediaRapida[1] > fMediaRapida[2]) then
        if Not ((Close <= fUltimoTopo) and (Close >= fUltimoFundo)) then
        if Not (Close <= fUltimoFundo) then
          bSinalCompra := True;
      end;
      
      if  bComprado 
      and (fMediaRapida < fMediaIntermediaria) 
      and (fMediaRapida[1] >= fMediaIntermediaria[1]) then
          bSinalLiquida := True;
    end;
    // ---------------------------------------------------------------------
    // ------------------- Envia ordens de compra/venda --------------------
    // OBS: Baseando-se nos sinais e na atual posição, cria as ordens de
    // compra e venda de acordo com o setup desejado
    // ---------------------------------------------------------------------
    // Abre posição comprada
    if Not (bComprado Or bVendido) and bSinalCompra then BuyAtMarket(pTamanhoPosicao);
  
    // Encerra posição comprada
    if (bComprado and bSinalLiquida) then SellToCoverAtMarket(pTamanhoPosicao);

  //end;

end;
				
			

Outros Snippets

Introdução

Esta seção visa apresentar outros exemplos de trechos de códigos que não se enquadram nas categorias anteriores.

Você pode acessar os Snippets diretamente pelo menu lateral direito, ou fazendo CRL+F (CTRL+L) para localizar algum texto específico na página, uma vez que o conteúdo tende a crescer ao longo do tempo, dificultando a navegação pelo menu.

Caso tenham sugestões de código para acrescentar à lista, gentileza deixar o código nos comentários com o link para seu perfil em rede social (para devido crédito de autoria).

Snippets

Escrevendo no Console com Timestamp para facilitar Debug

A partir da versão beta 215, tornou-se possível no Backtesting escrever texto no Console, o que facilita a depuração de estratégias.

Segue abaixo um snippet no qual há uma função que retorna o timestamp da barra. O corpo principal da estratégia apenas gera na aba “Compilação” o log com mensagem “Teste” precedido do timestamp no formato “DD/MM/AAAA HH:MM”.

				
					var
  horario: integer;
  timestamp : string;


//---------------------------------------------------
function getTimestamp: string;
var
  dia, mes_ano, hora: string;
begin

  if Month(Date) < 10 then 
    mes_ano := "0" + Month(Date) + "/" + Year(Date)
  else
    mes_ano := Month(Date) + "/" + Year(Date);    

  if DayofMonth(Date) < 10 then
    dia := "0" + DayofMonth(Date) + "/" + mes_ano
  else 
    dia := DayofMonth(Date) + "/" + mes_ano;

  if Floor(Time/100) < 10 then
    hora := "0" + Floor(Time/100)
  else
    hora := Floor(Time/100);

  if Mod(Time,100) < 10 then
    hora := hora + ":" + "0" + Mod(Time,100)
  else
    hora := hora + ":" + Mod(Time,100);    

  Result :=  dia + " " + hora + " - ";
end;
//---------------------------------------------------

begin
  if horario <> Time then
  begin
    timestamp := getTimestamp;
    ConsoleLog(getTimestamp() + "Teste", clBlue);
    horario := Time;
  end;
  
end;





				
			

Arrendondamento de valores para N casas decimais

Reproduzir vídeo

Como o Profit não tem nativamente uma função para arrendondar um float para uma determinada quantidade de casas decimais (N), a função abaixo foi implementada com esta finalidade.

				
					var
  fValorOriginal: float;
  fValorArred: float;

function NTB_ArredondarFloat(Value: float; nCasas: integer):float;
var
    fValor: float;
    fParteInteira: float;
    fParteDecimal: float;
begin
  fValor := Value;
  fParteInteira := IntPortion(fValor);
  fParteDecimal := Round((fValor - fParteInteira)*Power(10,nCasas));

  Result := fParteInteira + fParteDecimal/Power(10,nCasas);

end;

begin
  fValorOriginal := 12.345819;
  fValorArred :=  NTB_ArredondarFloat(fValorOriginal,2);

  if LastBarOnChart then
    PlotText(fValorArred,clWhite, - 1,8);
end;
				
			

Restrição de estratégia pelo código do ativo

O código abaixo visa identificar o código do ativo no qual a estratégia ou robô está sendo aplicado. A estratégia apenas é executada se o ticker do ativo for igual a constante “cAtivoEstrategia”.

Isto evita que as estratégias sejam rodadas de forma equivocada em ativos para os quais os parâmetros da estratégia não foram otimizados.

				
					const
  cAtivoEstrategia = "PETR4";
begin
  if GetAsset = cAtivoEstrategia then
  begin
    //TODO CÓDIGO FONTE DA SUA ESTRATÉGIA DEVE ESTAR AQUI DENTRO
    PaintBar(clGreen);
  end
  else
    if LastBarOnChart then
      plotText("Usar em " + cAtivoEstrategia,clWhite,-1,12);
end
				
			

Restrição de estratégia pelo tipo/frequência do gráfico

Reproduzir vídeo

O código abaixo visa identificar o tipo de gráfico no qual a estratégia ou robô está sendo aplicado. Caso não corresponda ao tipo de gráfico para o qual a estratégia foi otimizada, é exibida mensagem com informação sobre o tipo de gráfico adequado.

Isto evita que as estratégias sejam rodadas de forma equivocada para tipos de gráficos e frequências temporais diferentes daquelas para as quais foi validada.

				
					var
  bStarted, bGraficoOK: boolean;
  iTipoGrafico: integer;
  strMensagemErro: string;
begin
  if Not bStarted then
  begin
    bStarted := true;
    iTipoGrafico := GraphicInterval;

    //Verificação de Renko 3R
    if (iTipoGrafico = itRenko) and (GraphicOffset = 3) then bGraficoOK := true
    else strMensagemErro := "Estratégia para 3R"; 
    
    //Verificação de Gráfico de 5 minutos    
    //if (iTipoGrafico = itMinute) and (GraphicOffset = 5) then bGraficoOK := true
    //else strMensagemErro := "Estratégia para 5 Minutos";
         
  end;

  // Robô/Estratégia só irá ser executada se o gráfico estiver configurado
  // adequadamente
  if bGraficoOK then
  begin


  end
  // Se gráfico não estiver na configuração adequada, pinta todas as barras de vermelho
  // e exibe texto na última barra
  else
  begin
  paintBar(clRed);
  if LastBarOnChart then
    plotText(strMensagemErro,clWhite,-1,9);
  end;

end
				
			

Ignorar boxes de Gap em gráficos de Renko

Reproduzir vídeo

É bastante comum, principalmente na operação de contratos futuros, a ocorrência de gaps na abertura. Quando se está em um gráfico de Renko, o código da estratégia é processado para cada box incluído no gráfico devido ao gap.

Este código apresenta uma forma simples de não executar lógica sobre boxes referentes à gap. Os boxes de gap possuem duração igual a zero. Para realizar a verificação da duração temporal em minutos de um box, basta utilizar o comando BarDurationF.

				
					var
  bLocalizouBoxesGap : boolean;
  iDataUltimoBox, iUltimoBoxDiaAnterior, iBoxDeGAP: integer;
begin
  
  // Código é aplicável apenas à gráficos do tipo Renko
  if GraphicInterval = itRenko then
  begin  
    // Identificação de Box relacionados a GAP
    if Date <> iDataUltimoBox then
    begin
      iUltimoBoxDiaAnterior := CurrentBar - 1;
      iBoxDeGAP := CurrentBar;
      bLocalizouBoxesGap := false;
    end;
  
   iDataUltimoBox := Date;
   
   if Not bLocalizouBoxesGap then
    if BarDurationF = 0 then 
    begin
      iBoxDeGAP := CurrentBar;
      PaintBar(clRed);
    end
    else
    begin
      //Aqui foi identificado o primeiro box que não é de GAP
      bLocalizouBoxesGAP := true;
    end;


    //Aqui executa a estratégia em boxes que não são devido à
    //gap de abertura
    if bLocalizouBoxesGAP then
    begin
      PaintBar(clGreen);
    end;



  end
  // O Gráfico não é do tipo Renko!
  else
    if LastBarOnChart then PlotText("Aplicável apenas a Renko",clWhite,-1,10);

end
				
			

Cálculo de Gap em gráficos de Renko em termos de boxes

É bastante comum, principalmente na operação de contratos futuros, a ocorrência de gaps na abertura. Este código visa calcular o tamanho do gap nos gráficos de Renko em termos da quantidade de boxes.

OBS: É importante ressaltar que devido à própria natureza do gráfico de Renko, o cálculo de gap não é preciso quanto o cálculo de gap pelo gráfico de Candle.

OBS2: Os comandos OpenD(0) e CloseD(1) também podem ser utilizados em gráficos de renko, reduzindo o código abaixo a gap := (OpenD(0) – CloseD(1))/((GraphicOffset-1)*MinPriceIncrement). No entanto, os valores encontrados divergem em alguns dias de gap por 1 box. Pela minha apuração, o código abaixo apresenta os resultados corretos.

				
					var
  bLocalizouBoxesGap : boolean;
  fTamanhoBox : float;
  iDataUltimoBox, iUltimoBoxDiaAnterior, iBoxDeGAP: integer;
  fGAPdoDiaBox, fAberturaBox, fFechamentoDiaAnteriorBox: float;
begin
  
  // Código é aplicável apenas à gráficos do tipo Renko
  if GraphicInterval = itRenko then
  begin  
    fTamanhoBox := (GraphicOffset-1)*MinPriceIncrement;
    
    // Identificação de Box relacionados a GAP
    if Date <> iDataUltimoBox then
    begin
      iUltimoBoxDiaAnterior := CurrentBar - 1;
      iBoxDeGAP := CurrentBar;
      bLocalizouBoxesGap := false;
    end;
  
   iDataUltimoBox := Date;
   
   if Not bLocalizouBoxesGap then
    if BarDurationF = 0 then iBoxDeGAP := CurrentBar
    else
    begin
      //Aqui foi identificado o primeiro box que não é de GAP
      bLocalizouBoxesGAP := true;
  
      //Coloque abaixo o que deseja fazer no primero box do dia que não é GAP
      // --------------------------------------------------------------------
      if (Open < Close[1]) Or (Open > Close[1]) then fAberturaBox := Open[1]
      else fAberturaBox := Close[1];
      fFechamentoDiaAnteriorBox := Close[CurrentBar - iUltimoBoxDiaAnterior];
       
      fGAPdoDiaBox := (fAberturaBox -  fFechamentoDiaAnteriorBox)/fTamanhoBox;
  
      if fGAPdoDiaBox <> 0 then 
      begin
        if fGAPdoDiaBox > 0 then
          PlotText("GAP:" + Floor(fGAPdoDiaBox) + " Box",clGreen,-1,9)
        else
          PlotText("GAP:" + Floor(fGAPdoDiaBox) + " Box",clRed,-1,9);
        PaintBar(clRed);
      end;
      // --------------------------------------------------------------------
    end;
  end
  // O Gráfico não é do tipo Renko!
  else
    if LastBarOnChart then PlotText("Aplicável apenas a Renko",clWhite,-1,10);

end
				
			

Execução de estratégia em frequência superamostrada

Reproduzir vídeo

É de conhecimento de quem opera gráficos com tempo gráfico maior os impactos de se executar ordens apenas no fechamento dos candles/boxes.

Este Snippet visa tornar as ordens mais tempestivas, exemplificando uma forma de executar uma estratégia/robô em um tempo gráfico menor do que o original. Naturalmente que isso exige um código fonte mais complexo para tratar de forma adequada os cálculos de indicadores utilizados na estratégia.

O código de exemplo abaixo, demonstra como utilizar uma média móvel em um tempo gráfico superamostrado equivalente ao tempo gráfico original da estratégia (e com valor superior). Bem como também demonstra como seria o cálculo para obter a média de fechamento em tempos gráficos superiores ao gráfico supermostrado.

OBS: Embora não seja um requisito, sugere-se que o tempo gráfico original seja um múltiplo do tempo gráfico superamostrado.

				
					//LIMITAÇÃO IMPORTANTE: Não dá para fazer em escala de segundos
//devido a função time não retornar segundos
const
  // Estratégia originalmente rodava em gráfico de 15 min
  cTempoGraficoOriginal = 15;
  //Qtde de periodos no tempo gráfico original
  cQtdePeriodosMedia = 20;
  //Horario inicial de negociação do ativo
  //0900 para futuros, 1000 para mercado a vista
  cHoraInicioNegociacao = 0900;
var
  bStarted: boolean;

  iTempoGraficoAtual: integer;
  iQtdePeriodosEquivalente: integer;
  fMediaSuperAmostradaEquivalente: float;

  fInicializacaoMedia: float;
  fMediaTempoGraficoOriginal: float;
  iQtdePeriodosCalculados: integer;

  iHorarioEmMinutos: integer;
  iHorarioGrafSuperior: integer;
  bCalculouTempoGrafSuperior: boolean;

begin
  //1a opção: Dar preferencia sempre que possível
  // Identifica tempo gráfico utilizado e qtde de periodos equivalente para média superamostrada
  iTempoGraficoAtual := GraphicOffset;
  iQtdePeriodosEquivalente := Floor(cTempoGraficoOriginal/iTempoGraficoAtual)*cQtdePeriodosMedia;

  // Obtem média superamostrada equivalente
  fMediaSuperAmostradaEquivalente := Media(iQtdePeriodosEquivalente,Close);

  //Plot da série para inspeção
  PlotN(1,fMediaSuperAmostradaEquivalente);
  SetPlotColor(1, clWhite);
  SetPlotWidth(1,2);
  SetPlotStyle(1, psDash);



  //2a opção: Exige mais linhas de código para gerenciar execução
  //Amostrando apenas os valores de fechamento do Tempo gráfico original
  iHorarioEmMinutos := Floor(Time/100)*60+Mod(Time,100)
                     - (Floor(cHoraInicioNegociacao/100)*60+Mod(cHoraInicioNegociacao,100));
  
  if Not bStarted then
  begin
    iHorarioGrafSuperior := CalcTime(Time,-Mod(iHorarioEmMinutos, cTempoGraficoOriginal));
    bStarted := true;
  end;

  // Bloco para criar mecanismo de calcular apenas uma vez para o gráfico superior
  if (CalcTime(Time,-Mod(iHorarioEmMinutos, cTempoGraficoOriginal)) <> iHorarioGrafSuperior) then
  begin
    iHorarioGrafSuperior := CalcTime(Time,-Mod(iHorarioEmMinutos, cTempoGraficoOriginal));
    bCalculouTempoGrafSuperior := false;
  end;


  // Cálculo da média no tempo gráfico original
  if (Mod(iHorarioEmMinutos, cTempoGraficoOriginal) = 0) and Not bCalculouTempoGrafSuperior then
  begin
    bCalculouTempoGrafSuperior := true;
    if (iQtdePeriodosCalculados < cQtdePeriodosMedia) then 
    begin
      iQtdePeriodosCalculados := iQtdePeriodosCalculados + 1;
      fInicializacaoMedia := fInicializacaoMedia + Close[1];
    end
    else
      if (iQtdePeriodosCalculados = cQtdePeriodosMedia) then
      begin
        fMediaTempoGraficoOriginal := fInicializacaoMedia/iQtdePeriodosCalculados;
        iQtdePeriodosCalculados := iQtdePeriodosCalculados + 1;
      end
      else
        fMediaTempoGraficoOriginal := (fMediaTempoGraficoOriginal*cQtdePeriodosMedia
                                     - Close[1+cQtdePeriodosMedia*Floor(cTempoGraficoOriginal/iTempoGraficoAtual)]
                                     + Close[1])/cQtdePeriodosMedia;
  end;


  //Plot da série para inspeção
  PlotN(2,fMediaTempoGraficoOriginal);
  SetPlotColor(2, clRed);
  SetPlotWidth(2,2);
  SetPlotStyle(2, psSolid);

end
				
			

Como utilizar dados de preço de outros ativos

O código abaixo apenas exemplifica como obter os dados OHLCV de outras ativos em uma estratégia, o que pode ser feito via parâmetro ou constante. Caso o ativo desejado seja uma ação, deve-se atentar para modificar o feedBMF para feedBovespa.

				
					const
  cAtivo1 = Asset("INDFUT",feedBMF);
input
  pAtivo2("WINFUT",feedBMF);
  pQtdePeriodos(50);
var
  fMediaAtivo1, fMediaAtivo2: float;
begin
  fMediaAtivo1 := Media(pQtdePeriodos,cAtivo1.Close);
  fMediaAtivo2 := Media(Floor(pQtdePeriodos*1/3),pAtivo2.Close);
  plot(fMediaAtivo1);
  plot2(fMediaAtivo2);

end;
				
			

Criando seu próprio Indicador

Reproduzir vídeo

Médias móveis, RSI, MACD, Bandas de Bollinger, Canal de Keltner, OBV, ATR, VWAP…Você já sabe do que eu estou falando: Dos indicadores de análise técnica! Nesse documento eu irei abordar o processo de criação de um indicador para que você entenda as etapas necessárias para criação do seu próprio indicador, desde a análise de dados e concepção do indicador até a implementação e verificação de consistência.

No vídeo acima, você poderá acompanhar o conteúdo deste documento de forma mais dinâmica, bem como acompanhar um exemplo do processo de criação do indicador Neo Volatility Band.

Introdução

Os indicadores nasceram com a análise técnica e se pudéssemos eleger o primeiro da espécie, seria a média móvel! Ela é usada há mais de um século…numa época e que não tinha computador, calculadoras digitais e os trades não ocorriam em alta frequencia como hoje. No entanto, já eram úteis para identificar tendências…Você sabe que elas podem ser aritméticas, exponenciais, ponderadas… E quando utilizadas em pares dão origem até a outros indicadores tal como o MACD.

Com o tempo surgiram vários outros indicadores, que passaram a ser agrupados entre indicadores de tendência, osciladores (que buscam identificar divergências que sinalizem reversões), indicadores de volatilidade, entre outros.

Criar um indicador qualquer não é tão difícil…o desafio é criar um que seja útil e consistente!

O que quero dizer com útil? Um indicador que possa ser usado como base para um setup operacional, afinal isso é o que se pretende fazer com indicadores! Além é claro de enfeitar o gráfico com toda a paleta de cores possíveis! (Só para deixar claro, isso foi uma ironia!)

E consistente…o que isso significa? Um indicador que responda objetivamente ao propósito pelo qual foi criado, ou seja, que tenha forte correlação com o que propõe sinalizar.

Então vamos direto ao ponto…Vamos abordar o fluxo para criação de um indicador e explicar em detalhes cada etapa.

Fluxo para criação de um indicador

A figura abaixo apresenta um diagrama das etapas necessárias para criação de um indicador. Observa-se que elas foram dispostas em um formato de ciclo onde, o fluxo se retroalimenta.

O mais natural é iniciar o fluxo pela “Análise de dados” passando pelas etapas de “Definição de Cálculo”, “Escrita de código fonte e “Verificação de consistência”.

Vamos abordar nas seções subsequentes o escopo de cada etapa.

1) Analisar dados

Esta é a primeira etapa do fluxo de criação de um indicador. Ao analisar os dados, temos que definir um enfoque: movimentação de preço, volume, agressão, volatilidade; bem como estudar a relação entre as variáveis analisadas.

O ideal é identificar um padrão que possa ser sinalizado com antecedência e confiança estatística. Os indicadores podem servir ao propósito de identificar tendências, reversões de preço, consolidações, exaustão de movimento, entre outros.

2) Definir Cálculo

Uma vez identificado um padrão nos dados, o desafio é conseguir converter números e ideias em fórmulas matemáticas. Afinal, teremos que programar o indicador, ainda que seja uma soma, divisão ou multiplicação, ou ponderação de algum valor, esta conta precisa fazer sentido!

Para definição do cálculo do indicador devemos sempre seguir a máxima de que “soluções devem ser tão simples quanto possível e tão complexas quanto for necessário”. Não tem como acertar sempre…portanto, o indicador será um modelo de aproximação da realidade, passível de erro e de falsas sinalizações. Outro cuidado que devemos ter nessa etapa é de não tornar as exceções regras do cálculo.

Ou seja, tente evitar criar muitas restrições no cálculo para mitigar o risco de estar no final das contas um ajuste de curva.

3) Escrever o código fonte

Dado o enorme desafio das etapas anteriores, talvez a codificação do indicador seja a parte mais fácil do processo!

Como sempre dizemos, comece seu código simples e vá complicando aos poucos, de forma iterativa. Não tente “abraçar o mundo”…um indicador é só um indicador…não comece a caracterizar seu indicador como um setup em si ou como uma regra de coloração. O indicador é parte de um processo de elaboração de setup! O indicador que está criando pode e deve permitir a elaboração de estratégias que se baseiem em seu valor, bem como regras de coloração…mas estes não são objetivos que devem ser incorporados no código do indicador!

4) Verificar a consistência

Esta é uma etapa de validação que pode representar o fim da elaboração do indicador, ou o início de um novo ciclo de desenvolvimento do indicador.

Nesta etapa temos que verificar se o indicador e os valores calculados fazem sentido e se os valores apresentados nos permitem construir hipóteses para analisar o mercado. Acima de tudo, os valores calculados pelo indicador cumprem o objetivo inicial? É factível a criação de um setup que se baseie no indicador?

Temos que verificar também as situações nas quais o indicador funciona bem e quando ele não funciona tão bem.

Por fim, precisamos definir quais são os parâmetros do indicador, que permitem ajustá-lo a diferentes ativos ou situações de mercado.

Conclusão

Espero que este conteúdo tenha agregado valor a você e que tenham percebido a semelhança com o processo de criação de um robô.

A diferença é que enquanto existe um trabalho de análise de dados, o qual você pode aprofundar-se ao nível desejado para criação do indicador, na criação de um robô o esforço maior concentra-se no backtesting e na otimização para administração de trades e gestão de risco.

Assim como os robôs, as estratégias de indicadores também podem ser otimizadas e avaliadas em backtesting. Iremos abordar estes temas em outros documentos da nossa Base de Conhecimento.

Código fonte do indicador: Neo Volatility Band

				
					// #######################################################################
// #######################################################################
// #######################################################################
// ######                            O                             #######
// ######                        ____|____                         #######
// ######                      _|         |_                       #######
// ######                     (_|  O   O  |_)                      #######
// ######                       |_________|                        #######
// ######                                                          #######
// ###### ____        __        ____________           ________    #######
// ###### | | \       | |       | |_________|         /  ____  \   #######
// ###### | |\ \      | |       | |                  /  /    \  \  #######
// ###### | | \ \     | |       | |____             |  |      |  | #######
// ###### | |  \ \    | |       | |____|            |  |      |  | #######
// ###### | |   \ \   | |       | |____|            |  |      |  | #######
// ###### | |    \ \  | |       | |                 |  |      |  | #######
// ###### | |     \ \ | |       | |_________         \  \____/  /  #######
// ###### |_|      \_\|_|       |_|_________|         \________/   #######
// ######                                                          #######
// ###### _______  __          __   ____  __   ___    __  _______  #######
// ######    |    |  \   /\   |  \ |     |  \ |   \  /  \    |     #######
// ######    |    |__/  /__\  |   ||__   |__/ |___/ |    |   |     #######
// ######    |    |\   /    \ |   ||     |\   |   \ |    |   |     #######
// ######    |    | \ /      \|__/ |____ | \  |___/  \__/    |     #######
// ######                                                          #######
// ######  Comunidade aberta de automatização de estratégias para  #######
// ######                    negociação de ativos                  #######
// ######                                                          #######
// ######                    www.NeoTraderBot.com                  #######
// #######################################################################
// #######################################################################
// #######################################################################
//
// -----------------------------------------------------------------------
// ---------------------- DADOS DA ESTRATÉGIA ----------------------------
// -----------------------------------------------------------------------
//
// NOME DA ESTRATÉGIA: NVI Neo Volatility Indicator
//   DESENVOLVIDA POR: NeoTraderBOt
//    DATA DE CRIAÇÃO: 12/10/2022
//             VERSÃO: 1.0
//      ATUALIZADA EM: 12/10/2022
// TIPO DE ESTRATÉGIA: (X) Indicador  ( ) Coloração ( ) Execução
//                     ( ) Screening  ( ) Texto     ( ) Alarme
//
// DESCRIÇÃO DA ESTRATÉGIA:
//    Indicador baseado em volatilidade utilizando função log-retorno e 
// desvio padrão em torno de uma média de curto prazo
//
//
//
//
//
// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
//
// ######################### FIM DO CABEÇALHO ############################
//
//
// -----------------------------------------------------------------------
// -------------------------- Constantes ---------------------------------
// OBS:
// -----------------------------------------------------------------------
//const
  //cCONSTANTE = 1;
  //
  // ---------------------------------------------------------------------
  // -------------------------- Parâmetros -------------------------------
  // OBS: Segue abaixo a descriação de cada parâmetro
  // 1) parametro1 ->
  // 2) parametro2 ->
  // ---------------------------------------------------------------------
input
  pQtdePeriodosVolatilidade(500);
  pQtdePeriodosMedia(36);
  pQtdeDesvioVol(2.0);
  // ---------------------------------------------------------------------
  // ---------------------- Variáveis globais ----------------------------
  // OBS:
  // ---------------------------------------------------------------------
var
bStarted, 	bPlotIndicador: boolean;
fLogRetorno: float;
fStdDev, fBandaSuperior, fBandaInferior: float;
fMedia: float;

begin
  // ---------------------------------------------------------------------
  // ----------------- Inicialização da estratégia -----------------------
  // OBS: Inicialização de variáveis a serem utilizadas na estratégia de
  // execução
  // ---------------------------------------------------------------------
  if Not bStarted then
  begin
    bStarted := True;
    //Colocar aqui ações que serão executadas apenas no primeiro processamento
    //da estratégia. Por exemplo, inicialização de variáveis.

  end;


  // ---------------------------------------------------------------------
  // ------------ Atribuição de variáveis por processamento --------------
  // ---------------------------------------------------------------------
  if Close[1] = 0 then fLogRetorno := 0 else fLogRetorno := Log(Close/close[1]);
  fMedia := Media(pQtdePeriodosMedia, Close);
  fStdDev := StdDevs(fLogRetorno, pQtdePeriodosVolatilidade);




  // ---------------------------------------------------------------------
  // --------------------- Cálculo do indicador  -------------------------
  // OBS: Inserir lógica de cálculo do indicador e caso ele possa ser plo_
  // tado, atribuir em algum momento True para variável bPlotIndicador
  // ---------------------------------------------------------------------
  bPlotIndicador := true;

  fBandaSuperior := fMedia*ExpValue(pQtdeDesvioVol*fStdDev);
  fBandaInferior := fMedia*ExpValue(-pQtdeDesvioVol*fStdDev);



  //
  // ---------------------------------------------------------------------
  // ------------------ Plota valores do indicador -----------------------
  // OBS: Atribuir na sessão anterior o valor para variavel bPlotIndicador
  // quando for possível plotar um valor para o indicador no instante atual
  // ---------------------------------------------------------------------
  if bPlotIndicador then
    begin
      PlotN(1, fMedia);
      PlotN(2, fBandaSuperior);
      PlotN(3, fBandaInferior);

      setPlotColor(1, clRed);
      setPlotColor(2, clWhite);
      setPlotColor(3, clWhite);
      SetPlotWidth(1,2);
      SetPlotWidth(2,2);
      SetPlotWidth(3,2);

    end;

end;
				
			

Criando uma Estratégia de Coloração

Reproduzir vídeo

As Estratégias de Coloração são o primeiro passo para a automatização de operações. No vídeo acima, explicamos o passo a passo para criar uma regra de coloração que se baseia em dois indicadores de Bandas de Bollinger. Assista ao vídeo para uma explicação dinâmica do processo de escrita do código fonte de uma estratégia de coloração!

Introdução

Se você já assistiu aos vídeos ou leu os documentos sobre como criar seu primeiro robô e como criar seu próprio indicador, então você já tem uma noção básica do processo de criar uma estratégia.

A criação de uma estratégia de coloração visa facilitar uma sinalização ao trader por uma cor no gráfico. Pode ser uma lógica simples ou um pouco mais complicada, englobando comparações de diferentes indicadores frente a valores de referência. Fato é que se espera que a coloração torne a ação do trader mais tempestiva, pois ele não terá que realizar as mesmas contas que a estratégia calculou para pintar o gráfico. Ao ver uma determinada cor no gráfico, o trader já saberá como agir ou se comportar.

Muitas soluções externas para automatização do roteamento de ordens do Profit utilizavam as regras de coloração para ativar envio de ordens. Embora tenha sido lançado o Módulo de Automação de Estratégias, acredito que o envio de ordens a mercado, baseado nas soluções visuais de automatização de ordens ainda representa uma vantagem em relação ao módulo (hoje!). A tendência é que essas soluções externas percam vantagem competitiva a medida que o Módulo de Automação de Estratégias seja aprimorado, tornando estas soluções obsoletas. Uma desvantagem dessas soluções é que os gráficos precisam estar abertos em tela, pois elas trabalham com o mapeamento da tela, limitando assim a quantidade de estratégias que podem rodar simultaneamente, além de não permitirem utilizar subcontas, pois a interface gráfica padrão do Profit não permite (em geral) essa opção fora do Módulo de Automação de Estratégias para clientes padrão.

Implementação de uma estratégia de coloração

A implementação de uma estratégias de coloração envolve três etapas: especificar regra de cor, implementar código e testar o funcionamento.

Acho que o próprio nome das etapas já torna bem intuitivo o que precisamos fazer para obter uma estratégia de coloração. É importante ressaltar, que muita gente gosta de colocar as lógicas de coloração dentro de estratégias de execução (robôs) ou indicadores, screenings. Assim, em um único código, você pode incluir no seu gráfico como indicador, como sinalização de ordens ou coloração.

No exemplo apresentado no vídeo, que não é uma recomendação de uso, realizamos a coloração de candles de acordo com sua posição em relação à 2 indicadores de bandas de Bollinger.

Se o preço estiver sendo negociado fora da primeira banda de bollinger, mas ainda dentro da segunda, entende-se que o preço pode estar em região de sobrevenda ou sobrecompra, mas ainda não engatou uma tendência forte. Se o preço estiver sendo negociado fora da segunda Banda de Bollinger, entende-se que o mercado está demonstrando uma tendência forte seja de alta ou de baixa.

Assim, foram estabelecidas cores para sinalizar essas situações e oferecer suporte para a operação manual do trader. O código fonte da referida estratégia encontra-se abaixo.

Código fonte: Estratégia de coloração baseada emduas Bandas de Bollinger

				
					// #######################################################################
// #######################################################################
// #######################################################################
// ######                            O                             #######
// ######                        ____|____                         #######
// ######                      _|         |_                       #######
// ######                     (_|  O   O  |_)                      #######
// ######                       |_________|                        #######
// ######                                                          #######
// ###### ____        __        ____________           ________    #######
// ###### | | \       | |       | |_________|         /  ____  \   #######
// ###### | |\ \      | |       | |                  /  /    \  \  #######
// ###### | | \ \     | |       | |____             |  |      |  | #######
// ###### | |  \ \    | |       | |____|            |  |      |  | #######
// ###### | |   \ \   | |       | |____|            |  |      |  | #######
// ###### | |    \ \  | |       | |                 |  |      |  | #######
// ###### | |     \ \ | |       | |_________         \  \____/  /  #######
// ###### |_|      \_\|_|       |_|_________|         \________/   #######
// ######                                                          #######
// ###### _______  __          __   ____  __   ___    __  _______  #######
// ######    |    |  \   /\   |  \ |     |  \ |   \  /  \    |     #######
// ######    |    |__/  /__\  |   ||__   |__/ |___/ |    |   |     #######
// ######    |    |\   /    \ |   ||     |\   |   \ |    |   |     #######
// ######    |    | \ /      \|__/ |____ | \  |___/  \__/    |     #######
// ######                                                          #######
// ######  Comunidade aberta de automatização de estratégias para  #######
// ######                    negociação de ativos                  #######
// ######                                                          #######
// ######                    www.NeoTraderBot.com                  #######
// #######################################################################
// #######################################################################
// #######################################################################
//
// -----------------------------------------------------------------------
// ---------------------- DADOS DA ESTRATÉGIA ----------------------------
// -----------------------------------------------------------------------
//
// NOME DA ESTRATÉGIA: _NTB_COL_2BandasBollinger
//   DESENVOLVIDA POR: NeoTraderBot
//    DATA DE CRIAÇÃO: 13/10/2022
//             VERSÃO: 1.0
//      ATUALIZADA EM: 13/10/2-22
// TIPO DE ESTRATÉGIA: (X) Indicador  (X) Coloração ( ) Execução
//                     ( ) Screening  ( ) Texto     ( ) Alarme
//
// DESCRIÇÃO DA ESTRATÉGIA:
//   Realiza a coloração de candles baseada na posição relativa do proço
// em função de dois indicadores de Bandas de Bollinger, um para histórico 
// recente e outro para histórico de médio prazo
//
//
//
//
// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
//
// ######################### FIM DO CABEÇALHO ############################
//
//
// -----------------------------------------------------------------------
// -------------------------- Constantes ---------------------------------
// OBS:
// -----------------------------------------------------------------------
//const
//  cXXXXXX = true;
  //
  // ---------------------------------------------------------------------
  // -------------------------- Parâmetros -------------------------------
  // OBS: Segue abaixo a descrição de cada parâmetro
  // 1) pXXXXXX ->
  //
  // 2) pYYYYYY ->
  //
  // 3) pZZZZZZ ->
  // ---------------------------------------------------------------------
input
  pQtdeDesvioBB1(1.5);
  pQtdePeriodoMediaBB1(36);
  pTipoMediaBB1(0);

  pQtdeDesvioBB2(2.0);
  pQtdePeriodoMediaBB2(100);
  pTipoMediaBB2(0);

  // ---------------------------------------------------------------------
  // ---------------------- Variáveis globais ----------------------------
  // OBS:
  // ---------------------------------------------------------------------
var
//Estrutura padrão do modelo
bStarted: boolean;


//Variáveis personalizadas
fBB1Sup, fBB1Inf: float;
fBB2Sup, fBB2Inf: float;


begin
  // ---------------------------------------------------------------------
  // ----------------- Inicialização da estratégia -----------------------
  // OBS: Inicialização de variáveis a serem utilizadas na estratégia de
  // coloração
  // ---------------------------------------------------------------------
  if Not bStarted then
  begin
    bStarted := True;
    //Colocar aqui ações que serão executadas apenas no primeiro processamento
    //da estratégia. Por exemplo, inicialização de variáveis.
  end;


  // ---------------------------------------------------------------------
  // ------------ Atribuição de variáveis por processamento --------------
  // ---------------------------------------------------------------------
  // Atribuições das variáveis da estratégia
  fBB1Sup := BollingerBands(pQtdeDesvioBB1, pQtdePeriodoMediaBB1, pTipoMediaBB1)|0|;
  fBB1Inf := BollingerBands(pQtdeDesvioBB1, pQtdePeriodoMediaBB1, pTipoMediaBB1)|1|;
  fBB2Sup := BollingerBands(pQtdeDesvioBB2, pQtdePeriodoMediaBB2, pTipoMediaBB2)|0|;
  fBB2Inf := BollingerBands(pQtdeDesvioBB2, pQtdePeriodoMediaBB2, pTipoMediaBB2)|1|;

  // ---------------------------------------------------------------------
  // ---------------------- Lógica de coloração  -------------------------
  // OBS: Inserir lógica de cálculo para coloração do gráfico
  // ---------------------------------------------------------------------

  //SITUAÇÃO 1: BB1 DENTRO de BB2
  if (fBB1Sup <= fBB2Sup) And (fBB1Inf >= fBB2Inf) then
  begin
    if (Close >= fBB2Sup) then PaintBar(clGreen)
    else
    if (Close <= fBB2Inf) then PaintBar(clRed)
    else
    if (Close >= fBB1Sup) And (Close < fBB2Sup) then PaintBar(clYellow)
    else
    if (Close <= fBB1Inf) And (Close > fBB2Inf) then PaintBar(clYellow);
  end
  else

  //SITUAÇÃO 2: Banda superior de BB1 ACIMA da banda superior de BB2
  //            Banda inferior de BB1 maior que banda inferior de BB2
  if (fBB1Sup > fBB2Sup) And (fBB1Inf >= fBB2Inf) then
  begin
    if (Close >= fBB2Sup) then PaintBar(clGreen)
    else
    if (Close <= fBB2Inf) then PaintBar(clRed)
    else
    if (Close <= fBB1Inf) And (Close > fBB2Inf) then PaintBar(clYellow);
  end
  else


  //SITUAÇÃO 3: Banda inferior de BB1 ABAIXO da banda inferior de BB2
  //            Banda superior de BB1 menor que banda superior de BB2
  if (fBB1Sup <= fBB2Sup) And (fBB1Inf < fBB2Inf) then
  begin
    if (Close >= fBB2Sup) then PaintBar(clGreen)
    else
    if (Close <= fBB2Inf) then PaintBar(clRed)
    else
    if (Close >= fBB1Sup) And (Close < fBB2Sup) then PaintBar(clYellow);
  end
  else

  //SITUAÇÃO 4: BB2 DENTRO de BB1
  if (fBB1Sup >= fBB2Sup) And (fBB1Inf <= fBB2Inf) then
  begin
    if (Close >= fBB1Sup) then PaintBar(clGreen)
    else
    if (Close <= fBB1Inf) then PaintBar(clRed);
  end;


  PlotN(1,fBB1Sup);
  PlotN(2,fBB1Inf);
  PlotN(3,fBB2Sup);
  PlotN(4,fBB2Inf);

  SetPlotStyle(1,psDash);
  SetPlotStyle(2,psDash);
  SetPlotStyle(3,psSolid);
  SetPlotStyle(4,psSolid);

  SetPlotColor(1,clWhite);
  SetPlotColor(2,clWhite);
  SetPlotColor(3,clYellow);
  SetPlotColor(4,clYellow);

  SetPlotWidth(1,1);
  SetPlotWidth(2,1);
  SetPlotWidth(3,2);
  SetPlotWidth(4,2);

end;
				
			

Documentação NTSL (Nelogica)

A documentação apresentada abaixo é elaborada pela Nelogica e disponibilizada neste link. O documento abaixo foi baixado do link informado em 31/05/2023.