English Русский 中文 Español Deutsch 日本語
Como implementar seus próprios critérios de otimização

Como implementar seus próprios critérios de otimização

MetaTrader 4Testador | 22 fevereiro 2016, 14:29
1 163 0
Nikolai Shevchuk
Nikolai Shevchuk

Introdução

De vez em quando ouvimos opiniões sobre a necessidade de aumentar o conjunto de critérios de optimização no verificador MT4. Ainda assim, você pode imaginar que não importa quais critérios os desenvolvedores acrescentem, sempre haverá usuários e situações que exigem outros critérios. Este problema pode ser resolvido dentro da MQL4 e do MetaTrader? Sim, pode. Este artigo mostra a implementação do uso de um critério de otimização personalizado no exemplo do Expert Advisor padrão Média Móvel. O critério aqui é a relação lucro/levantamento de crédito.

Expert Advisor

Vamos começar com o critério de otimização. Para seu cálculo, precisamos traçar durante o teste a máxima do balanço e o levantamento de crédito. A fim de não depender da lógica da operação do Expert Advisor, vamos adicionar as strings do código existente no início da função start().

  if (AccountEquity() > MaxEqu) MaxEqu = AccountEquity();
   if (MaxEqu-AccountEquity() > MaxDD) MaxDD = MaxEqu-AccountEquity();

Para processar o último crédito, elas devem ser duplicadas no deinit(). Depois disso, podemos calcular o valor do critério de otimização.

    Criterion = (AccountBalance()-StartBalance)/MaxDD;

Agora podemos começar a parte principal - a manutenção do processo de otimização. Temos um problema - o MQL4 não têm os meios internos de determinar o final da otimização. A única saída que conheço é a chamada "otimização em um contador". O significado é o seguinte: o único parâmetro variável do Expert Advisor é o contador variável especial externo. Ainda aqui é uma consequência grave - perdemos a possibilidade de alterar os parâmetros reais do Expert Advisor de forma padrão e devemos fornecer isto nós mesmos. Outra desvantagem é que o cache de otimização do nosso amigo se transforma no nosso inimigo. Mas o fim justifica os meios, então vamos continuar.

Vamos adicionar variáveis externas:

extern int Counter                    = 1;    // Counter of the tester's running
extern int TestsNumber                = 200;  // he check digit - total number of runs 
extern int MovingPeriodStepsNumber    = 20;   // Number of optimization steps for MovingPeriod 
extern int MovingShiftStepsNumber     = 10;   // Number of optimization steps for MovingShift
extern double MovingPeriodLow         = 150;  // Lower limit of the optimization range for MovingPeriod
extern double MovingShiftLow          = 1;    // Lower limit of the optimization range for MovingShift
extern double MovingPeriodStep        = 1;    // Optimization step for MovingPeriod 
extern double MovingShiftStep         = 1;    // Optimization step for MovingShift

Primeiro vem o contador. A próxima variável é a de verificação (e informação). Em seguida, atribuímos o número de passos, limite inferior e etapa de otimização para as duas variáveis internas de média móvel destinadas a otimização. Você pode ver alguns excessos: se vamos fazer o exame completo (e vamos fazê-lo) o produto do MovingPeriodStepsNumber e MovingShiftStepsNumber deve ser igual ao TestsNumber.

Depois que cada teste executa o Expert Advisor, isto termina plenamente o seu trabalho e a próxima execução pode ser considerada sua reencarnação. Nós temos duas formas de organizar "o armazenamento genético": variáveis globais e um arquivo separado. Usaremos os dois.

Vamos modificar a função init():

int init() {
  if (IsTesting() && TestsNumber > 0) {
    if (GlobalVariableCheck("FilePtr")==false || Counter == 1) {
      FilePtr = 0; 
      GlobalVariableSet("FilePtr",0); 
    } else {
      FilePtr = GlobalVariableGet("FilePtr"); 
    }
    MovingPeriod = MovingPeriodLow+((Counter-1)/MovingShiftStepsNumber)*MovingPeriodStep;
    MovingShift = MovingShiftLow+((Counter-1)%MovingShiftStepsNumber)*MovingShiftStep;
    StartBalance = AccountBalance();
    MaxEqu = 0;
    MaxDD = 0;
  }   
  return(0);
}

Nossa adição está localizada dentro das condições de operação unicamente no verificador e no TestsNumber diferente de zero. Assim, a tarefa TestsNumber=0 irá transformar o Expert Advisor em um padrão de Média Móvel. Enquanto estamos discutindo o processo de otimização, devemos usar qualquer possibilidade de aceleração do processo. É por isso que o código começa com o fornecimento de gestão por meio (através da execução de verificadores) do indicador de arquivo usando uma variável global. Em seguida, calculamos valores de parâmetros mutáveis e inicializamos variáveis utilizadas para o cálculo do critério de otimização.

O trabalho principal deve ser feito na função deinit(). Mediante os resultados dos testes, iremos salvar em um arquivo de texto os valores do critério de otimização, os valores dos parâmetros otimizados e o número de execuções do teste. Após o fim da otimização, os resultados serão classificados de acordo com o critério de otimização e salvos no mesmo arquivo. Então, precisamos processar três situações: a primeira partida, a segunda partida e todos as outras. Vamos usar o contador de execução do verificador para esta separação.
Processamento da primeira partida:

    if (Counter == 1) {
// First run, create/initialize a datafile.
      h=FileOpen("test.txt",FILE_CSV|FILE_WRITE,';');
      FileWrite(h,Criterion,MovingPeriod,MovingShift,Counter);
// Remember the position of the file pointer after writing in the global variable
      FilePtr = FileTell(h); 
      GlobalVariableSet("FilePtr",FilePtr);
      FileClose(h);

A peculiaridade de processar outros inícios é que os novos dados são adicionados ao arquivo:

    } else {
//  After the first start is processed, the data are added into the file
      h=FileOpen("test.txt",FILE_CSV|FILE_READ|FILE_WRITE,';');
//  It is time to use the file pointer written in the global variable
      FilePtr = GlobalVariableGet("FilePtr");
      FileSeek(h,FilePtr, SEEK_SET);
      FileWrite(h,Criterion,MovingPeriod,MovingShift,Counter);
//  Remember the file pointer position once again
      FilePtr = FileTell(h); 
      GlobalVariableSet("FilePtr",FilePtr);

Agora vamos processar a última partida:

      if (Counter == TestsNumber) {
        ArrayResize(Data,TestsNumber); 
// Returns the file pointer to the beginning       
        FileSeek(h,0,SEEK_SET);
// Read from the file the results of all testings
        int i = 0;
        while (i<TestsNumber && FileIsEnding(h)== false) {
          for (int j=0;j<4;j++) {
            Data[i][j]=FileReadNumber(h); 
          }
          i++;
        } 
// Sort the array according to our optimization criterion
        ArraySort(Data,WHOLE_ARRAY,0,MODE_DESCEND);
// Now let us arrange the results. Reopen the file        
        FileClose(h); 
        h=FileOpen("test.txt",FILE_CSV|FILE_WRITE,' ');
        FileWrite(h,"  Criterion","     MovingPeriod"," MovingShift"," Counter");
        for (i=0;i<TestsNumber;i++) {
          FileWrite(h,DoubleToStr(Data[i][0],10),"        ",Data[i][1],"        ",Data[i][2],"        ",Data[i][3]);
        }

A matriz foi preliminarmente inicializada como dados duplos[][4]. Isto é tudo! Vamos limpar:

       GlobalVariableDel("FilePtr");
      }
      FileClose(h); 
    }
  }

Compile, abra o verificador e selecione o Expert Advisor. Em seguida, abra a folha de propriedades do Expert Advisor e verifique quatro posições:

- O produto de MovingPeriodStepsNumber da MovingShiftStepsNumber DEVE ser igual ao TestsNumber.
- A otimização deve ser realizada APENAS para o contador,
- A faixa de otimização DEVE ser de 1 para números de teste com o passo 1.
- O algoritmo genético deve ser desativado.

Inicie a otimização. Após o final, mude para a pasta [Metatrader]\tester\ arquivos e exiba o resultado no arquivo test.txt. O autor fez isto paraEURUSD_H1 a partir de meados de 2004 sobre os preços de abertura e obteve os seguintes resultados:

E agora vamos voltar para a afirmação de que o cache é nosso inimigo. O fato é que, quando levamos os resultados dos testes a partir do cache, as funções init() e deinit() não estão iniciadas. Como resultado, no reinício da otimização todas as variantes ou parte das variantes estão desaparecidas. Além disso, embora o número real de execuções sejam menores do que o número de testes, os dados da matriz irão conter alguns zeros. O autor sugere duas formas de eliminar o "efeito cache": recompilação de um Expert Advisor ou o fechamento/ pausa/abertura da janela do verificador.
A interferência do cache pode ser detectada por uma contagem independente dos testes. Há três inserções comentadas para a organização de tal contagem usando uma variável global especial, sugeridas no código do EA em anexo:

// Code of the independent counter
    if (GlobalVariableCheck("TestsCnt")==false || Counter == 1) {
      TestsCnt = 0; 
      GlobalVariableSet("TestsCnt",0); 
    } else {
      TestsCnt = GlobalVariableGet("TestsCnt"); 
    }
 
// Code of the independent counter
    TestsCnt++;
    GlobalVariableSet("TestsCnt",TestsCnt); 
 
// Code of the independent counter
        GlobalVariableDel("TestsCnt");

Uma última coisa. Um leitor atento deve ter notado o fato de que nós podemos fazer sem a variável FilePtr (e a variável global de acompanhamento) - os dados são escritos no final do arquivo e lidos desde o início. Então, para que serve isto? A resposta é a seguinte: este Expert Advisor é destinado para a demonstração do método de manutenção de otimização. O método permite gerenciar a operação em tempo real com os resultados de testes anteriores. E aqui o canal do ponteiro do arquivo pode ser bastante útil, bem como o contador independente. Como um exemplo de tarefas que exigem ser trabalhadas com os resultados anteriores em tempo real, podemos citar a gestão dos testes de fora da amostra e a implementação do próprio algoritmo genético.

Conclusão

As causas para tal interesse para este problema foram temas do fórum http://forum.mql4.com.


Traduzido do russo pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/ru/articles/1498

Arquivos anexados |
Abordagem do objeto no MQL Abordagem do objeto no MQL
Este artigo vai ser interessante, em primeiro lugar, para programadores novatos e profissionais que trabalham no ambiente MQL. Também seria útil se este artigo fosse lido por desenvolvedores e ideólogos do ambiente MQL pois as questões aqui analisadas podem tornar-se projetos para uma futura implementação do MetaTrader e da MQL.
Linguagem MQL4 para Iniciantes. Indicadores técnicos e funções integradas Linguagem MQL4 para Iniciantes. Indicadores técnicos e funções integradas
Este é o terceiro artigo da série "Linguagem MQL4 para Iniciantes". Agora, vamos aprender a utilizar funções integradas e funções para trabalhar com indicadores técnicos. Estes últimas serão essenciais para o desenvolvimento futuro de seus próprios Advisors e indicadores. Além disso, veremos em um exemplo simples, como rastrear sinais de trading para entrar no mercado, assim, você entenderá como usar indicadores corretamente. E no final do artigo você aprenderá algo novo e interessante sobre a própria linguagem.
Linguagem MQL4 para Iniciantes. Indicadores personalizados (Parte 1) Linguagem MQL4 para Iniciantes. Indicadores personalizados (Parte 1)
Este é o quarto artigo da série "Linguagem MQL4 para Iniciantes". Hoje aprenderemos a escrever indicadores personalizados. Iremos nos familiarizar com a classificação das características indicadoras, veremos como essas características influenciam o indicador, aprenderemos sobre novas funções e otimização, e, finalmente, escreveremos nossos próprios indicadores. Além disso, no final do artigo você vai encontrará dicas sobre o estilo de programação. Se este é o primeiro artigo "para iniciantes" que você está lendo, talvez seja melhor você ler os anteriores. Além disso, certifique-se que você tenha entendido corretamente o material anterior pois este artigo não explica o básico.
Modelo Universal do Expert Advisor Modelo Universal do Expert Advisor
Este artigo ajudará iniciantes em trading a criar Expert Advisors ajustáveis.