English Русский 中文 Español Deutsch 日本語
preview
Medindo o valor informativo do Indicador

Medindo o valor informativo do Indicador

MetaTrader 5Exemplos | 23 maio 2023, 10:16
363 0
Francis Dube
Francis Dube

Introdução

O aprendizado de máquina depende de dados de treinamento para entender o comportamento geral do mercado e fazer previsões precisas. A escolha do algoritmo de aprendizado requer uma amostra cuidadosamente selecionada para extrair informações relevantes. Muitas vezes, as pessoas não têm sucesso ao aplicar essas ferramentas complexas porque a informação significativa fica oculta em dados ruidosos. É possível que muitos estrategistas não percebam que os conjuntos de dados utilizados podem não ser adequados para treinar o modelo.

Os indicadores podem fornecer informações sobre a série de preços subjacente a que são aplicados. Com base nessa premissa, a entropia pode ser usada para medir a quantidade de informação transmitida por um indicador. Seguindo as etapas e ferramentas descritas no livro "Testing and Tuning Market Trading Systems" (TTMTS) de Timothy Masters, demonstraremos como avaliar a estrutura de dados de um indicador.


Por que medir o conteúdo informativo do indicador?

Com frequência, ao usar ferramentas de aprendizado de máquina para desenvolver uma estratégia, acabamos alimentando os algoritmos com diversos tipos de dados na esperança de obter algum resultado. No entanto, o sucesso dependerá da qualidade dos preditores utilizados no modelo, e os preditores eficazes geralmente apresentam certas características. Uma delas é o conteúdo informativo.

A quantidade de informação contida nas variáveis utilizadas para treinar o modelo é importante, mas não é o único requisito para um treinamento eficiente. Assim, a medição do conteúdo informativo pode ser utilizada para avaliar métricas que, de outra forma, seriam utilizadas no processo de aprendizado sem considerar esse aspecto. É nesse contexto que surge o conceito de entropia.


Entropia

O tópico sobre entropia foi abordado muitas vezes em MQL5.com. Espero que o leitor me perdoe por mais uma tentativa de defini-la, pois é importante para entender a aplicação do conceito. Artigos anteriores apresentaram a história e a derivação do cálculo da entropia, portanto, por uma questão de brevidade, começaremos com a equação.

                                                        

equação da entropia

H(X)" representa a entropia de "X". "X" é uma variável discreta que representa uma variável arbitrária, como uma mensagem. O conteúdo da mensagem só pode ter um número limitado de valores, representados como "x" pequenos na equação. Os "x" pequenos são os valores observados da mensagem, como se todos os possíveis valores de "x" estivessem listados no conjunto "N".

Vamos considerar o exemplo de um dado "correto". Um dado lançado pode ser visto como fornecendo informações que determinam o resultado de um jogo. Um dado tem 6 faces numeradas de 1 a 6. A probabilidade de ver qualquer número é 1/6.

Usando esse exemplo, o "X" grande seria o dado, e o "x" pequeno poderia ser qualquer número nas faces do dado. Todos os números são colocados no conjunto N = {1, 2, 3, 4, 5, 6}. Ao aplicar a fórmula, descobrimos que a entropia desse dado é 0,7781.

                                                         

Dado correto


Agora consideremos outro dado que tem um defeito de fabricação. O mesmo número é repetido em duas faces. Para esse dado defeituoso, o conjunto de possíveis valores "N" é {1, 1, 3, 4, 5, 6}. Usando a fórmula novamente, obtemos uma média de entropia de 0,6778.

                                                 

Dado defeituoso

Ao comparar os valores, notamos que a informação diminuiu. Quando todas as probabilidades de observar cada valor possível são iguais, a fórmula de entropia retorna o valor máximo possível. Portanto, a entropia atinge seu valor médio máximo quando todas as probabilidades de valores possíveis são iguais.

Se descartarmos o dado defeituoso e usarmos um indicador que produz números reais tradicionais, "X" se torna o indicador e o "x" pequeno é o intervalo de valores que o indicador pode assumir. A fórmula de entropia lida apenas com variáveis discretas. É possível converter a fórmula para trabalhar com variáveis contínuas, mas a implementação seria mais difícil. Portanto, é mais simples usar números discretos.


Cálculo da entropia do indicador

Para aplicar a equação da entropia a variáveis contínuas, é necessário discretizar os valores dos indicadores. Isso é feito dividindo o intervalo de valores em intervalos do mesmo tamanho e contando o número de valores que se enquadram em cada intervalo. Ao usar esse método, o conjunto original que lista o intervalo máximo de todos os valores do indicador é substituído por subconjuntos, cada um representando os intervalos selecionados.

Ao lidar com variáveis contínuas, as variações nas probabilidades dos possíveis valores que uma variável pode assumir se tornam significativas, pois fornecem um aspecto importante da aplicação da entropia aos indicadores.

Vamos voltar ao primeiro exemplo dos dados. Se dividirmos os valores finais de entropia de cada um por log(N) para cada um dos respectivos "n's", o dado correto será 1 e o dado defeituoso será 0,87. Dividir o valor da entropia pelo logaritmo do número de valores que uma variável pode assumir fornece uma medida relativa à entropia máxima teórica da variável, chamada entropia proporcional ou relativa.

Esse valor seria útil na avaliação dos indicadores, pois indicará o quão próxima a entropia do indicador está de seu valor teórico médio máximo. Quanto mais próximo, melhor. Caso contrário, o indicador provavelmente não é adequado para uso em aprendizado de máquina. 

                                  

Equação de entropia relativa

Equação da entropia relativa A equação final é mostrada acima, e o código está implementado abaixo como um script MQL5, que está disponível para download como anexo no final do artigo. Com a ajuda desse script, é possível analisar a maioria dos indicadores.


Script para calcular a entropia do indicador

O script é chamado com os seguintes parâmetros:

  • TimeFrame - período gráfico selecionado para analisar os valores do indicador.
  • IndicatorType - escolha de um dos indicadores integrados para análise. Para especificar um indicador personalizado, selecione "Indicador personalizado" e insira o nome no próximo valor de parâmetro.
  • CustomIndicatorName - se a opção "Indicador personalizado" for selecionada para o parâmetro anterior, um nome válido de indicador deve ser inserido.
  • UseDefaults - se true, os parâmetros padrão de entrada do usuário codificados no indicador serão usados.
  • IndicatorParameterTypes - string separada por vírgulas que lista os tipos de dados do indicador na ordem correta. Por exemplo, se o indicador que está sendo analisado leva quatro parâmetros de entrada do tipo double, integer, integer e string, basta inserir "double, integer, integer, string". A forma abreviada "d, i, i, s" também é suportada. Os valores de enumeração são mapeados para um tipo integral.
  • IndicatorParameterValues - assim como o parâmetro anterior, esta também é uma lista de valores separados por vírgula. Continuando o exemplo anterior, a linha ficará assim: "0.5,4,5,string_value". Se houver algum erro na geração de parâmetros para IndicatorParameterValues ou IndicatorParameterTypes, isso fará com que os valores padrão do indicador sejam usados para quaisquer valores específicos que não podem ser decodificados ou estão ausentes.
    Verifique se na guia Experts há mensagens de erro. Observe que não é necessário especificar o nome do indicador. Se um indicador personalizado estiver sendo considerado, ele deverá ser especificado em CustomIndicatorName.
  • IndicatorBuffer - buffer de indicador a ser analisado.
  • HistoryStart - data de início da amostragem do histórico.
  • HistorySize - número de barras para analisar em relação ao HistoryStart.
  • Intervalos - número de intervalos para amostragem. O autor do TTMTS especifica 20 intervalos para um tamanho de amostra de vários milhares, sendo 2 o mínimo absoluto. Adicionei minha própria abordagem ao valor apropriado, implementando a capacidade de variar o número de intervalos em relação ao tamanho da amostra, especificamente 51 para cada 1.000 amostras. Essa opção está disponível se o usuário inserir qualquer valor menor que 2. Assim, ao definir Intervalo para qualquer número menor que 2, o número de intervalos usados mudará dependendo do número de barras analisadas.

//--- input parameters
input ENUM_TIMEFRAMES Timeframe=0;
input ENUM_INDICATOR  IndicatorType=IND_BEARS;
input string   CustomIndicatorName="";
input bool     UseDefaults=true;
input string   IndicatorParameterTypes="";
input string   IndicatorParameterValues="";
input int      IndicatorBuffer=0;
input datetime HistoryStart=D'2023.02.01 04:00';
input int HistorySize=50000;
input int      Intervals=0;

int handle=INVALID_HANDLE;
double buffer[];
MqlParam b_params[];
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
   if(!processParameters(UseDefaults,b_params))
      return;

   int y=10;
   while(handle==INVALID_HANDLE && y>=0)
     {
      y--;
      handle=IndicatorCreate(Symbol(),Timeframe,IndicatorType,ArraySize(b_params),b_params);
     }
//---
   if(handle==INVALID_HANDLE)
     {
      Print("Invalid indicator handle, error code: ",GetLastError());
      return;
     }

   ResetLastError();
//---
   if(CopyBuffer(handle,IndicatorBuffer,HistoryStart,HistorySize,buffer)<0)
     {
      Print("error copying to buffer, returned error is ",GetLastError());
      IndicatorRelease(handle);
      return;
     }
//---
   Print("Entropy of ",(IndicatorType==IND_CUSTOM)?CustomIndicatorName:EnumToString(IndicatorType)," is ",relativeEntroy(Intervals,buffer));
//---
   IndicatorRelease(handle);
  }
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool processParameters(bool use_defaults,MqlParam &params[])
  {

   bool custom=(IndicatorType==IND_CUSTOM);

   string ind_v[],ind_t[];

   int types,values;

   if(use_defaults)
      types=values=0;
   else
     {
      types=StringSplit(IndicatorParameterTypes,StringGetCharacter(",",0),ind_t);
      values=StringSplit(IndicatorParameterValues,StringGetCharacter(",",0),ind_v);
     }

   int p_size=MathMin(types,values);

   int values_to_input=ArrayResize(params,(custom)?p_size+1:p_size);

   if(custom)
     {
      params[0].type=TYPE_STRING;
      params[0].string_value=CustomIndicatorName;
     }

//if(!p_size)
//  return true;

   if(use_defaults)
      return true;

   int i,z;
   int max=(custom)?values_to_input-1:values_to_input;

   for(i=0,z=(custom)?i+1:i; i<max; i++,z++)
     {
      if(ind_t[i]=="" || ind_v[i]=="")
        {
         Print("Warning: Encountered empty string value, avoid adding comma at end of string parameters");
         break;
        }

      params[z].type=EnumType(ind_t[i]);

      switch(params[z].type)
        {
         case TYPE_INT:
            params[z].integer_value=StringToInteger(ind_v[i]);
            break;
         case TYPE_DOUBLE:
            params[z].double_value=StringToDouble(ind_v[i]);
            break;
         case TYPE_STRING:
            params[z].string_value=ind_v[i];
            break;
         default:
            Print("Error: Unknown specified parameter type");
            break;
        }
     }

   return true;

  }


//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
ENUM_DATATYPE EnumType(string type)
  {
   StringToLower(type);
   const ushort firstletter=StringGetCharacter(type,0);

   switch(firstletter)
     {
      case 105:
         return TYPE_INT;
      case 100:
         return TYPE_DOUBLE;
      case 115:
         return TYPE_STRING;
      default:
         Print("Error: could not parse string to match data type");
         return ENUM_DATATYPE(-1);
     }

   return ENUM_DATATYPE(-1);
  }
//+------------------------------------------------------------------+

Observando o valor escolhido para os Intervalos: alterar o número de intervalos usados no cálculo afetará o valor final da entropia. Ao conduzir a análise, é aconselhável seguir alguma sequência para minimizar a influência de dados de entrada independentes. No script, o cálculo da entropia relativa está encapsulado em uma função definida no arquivo Entropy.mqh.


O script simplesmente exibe o valor da entropia obtido na guia "Experts". Após executar o script para vários indicadores integrados e personalizados, obtemos os resultados mostrados abaixo. É interessante notar que o intervalo percentual de Williams possui uma entropia relativa próxima da perfeição. Vamos compará-lo com o Market Facilitation Index, que apresenta um resultado decepcionante.

Resultados

Com esses resultados, podemos dar mais passos para processar os dados e torná-los adequados para algoritmos de aprendizado de máquina. Isso envolve uma análise completa das propriedades estatísticas do indicador. Examinar a distribuição dos valores dos indicadores revelará quaisquer problemas de distorção e discrepância que possam prejudicar o treinamento do modelo.

Como exemplo, consideremos algumas das propriedades estatísticas dos dois indicadores analisados anteriormente.

Intervalo percentual de Williams

A distribuição do intervalo percentual de Williams mostra como quase todos os valores são distribuídos em todo o intervalo. Além de ser multimodal, a distribuição é bastante uniforme. Essa distribuição é ideal e reflete-se no valor da entropia.

Market Facilitation Index,
Índice de Facilitação de Mercado Isso difere da distribuição do Índice de Facilitação de Mercado, que possui uma cauda longa. Tal indicador não é adequado para a maioria dos algoritmos de aprendizado e requer uma transformação nos valores. A transformação dos valores deve levar a uma melhoria na entropia relativa do indicador.


Aumentando o conteúdo de informação do indicador

Deve-se notar que mudanças que aumentam a entropia do indicador não devem ser vistas como uma forma de melhorar a precisão dos sinais fornecidos pelo indicador. Aumentar a entropia não transformará um indicador inútil em uma fórmula mágica. A melhoria da entropia está relacionada ao processamento de dados dos indicadores para uso eficiente em modelos preditivos.

Essa opção deve ser considerada quando o valor da entropia for extremamente baixo - qualquer valor significativamente abaixo de 0,5 e próximo de zero. Os limites superiores são puramente arbitrários. Cabe ao desenvolvedor escolher um valor mínimo aceitável. O objetivo é chegar o mais próximo possível de uma distribuição uniforme dos valores dos indicadores. A decisão de aplicar a transformação deve ser baseada em uma análise realizada em uma amostra significativa e representativa dos valores dos indicadores.

A transformação aplicada não deve alterar o comportamento do indicador. O indicador transformado deve manter o mesmo formato do indicador bruto, por exemplo, a localização dos vales e picos deve ser a mesma em ambas as linhas. Caso contrário, corre-se o risco de perder informações potencialmente úteis.

Existem muitos métodos de transformação que visam corrigir várias imperfeições nos dados de teste. No entanto, neste contexto, consideraremos apenas algumas transformações simples destinadas a corrigir defeitos óbvios identificados por meio de análise estatística básica. O pré-processamento de dados é uma área extensa no campo do aprendizado de máquina, e aqueles que desejam dominar a aplicação de métodos de aprendizado de máquina são encorajados a adquirir mais conhecimento nessa área.

Para demonstrar o efeito de algumas transformações, apresentamos um script que possui a capacidade de aplicar diversas transformações e também exibe a distribuição dos dados analisados. O script implementa seis exemplos de funções de transformação:

  • A transformação da função de raiz quadrada é adequada para compactar valores de indicadores aleatórios que se desviam significativamente da maioria.
  • A transformação da raiz cúbica é outra função de compressão que é mais adequada para indicadores com valores negativos.
  • Enquanto a transformação logarítmica comprime os valores em uma extensão maior do que as mencionadas anteriormente.
  • As transformações tangente hiperbólica e logística devem ser aplicadas a valores de dados em uma escala adequada para evitar problemas com a obtenção de números inválidos (erro nan).
  • A transformação extrema causa uma extrema homogeneidade no conjunto de dados. Ela só deve ser aplicada a indicadores que produzem principalmente valores únicos com muito poucos números semelhantes.

    Script para comparar valores de indicadores convertidos

    O script contém os mesmos dados personalizados para especificar o indicador analisado, assim como o anterior. Os novos parâmetros de entrada são descritos abaixo:

    • DisplayTime - exibe o gráfico de distribuição do indicador. DisplayTime - valor inteiro em segundos que representa a quantidade de tempo que a imagem será exibida antes de ser excluída.
    • ApplyTransfrom - valor booleano que especifica o modo de operação do script. Se for false, o script desenha a distribuição e exibe as estatísticas da amostra subjacente junto com a entropia relativa. Quando for true, aplica a transformação aos valores brutos do indicador e exibe os valores relativos de entropia antes e depois da transformação. A distribuição das amostras modificadas é representada como uma curva vermelha.
    • select_transform - enumeração que fornece as transformações descritas anteriormente que podem ser aplicadas para possivelmente aumentar a entropia do indicador.
    //+------------------------------------------------------------------+
    //|                                            IndicatorAnalysis.mq5 |
    //|                        Copyright 2023, MetaQuotes Software Corp. |
    //|                                             https://www.mql5.com |
    //+------------------------------------------------------------------+
    #property copyright "Copyright 2023, MetaQuotes Software Corp."
    #property link      "https://www.mql5.com"
    #property version   "1.00"
    #property script_show_inputs
    #include<Entropy.mqh>
    //--- input parameters
    input ENUM_TIMEFRAMES Timeframe=0;
    input ENUM_INDICATOR  IndicatorType=IND_CUSTOM;
    input string   CustomIndicatorName="";
    input bool     UseDefaults=false;
    input string   IndicatorParameterTypes="";
    input string   IndicatorParameterValues="";
    input int      IndicatorBuffer=0;
    input datetime HistoryStart=D'2023.02.01 04:00';;
    input int HistorySize=50000;
    input int DisplayTime=30;//secs to keep graphic visible
    input bool ApplyTransform=true;
    input ENUM_TRANSFORM Select_transform=TRANSFORM_LOG;//Select function transform
    
    int handle=INVALID_HANDLE;
    double buffer[];
    MqlParam b_params[];
    //+------------------------------------------------------------------+
    //| Script program start function                                    |
    //+------------------------------------------------------------------+
    void OnStart()
      {
    //---
       if(!processParameters(UseDefaults,b_params))
          return;
    
       int y=10;
       while(handle==INVALID_HANDLE && y>=0)
         {
          y--;
          handle=IndicatorCreate(_Symbol,Timeframe,IndicatorType,ArraySize(b_params),b_params);
         }
    //---
       if(handle==INVALID_HANDLE)
         {
          Print("Invalid indicator handle, error code: ",GetLastError());
          return;
         }
    
       ResetLastError();
    //---
       if(CopyBuffer(handle,IndicatorBuffer,HistoryStart,HistorySize,buffer)<0)
         {
          Print("error copying to buffer, returned error is ",GetLastError());
          IndicatorRelease(handle);
          return;
         }
    //---
       DrawIndicatorDistribution(DisplayTime,ApplyTransform,Select_transform,IndicatorType==IND_CUSTOM?CustomIndicatorName:EnumToString(IndicatorType),buffer);
    //---
       IndicatorRelease(handle);
      }
    //+------------------------------------------------------------------+
    bool processParameters(bool use_defaults,MqlParam &params[])
      {
    
       bool custom=(IndicatorType==IND_CUSTOM);
    
       string ind_v[],ind_t[];
    
       int types,values;
    
       if(use_defaults)
          types=values=0;
       else
         {
          types=StringSplit(IndicatorParameterTypes,StringGetCharacter(",",0),ind_t);
          values=StringSplit(IndicatorParameterValues,StringGetCharacter(",",0),ind_v);
         }
    
       int p_size=MathMin(types,values);
    
       int values_to_input=ArrayResize(params,(custom)?p_size+1:p_size);
    
       if(custom)
         {
          params[0].type=TYPE_STRING;
          params[0].string_value=CustomIndicatorName;
         }
    
       if(use_defaults)
          return true;
    
       int i,z;
       int max=(custom)?values_to_input-1:values_to_input;
    
       for(i=0,z=(custom)?i+1:i; i<max; i++,z++)
         {
          if(ind_t[i]=="" || ind_v[i]=="")
            {
             Print("Warning: Encountered empty string value, avoid adding comma at end of string parameters");
             break;
            }
    
          params[z].type=EnumType(ind_t[i]);
    
          switch(params[z].type)
            {
             case TYPE_INT:
                params[z].integer_value=StringToInteger(ind_v[i]);
                break;
             case TYPE_DOUBLE:
                params[z].double_value=StringToDouble(ind_v[i]);
                break;
             case TYPE_STRING:
                params[z].string_value=ind_v[i];
                break;
             default:
                Print("Error: Unknown specified parameter type");
                break;
            }
         }
    
       return true;
    
      }
    
    
    //+------------------------------------------------------------------+
    //|                                                                  |
    //+------------------------------------------------------------------+
    ENUM_DATATYPE EnumType(string type)
      {
       StringToLower(type);
       const ushort firstletter=StringGetCharacter(type,0);
    
       switch(firstletter)
         {
          case 105:
             return TYPE_INT;
          case 100:
             return TYPE_DOUBLE;
          case 115:
             return TYPE_STRING;
          default:
             Print("Error: could not parse string to match data type");
             return ENUM_DATATYPE(-1);
         }
    
       return ENUM_DATATYPE(-1);
      }
    //+------------------------------------------------------------------+
    


    Continuando com os exemplos, comparamos a aplicação das transformações de raiz quadrada e raiz cúbica.

    Transformação Raiz Quadrada MFI


    Transformação cúbica MFI


    Ambas fornecem uma melhoria na entropia, mas a cauda direita pode ser problemática. As duas transformações aplicadas não conseguiram lidar com isso de forma eficaz.

    Transformação logarítmica MFI


    A transformação logarítmica fornece um valor de entropia ainda melhor. No entanto, as caudas ainda são significativas. Como último recurso, podemos aplicar uma transformação extrema.


    Considerações finais

    Exploramos o conceito de entropia para avaliar a necessidade de transformar os valores dos indicadores antes de usá-los no treinamento do modelo preditivo.

    O conceito foi implementado em dois scripts. Em particular, o script "EntropyIndicatorAnalyis" exibe a entropia relativa de uma amostra na guia de Experts. Outro script, "IndicatorAnalysis", vai um passo além, desenhando a distribuição dos valores brutos e convertidos do indicador, além de exibir os valores de entropia relativos antes e depois.

    Embora essas ferramentas possam ser úteis, elas não são aplicáveis a todos os tipos de indicadores. Como regra geral, indicadores baseados em setas que possuem valores vazios não são adequados para os scripts mencionados aqui. Nesses casos, serão necessários outros métodos de codificação.

    A transformação de dados é apenas uma das várias etapas de pré-processamento que devem ser consideradas ao criar qualquer modelo preditivo. A utilização dessas técnicas ajudará a identificar relacionamentos verdadeiramente únicos que podem fornecer a vantagem necessária para vencer os mercados.

    Nome do arquivo
     Descrição
    Mql5/Include/Entropy.mqh
    Arquivo include que contém as diversas definições das funções usadas para calcular a entropia, bem como as funções de serviço usadas pelos scripts propostos.
    Mql5/Scripts/IndicatorAnalysis.mq5
    Script que exibe um gráfico que mostra a distribuição dos valores do indicador junto com sua entropia.
    Mql5/Scripts/EntropyIndicatorAnalysis Script que pode ser usado para calcular a entropia do indicador


    Traduzido do Inglês pela MetaQuotes Ltd.
    Artigo original: https://www.mql5.com/en/articles/12129

    Arquivos anexados |
    Mql5.zip (5.26 KB)
    Esperança moral na negociação Esperança moral na negociação
    Este artigo trata da esperança moral. Veremos vários exemplos de como ela é aplicada na negociação e quais resultados podem ser obtidos com ela.
    Exemplo de criação da estratégia de negociação abrangente Owl Exemplo de criação da estratégia de negociação abrangente Owl
    Minha estratégia se baseia em fundamentos clássicos de negociação e no aprimoramento de indicadores amplamente usados em todos os tipos de mercados. Na verdade, trata-se de uma ferramenta pronta para trabalhar integralmente com a nova estratégia de negociação lucrativa que proponho.
    Alan Andrews e suas técnicas de análise de séries temporais Alan Andrews e suas técnicas de análise de séries temporais
    Alan Andrews é um dos mais renomados "educadores" do mundo do trading atual, no campo da análise de mercado. Suas "forquilhas" estão presentes em praticamente todos os programas modernos de análise de cotações. No entanto, a maioria dos traders utiliza apenas uma pequena fração das possibilidades oferecidas por essa ferramenta. O curso original de Andrews abrange não apenas a descrição das forquilhas (embora sejam o aspecto principal), mas também outras diretrizes úteis. Este artigo apresenta uma visão dessas incríveis técnicas de análise de gráficos que Andrews ensinou em seu curso original. Atenção: muitas imagens serão utilizadas.
    Como escolher um Expert Advisor: Vinte caraterísticas de um robô de baixa qualidade Como escolher um Expert Advisor: Vinte caraterísticas de um robô de baixa qualidade
    Neste artigo, iremos responder à pergunta de como escolher o Expert Advisor correto. Quais são os mais adequados para o nosso portfólio e como podemos filtrar a maioria dos robôs de negociação disponíveis no mercado? Este artigo apresenta vinte caraterísticas evidentes de um EA de baixa qualidade. Ele ajudará você a tomar decisões mais informadas e criar uma coleção de EAs lucrativos.