Русский
preview
Algoritmo de otimização caótica — Chaos optimization algorithm (COA): Continuação

Algoritmo de otimização caótica — Chaos optimization algorithm (COA): Continuação

MetaTrader 5Testador |
24 0
Andrey Dik
Andrey Dik

Conteúdo

  1. Introdução
  2. Implementação do algoritmo
  3. Resultados dos testes
  4. Considerações finais


Introdução

No artigo anterior, nos familiarizamos com o método de otimização caótica e analisamos parte dos métodos que compõem o algoritmo. Neste artigo, finalizaremos a análise dos métodos restantes e passaremos diretamente ao teste do algoritmo em funções de teste. 

O método de otimização caótica, nesta implementação, utiliza caos determinístico para explorar o espaço de soluções. O princípio-chave é a aplicação de três diferentes mapeamentos caóticos, logístico, sinusoidal e tent mapping, para a geração de sequências que possuem propriedades de pseudoaleatoriedade e ergodicidade. O algoritmo opera em três fases: busca caótica inicial, refinamento da solução pelo método do gradiente ponderado e busca local final com estreitamento adaptativo da região.

O uso de vetores de velocidade com inércia e mecanismos de detecção de estagnação permite evitar extremos locais. A adaptação dinâmica de parâmetros e diferentes tipos de mutações garantem o equilíbrio entre a exploração global e a exploração local das soluções encontradas. Isso é um resumo do principal e, agora, continuemos a analisar os métodos restantes.



Implementação do algoritmo

O método "ApplyMutation" é destinado à introdução de mutações em um agente. Sua principal tarefa é a modificação aleatória dos parâmetros de um agente específico.

O método começa com a verificação da correção do índice do agente especificado. Se o índice estiver fora do intervalo permitido, a execução do método é encerrada. Em seguida, é realizada a coleta de informações sobre o tamanho de diferentes arrays associados ao agente, como os tamanhos de seus parâmetros e das velocidades. Isso permite evitar acessos fora dos limites desses arrays durante a execução do método.

O método calcula o número máximo de coordenadas que podem ser alteradas, com base nos tamanhos dos arrays disponíveis, para garantir a segurança das operações. É selecionado um número aleatório que determina quantas coordenadas serão submetidas à mutação. Esse valor varia de 1 até 30% do número máximo de coordenadas disponíveis. Forma-se um array de índices que representa as coordenadas que podem ser alteradas. Esse array é embaralhado para garantir a seleção aleatória durante a aplicação das mutações.

No loop ocorre a seleção das coordenadas para mutação a partir do array embaralhado. Para cada coordenada selecionada, é determinado o tipo de mutação com base em um valor aleatório. Os tipos possíveis incluem mutação totalmente aleatória, na qual o novo valor é escolhido aleatoriamente dentro de um intervalo especificado, mutação em relação à melhor solução global e mutação com uso de mapeamentos caóticos.

Após a alteração do valor para cada coordenada, a velocidade do agente é redefinida, para que o novo valor não sofra influência das velocidades anteriores. Por fim, o novo valor da coordenada correspondente do agente é definido levando em conta os intervalos e os passos, o que garante que os valores permaneçam dentro dos limites permitidos.

//——————————————————————————————————————————————————————————————————————————————
void C_AO_COA_chaos::ApplyMutation (int agentIdx)
{
  // Определяем количество координат для мутации (от 1 до 30% координат)
  int mutationCount = 1 + (int)(u.RNDprobab () * coords * 0.3);
  mutationCount = MathMin (mutationCount, coords);

  // Создаем массив индексов для мутации без повторений
  int mutationIndices [];
  ArrayResize (mutationIndices, coords);

  // Заполняем массив индексами
  for (int i = 0; i < coords; i++)
  {
    mutationIndices [i] = i;
  }

  // Перемешиваем индексы
  for (int i = coords - 1; i > 0; i--)
  {
    int j = (int)(u.RNDprobab () * (i + 1));
    if (j <= i) // Дополнительная проверка для безопасности
    {
      int temp = mutationIndices [i];
      mutationIndices [i] = mutationIndices [j];
      mutationIndices [j] = temp;
    }
  }

  // Применяем мутации к выбранным координатам
  for (int m = 0; m < mutationCount; m++)
  {
    int c = mutationIndices [m];

    // Различные типы мутаций для разнообразия
    double r = u.RNDprobab ();
    double x;

    if (r < 0.3)
    {
      // Полная случайная мутация
      x = rangeMin [c] + u.RNDprobab () * (rangeMax [c] - rangeMin [c]);
    }
    else
      if (r < 0.6)
      {
        // Мутация относительно глобального лучшего
        double offset = (u.RNDprobab () - 0.5) * (rangeMax [c] - rangeMin [c]) * 0.2;
        x = cB [c] + offset;
      }
      else
      {
        // Мутация с использованием хаотического отображения
        agent [agentIdx].gamma [c] = SelectChaosMap (agent [agentIdx].gamma [c], (epochNow + c) % 3);
        x = rangeMin [c] + agent [agentIdx].gamma [c] * (rangeMax [c] - rangeMin [c]);
      }

    // Сбрасываем скорость
    agent [agentIdx].velocity [c] = 0.0;

    // Применяем новое значение с проверкой диапазона
    a [agentIdx].c [c] = u.SeInDiSp (x, rangeMin [c], rangeMax [c], rangeStep [c]);
  }
}
//——————————————————————————————————————————————————————————————————————————————

O método "UpdateSigma" na classe é responsável pela adaptação dinâmica do parâmetro de penalização, que é utilizado no processo de otimização. Ele ajusta o valor da penalização dependendo da quantidade de soluções viáveis na população de agentes.

Se o método for chamado pela primeira vez, quando a época é igual a 1, o valor da penalização atual (currentSigma) é definido como metade do valor base (sigma). O método percorre toda a população de agentes e contabiliza o número de soluções viáveis. Para isso, é utilizada uma função auxiliar que determina se um agente é viável. Nesse ponto, é realizada a iteração por todos os agentes, o que permite determinar quantos deles atendem aos critérios estabelecidos.

Em seguida, o método calcula a proporção de soluções viáveis em relação à população total, dividindo o número de soluções viáveis pelo número total de agentes. Essa relação ajuda a compreender o quão bem a estratégia atual está funcionando. Com base na proporção calculada de soluções viáveis, o método toma decisões sobre o ajuste da penalização: se a proporção de soluções viáveis for inferior a 30%, isso indica que o algoritmo está excessivamente rigoroso, e a penalização é aumentada para forçar os agentes a apresentarem maior diversidade em suas soluções. Se, por outro lado, a proporção ultrapassar 70%, isso indica que muitos agentes encontram soluções viáveis, e a penalização é reduzida para evitar convergência prematura.

Ao final, o método garante que o valor da penalização atual permaneça dentro de limites aceitáveis. Se ele se tornar muito pequeno, inferior a 10% do valor base, a penalização é elevada até esse nível. De forma análoga, se a penalização exceder 500% do valor base, ela é limitada a esse patamar.

//——————————————————————————————————————————————————————————————————————————————
void C_AO_COA_chaos::UpdateSigma ()
{
  // Динамическая адаптация параметра штрафа
  // Начинаем с малого значения и увеличиваем его при необходимости

  if (epochNow == 1)
  {
    currentSigma = sigma * 0.5;
    return;
  }

  // Подсчет количества допустимых решений
  int feasibleCount = 0;
  for (int i = 0; i < popSize; i++)
  {
    if (IsFeasible (i))
    {
      feasibleCount++;
    }
  }

  double feasibleRatio = (double)feasibleCount / MathMax (1, popSize);

  // Адаптация параметра штрафа в зависимости от доли допустимых решений
  if (feasibleRatio < 0.3)
  {
    // Слишком мало допустимых решений - увеличиваем штраф
    currentSigma *= 1.2;
  }
  else
    if (feasibleRatio > 0.7)
    {
      // Слишком много допустимых решений - уменьшаем штраф
      currentSigma *= 0.9;
    }

  // Ограничиваем значение sigma
  if (currentSigma < sigma * 0.1) currentSigma = sigma * 0.1;
  else
    if (currentSigma > sigma * 5.0) currentSigma = sigma * 5.0;
}
//——————————————————————————————————————————————————————————————————————————————

O método "IsFeasible" determina se uma solução específica, representada por um agente com o índice especificado "agentIdx", é viável (feasible) em relação às restrições definidas.

Primeiramente, o método verifica se o índice do agente especificado (agentIdx) está dentro do intervalo permitido, isto é, maior ou igual a 0 e menor que o tamanho da população (popSize). Se o índice for incorreto, o método retorna "false", sinalizando a inviabilidade da solução. Se o índice do agente for válido, o método prossegue para a verificação das restrições dessa solução. Ele percorre todas as coordenadas (coords) da solução e, para cada coordenada, calcula o valor de violação da restrição por meio da função "CalculateConstraintValue".

A função "CalculateConstraintValue" retorna um valor que reflete o grau de violação das restrições para uma coordenada específica da solução. Se, após a verificação de todas as coordenadas, nenhuma restrição for violada, isto é, todos os valores de violação forem menores ou iguais a "eps", a solução é considerada viável, e o método retorna "true".

//——————————————————————————————————————————————————————————————————————————————
bool C_AO_COA_chaos::IsFeasible (int agentIdx)
{
  // Проверяем, находится ли решение в допустимой области
  for (int c = 0; c < coords; c++)
  {
    double violation = CalculateConstraintValue (agentIdx, c);
    if (violation > eps)
    {
      return false;
    }
  }
  return true;
}
//——————————————————————————————————————————————————————————————————————————————

O método "UpdateBestHistory" é necessário para armazenar o melhor valor atual no histórico da busca. Ele recebe um novo melhor valor e, inicialmente, verifica sua correção ou viabilidade. Se o valor for válido, ele é salvo no array que armazena o histórico dos melhores resultados, na posição indexada atual. Em seguida, o índice é atualizado para o próximo armazenamento, utilizando atualização cíclica por meio da operação de resto da divisão pelo tamanho do array de histórico, o que garante o preenchimento contínuo do histórico com os últimos 10 valores, sem ultrapassar os limites do array.

Esse método permite acompanhar o progresso da busca e utilizar o histórico das melhores soluções para análise.

//——————————————————————————————————————————————————————————————————————————————
void C_AO_COA_chaos::UpdateBestHistory (double newBest)
{
  // Защита от некорректных значений
  if (!MathIsValidNumber (newBest)) return;

  // Обновляем историю лучших значений
  globalBestHistory [historyIndex] = newBest;
  historyIndex = (historyIndex + 1) % 10;
}
//——————————————————————————————————————————————————————————————————————————————

O método "IsConverged" é destinado a determinar se o algoritmo atingiu um estado de convergência. Ele analisa o histórico das melhores soluções globais para avaliar o quão significativas são as melhorias das soluções ao longo do tempo. Se as melhorias se tornarem insignificantes, considera-se que o algoritmo convergiu.

O método inicializa variáveis para contabilizar a quantidade de valores viáveis, a soma dos valores, o valor mínimo e o valor máximo a partir do histórico das melhores soluções globais (globalBestHistory). As variáveis "minVal" e "maxVal" são inicializadas, respectivamente, com o maior e o menor valor possível do tipo "double", para permitir a correta determinação dos valores mínimo e máximo posteriormente.

O método itera pelo array "globalBestHistory" e, para cada valor no histórico, realiza verificações de viabilidade dos valores, suficiência dos dados e diversidade, calcula o valor médio e a diferença relativa, e verifica a convergência. De modo geral, o método "IsConverged" fornece uma forma de determinar a convergência do algoritmo de otimização, analisando o histórico das melhores soluções e avaliando o quão significativas são as melhorias ao longo do tempo. 

//——————————————————————————————————————————————————————————————————————————————
bool C_AO_COA_chaos::IsConverged ()
{
  // Проверка достаточного количества данных в истории
  int validValues = 0;
  double sum      = 0.0;
  double minVal   = DBL_MAX;
  double maxVal   = -DBL_MAX;

  // Находим min, max и sum значений в истории
  for (int i = 0; i < 10; i++)
  {
    if (globalBestHistory [i] == -DBL_MAX || !MathIsValidNumber (globalBestHistory [i])) continue;

    minVal = MathMin (minVal, globalBestHistory [i]);
    maxVal = MathMax (maxVal, globalBestHistory [i]);
    sum += globalBestHistory [i];
    validValues++;
  }

  // Если недостаточно данных или все значения одинаковые
  if (validValues < 5 || minVal == maxVal) return false;

  // Вычисляем среднее значение
  double average = sum / validValues;

  // Проверка случая, когда среднее близко к нулю
  if (MathAbs (average) < eps) return MathAbs (maxVal - minVal) < eps * 10.0;

  // Относительная разница для проверки сходимости
  double relDiff = MathAbs (maxVal - minVal) / MathAbs (average);

  return relDiff < 0.001; // Порог сходимости - 0.1%
}
//——————————————————————————————————————————————————————————————————————————————

O método "ResetStagnatingAgents" é destinado ao gerenciamento dos agentes no processo de otimização, especialmente para lidar com casos em que os agentes deixam de demonstrar melhorias em seus resultados. Ele monitora o estado de estagnação dos agentes e, quando necessário, aplica mutação àqueles que ficaram presos em extremos locais.

Para cada agente, é verificado se o valor atual da função de fitness (a[i].f) melhorou em comparação com o valor anterior (a[i].fB). Se o valor atual não tiver melhorado ou tiver piorado, o "stagnationCounter" desse agente é incrementado, sinalizando que o agente se encontra em estado de estagnação. Caso o valor tenha melhorado, o contador de estagnação é zerado.

Se o agente permanecer em estagnação por mais de 5 iterações, o método calcula a probabilidade de reset (resetProb). Essa probabilidade é proporcional ao valor atual do contador de estagnação, o que significa que quanto mais tempo o agente permanece estagnado, maior é a probabilidade de seu reset. A fórmula de cálculo da probabilidade considera um valor fixo (0.2) e o valor relativo do contador de estagnação. Se um valor gerado aleatoriamente for menor que a probabilidade calculada "resetProb", é aplicada uma mutação ao agente por meio da função "ApplyMutation". Após a aplicação da mutação, o contador de estagnação do agente é zerado, e o contador "resetCount" é incrementado.

O método encerra sua execução após processar todos os agentes, realizando o reset daqueles que ultrapassaram o limiar de estagnação e atenderam às condições para mutação.

//——————————————————————————————————————————————————————————————————————————————
void C_AO_COA_chaos::ResetStagnatingAgents ()
{
  int resetCount = 0;

  for (int i = 0; i < popSize; i++)
  {
    // Увеличиваем счетчик стагнации, если нет улучшения
    if (a [i].f <= a [i].fB)
    {
      agent [i].stagnationCounter++;
    }
    else
    {
      agent [i].stagnationCounter = 0;
    }

    // Сбрасываем агента, если он находится в стагнации слишком долго
    if (agent [i].stagnationCounter > 5)
    {
      // Сброс только части агентов с вероятностью, зависящей от стагнации
      double resetProb = 0.2 * (1.0 + (double)agent [i].stagnationCounter / 10.0);

      if (u.RNDprobab () < resetProb)
      {
        ApplyMutation (i);
        agent [i].stagnationCounter = 0;
        resetCount++;
      }
    }
  }
}
//——————————————————————————————————————————————————————————————————————————————

O método "CalculateWeightedGradient" é utilizado para avaliar o gradiente da restrição para um agente e uma coordenada específicos, levando em consideração o grau de violação dessas restrições. Ele auxilia a determinar em que direção e com que intensidade a solução deve ser ajustada para eliminar a violação, ponderando o gradiente pelo nível de violação.

Inicialmente, são verificados os índices do agente e da coordenada, para garantir que estejam dentro dos limites permitidos. Se os índices forem incorretos, é retornado um valor zero, o que indica a ausência de uma direção para correção. Em seguida, o método percorre todas as coordenadas associadas ao agente atual e calcula o valor de violação para cada uma delas. Ao longo desse processo, ele identifica a maior violação entre todas. Se a violação para a coordenada em questão for maior que o limiar "eps", considera-se que faz sentido executar ações corretivas; caso contrário, é retornado zero, pois o movimento nessa direção não faz sentido ou não é necessário.

Se a violação for significativa, para a coordenada é calculado o gradiente da restrição, que é uma medida da direção e da intensidade da mudança da restrição em relação às alterações dessa coordenada. O gradiente é multiplicado por um peso, que é definido como a razão entre a violação da coordenada atual e a violação máxima entre todas as restrições. Isso garante que uma violação maior exerça uma influência mais forte sobre a direção da correção. O valor final é o gradiente de restrição ponderado, que indica o quanto e em que direção a solução precisa ser ajustada para eliminar a violação nessa coordenada, de forma proporcional ao seu grau.

//——————————————————————————————————————————————————————————————————————————————
double C_AO_COA_chaos::CalculateWeightedGradient (int agentIdx, int coordIdx)
{
  // Вычисляем максимальное значение нарушения ограничений
  double maxViolation = eps;

  for (int c = 0; c < coords; c++)
  {
    double violation = CalculateConstraintValue (agentIdx, c);
    maxViolation = MathMax (maxViolation, violation);
  }

  // Нарушение для текущей координаты
  double violation = CalculateConstraintValue (agentIdx, coordIdx);

  // Если нет значительного нарушения, возвращаем 0
  if (violation <= eps) return 0.0;

  // Вычисляем градиент
  double gradient = CalculateConstraintGradient (agentIdx, coordIdx);

  // Нормализуем влияние в зависимости от степени нарушения
  double weight = violation / maxViolation;

  return gradient * weight;
}
//——————————————————————————————————————————————————————————————————————————————

O método "CalculateConstraintValue" é utilizado para avaliar o grau de violação das restrições para uma coordenada específica de um agente específico. Ele determina o quanto o valor atual da coordenada ultrapassa os limites permitidos e retorna um valor numérico que reflete a magnitude dessa violação.

Inicialmente, o método verifica a correção dos índices do agente (agentIdx) e da coordenada (coordIdx). O método obtém o valor atual da coordenada "x" a partir do estado do agente, bem como determina os limites mínimo (min) e máximo (max) permitidos para essa coordenada, respectivamente. Em seguida, o método verifica se o valor "x" se encontra dentro do intervalo permitido, entre min e max. Ao final, o método retorna o valor "violation", que representa a magnitude total da violação das restrições para essa coordenada desse agente.

Principais características:

  • O método retorna um valor positivo se a restrição for violada e 0 se ela for respeitada.
  • A magnitude da violação é proporcional ao quanto o valor da coordenada ultrapassa os limites permitidos.

Em resumo, o método "CalculateConstraintValue" fornece informações importantes sobre o quanto cada agente da população atende às restrições do problema. Ele mede a magnitude da violação, o que ajuda o algoritmo a entender o quanto é necessário ajustar a posição do agente.

//——————————————————————————————————————————————————————————————————————————————
double C_AO_COA_chaos::CalculateConstraintValue (int agentIdx, int coordIdx)
{
  double x = a [agentIdx].c [coordIdx];
  double min = rangeMin [coordIdx];
  double max = rangeMax [coordIdx];

  // Сглаженная функция нарушения ограничений с плавным переходом на границе
  double violation = 0.0;

  // Проверка нижней границы
  if (x < min)
  {
    violation += min - x;
  }
  // Проверка верхней границы
  else
    if (x > max)
    {
      violation += x - max;
    }

  return violation;
}
//——————————————————————————————————————————————————————————————————————————————

O método "CalculateConstraintGradient" realiza o cálculo do gradiente da restrição para uma coordenada específica de um agente específico. Esse método determina em que direção e com que intensidade é necessário alterar o valor da coordenada em função da violação das restrições.

Inicialmente, o método verifica os índices de entrada do agente (agentIdx) e da coordenada (coordIdx) para garantir sua correção. Se pelo menos um dos índices estiver fora do intervalo permitido, o método retorna 0.0, o que indica a impossibilidade de calcular o gradiente. O método extrai o valor atual da coordenada do agente, bem como os limites mínimo e máximo estabelecidos para essa coordenada. Esses valores são necessários para as avaliações subsequentes. Em seguida, o método verifica se o valor atual da coordenada "x" está fora dos limites estabelecidos.

O valor final retornado pelo método reflete a direção e a necessidade de alteração do valor atual da coordenada do agente, levando em consideração as restrições definidas.

//——————————————————————————————————————————————————————————————————————————————
double C_AO_COA_chaos::CalculateConstraintGradient (int agentIdx, int coordIdx)
{
  double x = a [agentIdx].c [coordIdx];
  double min = rangeMin [coordIdx];
  double max = rangeMax [coordIdx];

  // Сглаженный градиент для лучшей стабильности
  if (x < min) return -1.0; // Нужно увеличивать значение
  else
    if (x > max) return 1.0;  // Нужно уменьшать значение

  return 0.0;
}
//——————————————————————————————————————————————————————————————————————————————

O método "CalculatePenaltyFunction" calcula os valores da função objetivo considerando a penalização por violação de restrições para um agente específico. Ele combina o valor base da função objetivo com uma penalização baseada na magnitude das violações das restrições.

O método inicia sua execução verificando a correção do índice do agente (agentIdx) e, se o índice for válido, obtém o valor base, não penalizado, da função objetivo desse agente (a[agentIdx].f) e o armazena na variável "baseValue". Em seguida, o método percorre todas as coordenadas (coords) de cada agente. Para cada coordenada, é calculada a magnitude da violação das restrições. Se a magnitude da violação (violation) exceder o pequeno valor especificado "eps", o quadrado da magnitude da violação é adicionado à soma das penalizações "penaltySum".

A penalização quadrática é utilizada para fornecer uma avaliação mais "suave" em casos de pequenas violações e mais "rígida" em casos de violações maiores. Após a soma de todas as penalizações por violação de restrições, é calculada a penalização total "penalty".

Por fim, o método calcula o valor "penalizado" da função objetivo subtraindo a penalização "penalty" do valor base da função objetivo "baseValue". O valor penalizado da função objetivo é então retornado.

//——————————————————————————————————————————————————————————————————————————————
double C_AO_COA_chaos::CalculatePenaltyFunction (int agentIdx)
{
  // Базовое значение целевой функции
  double baseValue = a [agentIdx].f;

  // Штрафной терм
  double penaltySum = 0.0;

  for (int c = 0; c < coords; c++)
  {
    double violation = CalculateConstraintValue (agentIdx, c);

    // Квадратичный штраф для лучшего разрешения близких к границе решений
    if (violation > eps)
    {
      penaltySum += violation * violation;
    }
  }

  // Применяем динамический коэффициент штрафа
  double penalty = currentSigma * penaltySum;

  // Для задачи максимизации: f_penalty = f - penalty
  return baseValue - penalty;
}
//——————————————————————————————————————————————————————————————————————————————

O método "Moving" é o principal procedimento de controle para o avanço da solução no processo de otimização. Ele executa etapas sequenciais voltadas à atualização do estado atual do sistema, à adaptação de parâmetros e ao gerenciamento das fases de busca.

Inicialmente, o contador da época atual é incrementado. Se este for o primeiro chamado do método, é iniciada a criação da população inicial de agentes e, em seguida, essa etapa encerra sua execução. Depois disso, ocorre a atualização dinâmica do parâmetro de penalização (sigma), o que ajuda a regular a influência das funções de penalização durante o processo de busca. Uma tarefa importante é a verificação periódica e o reset de agentes que ficaram presos ou não apresentam progresso, o que contribui para evitar estagnação em armadilhas locais.

Em seguida, a fase atual da busca é determinada com base no valor do contador de épocas, isto é, nas etapas iniciais é realizada a busca global e, posteriormente, ocorre a transição para uma busca mais restrita, de caráter local. Dependendo da fase, são chamadas as estratégias de busca correspondentes, que controlam o movimento dos agentes.

//——————————————————————————————————————————————————————————————————————————————
void C_AO_COA_chaos::Moving ()
{
  epochNow++;

  if (!revision)
  {
    InitialPopulation ();

    revision = true;
    return;
  }

  // Динамическое обновление параметра штрафа
  UpdateSigma ();

  // Сброс агентов, находящихся в стагнации
  if (epochNow % 5 == 0)
  {
    ResetStagnatingAgents ();
  }

  // Определяем фазу поиска
  if (epochNow <= S1)
  {
    FirstCarrierWaveSearch ();
  }
  else
    if (epochNow <= S1 + S2)
    {
      SecondCarrierWaveSearch ();
    }
}
//——————————————————————————————————————————————————————————————————————————————

O método "Revision" é responsável por aprimorar as soluções e adaptar os parâmetros de busca ao longo do processo iterativo de otimização. Ele realiza uma reavaliação do estado atual da população, atualiza as melhores soluções e ajusta os parâmetros de busca com base na eficiência das etapas mais recentes.

O método percorre todas as soluções da população, calculando seu novo valor "penalizado" por meio da função de penalização, o que permite levar em conta as violações de restrições. A correção do valor obtido é verificada e, se ele for admissível, é armazenado como o valor atual da função. Para cada agente cujo novo valor da função seja melhor que o anterior, ocorre a atualização de seus dados pessoais: o novo valor é salvo, assim como as coordenadas atuais são copiadas. Isso garante o armazenamento da melhor solução local de cada agente. Se for identificada, em um agente, uma solução melhor que a atual solução global, o melhor resultado global é atualizado e as coordenadas correspondentes são armazenadas. A história das melhores soluções também é atualizada.

Após o primeiro nível de iterações (epochNow > 1), é realizada uma avaliação do sucesso da busca, determinando-se a proporção de melhorias entre todos os agentes. Com base nessa avaliação, os parâmetros são adaptados, em especial o parâmetro "alpha", que define a área de busca para cada coordenada. Dependendo da fase atual da busca, global ou local, as regras de ajuste de "alpha" podem diferir: na fase de busca global, com baixo nível de melhorias, a área de busca é ampliada para expandir as possibilidades; na fase de busca local, em caso de falta de melhorias, a área de busca também é ampliada, enquanto que, em caso de sucessos significativos, a área de busca é reduzida, o que ajuda a localizar a solução ótima. Ao mesmo tempo, o parâmetro "alpha" é limitado por valores máximos e mínimos, com base no intervalo de valores permitidos para a coordenada.

Essa abordagem permite equilibrar dinamicamente a exploração de novas soluções e a localização das soluções ótimas, utilizando informações sobre o desempenho das iterações anteriores.

//——————————————————————————————————————————————————————————————————————————————
void C_AO_COA_chaos::Revision ()
{
  int    improvementCount = 0;
  double bestImprovement  = 0.0;

  // Оценка всех решений
  for (int i = 0; i < popSize; i++)
  {
    double newValue = CalculatePenaltyFunction (i);

    // Проверка на валидность нового значения
    if (!MathIsValidNumber (newValue)) continue;

    // Сохраняем текущее значение для следующей итерации
    a [i].f = newValue;

    // Обновление личного лучшего решения (перед глобальным для эффективности)
    if (newValue > a [i].fB)
    {
      a [i].fB = newValue;
      ArrayCopy (a [i].cB, a [i].c, 0, 0, WHOLE_ARRAY);
      improvementCount++;
    }

    // Обновление глобального лучшего решения
    if (newValue > fB)
    {
      double improvement = newValue - fB;
      fB = newValue;
      ArrayCopy (cB, a [i].c, 0, 0, WHOLE_ARRAY);

      // Обновляем историю лучших значений
      UpdateBestHistory (fB);

      bestImprovement = MathMax (bestImprovement, improvement);
      improvementCount++;
    }
  }

  // Адаптация параметров поиска в зависимости от фазы и успешности
  if (epochNow > 1)
  {
    // Коэффициент успешности поиска (предотвращение деления на ноль)
    double successRate = (double)improvementCount / MathMax (1, 2 * popSize);

    // Адаптация параметра alpha
    for (int c = 0; c < coords; c++)
    {
      double oldAlpha = alpha [c];

      if (epochNow <= S1)
      {
        // В фазе глобального поиска
        if (successRate < 0.1)
        {
          // Очень мало улучшений - увеличиваем область поиска
          alpha [c] *= t3;
        }
        else
          if (successRate < 0.3)
          {
            // Мало улучшений - слегка увеличиваем область
            alpha [c] *= 1.2;
          }
          else
            if (successRate > 0.7)
            {
              // Много улучшений - сужаем область
              alpha [c] *= 0.9;
            }
      }
      else
      {
        // В фазе локального поиска
        if (successRate < 0.05)
        {
          // Очень мало улучшений - увеличиваем область поиска
          alpha [c] *= t3;
        }
        else
          if (successRate > 0.2)
          {
            // Достаточно улучшений - сужаем область
            alpha [c] *= 0.8;
          }
      }

      // Ограничения на диапазон alpha с безопасной проверкой границ
      if (c < ArraySize (rangeMax) && c < ArraySize (rangeMin))
      {
        double maxAlpha = 0.2 * (rangeMax [c] - rangeMin [c]);
        double minAlpha = 0.0001 * (rangeMax [c] - rangeMin [c]);

        if (alpha [c] > maxAlpha)
        {
          alpha [c] = maxAlpha;
        }
        else
          if (alpha [c] < minAlpha)
          {
            alpha [c] = minAlpha;
          }
      }
    }
  }
}
//——————————————————————————————————————————————————————————————————————————————

Agora que todos os métodos foram analisados, podemos passar diretamente ao teste do algoritmo.


Resultados dos testes

De fato, o resultado fala por si só, alguns parâmetros externos foram levemente otimizados, enquanto os internos permaneceram inalterados e são apresentados exatamente como descritos anteriormente nos métodos.

COA(CHAOS)|Chaos Optimization Algorithm|50.0|10.0|40.0|2.0|1.2|0.0001|
=============================
5 Hilly's; Func runs: 10000; result: 0.6083668756744218
25 Hilly's; Func runs: 10000; result: 0.4079413401686229
500 Hilly's; Func runs: 10000; result: 0.2678056430575926
=============================
5 Forest's; Func runs: 10000; result: 0.668343763134901
25 Forest's; Func runs: 10000; result: 0.38894787694645416
500 Forest's; Func runs: 10000; result: 0.2198998763835145
=============================
5 Megacity's; Func runs: 10000; result: 0.32307692307692304
25 Megacity's; Func runs: 10000; result: 0.1987692307692308
500 Megacity's; Func runs: 10000; result: 0.10598461538461638
=============================
All score: 3.18914 (35.43%)

Gostaria de chamar a atenção para a visualização do funcionamento do algoritmo: a combinação da diversidade dos métodos de busca aplicados gera um efeito visual incomum.

Hilly

COA(CHAOS) na função de teste Hilly

Forest

COA(CHAOS) na função de teste Forest

Megacity

COA(CHAOS) na função de teste Megacity

Com base nos resultados dos testes, o algoritmo COA(CHAOS) é apresentado de forma informativa em nossa tabela de classificação.

AO Description Hilly Hilly
Final
Forest Forest
Final
Megacity (discrete) Megacity
Final
Final
Result
% of
MAX
10 p (5 F)50 p (25 F)1000 p (500 F)10 p (5 F)50 p (25 F)1000 p (500 F)10 p (5 F)50 p (25 F)1000 p (500 F)
1ANSacross neighbourhood search0,949480,847760,438572,235811,000000,923340,399882,323230,709230,634770,230911,574916,13468,15
2CLAcode lock algorithm (joo)0,953450,871070,375902,200420,989420,917090,316422,222940,796920,693850,193031,683806,10767,86
3AMOmanimal migration ptimization M0,903580,843170,462842,209590,990010,924360,465982,380340,567690,591320,237731,396755,98766,52
4(P+O)ES(P+O) evolution strategies0,922560,881010,400212,203790,977500,874900,319452,171850,673850,629850,186341,490035,86665,17
5CTAcomet tail algorithm (joo)0,953460,863190,277702,094350,997940,857400,339492,194840,887690,564310,105121,557125,84664,96
6TETAtime evolution travel algorithm (joo)0,913620,823490,319902,057010,970960,895320,293242,159520,734620,685690,160211,580525,79764,41
7SDSmstochastic diffusion search M0,930660,854450,394762,179880,999830,892440,196192,088460,723330,611000,106701,441035,70963,44
8BOAmbilliards optimization algorithm M0,957570,825990,252352,035901,000000,900360,305022,205380,735380,525230,095631,356255,59862,19
9AAmarchery algorithm M0,917440,708760,421602,047800,925270,758020,353282,036570,673850,552000,237381,463235,54861,64
10ESGevolution of social groups (joo)0,999060,796540,350562,146161,000000,828630,131021,959650,823330,553000,047251,423585,52961,44
11SIAsimulated isotropic annealing (joo)0,957840,842640,414652,215130,982390,795860,205071,983320,686670,493000,090531,270205,46960,76
12ACSartificial cooperative search0,755470,747440,304071,806981,000000,888610,224132,112740,690770,481850,133221,305835,22658,06
13DAdialectical algorithm0,861830,700330,337241,899400,981630,727720,287181,996530,703080,452920,163671,319675,21657,95
14BHAmblack hole algorithm M0,752360,766750,345831,864930,935930,801520,271772,009230,650770,516460,154721,321955,19657,73
15ASOanarchy society optimization0,848720,746460,314651,909830,961480,791500,238031,991010,570770,540620,166141,277525,17857,54
16RFOroyal flush optimization (joo)0,833610,737420,346291,917330,894240,738240,240981,873460,631540,502920,164211,298675,08956,55
17AOSmatomic orbital search M0,802320,704490,310211,817020,856600,694510,219961,771070,746150,528620,143581,418355,00655,63
18TSEAturtle shell evolution algorithm (joo)0,967980,644800,296721,909490,994490,619810,227081,841390,690770,426460,135981,253225,00455,60
19DEdifferential evolution0,950440,616740,303081,870260,953170,788960,166521,908650,786670,360330,029531,176534,95555,06
20SRAsuccessful restaurateur algorithm (joo)0,968830,634550,292171,895550,946370,555060,191241,692670,749230,440310,125261,314804,90354,48
21CROchemical reaction optimisation0,946290,661120,298531,905930,879060,584220,211461,674730,758460,426460,126861,311784,89254,36
22BIOblood inheritance optimization (joo)0,815680,653360,308771,777810,899370,653190,217601,770160,678460,476310,139021,293784,84253,80
23BSAbird swarm algorithm0,893060,649000,262501,804550,924200,711210,249391,884790,693850,326150,100121,120124,80953,44
24HSharmony search0,865090,687820,325271,878180,999990,680020,095901,775920,620000,422670,054581,097254,75152,79
25SSGsaplings sowing and growing0,778390,649250,395431,823080,859730,624670,174291,658690,646670,441330,105981,193984,67651,95
26BCOmbacterial chemotaxis optimization M0,759530,622680,314831,697040,893780,613390,225421,732590,653850,420920,144351,219124,64951,65
27ABOafrican buffalo optimization0,833370,622470,299641,755480,921700,586180,197231,705110,610000,431540,132251,173784,63451,49
28(PO)ES(PO) evolution strategies0,790250,626470,429351,846060,876160,609430,195911,681510,590000,379330,113221,082554,61051,22
29TSmtabu search M0,877950,614310,291041,783300,928850,518440,190541,637830,610770,382150,121571,114494,53650,40
30BSObrain storm optimization0,937360,576160,296881,810410,931310,558660,235371,725340,552310,290770,119140,962224,49849,98
31WOAmwale optimization algorithm M0,845210,562980,262631,670810,931000,522780,163651,617430,663080,411380,113571,188034,47649,74
32AEFAartificial electric field algorithm0,877000,617530,252351,746880,927290,726980,180641,834900,666150,116310,095080,877544,45949,55
33AEOartificial ecosystem-based optimization algorithm0,913800,467130,264701,645630,902230,437050,214001,553270,661540,308000,285631,255174,45449,49
34ACOmant colony optimization M0,881900,661270,303771,846930,858730,586800,150511,596040,596670,373330,024720,994724,43849,31
35BFO-GAbacterial foraging optimization - ga0,891500,551110,315291,757900,969820,396120,063051,428990,726670,275000,035251,036924,22446,93
36SOAsimple optimization algorithm0,915200,469760,270891,655850,896750,374010,169841,440600,695380,280310,108521,084224,18146,45
37ABHAartificial bee hive algorithm0,841310,542270,263041,646630,878580,477790,171811,528180,509230,338770,103970,951974,12745,85
38ACMOatmospheric cloud model optimization0,903210,485460,304031,692700,802680,378570,191781,373030,623080,244000,107950,975034,04144,90
39ADAMmadaptive moment estimation M0,886350,447660,266131,600140,844970,384930,168891,398800,661540,270460,105941,037944,03744,85
40CGOchaos game optimization0,572560,371580,320181,264320,611760,619310,621611,852670,375380,219230,190280,784903,90243,35
41ATAmartificial tribe algorithm M0,717710,553040,252351,523100,824910,559040,204731,588670,440000,186150,094110,720263,83242,58
42CROmcoral reefs optimization M0,785120,460320,259581,505020,866880,352970,162671,382520,632310,267380,107341,007033,89543,27
43CFOcentral force optimization0,609610,549580,278311,437500,634180,468330,225411,327920,572310,234770,095860,902943,66840,76
44ASHAartificial showering algorithm0,896860,404330,256171,557370,803600,355260,191601,350460,476920,181230,097740,755893,66440,71
45ASBOadaptive social behavior optimization0,763310,492530,326191,582020,795460,400350,260971,456770,264620,171690,182000,618313,65740,63
CHAOSchaos optimization algorithm0,608370,407940,267811,284120,668340,388950,219901,277190,323080,198770,105980,627833,18935,43
RWneuroboids optimization algorithm 2(joo)0,487540,321590,257811,066940,375540,219440,158770,753750,279690,149170,098470,527342,34826,09


Considerações finais

O resultado de 35% após os testes demonstra um bom potencial do algoritmo COA(CHAOS), especialmente considerando sua complexidade e a quantidade de parâmetros externos ajustáveis, incluindo os internos, que não foram otimizados. O algoritmo simplesmente ainda não demonstrou seu desempenho máximo.

Os aspectos mais interessantes e promissores do algoritmo parecem ser os seguintes: o uso de três diferentes mapeamentos, logístico, sinusoidal e tent mapping, para ampliar as capacidades de busca do algoritmo; a adição de inércia ajuda o algoritmo a manter o "impulso" do movimento, com a possibilidade de superar armadilhas locais; a alteração dinâmica dos parâmetros, dependendo do sucesso e da fase da otimização, aumenta sua flexibilidade; o acompanhamento do histórico de soluções e o reset de agentes "presos" permitem que o algoritmo não desperdice recursos computacionais em áreas sem perspectiva. Além disso, o uso do hipercubo latino e de diferentes abordagens para o posicionamento inicial dos agentes garante uma boa cobertura do espaço de busca desde o início. Para um aprimoramento adicional do algoritmo, seria recomendável realizar uma otimização mais aprofundada dos parâmetros internos.

Este algoritmo representa uma rica fonte de ideias para a melhoria de outros métodos de otimização, em particular seus mecanismos adaptativos e as formas de tratamento da estagnação poderiam ser transferidos com sucesso para outros algoritmos de aprendizado de máquina e de otimização para os mercados financeiros.

Tab

Figura 1. Graduação de cores dos algoritmos de acordo com os testes

chart

Figura 2. Histograma dos resultados dos testes dos algoritmos (na escala de 0 a 100, quanto maior, melhor, onde 100 é o resultado teórico máximo possível, no arquivo está o script para calcular a tabela de classificação)

Vantagens e contras do algoritmo COA(CHAOS):

Vantagens:

  1. Diversidade de métodos de busca.
  2. Desenvolvimento promissor.
  3. Resultados estáveis.

Contras:

  1. Grande quantidade de parâmetros externos.
  2. Grande quantidade de parâmetros internos não otimizáveis.

Junto ao artigo está anexado um arquivo com as versões atualizadas dos códigos dos algoritmos. O autor do artigo não se responsabiliza pela absoluta precisão na descrição dos algoritmos canônicos, pois muitos deles foram modificados para melhorar as capacidades de busca. As conclusões e julgamentos apresentados nos artigos baseiam-se nos resultados dos experimentos realizados.


Programas utilizados no artigo

#NomeTipoDescrição
1#C_AO.mqh
Arquivo incluído
Classe base dos algoritmos populacionais de otimização
2#C_AO_enum.mqh
Arquivo incluído
Enumeração dos algoritmos populacionais de otimização
3TestFunctions.mqh
Arquivo incluído
Biblioteca de funções de teste
4
TestStandFunctions.mqh
Arquivo incluído
Biblioteca de funções do test stand
5
Utilities.mqh
Arquivo incluído
Biblioteca de funções auxiliares
6
CalculationTestResults.mqh
Arquivo incluído
Script para cálculo dos resultados em tabela comparativa
7
Testing AOs.mq5
ScriptTest stand unificado para todos os algoritmos populacionais de otimização
8
Simple use of population optimization algorithms.mq5
Script
Exemplo simples de uso de algoritmos populacionais de otimização sem visualização
9
Test_AO_COA_chaos.mq5
ScriptTest stand para COA(CHAOS)

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

Arquivos anexados |
COAcCHAOSd.ZIP (268.29 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.
Trading de arbitragem no Forex: sistema de negociação matricial para retorno ao valor justo com limitação de risco Trading de arbitragem no Forex: sistema de negociação matricial para retorno ao valor justo com limitação de risco
O artigo contém uma descrição detalhada do algoritmo de cálculo de taxas cruzadas, a visualização da matriz de desequilíbrios e recomendações para a configuração ideal dos parâmetros MinDiscrepancy e MaxRisk para uma negociação eficiente. O sistema calcula automaticamente o "valor justo" de cada par de moedas por meio de taxas cruzadas, gerando sinais de compra em desvios negativos e de venda em desvios positivos.
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.
Desenvolvimento do Toolkit de Análise de Price Action (Parte 8): Painel de Métricas Desenvolvimento do Toolkit de Análise de Price Action (Parte 8): Painel de Métricas
Como um dos mais poderosos toolkits de análise de Price Action, o Painel de Métricas foi projetado para otimizar a análise de mercado, fornecendo instantaneamente métricas essenciais do mercado com apenas um clique de botão. Cada botão exerce uma função específica, seja para analisar tendências de máxima/mínima, volume ou outros indicadores-chave. Esta ferramenta entrega dados precisos e em tempo real exatamente quando você mais precisa. Vamos explorar mais profundamente seus recursos neste artigo.