English Русский 中文 Español Deutsch 日本語
preview
Uma Nova Abordagem para Critérios Personalizados em Otimizações (Parte 1): Exemplos de Funções de Ativação

Uma Nova Abordagem para Critérios Personalizados em Otimizações (Parte 1): Exemplos de Funções de Ativação

MetaTrader 5Testador |
26 0
Andrew Thompson
Andrew Thompson

Introdução

A busca pela otimização ideal para encontrar a combinação correta de parâmetros continua. O fórum está repleto de métodos sugeridos para persuadir o Otimizador do MetaTrader a retornar e classificar as várias execuções, permitindo que um desenvolvedor escolha uma combinação (ou combinações) de parâmetros que sejam estáveis. A introdução das prop firms na equação, com seus limites rigorosos — compreensivelmente muito mais rigorosos do que os exigidos por um trader individual — tornou isso ainda mais desafiador.

A capacidade de definir um Critério Personalizado, e até mesmo utilizar o Critério Complexo com sua metodologia opaca, introduziu a possibilidade de reduzir a análise — ou pelo menos a inspeção — dos resultados em Excel, Python, R ou em software proprietário, para obter a melhor permutação de parâmetros.

O problema é que ainda não é incomum ver o uso de return(0) em Critérios Personalizados publicados. Isso está repleto de perigos reais ou potenciais, incluindo a possibilidade de descartar resultados (ligeiramente) indesejados ou, pior ainda, desviar o processo de otimização genética de caminhos potencialmente produtivos.

Em uma tentativa de retornar a alguns primeiros princípios, após conduzir alguns experimentos bastante empíricos, procurei encontrar algumas equações de curvas. Para isso, analisei “Funções de Ativação em Redes Neurais” e adotei e modifiquei algumas para uso aqui. Além disso, tendo esclarecido essas funções, sugeri alguns métodos para colocá-las em uso prático.

O plano para esta série de artigos é o seguinte:

  1. Introdução e funções de ativação padrão com código MQL5
  2. Modificações, escalonamento e ponderação e exemplos reais
  3. Uma ferramenta para explorar diferentes curvas, escalonamento e ponderação
  4. Quaisquer outros pontos que surgirem...


Estado atual do uso de Critérios Personalizados

Dois colaboradores, pelos quais tenho o maior respeito, fizeram excelentes observações para ilustrar o problema, com preocupações sobre o uso de return(0) e os resultados retornados pelo Critério Complexo. Alain Verleyen, moderador do fórum, relata uma execução retornando uma perda de 6.000 pontuando mais alto do que outra retornando um lucro de 1.736 com mais operações (e pontuando consideravelmente melhor em Fator de Lucro, RF, índice de Sharpe E drawdown). Alain diz: ‘o enigmático "critério complexo" produz alguns resultados estranhos.’ Eu iria além e diria que isso certamente levanta dúvidas significativas sobre a metodologia por trás do Critério Complexo. Se de fato, como Muhammad Fahad comenta mais adiante na mesma discussão — e tenho certeza de que ele está correto — ‘resultados com saldo negativo não são particularmente ruins para otimização, eles desempenham um papel crucial no julgamento da geração futura do ruim versus o pior enquanto os genes estão sendo cruzados’, o retorno de uma pontuação tão positiva pode possivelmente direcionar erroneamente o otimizador genético.

Já faz muito, muito tempo desde que utilizei o MT4, mas lembro vagamente da capacidade de inserir restrições para certas estatísticas de resultado. No MQL5, à primeira vista, não parece haver como fazer isso além de usar o instrumento bastante rudimentar de return(0) em um Critério Personalizado, cujas desvantagens potenciais já foram mencionadas. Ocorre-me que, se pudermos obter um valor de retorno muito próximo de 1 quando a razão ou métrica estiver no ou acima do mínimo desejado, no ou abaixo do máximo desejado, ou até mesmo no ou próximo de um alvo específico, e então multiplicando os valores para cada métrica/razão e depois multiplicando o resultado por 100, podemos estar diante de algo interessante...


Por que buscar inspiração em Redes Neurais?

i) Otimização genética como Rede Neural... 

Independentemente de o algoritmo genético possuir ou não uma rede neural por trás, o processo lógico parece ser o mesmo — testar uma combinação paramétrica, pontuá-la (de acordo com o critério de otimização selecionado), reter seleções potencialmente lucrativas para aprimoramento adicional e descartar o restante. Isso é repetido até que a melhoria na pontuação selecionada atinja um platô.

ii) Vales, gradientes explosivos, ponderação, normalização e seleção manual 

O problema da superfície de erro não convexa é bem conhecido em Machine Learning. Da mesma forma, parece que, na otimização genética, podemos acabar em mínimos locais ou pontos de sela, desviados por instruções return(0) que causam o descarte de ‘conhecimento’ pelo algoritmo genético.

O processamento de várias métricas para formar um critério personalizado também exige bastante reflexão... minhas primeiras tentativas foram muito rudimentares, utilizando diversos fatores para divisão e multiplicação, sem mencionar fatores exponenciais, levando a pontuações beirando o absurdamente alto (gradiente explosivo)... O algoritmo de pontuação do critério complexo claramente usa uma função para limitar a pontuação entre 0 e 100, sugerindo o uso de uma função do tipo Sigmoide ou logística.

A necessidade de aplicar pesos aos componentes individuais de um critério personalizado é clara: precisamos usar pesos para determinar a prioridade dos vários componentes, e normalização tanto das entradas, para ajustar a sensibilidade do nosso modelo, quanto da saída, para permitir comparação entre modelos. Abordaremos ponderação e normalização em um artigo futuro.

Quando observamos a saída de uma execução de otimização, seja manualmente ou em uma planilha, podemos ordenar por várias medidas de saída, filtrar resultados e, rapidamente, quase subconscientemente, selecionar conjuntos de parâmetros pela cor das métricas principais. Aqui estamos simplesmente reaplicando os processos descritos, que por si só são uma tentativa de imitar nosso próprio processamento intelectual do resultado completo.


Funções de Ativação em Redes Neurais

Parece-me que as funções que eu estava procurando eram semelhantes às que encontrei há um ou dois anos ao estudar Funções de Ativação em Redes Neurais.

As Funções de Ativação em Redes Neurais podem ser amplamente classificadas em três tipos: binárias, lineares e não lineares:

  • Funções binárias classificam valores em 1 de 2 classes retornando 1 ou 0. Elas não são particularmente úteis no nosso caso de uso;
  • Funções lineares retornam transformações por simples adição, multiplicação, subtração ou divisão, ou uma combinação dessas operações. Elas também são de pouca ajuda no nosso caso de uso.
  • Funções não lineares retornam curvas de resultados que são limitadas nos extremos de x, mas permitem discriminação dos valores de x em uma faixa centrada em 0. Essa faixa e centro podem ser modificados por meio do uso de offsets.

Deve-se dizer que o uso de

return(0);

bem como o retorno irrestrito do produto de inúmeras medidas de resultado, ambos dos quais fui culpado, e ambos os quais ainda vejo nos fóruns, são métodos que replicam os problemas associados a essas duas primeiras classes; por outro lado, funções não lineares tendem a ser limitadas para evitar gradientes explosivos, enquanto mantêm um gradiente de -∞ a ∞.

Como forma de explicação, recapitularei alguns dos exemplos padrão. Vamos analisar ReLU, Softplus, Sigmoid e Tanh, juntamente com, no próximo artigo, minhas próprias modificações: Flipped ReLU, Point ReLU, Flipped Sigmoid, Point Sigmoid, Flipped Tanh e Point Tanh.

a) Função de Ativação ReLU


O objetivo desta função é retornar zero quando x é <= 0 e x quando x > 0, ou, em notação matemática, f(x) = max(0,x). A linha obtida é ilustrada abaixo, e a função MQL5 pode ser definida assim:

double ReLU(double x) {
   return(MathMax(0, x));
}

Função de Ativação ReLU

Até aqui, tudo bem, você pode dizer, mas eu quero definir um valor mínimo para o Recovery Factor de 5 ou mais..., bem, simplesmente altere o código para * :

input double MinRF = 5.0;

double RF = TesterStatistics(STAT_RECOVERY_FACTOR);
double DeviationRF = RF - MinRF;

double ReLU(double x) {
   return(MathMax(0, x));
}

double ScoreRF = ReLU(DeviationRF);

assim deslocando a linha para a direita, iniciando em 0 quando RF = 5.0, conforme ilustrado:

Função de Ativação ReLU com Alvo

Isso, claro, dificilmente é mais avançado do que escrever*

input double MinRF = 5.0;

double RF = TesterStatistics(STAT_RECOVERY_FACTOR);
double ScoreRF = (RF - MinRF);

mas nos dá um ponto de partida...

* há também outra questão: o valor alvo, 5, na verdade retornará 0 e apenas valores >5 retornarão diferente de zero. Não pretendo dedicar tempo a essa questão, pois os diversos outros problemas desta função impedem sua utilidade adicional em nosso caso de uso.

Problemas

Logo fica claro que ainda temos 2 problemas, ambos decorrentes da simplicidade inerente do nosso código... Eu disse, acima:

"Isso, claro, dificilmente é mais avançado do que escrever

input double MinRF = 5.0;
double RF = TesterStatistics(STAT_RECOVERY_FACTOR);


double ScoreRF = (RF - MinRF);

mas nos dá um ponto de partida..."

Os problemas são bem conhecidos em Redes Neurais:

  • ReLU Morta: a principal fraqueza da ReLU é que neurônios podem "morrer" permanentemente quando produzem apenas zeros. Isso ocorre quando entradas fortemente negativas criam gradientes zero, tornando esses neurônios inativos e incapazes de continuar aprendendo. Isso também é referido como o problema do gradiente que desaparece.

  • Saída Não Limitada: as saídas da ReLU podem crescer indefinidamente para entradas positivas, ao contrário das funções Sigmoid ou Tanh, que possuem limites superiores incorporados. Essa ausência de limite superior pode, às vezes, causar problemas de explosão de gradiente durante o treinamento de redes neurais profundas. Isso também é referido como o problema do gradiente explosivo.

A segunda questão é tratada em estatística pela normalização de valores ao longo de uma janela de observação, mas esse método não está disponível para nós dentro das limitações do otimizador.

Portanto, precisamos de uma solução que

  1. gere matematicamente restrição, fornecendo uma normalização automatizada; e
  2. forneça algum grau de linearidade, em vez de retornar 0, ao longo de uma seção significativa da amostra...

    b) Função de Ativação Softplus


    Não pretendo entrar em muitos detalhes aqui, mas a menciono de passagem como uma etapa entre ReLU e as funções mais avançadas. Ela é bem descrita em Geeksforgeeks e eu simplesmente apresentarei a seguinte imagem, fórmula e código. Deve ficar claro que, embora resolva o problema da ReLU Morta, o problema de Saída Não Limitada permanece. Além disso, há a transição suave entre a cauda muito rasa e a inclinação do lado direito. Isso introduz a necessidade de considerar um offset de correção — um conceito ao qual retornaremos mais adiante:

    Função de Ativação Softplus comparada à ReLU

    A fórmula é Softplus(x) = ln(1 + e^x) e o código MQL5 é
    double Softplus(double x) {
       return(MathLog(1 + MathExp(x)));
    }

    Aproveite a leitura se desejar, mas agora chegamos às funções que nos fornecem resultados limitados entre 0 e 1...

    c) Função de Ativação Sigmoid


    A Função Sigmoid é expressa matematicamente como f(x) = 𝛔(x) = 1 / (1 + e^(-x)). Ela é idêntica à derivada da função Softplus e pode ser codificada em MQL5 assim:

    double Sigmoid(double x) {
       return(1 / (1 + MathExp(-x)));
    }

    Observando a curva (abaixo), é imediatamente evidente que

    1. ela é limitada entre 0 e 1, resolvendo assim nosso problema de Saída Não Limitada;

    2. embora difícil de perceber nesta escala, um gradiente variável, que nunca se torna zero, é mantido de -∞ a ∞; e 

    3. a curva não deslocada apresenta valor 0,5 quando x = 0.

    Para lidar com 3), de modo a aproximar-se de 1 quando x == nosso valor limite (alvo), é necessário deslocar a curva para a esquerda, não apenas pelo nosso valor limite, mas também por uma correção que é obtida na prática usando um valor de correção >= 5. 

    A implementação em MQL5 é, portanto

    input double MinRF = 5.0;
    sinput double SigCorrection = 5;
    
    double RF = TesterStatistics(STAT_RECOVERY_FACTOR);
    double DeviationRF = RF - MinRF;
    
    double CorrectedSigmoid(double x) {
       return(1 / (1 + MathExp(-(x - SigCorrection))));
    }
    
    double ScoreRF = CorrectedSigmoid(DeviationRF);
    A curva da Função Sigmoid não corrigida é ilustrada abaixo para um alvo de 5, juntamente com a derivada (multiplicada por 4), que será discutida a seguir.

    Sigmoid vs Derivada da Sigmoid, sem deslocamento

    d) Derivada da Sigmoid (𝛔')


    Isso nos fornece uma forma agradável, centrada e maximizada em x = 0... Ela representa a inclinação da Função Sigmoid, e a fórmula é f(x) = 𝛔(x) - 𝛔^2(x) ou 𝛔(x) * (1 - 𝛔(x)). 

    A função sofre potencialmente (assim como todas as funções que consideraremos) do problema do gradiente que desaparece, um risco que pode ser amenizado pelo simples expediente de multiplicá-la por 4 (uma vez que 𝛔’(x) = 0.25), o que também, de forma útil, restringe novamente o resultado entre 0 e 1. A centralização em um valor de x nos permite definir um alvo para um ponto ou, mais corretamente, um intervalo centrado em um ponto.

    Em MQL5 podemos fazer

    input double TargetTrades = 100;
    
    double Trades = TesterStatistics(STAT_TRADES);
    double DeviationTrades = Trades - TargetTrades;
    
    double Sigmoid(double x) {
       return(1 / (1 + MathExp(-x)));
    }
    
    double Deriv4Sigmoid(double x) {
       return(4 * (Sigmoid(x) * (1 - Sigmoid(x))));
    }
    
    double ScoreTrades = Deriv4Sigmoid(DeviationTrades);

    Nota: como nossos resultados para Sigmoid, sua Derivada (multiplicada por 4), e a seguir Tanh e sua Derivada, ambos reescalados entre 0 & 1, estão todos restritos entre 0 e 1, não precisamos fornecer qualquer escalar adicional em produção. Podemos, claro, multiplicar por qualquer fator para normalizá-los em relação a, ou priorizá-los sobre, quaisquer outros Índices de Otimização que possamos incluir em nosso Critério Personalizado final. Veremos isso no próximo artigo.

    Temos uma última função padrão para explorar, e essa é a Tanh...

    e) Tangente hiperbólica ou Tanh


    Tanh é a última das nossas Funções de Ativação que iremos explorar em nossa busca por utilidade em Critérios Personalizados. Seguirei um padrão semelhante com menos explicação do que antes, mas aplicando os mesmos princípios.

    O gráfico a seguir exibe a plotagem da Tanh com sua Derivada.

    Tanh vs Derivada da Tanh

    A fórmula da Tanh é f(x) = (e^x - e^(-x))/(e^x + e^(-x)) e em MQL5 ela possui sua própria função, portanto é simples de codificar. Claro, precisamos lidar com valores alvo e fatores de correção, mas ainda assim isso facilita o processo:

    input double MinRF = 5.0;
    sinput double TanhCorrection = 2.5; // Anything between 2 and 3 would be reasonable (see last figure)
    
    double RF = TesterStatistics(STAT_RECOVERY_FACTOR);
    double DeviationRF = RF - MinRF;
    
    double CorrectedRSTanh(double x) {
       return((MathTanh(x  + TanhCorrection) + 1) / 2);  // rescaled and corrected
    }
    
    double ScoreRF = CorrectedRSTanh(DeviationRF);

    O código acima reescala a função subjacente para restringi-la entre 0 e 1 (somando 1 e dividindo por 2). Ele também introduz um fator de correção e um alvo, e a curva resultante é mostrada no próximo gráfico, ilustrando a Derivada da Tanh. Não deve passar despercebido que a Tanh possui uma forma semelhante à Sigmoid, e as Derivadas entre si; exploraremos essas semelhanças no próximo artigo.

    f) Derivada da Tanh


    A fórmula matemática para a Derivada da Tanh é f(x) = 1 - Tanh^2(x).

    Em MQL5 podemos fazer

    input double TargetTrades = 100;
    
    double Trades = TesterStatistics(STAT_TRADES);
    double DeviationTrades = Trades - TargetTrades;
    
    double DerivTanh(double x) {
       return(1 - MathPow(x, 2));
    
    }double ScoreTrades = DerivTanh(DeviationTrades);

    O próximo gráfico mostra o efeito de reescalar a Tanh, corrigindo-a para aproximar o ponto de partida em 0 com o valor alvo (limiar) de x, e introduzindo um alvo tanto na Tanh quanto na Derivada da Tanh.

    Tanh Reescalada Corrigida vs Derivada da Tanh


    Resumo e Próximos Passos

    Neste artigo, consideramos brevemente a relação entre Machine Learning, por um lado, e o processo de otimização com ‘pós-processamento’ (seja genético ou completo), além de Excel ou pós-processamento manual, por outro. Começamos a analisar como diferentes tipos de Funções de Ativação podem refinar Critérios Personalizados e como codificá-las.

    Os problemas dos gradientes que desaparecem e dos gradientes explosivos em ReLU e Softplus nos levaram a direcionar nossa atenção para funções com curvas como a da função Sigmoid e também a de sua Derivada. Vimos como essas funções nos permitem favorecer, em nossa pontuação, intervalos com limite único (ou seja, x > t) ou intervalos com duplo limite (t1 < x < t2), eliminando o problema dos gradientes explosivos e mitigando o dos gradientes que desaparecem.

    Analisamos o uso de offsets de correção e offsets de alvo para ajudar a garantir o foco nas faixas de valores de atributos desejadas.

    No próximo artigo, analisaremos algumas modificações desta lista de funções padrão com atributos semelhantes, mas não idênticos. Também exploraremos a ideia de escalonamento e ponderação antes de analisar exemplos do uso de diferentes funções em Critérios Personalizados.


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

    Arquivos anexados |
    BaseFunctions.mqh (5.67 KB)
    Caminhe em novos trilhos: Personalize indicadores no MQL5 Caminhe em novos trilhos: Personalize indicadores no MQL5
    Vou agora listar todas as possibilidades novas e recursos do novo terminal e linguagem. Elas são várias, e algumas novidades valem a discussão em um artigo separado. Além disso, não há códigos aqui escritos com programação orientada ao objeto, é um tópico muito importante para ser simplesmente mencionado em um contexto como vantagens adicionais para os desenvolvedores. Neste artigo vamos considerar os indicadores, sua estrutura, desenho, tipos e seus detalhes de programação em comparação com o MQL4. Espero que este artigo seja útil tanto para desenvolvedores iniciantes quanto para experientes, talvez alguns deles encontrem algo novo.
    Introdução às curvas ROC (Receiver Operating Characteristic) Introdução às curvas ROC (Receiver Operating Characteristic)
    As curvas ROC são representações gráficas utilizadas para avaliar o desempenho de classificadores. Apesar de os gráficos ROC serem relativamente simples, existem equívocos e armadilhas comuns ao utilizá-los na prática. Este artigo tem como objetivo fornecer uma introdução aos gráficos ROC como uma ferramenta para profissionais que buscam compreender a avaliação de desempenho de classificadores.
    Está chegando o novo MetaTrader 5 e MQL5 Está chegando o novo MetaTrader 5 e MQL5
    Esta é apenas uma breve resenha do MetaTrader 5. Eu não posso descrever todos os novos recursos do sistema por um período tão curto de tempo - os testes começaram em 09.09.2009. Esta é uma data simbólica, e tenho certeza que será um número de sorte. Alguns dias passaram-se desde que eu obtive a versão beta do terminal MetaTrader 5 e MQL5. Eu ainda não consegui testar todos os seus recursos, mas já estou impressionado.
    Ciência de Dados e ML (Parte 34): Decomposição de séries temporais, desmembrando o mercado de ações até o núcleo Ciência de Dados e ML (Parte 34): Decomposição de séries temporais, desmembrando o mercado de ações até o núcleo
    Em um mundo repleto de dados ruidosos e imprevisíveis, identificar padrões significativos pode ser desafiador. Neste artigo, exploraremos a decomposição sazonal, uma poderosa técnica analítica que ajuda a separar os dados em seus principais componentes: tendência, padrões sazonais e ruído. Ao decompor os dados dessa forma, podemos revelar insights ocultos e trabalhar com informações mais limpas e interpretáveis.