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

Programando Estratégias no Profit

Melhorando o desempenho do seu robô

Leitura estimada: 16 minutos 529 views
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;
				
			

Leave a Comment

CONTENTS