English Русский 中文 Español Deutsch 日本語
preview
Um algoritmo de seleção de características usando aprendizado baseado em energia em MQL5 puro

Um algoritmo de seleção de características usando aprendizado baseado em energia em MQL5 puro

MetaTrader 5Exemplos |
253 0
Francis Dube
Francis Dube

Introdução

No domínio da negociação algorítmica, o uso generalizado de aprendizado de máquina tem incentivado a adoção de técnicas de mineração de dados para descobrir padrões ocultos em dados financeiros. Nesse contexto, os praticantes frequentemente enfrentam o desafio de classificar inúmeras variáveis para identificar aquelas que são mais propensas a ser benéficas para alcançar objetivos específicos ou resolver problemas particulares. Neste artigo, exploramos a implementação de um algoritmo de seleção de características com o objetivo de avaliar a relevância de um conjunto de variáveis candidatas para uma tarefa de previsão específica.

Yun Li, Jennie Si, Guojing Zhou, Shasha Huang e Songcan Chen coautoraram um artigo de pesquisa intitulado "FREL: Um Algoritmo Estável de Seleção de Características." Este artigo introduz um algoritmo chamado Ponderação de Características como Aprendizado Baseado em Energia Regularizada (FREL), que serve como uma técnica de seleção ou ponderação de características projetada para oferecer precisão e estabilidade. Em nossa discussão, fornecemos uma visão geral dos fundamentos teóricos por trás do aprendizado baseado em energia regularizada e da ponderação de características. Além disso, ilustramos a eficácia da abordagem proposta por meio da implementação de um exemplo de programa MQL5, desenvolvido como um script, para destacar o potencial do método como uma ferramenta de seleção de características.


Classificação de vizinho mais próximo ponderado

O conceito por trás do FREL é inspirado em uma técnica conhecida como classificação de vizinho mais próximo ponderado, que utiliza as distâncias entre os pontos de um conjunto de dados para fazer previsões. Ao determinar os pesos adequados para cada característica, esse método melhora a precisão da previsão. A classificação de vizinho mais próximo ponderado representa uma variação do algoritmo k-nearest neighbor (k-NN), uma abordagem amplamente utilizada em aprendizado de máquina para tarefas de classificação. Na classificação k-NN padrão, o algoritmo examina os k pontos de dados mais próximos no conjunto de treinamento ao classificar um novo ponto de dados, atribuindo, por fim, a classe majoritária entre esses vizinhos ao novo ponto de dados.

Na classificação de vizinho mais próximo ponderado, no entanto, em vez de simplesmente contar os votos dos vizinhos mais próximos, cada voto de vizinho é ponderado de acordo com sua distância do novo ponto de dados. A justificativa é que vizinhos mais próximos devem exercer uma influência mais forte na decisão de classificação do que aqueles mais distantes. Esse processo de ponderação envolve o cálculo da distância entre o novo ponto de dados e cada ponto no conjunto de treinamento. Métricas de distância comuns utilizadas incluem distância euclidiana, distância de Manhattan ou similaridade cosseno, escolhidas com base nas características dos dados. Nesse contexto, utilizamos a distância de Manhattan, também referida como distância de bloco da cidade, entre os pontos de dados. A fórmula para calcular essa distância está mostrada abaixo. Onde, w, são os pesos e um caso de teste está sendo avaliado em relação a outros dados de treinamento, dado como caso de treinamento.

Fórmula da distância de vizinhos mais próximos ponderados


Entendendo modelos baseados em energia

Modelagem baseada em energia no aprendizado de máquina serve como uma estrutura versátil aplicável a tarefas de aprendizado supervisionado e não supervisionado. Ela opera com o princípio de atribuir valores de energia a várias configurações de dados e aprender um modelo capaz de distinguir entre configurações desejáveis e indesejáveis. Isso é alcançado minimizando a energia dos dados observados enquanto maximiza a energia das configurações de dados não observados ou indesejáveis.

No cerne dos modelos baseados em energia está a definição de uma função de energia, denotada como E(). Essa função recebe como entrada uma configuração de variáveis ou preditores, junto com um conjunto de parâmetros do modelo. A saída da função de energia fornece uma indicação da relevância da configuração das variáveis de entrada. Por exemplo, no contexto de avaliação de um modelo de regressão, a função de energia pode ser representada como o erro quadrático médio. Quando preditores relevantes são inseridos na equação do erro quadrático médio, o valor de saída tende a ser menor, refletindo maior relevância. Por outro lado, preditores ruins levam a valores maiores de erro quadrático médio. A função de energia atribui um valor escalar a cada configuração concebível de variáveis.

O objetivo do treinamento de um modelo baseado em energia é aprender os parâmetros da função de energia para que ela atribua baixas energias às variáveis de entrada relevantes e altas energias às irrelevantes. Isso implica definir uma função objetivo que penalize altas energias para variáveis corretas e baixas energias para variáveis incorretas. Para conseguir isso, o objetivo é identificar a configuração de variáveis incorretas que gera a menor energia, representando uma amostra que provavelmente causará previsões errôneas do modelo. A função abaixo representa a energia da configuração de entradas, x, e o parâmetro do modelo, w, que produz o valor incorreto, y, muito baixo para distinguir das configurações de variáveis de entrada que produzem previsões precisas. 

Fórmula de energia para configuração incorreta com menor energia

Por fim, a função objetivo visa maximizar a discrepância entre a configuração incorreta com menor energia e a configuração correta mais próxima de variáveis. A energia de tal configuração é dada abaixo.

Fórmula de energia para a configuração correta mais próxima de variáveis

A função objetivo, conhecida como funcional de perda, compreende uma função de perda média por amostra. Dada abaixo como a perda logarítmica.

Função de perda média por amostra (perda logarítmica)

Vários critérios de perda podem servir como a função de perda por amostra, como perda hinge, perda logarítmica, perda quadrática e perda quadrático-exponencial, dependendo da aplicação.

Em resumo, esses são os conceitos fundamentais subjacentes ao FREL. A seção subsequente detalha as especificidades do próprio algoritmo.


O algoritmo FREL

Para aplicar efetivamente o algoritmo FREL, certas considerações fundamentais devem ser seguidas. Primeiramente, é crucial avaliar cuidadosamente os dados de treinamento. O FREL é idealmente adequado para conjuntos de dados que mapeiam um conjunto de variáveis candidatas para um único alvo. Igualmente importante é garantir que as variáveis sejam semelhantes em escala. Expor o FREL a preditores candidatos com escalas inconsistentes pode distorcer significativamente os resultados finais.

Em segundo lugar, dado que o FREL é um procedimento de aprendizado baseado em energia, ele exige a definição de uma função de energia que incorpore parâmetros de ponderação. Portanto, o modelo usado deve ser configurado para aceitar um conjunto de variáveis candidatas junto com as ponderações correspondentes. Portanto, o modelo usado deve ser configurado para aceitar um conjunto de variáveis candidatas junto com as ponderações correspondentes. Cada peso seria emparelhado com um preditor candidato.

Por fim, deve-se selecionar uma função de perda por amostra para determinar o funcional de perda. O funcional de perda, que incorpora os parâmetros de ponderação do modelo, é a função (de funções) minimizada para obter os pesos ideais.

Os passos principais do algoritmo FREL são os seguintes:

Matriz de dados de treinamento

  1. Comece com um conjunto de dados de treinamento composto por n observações com d preditores candidatos correspondentes a n valores-alvo. O objetivo é determinar os preditores mais relevantes do conjunto de d candidatos para determinar os valores-alvo. Isso resulta na atribuição de pesos a cada um dos d preditores, indicando a importância da variável em relação aos outros. Um peso maior significa maior relevância na definição do valor-alvo. 
  2. Inicialmente, atribua a todos os pesos o valor de 1.
  3.  Aplique a classificação de vizinhos mais próximos ponderados a cada observação nos dados de treinamento para identificar a configuração de variáveis incorretas que geram a menor energia e a configuração mais próxima de variáveis corretas com alta energia. Utilize esses valores de energia para calcular a perda por amostra usando a função de perda selecionada.
  4.  Por fim, minimize a função de perda objetivo, opcionalmente com regularização, usando um procedimento de otimização apropriado. Este constitui o algoritmo central do FREL.
No artigo de pesquisa, os autores também demonstram uma melhoria no algoritmo central empregando bootstrap. A amostragem deve ser conduzida sem reposição, e as ponderações resultantes são os valores médios de cada amostra de bootstrap.


Implementação do FREL em MQL5

A implementação do FREL mostrada neste texto utiliza o método de otimização de Powell. Embora o método de otimização específico usado não seja crítico, os resultados devem ser relativamente consistentes entre os métodos. Nesta implementação, o método de Powell é representado como a classe "PowellsMethod", definida em Powells.mqh. O algoritmo FREL está encapsulado na classe "FREL", uma descendente de "PowellsMethod", especificada em frel.mqh.

//+------------------------------------------------------------------+
   //| constructor                                                      |
   //+------------------------------------------------------------------+

                     FREL(matrix &in_data,int numboot=1, int bootsize=0)
     {
      m_data = in_data;
      m_num_boot=(numboot>0)?numboot:1;
      m_bootsize=(bootsize>2 && bootsize<=int(m_data.Rows()) && m_num_boot>1)?bootsize:int(m_data.Rows());
      
      
      if(ArrayResize(m_indices, int(m_data.Rows()))!=int(m_data.Rows()) ||
         ArrayResize(m_target_bin, int(m_data.Rows()))!=int(m_data.Rows()) ||
         ArrayResize(m_trial_weights, int(m_data.Cols()-1))!=int(m_data.Cols()-1) ||
         ArrayResize(m_work_weights, int(m_data.Cols()-1))!=int(m_data.Cols()-1)
        )
        {
         Print(__FUNCTION__, " error ", GetLastError());
         m_memory_allocated = false;
        }
      else
         m_memory_allocated = true;
     }

Vamos nos aprofundar na descrição do construtor paramétrico. Ele é invocado com pelo menos um parâmetro: uma matriz de dados de treinamento. É crucial notar como os dados de treinamento devem ser estruturados na matriz. Cada linha representa uma observação ou uma amostra individual, enquanto as colunas representam as variáveis candidatas ou preditores a serem avaliados. O alvo é esperado na última coluna da matriz. Os parâmetros opcionais do construtor são explicados mais detalhadamente na tabela abaixo.

 Nome do parâmetro
 Tipo de dados
Valor Padrão
 Descrição
numboot
inteiro
1
"numboot" define o número de bootstraps a serem realizados.
bootsize
inteiro
0
"bootsize" define o tamanho de cada bootstrap. Tome cuidado ao definir esse parâmetro. Se for usado um valor maior do que o número de observações na matriz, "numboot" automaticamente volta para 1 e "bootsize" para o número de observações.

Há apenas um método com o qual os usuários precisam se familiarizar para utilizar a classe "FREL": "WeighVars()."

//+-----------------------------------------------------------------------+
   //| Find the most relevant variables from a dataset of candidate variables|
   //+-----------------------------------------------------------------------+

   bool               WeighVars(int num_bins_target, double reg_factor,int &index[],double &weights[])
     {
      
      if(!m_memory_allocated)
        {
         Print(" INTERNAL ERROR ");
         return false;
        }
        
        
      if(num_bins_target<=1 || num_bins_target>int(m_data.Rows()))
       {
        Print(__FUNCTION__, " invalid function parameter: num_bins_target. Parameter should be >=2 ");
        return false;
       }  

      int ret=0;
      double target[], target_thresholds[] ;
      double sum ;

      int n_cases = int(m_data.Rows());
      m_reg_factor = MathAbs(reg_factor);
      m_loss = 0.0;


      if(ArrayResize(index,int(m_data.Cols()-1))!=int(m_data.Cols()-1) ||
         !np::vecAsArray(m_data.Col(m_data.Cols()-1),target)
        )
        {
         Print(__FUNCTION__, " error ", GetLastError());
         return false;
        }

      int k = num_bins_target ;
      if(!bin_array(target, k, target_thresholds, m_target_bin))
         return false;

      if(k<num_bins_target)
        {
         Print("error bins of target vector ", num_bins_target," : ", k);
         return false;
        }

      for(int i=0 ; i<n_cases ; i++)
        {
         if(m_target_bin[i] >= num_bins_target)
           {
            Print("error m_target_bin array at index ", i, " is ",m_target_bin[i], " should be less than ", num_bins_target);
            return false;
           }
        }

      ret = calc_wt(num_bins_target,m_loss,weights);

      if(ret<0)
         return false;

      sum = 0.0 ;
      for(ulong var=0 ; var<m_data.Cols()-1 ; var++)
        {
         weights[var] = m_data.Col(var).Std() * exp(weights[var]);
         sum += weights[var] ;
        }

      for(ulong var=0 ; var<m_data.Cols()-1 ; var++)
        {
         weights[var] *= 100.0 / sum ;
         index[var] = int(var) ;
        }

      MathQuickSortDescending(weights,index,0,int(weights.Size()-1)) ;

      return true;
     }

Este método avalia os dados de treinamento especificados no construtor. Ele retorna um valor booleano, com "false" indicando que o procedimento falhou em ser concluído. Os parâmetros deste método são os seguintes:

  • "num_bins_target": Um número inteiro que define o número de intervalos em que os valores-alvo serão particionados. Esse parâmetro deve ser definido para qualquer número inteiro >= 2, mas <= o número de observações nos dados de treinamento.
  • "reg_factor": Um valor de ponto flutuante positivo que controla o grau de regularização. Um valor de 0 desativa a regularização.
  • "index[]": Um array de inteiros para o qual parte dos resultados da operação será escrita. Ele contém os índices das colunas originais, conforme fornecido ao construtor, organizados em ordem decrescente de relevância para o alvo.
  • "weights[]": Um array de ponto flutuante contendo as ponderações ótimas, organizadas em ordem decrescente.

Quando "WeighVars()" é invocado, os valores-alvo são extraídos da matriz e colocados em um array em preparação para uma chamada ao método privado "bin_array()". Esse método segmenta o array em categorias aproximadamente de mesmo tamanho, retornando dois arrays após a conclusão bem-sucedida. "upperbound_thresholds[]" é um array de limites superiores para cada segmento, enquanto o array de inteiros "categories[]" contém valores de índice representando o segmento ao qual cada valor-alvo correspondente pertence. Cada um desses valores é verificado para garantir que todos os valores-alvo foram corretamente classificados.

//+------------------------------------------------------------------+
   //| calculates the optimal weights of candidate variables            |
   //+------------------------------------------------------------------+

   int               calc_wt(int num_bins_target,double &loss_value, double &w[])
     {
      int ret,rand_error, class_count[] ;

      ret = 0;

      if(ArrayResize(class_count,num_bins_target)!=num_bins_target || (w.Size()!=uint(m_data.Cols()-1) && ArrayResize(w,int(m_data.Cols()-1))!=int(m_data.Cols()-1)))
        {
         Print(__FUNCTION__, " error ", GetLastError());
         return -1;
        }

      ArrayInitialize(w,0.0);
      loss_value = 0.0 ;

      for(ulong i=0 ; i<m_data.Rows() ; i++)
         m_indices[i] = int(i) ;
     
      for(int ibootstrap=0 ; ibootstrap<m_num_boot; ibootstrap++)
        { 
         Comment(" Bootstrap iteration ", ibootstrap+1);
           
         ArrayInitialize(class_count,0);

         int ii, j, k, m;

         ii = int (m_data.Rows()) ;
         while(ii > 1)
           {
            m = int (m_data.Rows()) - ii ;
            if(m >= m_bootsize)
               break ;
            j = (int)(MathRandomUniform(0.0,1.0,rand_error) * ii) ;
            if(j >= ii)
               j = ii - 1 ;
            k = m_indices[m] ;
            m_indices[m] = m_indices[m+j] ;
            m_indices[m+j] = k ;
            --ii ;
            ++class_count[m_target_bin[m_indices[m]]] ;
           }
           

         for(int i=0 ; i<num_bins_target ; i++)
           {
            if(class_count[i] < 2)
               Print(__FUNCTION__, "  class at ", i, " has less than 2 members. Considere ajustar os parâmetros Frel. (number of partitions or bootstrap sample size)");
           }
            
         ArrayInitialize(m_trial_weights,0.0);

         ret += Optimize(m_trial_weights);
         loss_value += PowellsMethod::GetFret() ;

         for(ulong i=0 ; i<m_data.Cols()-1 ; i++)
            w[i] += m_trial_weights[i] ; 

        }

      for(ulong i=0 ; i<m_data.Cols()-1; i++)
        w[i] /= double(m_num_boot) ;

      return ret ;

     }

A estimativa de pesos começa com uma chamada para "calc_wt()". Aqui, a amostragem bootstrap é realizada, embaralhando os dados antes de os pesos iniciais serem otimizados. A otimização é realizada pelo método da classe pai "Optimize()". Os pesos ótimos para cada bootstrap são somados em "w[]", para serem promediados antes de sair de "calc_wt()".

//+------------------------------------------------------------------+
   //| function minimized by Powells optimization method                |
   //+------------------------------------------------------------------+
   virtual double          func(const double& p[])
     {
      double pen = 0.0 ;

      for(ulong i=0 ; i<m_data.Cols()-1 ; i++)
        {
         if(p[i] > 4.0)
           {
            m_work_weights[i] = exp(4.0) + p[i] - 4.0 ;
            pen += (p[i] - 4.0) * (p[i] - 4.0) ;
           }
         else
            if(p[i] < -3.0)
              {
               m_work_weights[i] = exp(-3.0) + p[i] + 3.0 ;
               pen += (p[i] + 3.0) * (p[i] + 3.0) ;
              }
            else
               m_work_weights[i] = exp(p[i]) ;
        }

      return (loss(m_work_weights) + pen) ;
     }

Lembre-se de que a função que está sendo minimizada é o funcional de perda, representado por um método sobrescrito da classe pai chamado "func()". — ¶ —————————————————————

//+------------------------------------------------------------------+
   //| calculates the loss function                                     |
   //+------------------------------------------------------------------+
   double            loss(double &w[])
     {
      double totaloss = total_loss(w);

      totaloss/=double(m_data.Rows());

      if(m_reg_factor>0.0)
        {
         for(ulong i=0; i<m_data.Cols()-1;i++)
            totaloss+=m_reg_factor*pow(w[i],2.0);
        }

      return totaloss;
     }

Dentro de "func()", o método "loss()" é acionado, desencadeando o cálculo da função de perda por amostra implementada como o método privado "total_loss()".

//+------------------------------------------------------------------+
   //|  loss over all data                                              |
   //+------------------------------------------------------------------+

   double            total_loss(double &w[])
     {
      int category,first, other ;
      double  distance, top, bottom, loss ;

      loss = 0.0 ;
      for(int i=0; i<m_bootsize; i++)
        {
         other = m_indices[i] ;
         category = m_target_bin[other] ;
         top = bottom = DBL_MAX ;

         for(int iother=0 ; iother<m_bootsize; iother++)
           {
            first = m_indices[iother] ;
            if(first == other)
               continue ;

            distance = 0.0 ;
            for(ulong v=0 ; v<m_data.Cols()-1; v++)
              {
               distance += w[v] * fabs(m_data[other][v] - m_data[first][v]) ;
              }

            if(m_target_bin[first] == category)
              {
               if(distance < top)
                  top = distance ;
              }
            else
              {
               if(distance < bottom)
                  bottom = distance ;
              }
           }

         distance = top - bottom ;
         if(distance > 30.0)
            loss += distance ;
         else
            loss += log(1.0 + exp(distance));
        }

      return loss ;
     }

Após a conclusão de todos os bootstraps, os pesos ótimos médios são escritos no array "weights[]" fornecido pelo usuário. Antes de ordenar em ordem decrescente, os pesos são transformados de modo que somem coletivamente 100, melhorando a interpretabilidade.


Um exemplo de seleção de características usando FREL

Para demonstrar o algoritmo FREL, fornecemos o script "FrelExample.mq5". Este script utiliza o FREL para analisar um conjunto de dados gerado aleatoriamente, composto por variáveis candidatas e um alvo, para identificar os melhores preditores. Os usuários podem ajustar todos os parâmetros do algoritmo FREL e certas características do conjunto de dados sintético. Isso inclui o número total de observações (num_observations) e o número de preditores candidatos (num_candidate_predictors). Abaixo está um trecho ilustrando as entradas ajustáveis pelo usuário no script:

//---user adjustable input parameters
input int number_of_partitions = 8; //Number of partitions
input double regularization_factor = 0.0; //Regularization factor
input int number_of_bootstraps = 1;
input int bootstrap_size = 0;
input ulong num_observations = 2000;// Sample size of random dataset
input ulong num_candidate_predictors = 10;// Maximum number of candidate predictors in dataset

O script gera uma matriz de números aleatórios com num_observations linhas e num_candidate_predictors + 1 colunas. A última coluna é sobrescrita com a soma das colunas nos índices 1, 3, 5 e 7, que serve como a variável alvo do conjunto de dados.

//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
   srand(126);
//---check user input parameters
   if(number_of_partitions<2 || num_observations<10 || num_candidate_predictors<8)
     {
      Print("Invalid input parameters");
      return;
     }
//---the data
   matrix dataset;
//---initialize size of random dataset
   dataset.Init(num_observations,num_candidate_predictors+1);
//---fill dataset with random data
   dataset.Random(1.0,10.0);
//---set the target variable in the last column
   if(!dataset.Col(dataset.Col(1) + dataset.Col(3) + dataset.Col(5) + dataset.Col(7),num_candidate_predictors))
     {
      Print("error ", GetLastError());
      return;
     }
//---initialize Frel object
   FREL frel(dataset,number_of_bootstraps,bootstrap_size);
//---declare containers to recieve output from Frel operation
   double optimal_weights[];
   int index[];
//---
   ulong timeIT = GetTickCount64();
//---find the most relevant predictors
   if(!frel.WeighVars(number_of_partitions,regularization_factor,index,optimal_weights))
      return;
//---calculate runtime
   Print("Runtime of FREL ", GetTickCount64() - timeIT, " ms");
//---display results
   for(uint i = 0; i<optimal_weights.Size(); i++)
      Print("Predictor at Column index ", index[i], " weight ", optimal_weights[i]);

  }
//+------------------------------------------------------------------+

O objetivo é observar se o FREL pode ponderar adequadamente as variáveis, designando as colunas 1, 3, 5 e 7 como tendo o relacionamento mais forte com o alvo. Inicialmente, executamos o script com os parâmetros padrão, observando que a regularização está desativada e apenas um bootstrap foi especificado.

Configurações padrão do script FREL

Saída:

ON      0       18:12:30.906    FrelExample (BTCUSD,D1) Runtime of FREL 273375 ms
GD      0       18:12:30.906    FrelExample (BTCUSD,D1) Predictor at Column index 7 weight 24.46987538756267
IH      0       18:12:30.906    FrelExample (BTCUSD,D1) Predictor at Column index 3 weight 24.22319404776024
EL      0       18:12:30.906    FrelExample (BTCUSD,D1) Predictor at Column index 5 weight 22.26820806768701
LP      0       18:12:30.906    FrelExample (BTCUSD,D1) Predictor at Column index 1 weight 22.13748732798876
DD      0       18:12:30.906    FrelExample (BTCUSD,D1) Predictor at Column index 0 weight 1.162036446785271
KK      0       18:12:30.906    FrelExample (BTCUSD,D1) Predictor at Column index 8 weight 1.1532145209345603
RO      0       18:12:30.906    FrelExample (BTCUSD,D1) Predictor at Column index 4 weight 1.1496286906955606
RS      0       18:12:30.906    FrelExample (BTCUSD,D1) Predictor at Column index 2 weight 1.1472521997561425
NG      0       18:12:30.906    FrelExample (BTCUSD,D1) Predictor at Column index 6 weight 1.14561384476096
DK      0       18:12:30.906    FrelExample (BTCUSD,D1) Predictor at Column index 9 weight 1.14348946606884

Em seguida, investigamos o impacto da regularização nos pesos estimados testando com graus de regularização de 0,1 e 1,0.

Configurações do FREL com fator de regularização 0,1

Saída:

MQ      0       18:19:03.951    FrelExample (BTCUSD,D1) Runtime of FREL 331296 ms
QD      0       18:19:03.951    FrelExample (BTCUSD,D1) Predictor at Column index 3 weight 19.63442784832085
PK      0       18:19:03.951    FrelExample (BTCUSD,D1) Predictor at Column index 5 weight 19.009699240770477
GO      0       18:19:03.951    FrelExample (BTCUSD,D1) Predictor at Column index 7 weight 18.823288529399388
GQ      0       18:19:03.951    FrelExample (BTCUSD,D1) Predictor at Column index 1 weight 18.18026689510982
NE      0       18:19:03.951    FrelExample (BTCUSD,D1) Predictor at Column index 0 weight 4.106428447842871
KI      0       18:19:03.951    FrelExample (BTCUSD,D1) Predictor at Column index 8 weight 4.075425288243113
OM      0       18:19:03.951    FrelExample (BTCUSD,D1) Predictor at Column index 2 weight 4.070169243578418
MQ      0       18:19:03.951    FrelExample (BTCUSD,D1) Predictor at Column index 6 weight 4.051103060690134
FE      0       18:19:03.951    FrelExample (BTCUSD,D1) Predictor at Column index 9 weight 4.025271426001863
FJ      0       18:19:03.951    FrelExample (BTCUSD,D1) Predictor at Column index 4 weight 4.0239200200430805

Configurações do FREL com fator de regularização 0,1

Saída:

HP      0       18:25:43.421    FrelExample (BTCUSD,D1) Runtime of FREL 362984 ms
FF      0       18:25:43.421    FrelExample (BTCUSD,D1) Predictor at Column index 3 weight 10.353013480731704
JJ      0       18:25:43.421    FrelExample (BTCUSD,D1) Predictor at Column index 7 weight 10.227015183302557
IM      0       18:25:43.421    FrelExample (BTCUSD,D1) Predictor at Column index 5 weight 10.213781888319609
KQ      0       18:25:43.421    FrelExample (BTCUSD,D1) Predictor at Column index 1 weight 10.079770794877978
PF      0       18:25:43.421    FrelExample (BTCUSD,D1) Predictor at Column index 0 weight 9.948300319843046
QJ      0       18:25:43.421    FrelExample (BTCUSD,D1) Predictor at Column index 8 weight 9.938367489770178
KN      0       18:25:43.421    FrelExample (BTCUSD,D1) Predictor at Column index 2 weight 9.897336276433514
DQ      0       18:25:43.421    FrelExample (BTCUSD,D1) Predictor at Column index 6 weight 9.79559491756489
EF      0       18:25:43.421    FrelExample (BTCUSD,D1) Predictor at Column index 9 weight 9.774541742551756
CI      0       18:25:43.421    FrelExample (BTCUSD,D1) Predictor at Column index 4 weight 9.77227790660475

Os resultados dos testes de regularização indicam que os pesos se espalham por outras variáveis, divergindo das variáveis corretas. É provável que especificar um grau maior de regularização leve a pesos menos distintos, dificultando a diferenciação entre variáveis úteis e irrelevantes.

Ao examinar os resultados de execução dos nossos testes, é evidente que o FREL opera relativamente devagar. O gargalo provavelmente está relacionado à função "total_loss()", que precisa iterar por todo o conjunto de dados várias vezes conforme o otimizador é executado. Para melhorar a eficiência de execução, realizamos vários bootstraps com um tamanho de amostra menor. Os seguintes resultados são obtidos a partir de uma execução com 100 bootstraps de 40 amostras.

Configurações do FREL com Bootstraps

Saída:

IN      0       18:30:55.441    FrelExample (BTCUSD,D1) Runtime of FREL 22985 ms
OK      0       18:30:55.441    FrelExample (BTCUSD,D1) Predictor at Column index 3 weight 18.706272752181135
OL      0       18:30:55.441    FrelExample (BTCUSD,D1) Predictor at Column index 1 weight 18.32079620338284
RS      0       18:30:55.441    FrelExample (BTCUSD,D1) Predictor at Column index 5 weight 18.194009676469012
HG      0       18:30:55.441    FrelExample (BTCUSD,D1) Predictor at Column index 7 weight 16.298306686632337
MI      0       18:30:55.441    FrelExample (BTCUSD,D1) Predictor at Column index 4 weight 5.838867272535404
LM      0       18:30:55.441    FrelExample (BTCUSD,D1) Predictor at Column index 9 weight 5.249285089162589
FQ      0       18:30:55.441    FrelExample (BTCUSD,D1) Predictor at Column index 8 weight 4.791606631149278
DE      0       18:30:55.441    FrelExample (BTCUSD,D1) Predictor at Column index 6 weight 4.770223641360407
KI      0       18:30:55.441    FrelExample (BTCUSD,D1) Predictor at Column index 0 weight 3.974977300216029
KM      0       18:30:55.441    FrelExample (BTCUSD,D1) Predictor at Column index 2 weight 3.855654746910961


Conclusão

Neste artigo, introduzimos uma implementação em MQL5 da ponderação de características usando modelagem baseada em energia regularizada. Fornecemos uma breve visão geral dos fundamentos teóricos do algoritmo e demonstramos sua eficácia em um conjunto de dados sintético. Embora os resultados fossem promissores, observamos que o algoritmo incorreu em custos computacionais significativos, levando a uma análise lenta. Para lidar com esse problema, propusemos a utilização de múltiplos bootstraps com tamanhos de amostra menores, o que melhorou significativamente a velocidade de execução geral do algoritmo. No entanto, nossa implementação ainda poderia se beneficiar grandemente de multithreading ou aceleração por GPU. Mesmo assim, encorajamos os interessados no método a personalizar o código de acordo com suas necessidades. O artigo inclui todo o código discutido, com cada arquivo-fonte detalhado na tabela abaixo.

Arquivo-fonte
Descrição
Mql5\include\np.mqh
Um arquivo de cabeçalho com várias ferramentas de manipulação de vetores e matrizes.
Mql5\include\Powells.mqh
Contém a definição da classe PowellsMethod, que implementa o método de minimização de funções de Powell.
Mql5\include\frel.mqh
Contém a definição da classe FREL, que representa a ponderação de características como um algoritmo de aprendizado baseado em energia regularizada.
Mql5\script\FrelExample.mq5
Um script demonstrando o uso da classe FREL


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

Arquivos anexados |
frel.mqh (14.08 KB)
Powells.mqh (17.57 KB)
np.mqh (37.73 KB)
FrelExample.mq5 (2.52 KB)
Mql5.zip (12.76 KB)
Desenvolvendo um sistema de Replay (Parte 67): Refinando o Indicador de controle Desenvolvendo um sistema de Replay (Parte 67): Refinando o Indicador de controle
Neste artigo mostrarei o que um pouco de refinamento no código é capaz de fazer. Tal refinamento tem como objetivo tornar mais simples o nosso código. Fazer um maior uso das chamadas de biblioteca do MQL5. Mas principalmente fazer com que o nosso código se torne bem mais estável, seguro e fácil de ser usado por outras classe, ou outros códigos que por ventura construiremos. O conteúdo exposto aqui, visa e tem como objetivo, pura e simplesmente a didática. De modo algum deve ser encarado como sendo, uma aplicação cuja finalidade não venha a ser o aprendizado e estudo dos conceitos mostrados.
Introdução ao MQL5 (Parte 7): Guia para Iniciantes na Criação de Expert Advisors e Utilização de Código Gerado por IA no MQL5 Introdução ao MQL5 (Parte 7): Guia para Iniciantes na Criação de Expert Advisors e Utilização de Código Gerado por IA no MQL5
Descubra o guia definitivo para iniciantes na criação de Expert Advisors (EAs) com MQL5 em nosso artigo abrangente. Aprenda passo a passo como construir EAs utilizando pseudocódigo e aproveite o poder do código gerado por IA. Seja você novo no trading algorítmico ou esteja buscando aprimorar suas habilidades, este guia oferece um caminho claro para criar EAs eficazes.
Arbitragem Estatística com previsões Arbitragem Estatística com previsões
Vamos explorar a arbitragem estatística, pesquisar com Python símbolos correlacionados e cointegrados, criar um indicador para o coeficiente de Pearson e desenvolver um EA para negociar arbitragem estatística com previsões feitas com Python e modelos ONNX.
Do básico ao intermediário: Array e Strings (I) Do básico ao intermediário: Array e Strings (I)
Neste artigo, começaremos a ver alguns tipos especiais de dados. Vamos começar definindo o que seria uma string e como usar alguns procedimentos básicos. Isto para que possamos começar a trabalhar com este tipo que é bem curioso. Apesar de em alguns momentos ser um tanto confuso para iniciantes. O conteúdo exposto aqui, visa e tem como objetivo, pura e simplesmente a didática. De modo algum deve ser encarado como sendo, uma aplicação cuja finalidade não venha a ser o aprendizado e estudo dos conceitos mostrados.