preview
Оптимизатор на основе экологического цикла — Ecological Cycle Optimizer (ECO)

Оптимизатор на основе экологического цикла — Ecological Cycle Optimizer (ECO)

MetaTrader 5Трейдинг |
180 0
Andrey Dik
Andrey Dik

Содержание

  1. Введение
  2. Реализация алгоритма
  3. Результаты тестов
  4. Выводы


Введение

Природа на протяжении миллиардов лет оттачивала механизмы выживания, адаптации и самоорганизации живых систем. Эти механизмы неизменно привлекают внимание исследователей в области вычислительного интеллекта, стремящихся перенести эффективные природные стратегии в алгоритмы оптимизации. Генетические алгоритмы черпают вдохновение из эволюции, роевые методы — из коллективного поведения насекомых и птиц, а алгоритмы иммунных систем моделируют защитные механизмы организма.

Однако до недавнего времени практически без внимания оставался один из фундаментальных процессов биосферы — экологический цикл, представляющий собой непрерывный круговорот энергии и вещества между различными трофическими уровнями экосистемы. В любой устойчивой экосистеме присутствует сложная сеть взаимодействий: продуценты (растения) преобразуют солнечную энергию в органическое вещество, травоядные потребляют продуцентов, хищники охотятся на травоядных, всеядные занимают промежуточные ниши, а редуценты замыкают цикл, разлагая органику и возвращая питательные вещества в среду.

Эта элегантная система баланса и взаимозависимости легла в основу алгоритма Ecological Cycle Optimizer (ECO), представленного в 2025 году группой китайских исследователей под руководством Boyu Ma и Jiaxiao Shi. Авторы предложили рассматривать популяцию поисковых агентов как экосистему, где каждая группа особей выполняет свою роль в общем цикле оптимизации.

Продуценты в алгоритме ECO — это элитные решения, накапливающие «энергию» в виде высокого значения целевой функции. Травоядные стремятся к продуцентам, перенимая их успешные характеристики. Плотоядные, в свою очередь, ориентируются на травоядных, а всеядные способны извлекать информацию из всех трофических уровней. Завершает цикл стадия декомпозиции, на которой все решения подвергаются трансформации — подобно тому, как редуценты перерабатывают органическое вещество, создавая основу для нового роста.

Ключевой особенностью ECO является адаптивный коэффициент хищничества, который регулирует интенсивность взаимодействия между группами. На ранних этапах оптимизации этот коэффициент высок, что способствует активному обмену информацией и глобальному исследованию пространства поиска. По мере приближения к оптимуму, коэффициент снижается, переводя алгоритм в режим локальной эксплуатации найденных перспективных областей.

Три режима декомпозиции — оптимальный, локальный случайный и глобальный случайный — обеспечивают разнообразие поисковых стратегий и помогают избегать преждевременной сходимости. Жадный отбор на этапе ревизии гарантирует, что качество решений не ухудшается от итерации к итерации.

В данной статье мы подробно рассмотрим математическую модель алгоритма ECO, проанализируем роль каждого компонента экологического цикла в процессе оптимизации и представим результаты тестирования на стандартном наборе функций, которые позволят оценить эффективность алгоритма и его место среди других метаэвристических методов.



Реализация алгоритма

Алгоритм ECO моделирует круговорот энергии в природной экосистеме. Представьте луг, на котором растут травы (продуценты), пасутся зайцы (травоядные), охотятся лисы (плотоядные), кормятся медведи (всеядные), а бактерии и грибы (редуценты) перерабатывают органику. Каждая группа выполняет свою роль, и вместе они образуют устойчивую систему.

В алгоритме ECO популяция поисковых агентов разделена на аналогичные группы. Каждый агент — это потенциальное решение задачи оптимизации, а его «приспособленность» (фитнес) — значение целевой функции.

Популяция делится на четыре группы в следующих пропорциях:

ГруппаДоляРоль в алгоритме
Продуценты (Producers)20%Лучшие решения, источник информации
Травоядные (Herbivores)30%Следуют за продуцентами
Плотоядные (Carnivores)30%Следуют за травоядными
Всеядные (Omnivores)20%Используют информацию от всех групп

Пример: при размере популяции 50 агентов получаем: 10 продуцентов, 15 травоядных, 15 плотоядных и 10 всеядных.

Ключевой параметр алгоритма — коэффициент хищничества G, который управляет интенсивностью перемещения агентов: G = 1 + 2 × rand × exp(-9 × (t/T)³) × sign, где: t - текущая итерация; T - максимальное число итераций; rand - случайное число от 0 до 1; sign - случайно выбранный знак (+1 или -1).

В начале оптимизации (t ≈ 0) экспонента близка к 1, и коэффициент G может достигать значений от -1 до 3. Агенты совершают большие прыжки, исследуя пространство поиска. К концу оптимизации (t → T) экспонента стремится к 0, G - приближается к 1, и движения становятся более осторожными - алгоритм переходит к локальному уточнению.

Пример: итерация 10 из 1000: G ≈ 1 + 2 × 0.7 × 0.99 × (+1) = 2.39 — агент может «перепрыгнуть» через цель; итерация 900 из 1000: G ≈ 1 + 2 × 0.7 × 0.001 × (+1) = 1.001 — агент движется почти точно к цели.

Стратегия продуцентов. Продуценты — это элита популяции. После каждой итерации вся популяция сортируется по значению фитнеса, и лучшие 20% автоматически становятся продуцентами.

Например, если у нас 50 агентов с фитнесами от 10 до 100, то 10 агентов с наивысшими значениями (скажем, от 85 до 100) станут продуцентами. Они не перемещаются активно — их задача служить «маяками» для остальных групп.

Стратегия травоядных. Травоядные движутся в направлении продуцентов, пытаясь «поедать» хорошие решения. Для каждого травоядного методом рулеточного отбора выбираются 3 продуцента (лучшие имеют больше шансов быть выбранными). Вычисляется новая позиция: новая позиция = текущая + G × (r₁×(prod₁ - текущая) + r₂×(prod₂ - текущая) + r₃×(prod₃ - текущая)), где r₁, r₂, r₃ - случайные числа от 0 до 1.

Пример для одномерного пространства: травоядный находится в позиции x = 20. Выбраны продуценты в позициях: 80, 90, 75. Случайные числа: r₁ = 0.6, r₂ = 0.3, r₃ = 0.4. Коэффициент G = 1.5. Вычисляем: движение = 0.6×(80-20) + 0.3×(90-20) + 0.4×(75-20) = 36 + 21 + 22 = 79, тогда новая позиция будет = 20 + 1.5 × 79 = 138.5. Травоядный переместился в направлении продуцентов, причём благодаря G > 1 он «перепрыгнул» дальше среднего положения целей.

Стратегия плотоядных. Плотоядные охотятся на травоядных по аналогичной схеме: выбираются 3 травоядных методом рулетки, плотоядный движется в их направлении с учётом коэффициента G. Травоядные уже сместились к хорошим областям, следуя за продуцентами. Плотоядные «охотятся» в этих же перспективных зонах, но с некоторым смещением, что помогает исследовать окрестности найденных решений.

Стратегия всеядных. Всеядные — универсальные исследователи. Они получают информацию от всех групп: выбирается 1 продуцент, 1 травоядный и 2 плотоядных. Всеядный движется к комбинации этих целей: новая позиция = текущая + G × (r₁×(prod - текущая) + r₂×(herb - текущая) + r₃×(carn₁ - текущая) + r₄×(carn₂ - текущая)). Всеядные могут обнаружить связи между разными областями поиска, которые другие группы могли пропустить.

Рулеточный отбор. При выборе целей для движения используется рулеточный отбор — агенты с лучшим фитнесом имеют больше шансов быть выбранными. Например, три продуцента с фитнесами 100, 80, 60. Вероятности выбора (после нормализации): продуцент 1: 100/240 = 41.7%; продуцент 2: 80/240 = 33.3%; продуцент 3: 60/240 = 25.0%. Это не означает, что худший никогда не будет выбран — он просто выбирается реже. Такой механизм сохраняет разнообразие поиска.

Стратегия декомпозиции. После движения всех групп наступает ключевая фаза — декомпозиция. Подобно тому, как редуценты перерабатывают органику в природе, алгоритм трансформирует все решения одним из трёх способов:

Режим 1: оптимальная декомпозиция (вероятность 50%). Агент смещается к окрестности лучшего решения: окрестность = лучший × rand_vector; новая позиция = окрестность + coef × (окрестность - текущая), где coef ∈ [-0 .2, 0.2] - это небольшое случайное смещение.
Пример, лучшая позиция: [100, 50]; текущая позиция: [70, 40]; rand_vector = [0.9, 0.8]; coef = 0.1; окрестность = [100×0.9, 50×0.8] = [90, 40]; новая позиция тогда рассчитается [90 + 0.1×(90-70), 40 + 0.1×(40-40)] = [92, 40]. Агент переместился ближе к лучшему решению с небольшой вариацией.

Режим 2: локальная случайная декомпозиция (вероятность 25%), агент делает случайный шаг в произвольном направлении, но размер шага пропорционален расстоянию до лучшего решения: расстояние = ||лучший - текущий||, случайное направление = нормализованный случайный вектор, тогда новая позиция = текущая + rand × расстояние × случайное направление. Смысл действий, если агент далеко от лучшего — он делает большой случайный шаг. Если близко — маленький. Это позволяет исследовать пропорционально «неизведанности» области.

Режим 3: глобальная случайная декомпозиция (вероятность 25%). Агент может переместиться в совершенно новую область пространства: H = (1 - t/(1.5T))^(5t/T) × cos(π × rand); новая позиция = weight × текущая + (1 - weight) × случайное блуждание. Коэффициент "H" уменьшается со временем, поэтому в начале оптимизации возможны большие прыжки, а к концу — только локальные корректировки. Почему сделано три режима: комбинация обеспечивает баланс между эксплуатацией (режим 1), локальным исследованием (режим 2) и глобальным исследованием (режим 3).

Ревизия (жадный отбор). После декомпозиции вычисляется фитнес новых позиций и применяется жадный отбор: если новый фитнес > старый, тогда фитнес → принять новую позицию; иначе → вернуться к старой позиции.

Например: агент был в позиции x = 50 с фитнесом 80, после декомпозиции переместился в x = 65 с фитнесом 75. Новый фитнес (75) хуже старого (80) → агент возвращается в x = 50. Этот механизм гарантирует, что качество лучшего найденного решения никогда не ухудшается. Алгоритм может экспериментировать с рискованными перемещениями, зная, что неудачные попытки будут отменены.

Обработка границ. Если агент выходит за пределы допустимой области поиска, его позиция заменяется случайным значением внутри границ: если позиция < минимум или позиция > максимум: позиция = случайное значение(минимум, максимум). Такой подход (в отличие от простого «отражения» от границы) помогает сохранить разнообразие популяции.

Подведём итог. Каждая итерация алгоритма ECO состоит из следующих шагов:

  • Обновить коэффициент G — он уменьшается со временем
  • Отсортировать популяцию по фитнесу
  • Определить продуцентов — лучшие 20% после сортировки
  • Переместить травоядных к продуцентам
  • Переместить плотоядных к травоядным
  • Переместить всеядных ко всем группам
  • Сохранить текущие позиции для возможного отката
  • Выполнить декомпозицию всех агентов (один из трёх режимов)
  • Вычислить фитнес новых позиций
  • Провести ревизию — откатить неудачные перемещения

ECO

Рисунок 1. Схема работы методов внутри алгоритма. 

Диаграмма показывает группы организмов:

Producers (зелёный) — лучшие решения после сортировки, к ним стремятся травоядные
Herbivores (светло-зелёный) — следуют за продуцентами, являются целью для плотоядных
Carnivores (красный) — следуют за травоядными
Omnivores (оранжевый) — получают информацию от всех групп
Decomposers (коричневый) — трансформируют все решения тремя способами
Центральный элемент Sorting (синий) — сортировка по фитнесу, лучшие становятся продуцентами

Потоки взаимодействия:

Сплошные стрелки — направление притяжения (attract)
Пунктирные стрелки — все решения проходят через декомпозицию
Синие стрелки — цикл через ревизию и сортировку

Информационные блоки:

Формула коэффициента хищничества G
Пропорции групп в популяции (20/30/30/20%)
Три режима декомпозиции с вероятностями

ИНИЦИАЛИЗАЦИЯ
Определить размеры групп на основе заданных пропорций:

Продуценты (producers): 20% популяции
Травоядные (herbivores): 30% популяции
Плотоядные (carnivores): 30% популяции
Всеядные (omnivores): 20% популяции

Случайно инициализировать позиции всех агентов в пространстве поиска
Сохранить начальные позиции каждого агента как "предыдущие" для последующего сравнения
Вычислить фитнес всех агентов

ОСНОВНОЙ ЦИКЛ ОПТИМИЗАЦИИ
Для каждой итерации t от 1 до MaxIterations:
Шаг 1: Обновление коэффициента хищничества G
Для каждой координаты вычислить коэффициент хищничества:
G[c] = 1 + 2 × rand × exp(-9 × (t/T)³) × случайный_знак(±1), где T — максимальное число итераций.
Коэффициент G уменьшается со временем, что обеспечивает переход от глобального исследования к локальной эксплуатации.

Шаг 2: Стратегия продуцентов (отбор лучших)
Отсортировать всю популяцию по убыванию фитнеса
Лучшие агенты автоматически становятся продуцентами (занимают первые позиции в отсортированном массиве)
Обновить глобально лучшее решение если найдено улучшение

Шаг 3: Стратегия травоядных (движение к продуцентам)
Для каждого травоядного агента i:
Выбрать 3 продуцента методом рулеточного отбора (вероятность пропорциональна фитнесу)
Сгенерировать 3 случайных коэффициента r₁, r₂, r₃ ∈ [0, 1]
Вычислить новую позицию:

новая_позиция = текущая_позиция + G × (r₁×(продуцент₁ - текущая) + r₂×(продуцент₂ - текущая) + r₃×(продуцент₃ - текущая))

Шаг 4: Стратегия плотоядных (движение к травоядным)
Для каждого плотоядного агента i:
Выбрать 3 травоядных методом рулеточного отбора
Сгенерировать 3 случайных коэффициента r₁, r₂, r₃ ∈ [0, 1]
Вычислить новую позицию:

новая_позиция = текущая_позиция + G × (r₁×(травоядный₁ - текущая) + r₂×(травоядный₂ - текущая) + r₃×(травоядный₃ - текущая))

Шаг 5: Стратегия всеядных (движение ко всем группам)
Для каждого всеядного агента i:
Выбрать по рулетке: 1 продуцента, 1 травоядного, 2 плотоядных
Сгенерировать 4 случайных коэффициента r₁, r₂, r₃, r₄ ∈ [0, 1]
Вычислить новую позицию:

новая_позиция = текущая_позиция + G × (r₁×(продуцент - текущая) + r₂×(травоядный - текущая) + r₃×(плотоядный₁ - текущая) + r₄×(плотоядный₂ - текущая))

Шаг 6: Сохранение позиций перед декомпозицией
Для всех агентов сохранить текущие позиции и фитнес как "предыдущие" для последующего сравнения в стадии ревизии.

Шаг 7: Стратегия декомпозиторов (три режима)
Для каждого агента i в популяции выбрать случайно один из трёх режимов:
Режим A: Оптимальная декомпозиция (вероятность 50%)

Сгенерировать коэффициент: coef = 0.4 × rand - 0.2 (диапазон [-0.2, 0.2])
Для каждой координаты:
окрестность_лучшего = позиция_лучшего[c] × rand[c]
новая_позиция[c] = окрестность_лучшего + coef × (окрестность_лучшего - текущая[c])
Режим B: Локальная случайная декомпозиция (вероятность 25%)

Вычислить расстояние до лучшего агента: dist = ||лучший - текущий||
Сгенерировать случайный единичный вектор направления
Вычислить новую позицию:
новая_позиция = текущая_позиция + rand × dist × единичный_вектор
Режим C: Глобальная случайная декомпозиция (вероятность 25%)

Вычислить затухающий коэффициент: H = (1 - t/(1.5×T))^(5t/T) × cos(π × rand)

Найти минимальную ширину диапазона поиска
Вычислить случайное блуждание: rand_walk = (2/3) × H × rand × min(rangeMin - rangeMax)

Вычислить новую позицию:
weight = rand
новая_позиция = weight × текущая_позиция + (1 - weight) × rand_walk

Шаг 8: Проверка границ
Для каждого агента и каждой координаты:
Если позиция вышла за границы — присвоить случайное значение в допустимом диапазоне
Применить дискретизацию согласно шагу поиска

Шаг 9: Вычисление фитнеса
Вычислить значение целевой функции для всех агентов.

Шаг 10: Ревизия (жадный отбор)
Для каждого агента i:

Сравнить новый фитнес с предыдущим
Если новый фитнес хуже или равен — откатить позицию и фитнес к предыдущим значениям
Обновить глобально лучшее решение если найдено улучшение

ЗАВЕРШЕНИЕ
Вернуть глобально лучшее найденное решение и его фитнес.

Класс наследуется от базового класса "C_AO". Конфигурационные параметры:

  • Размер популяции (popSize) — определяет общее количество агентов в моделируемой экосистеме.
  • Соотношение потребителей, доля организмов:

    • ratioProd (продуценты) производящих пищу (например, растения).
    • ratioHerb (травоядные) питающихся продуцентами.
    • ratioCarn (хищники) питающихся другими животными.
    • ratioOmni (всеядные) питающихся как растениями, так и животными.
Эти параметры задаются при создании объекта класса и могут быть позже изменены через метод "SetParams".
  • Состояние и внутренние переменные:

    • maxIter и currIter отслеживают максимальное количество итераций (шагов симуляции) и текущую итерацию.
    • numProd, numHerb, numCarn, numOmni: хранят фактическое количество агентов каждого типа (продуцентов, травоядных, хищников, всеядных) на основе  popSize  и соотношений.
    • prodEnd, herbEnd, carnEnd: указывают на индексы в неком общем массиве агентов, разделяя их по экологическим группам.
    • huntCoef: массив коэффициентов, предполагающий модель "хищничества" или взаимодействия между хищниками и их жертвами.
    • aT: временный массив, используемый для сортировки или временного хранения агентов.
  • Методы:

    • SetParams  — позволяет обновить внутренние переменные "popSize", "ratioProd", "ratioHerb", "ratioCarn", "ratioOmni" на основе значений, установленных в структуре "params".
    • Init  — инициализация, принимает диапазоны и шаги для параметров, а также количество эпох. Вероятно, настраивает начальное состояние экосистемы.
    • Moving  — моделирует перемещение или поведение агентов в течение одной итерации.
    • Revision  — выполняет "пересмотр" или обновление состояния экосистемы после одного шага.
    • SelectFromGroup (приватный)  — вспомогательный метод для выбора определенного количества агентов из указанной группы (диапазона индексов).
    • VectorNorm (приватный)  — вспомогательный метод для вычисления некоторой нормы или расстояния между двумя агентами.

Класс  C_AO_ECOc  представляет собой инструментарий для симуляции динамики экосистемы. Он позволяет моделировать различные типы организмов (продуценты, потребители разных уровней) и их взаимоотношения, включая потребление пищи и хищничество. Параметры позволяют гибко настраивать состав популяции и поведение агентов, а методы  Moving  и  Revision  реализуют логику симуляции.

//————————————————————————————————————————————————————————————————————
class C_AO_ECOc : public C_AO
{
  public:
  ~C_AO_ECOc () { }2

  C_AO_ECOc ()
  {
    ao_name = "ECOc";
    ao_desc = "Ecological Cycle Optimizer";
    ao_link = "https://www.mql5.com/ru/articles/20611";

    popSize   = 50;
    ratioProd = 0.2;
    ratioHerb = 0.3;
    ratioCarn = 0.3;
    ratioOmni = 0.2;

    ArrayResize (params, 5);
    params [0].name = "popSize";    params [0].val = popSize;
    params [1].name = "ratioProd";  params [1].val = ratioProd;
    params [2].name = "ratioHerb";  params [2].val = ratioHerb;
    params [3].name = "ratioCarn";  params [3].val = ratioCarn;
    params [4].name = "ratioOmni";  params [4].val = ratioOmni;
  }

  void SetParams ()
  {
    popSize   = (int)params [0].val;
    ratioProd = params      [1].val;
    ratioHerb = params      [2].val;
    ratioCarn = params      [3].val;
    ratioOmni = params      [4].val;
  }

  bool Init (const double &rangeMinP  [],
             const double &rangeMaxP  [],
             const double &rangeStepP [],
             const int     epochsP);

  void Moving   ();
  void Revision ();

  //------------------------------------------------------------------
  double ratioProd;
  double ratioHerb;
  double ratioCarn;
  double ratioOmni;

  private: //—————————————————————————————————————————————————————————
  int    maxIter;
  int    currIter;

  int    numProd;
  int    numHerb;
  int    numCarn;
  int    numOmni;

  // Индексы групп в общем массиве a[]
  int    prodEnd;
  int    herbEnd;
  int    carnEnd;

  // Коэффициент хищничества
  double huntCoef [];

  // Временный массив для сортировки
  S_AO_Agent aT [];

  // Вспомогательные методы
  void   SelectFromGroup (int startIdx, int endIdx, int selCount, int &indices []);
  double VectorNorm      (int idx1, int idx2);
};
//————————————————————————————————————————————————————————————————————

Метод "Init" выполняет инициализацию объекта класса  C_AO_ECOc  для начала работы оптимизатора. Первым делом вызывается метод "StandardInit", которому передаются параметры "rangeMinP", "rangeMaxP" и "rangeStepP". Этот метод устанавливает границы и шаги для координат в пространстве поиска. Если стандартная инициализация не удалась, метод возвращает "false".

Метод подготавливает оптимизатор к работе, настраивая начальные параметры, распределяя агентов по экологическим группам и выделяя необходимую память. Он служит точкой входа для запуска алгоритма оптимизации.

//————————————————————————————————————————————————————————————————————
bool C_AO_ECOc::Init (const double &rangeMinP  [],
                      const double &rangeMaxP  [],
                      const double &rangeStepP [],
                      const int     epochsP)
{
  if (!StandardInit (rangeMinP, rangeMaxP, rangeStepP)) return false;

  //------------------------------------------------------------------
  maxIter  = epochsP;
  currIter = 0;

  // Вычисление размеров групп
  numProd = (int)MathRound (popSize * ratioProd);
  numHerb = (int)MathRound (popSize * ratioHerb);
  numCarn = (int)MathRound (popSize * ratioCarn);
  numOmni = popSize - numProd - numHerb - numCarn;

  if (numProd < 1) numProd = 1;
  if (numHerb < 1) numHerb = 1;
  if (numCarn < 1) numCarn = 1;
  if (numOmni < 1) numOmni = 1;

  // Корректировка numOmni если сумма не равна popSize
  numOmni = popSize - numProd - numHerb - numCarn;

  // Индексы групп (начало группы = конец предыдущей)
  prodEnd = numProd;
  herbEnd = prodEnd + numHerb;
  carnEnd = herbEnd + numCarn;

  // Выделяем память
  ArrayResize (huntCoef, coords);
  ArrayResize (aT, popSize);
  ArrayResize (u.roulette, popSize);

  for (int i = 0; i < popSize; i++) aT [i].Init (coords);

  return true;
}
//————————————————————————————————————————————————————————————————————

Метод "Moving" моделирует эволюцию и поведение агентов в экосистеме на протяжении одной итерации алгоритма. Он разделен на несколько логических блоков, каждый из которых отражает определенную "стратегию".

Если алгоритм находится на первой итерации, то происходит случайная инициализация позиций всех агентов в пределах заданных диапазонов и с учетом дискретизации.

Увеличивается счетчик текущих итераций. Вычисляются относительные значения текущей и максимальной итераций. Для каждой координаты вычисляется новый коэффициент хищничества. Этот коэффициент динамически меняется в зависимости от стадии оптимизации и случайного фактора. Он может быть как положительным, так и отрицательным.

Стратегия продуцентов. Весь массив агентов "a" сортируется по значению фитнеса "f" в порядке убывания. Это делается с помощью вспомогательного метода "u.Sorting", который использует временный массив "aT". Если лучший агент после сортировки имеет лучший фитнес, чем текущий глобальный максимум "fB", то "fB" и лучшая позиция "cB" обновляются.

Стратегия травоядных (движение к продуцентам). Выбираются три случайных продуцента из группы продуцентов. Каждый травоядный агент (a[i] из группы "prodEnd" до "herbEnd") перемещается. Его новое положение вычисляется как комбинация его текущего положения и взвешенной суммы позиций выбранных продуцентов. Весовые коэффициенты "r1", "r2", "r3" случайны, а общий вектор движения умножается на "huntCoef[c]". Это имитирует поиск и потребление "пищи" (продуцентов).

Стратегия плотоядных (движение к травоядным). Аналогично травоядным, выбираются три случайных травоядных агента "selHerb". Каждый хищник (a[i] из группы "herbEnd" до "carnEnd") перемещается, стремясь к позициям выбранных травоядных. Формула движения похожа на стратегию травоядных, но направлена на другую группу.

Стратегия всеядных (движение ко всем группам). Всеядные агенты (a[i] с "carnEnd" до "popSize") также перемещаются. Их движение является комбинацией стремления к продуценту, одному травоядному и двум хищникам. Это отражает их способность питаться разнообразными источниками.

Стратегия декомпозиторов (поиск решения). Перед применением стратегии декомпозиторов, текущие позиции и фитнес всех агентов сохраняются в "cP" и "fP" соответственно. 

  • Оптимальная декомпозиция (rnd < 0.5) — агент смещается от своего предыдущего положения к позиции, определяемой комбинацией случайного коэффициента и положения лучшего агента. 
  • Локальная случайная декомпозиция (0.5 <= rnd < 0.75) — агент перемещается в направлении, заданном случайным единичным вектором, на расстояние, которое зависит от предыдущего положения агента, а также расстояния до лучшего агента и случайного множителя. 
  • Глобальная случайная декомпозиция (rnd >= 0.75) — агент перемещается на основе взвешенной комбинации его предыдущего положения и некоторого случайного "блуждания", величина которого зависит от стадии оптимизации (t/T) и случайных множителей. Этот тип движения становится менее активным по мере приближения к концу оптимизации.

После применения любой из стратегий перемещения (травоядные, хищники, всеядные, декомпозиторы), для каждого агента проверяется, не вышли ли его новые координаты за пределы допустимых диапазонов. Если это произошло, его позиция случайно генерируется заново в пределах диапазона и затем дискретизируется с помощью "u.SeInDiSp" в соответствии с заданным шагом.

В целом, метод  Moving  выполняет следующую логику:

Первый шаг: случайная инициализация всей популяции.

Последующие шаги:

  1. динамически изменяет "силу" хищничества,
  2. сортирует агентов по качеству решения, обновляя лучший найденный результат,
  3. имитирует поиск пищи и хищничество, где каждая группа (травоядные, хищники, всеядные) "стремится" к агентам из нижележащих или смежных групп,
  4. применяет различные стратегии "декомпозиции" (по сути, методы поиска и улучшения решения), которые могут быть как более направленными (к лучшему агенту), так и более случайными, с разной степенью глобальности и активности в зависимости от стадии оптимизации,
  5. принудительно удерживает всех агентов в заданных границах поиска.

Данный метод моделирует экосистему, где различные "виды" (группы агентов) взаимодействуют, а также применяется механизм оптимизации (стратегии декомпозиторов) для поиска наилучшего решения.

//————————————————————————————————————————————————————————————————————
void C_AO_ECOc::Moving ()
{
  //------------------------------------------------------------------
  // Первая итерация: случайная инициализация
  if (!revision)
  {
    for (int i = 0; i < popSize; i++)
    {
      for (int c = 0; c < coords; c++)
      {
        a [i].c [c] = u.RNDfromCI (rangeMin [c], rangeMax [c]);
        a [i].c [c] = u.SeInDiSp  (a [i].c [c], rangeMin [c], rangeMax [c], rangeStep [c]);

        // Сохраняем в cP для сравнения в Revision
        a [i].cP [c] = a [i].c [c];
      }
      a [i].f  = -DBL_MAX;
      a [i].fP = -DBL_MAX;
    }

    revision = true;
    return;
  }

  //------------------------------------------------------------------
  currIter++;
  double t = (double)currIter;
  double T = (double)maxIter;

  // Обновление коэффициента хищничества G
  for (int c = 0; c < coords; c++)
  {
    int sign = (u.RNDprobab () < 0.5) ? -1 : 1;
    huntCoef [c] = 1.0 + 2.0 * u.RNDfromCI (0.0, 1.0) * MathExp (-9.0 * MathPow (t / T, 3)) * sign;
  }

  //==================================================================
  // (1) Стратегия продуцентов - сортировка популяции по фитнесу
  //==================================================================
  // Используем готовую сортировку из утилит
  u.Sorting (a, aT, popSize);

  // Обновляем лучшее решение
  if (a [0].f > fB)
  {
    fB = a [0].f;
    ArrayCopy (cB, a [0].c, 0, 0, coords);
  }

  //==================================================================
  // (2) Стратегия травоядных - движение к продуцентам
  //==================================================================
  int selProd [];
  SelectFromGroup (0, prodEnd, 3, selProd);

  for (int i = prodEnd; i < herbEnd; i++)
  {
    double r1 = u.RNDfromCI (0.0, 1.0);
    double r2 = u.RNDfromCI (0.0, 1.0);
    double r3 = u.RNDfromCI (0.0, 1.0);

    for (int c = 0; c < coords; c++)
    {
      double move = r1 * (a [selProd [0]].c [c] - a [i].c [c]) +
                    r2 * (a [selProd [1]].c [c] - a [i].c [c]) +
                    r3 * (a [selProd [2]].c [c] - a [i].c [c]);

      a [i].c [c] = a [i].c [c] + huntCoef [c] * move;
    }
  }

  //==================================================================
  // (3) Стратегия плотоядных - движение к травоядным
  //==================================================================
  int selHerb [];
  SelectFromGroup (prodEnd, herbEnd, 3, selHerb);

  for (int i = herbEnd; i < carnEnd; i++)
  {
    double r1 = u.RNDfromCI (0.0, 1.0);
    double r2 = u.RNDfromCI (0.0, 1.0);
    double r3 = u.RNDfromCI (0.0, 1.0);

    for (int c = 0; c < coords; c++)
    {
      double move = r1 * (a [selHerb [0]].c [c] - a [i].c [c]) +
                    r2 * (a [selHerb [1]].c [c] - a [i].c [c]) +
                    r3 * (a [selHerb [2]].c [c] - a [i].c [c]);

      a [i].c [c] = a [i].c [c] + huntCoef [c] * move;
    }
  }

  //==================================================================
  // (4) Стратегия всеядных - движение ко всем группам
  //==================================================================
  int selProd1 [];
  int selHerb1 [];
  int selCarn2 [];
  SelectFromGroup (0,       prodEnd, 1, selProd1);
  SelectFromGroup (prodEnd, herbEnd, 1, selHerb1);
  SelectFromGroup (herbEnd, carnEnd, 2, selCarn2);

  for (int i = carnEnd; i < popSize; i++)
  {
    double r1 = u.RNDfromCI (0.0, 1.0);
    double r2 = u.RNDfromCI (0.0, 1.0);
    double r3 = u.RNDfromCI (0.0, 1.0);
    double r4 = u.RNDfromCI (0.0, 1.0);

    for (int c = 0; c < coords; c++)
    {
      double move = r1 * (a [selProd1 [0]].c [c] - a [i].c [c]) +
                    r2 * (a [selHerb1 [0]].c [c] - a [i].c [c]) +
                    r3 * (a [selCarn2 [0]].c [c] - a [i].c [c]) +
                    r4 * (a [selCarn2 [1]].c [c] - a [i].c [c]);

      a [i].c [c] = a [i].c [c] + huntCoef [c] * move;
    }
  }

  //==================================================================
  // (5) Стратегия декомпозиторов
  //==================================================================

  // Сохраняем текущие позиции в cP перед декомпозицией
  for (int i = 0; i < popSize; i++)
  {
    for (int c = 0; c < coords; c++)
    {
      a [i].cP [c] = a [i].c [c];
    }
    a [i].fP = a [i].f;
  }

  // Лучший агент - индекс 0 после сортировки
  int bestIdx = 0;

  // Декомпозиция
  for (int i = 0; i < popSize; i++)
  {
    double rnd = u.RNDfromCI (0.0, 1.0);

    if (rnd < 0.5)
    {
      //--- Оптимальная декомпозиция ---
      double coef = 0.4 * u.RNDfromCI (0.0, 1.0) - 0.2;

      for (int c = 0; c < coords; c++)
      {
        double randC = u.RNDfromCI (0.0, 1.0);
        double bestNeighbor = a [bestIdx].cP [c] * randC;
        a [i].c [c] = bestNeighbor + coef * (bestNeighbor - a [i].cP [c]);
      }
    }
    else
      if (rnd < 0.75)
      {
        //--- Локальная случайная декомпозиция ---
        double dist = VectorNorm (bestIdx, i);

        // Генерация случайного единичного вектора
        double randDir [];
        ArrayResize (randDir, coords);
        double norm = 0.0;

        for (int c = 0; c < coords; c++)
        {
          randDir [c] = 2.0 * u.RNDfromCI (0.0, 1.0) - 1.0;
          norm += randDir [c] * randDir [c];
        }
        norm = MathSqrt (norm) + 1e-10;

        double randMult = u.RNDfromCI (0.0, 1.0);

        for (int c = 0; c < coords; c++)
        {
          randDir [c] /= norm;
          a [i].c [c] = a [i].cP [c] + randMult * dist * randDir [c];
        }
      }
      else
      {
        //--- Глобальная случайная декомпозиция ---
        double tRatio = t / (1.5 * T);
        if (tRatio > 1.0) tRatio = 1.0;

        double H = MathPow (1.0 - tRatio, 5.0 * t / T) * MathCos (M_PI * u.RNDfromCI (0.0, 1.0));

        // min(Low - Up)
        double minRange = rangeMin [0] - rangeMax [0];
        for (int c = 1; c < coords; c++)
        {
          double diff = rangeMin [c] - rangeMax [c];
          if (diff < minRange) minRange = diff;
        }

        double randWalk = (2.0 / 3.0) * H * u.RNDfromCI (0.0, 1.0) * minRange;
        double weight   = u.RNDfromCI (0.0, 1.0);

        for (int c = 0; c < coords; c++)
        {
          a [i].c [c] = weight * a [i].cP [c] + (1.0 - weight) * randWalk;
        }
      }

    // Проверка границ и дискретизация
    for (int c = 0; c < coords; c++)
    {
      if (a [i].c [c] < rangeMin [c] || a [i].c [c] > rangeMax [c])
      {
        a [i].c [c] = u.RNDfromCI (rangeMin [c], rangeMax [c]);
      }
      a [i].c [c] = u.SeInDiSp (a [i].c [c], rangeMin [c], rangeMax [c], rangeStep [c]);
    }
  }
}
//————————————————————————————————————————————————————————————————————

Метод "Revision" служит для "самокоррекции" популяции. Он гарантирует, что ни один агент не останется с состоянием хуже, чем было до его последнего действия (путем отката). Параллельно он отслеживает и сохраняет лучшее найденное решение во всей популяции за время работы алгоритма. Это классический аспект многих эволюционных алгоритмов, где важно сохранять наилучшие достижения и не принимать ухудшающие шаги.

//————————————————————————————————————————————————————————————————————
void C_AO_ECOc::Revision ()
{
  for (int i = 0; i < popSize; i++)
  {
    // Если новая позиция хуже - откат к предыдущей
    if (a [i].f <= a [i].fP)
    {
      a [i].f = a [i].fP;
      ArrayCopy (a [i].c, a [i].cP, 0, 0, coords);
    }

    // Обновление лучшего глобального решения
    if (a [i].f > fB)
    {
      fB = a [i].f;
      ArrayCopy (cB, a [i].c, 0, 0, coords);
    }
  }
}
//————————————————————————————————————————————————————————————————————

Метод "SelectFromGroup" реализует рулеточную селекцию для выбора "selCount"  индексов из группы агентов (startIdx до endIdx).

  1. Подготовка: инициализирует выходной массив "indices", определяет размер группы. Обрабатывает случаи, когда группа пуста или слишком мала.
  2. Расчет весов: находит минимальный фитнес в группе и использует его для преобразования фитнесов агентов в положительные веса.
  3. Построение рулетки: создает "рулетку" (массивы интервалов), где каждый интервал соответствует агенту, а его размер пропорционален его весу (с учетом минимального фитнеса).
  4. Выбор: "selCount" раз генерирует случайное число на рулетке и выбирает агента, чей интервал попадает в это число. Результат сохраняется в "indices".
//————————————————————————————————————————————————————————————————————
void C_AO_ECOc::SelectFromGroup (int startIdx, int endIdx, int selCount, int &indices [])
{
  ArrayResize (indices, selCount);
  int groupSize = endIdx - startIdx;

  if (groupSize <= 0)
  {
    for (int s = 0; s < selCount; s++) indices [s] = startIdx;
    return;
  }

  if (groupSize < selCount)
  {
    for (int s = 0; s < selCount; s++) indices [s] = startIdx + (s % groupSize);
    return;
  }

  // Подготовка рулетки для группы
  double minFit = a [startIdx].f;
  for (int i = startIdx + 1; i < endIdx; i++)
  {
    if (a [i].f < minFit) minFit = a [i].f;
  }

  // Заполняем структуру рулетки
  double cumSum = 0.0;
  for (int i = 0; i < groupSize; i++)
  {
    u.roulette [i].start = cumSum;
    double prob = a [startIdx + i].f - minFit + 1e-10;
    cumSum += prob;
    u.roulette [i].end = cumSum;
  }

  // Выбор
  for (int s = 0; s < selCount; s++)
  {
    double r = u.RNDfromCI (0.0, cumSum);
    indices [s] = startIdx;

    for (int i = 0; i < groupSize; i++)
    {
      if (r >= u.roulette [i].start && r < u.roulette [i].end)
      {
        indices [s] = startIdx + i;
        break;
      }
    }
  }
}
//————————————————————————————————————————————————————————————————————

Метод "VectorNorm" вычисляет Евклидово расстояние между двумя точками (координатами агентов "idx1" и "idx2") в "coords"-мерном пространстве.

  1. Суммирование квадратов разностей: проходит по всем "coords" измерениям, вычисляет разницу между соответствующими координатами двух агентов, возводит эту разницу в квадрат и накапливает сумму.
  2. Извлечение корня: возвращает квадратный корень из полученной суммы, что является длиной вектора (Евклидовым расстоянием).
//————————————————————————————————————————————————————————————————————
double C_AO_ECOc::VectorNorm (int idx1, int idx2)
{
  double sum = 0.0;
  for (int c = 0; c < coords; c++)
  {
    double diff = a [idx1].cP [c] - a [idx2].cP [c];
    sum += diff * diff;
  }
  return MathSqrt (sum);
}
//————————————————————————————————————————————————————————————————————


Результаты тестов

ECO|Ecological Cycle Optimizer|50.0|0.2|0.3|0.3|
=============================
5 Hilly's; Func runs: 10000; result: 0.7030067722054903
25 Hilly's; Func runs: 10000; result: 0.3712282206716303
500 Hilly's; Func runs: 10000; result: 0.3380465748120792
=============================
5 Forest's; Func runs: 10000; result: 0.4856459718015104
25 Forest's; Func runs: 10000; result: 0.2948314767505128
500 Forest's; Func runs: 10000; result: 0.1987204244277699
=============================
5 Megacity's; Func runs: 10000; result: 0.5892307692307692
25 Megacity's; Func runs: 10000; result: 0.3683076923076923
500 Megacity's; Func runs: 10000; result: 0.35736923076923105
=============================
All score: 3.70639 (41.18%)


Визуализация работы алгоритма на различных тестовых функциях.

ECOc на тестовой функции Hilly

Forest

ECOc на тестовой функции Forest

Megacity

ECOc на тестовой функции Megacity

Shaffer

ECOc на стандартной тестовой функции Shaffer

Peaks

ECOc на стандартной тестовой функции Peaks

AO Description HillyHilly
Final
ForestForest
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)
1DOAdingomdingo_optimization_algorithm_M0,479680,453670,463691,397040,941450,879090,914542,735080,786150,860610,848052,494816,62773,63
2ANSacross neighbourhood search0,949480,847760,438572,235811,000000,923340,399882,323230,709230,634770,230911,574916,13468,15
3CLAcode lock algorithm (joo)0,953450,871070,375902,200420,989420,917090,316422,222940,796920,693850,193031,683806,10767,86
4AMOmanimal migration ptimization M0,903580,843170,462842,209590,990010,924360,465982,380340,567690,591320,237731,396755,98766,52
5(P+O)ES(P+O) evolution strategies0,922560,881010,400212,203790,977500,874900,319452,171850,673850,629850,186341,490035,86665,17
6CTAcomet tail algorithm (joo)0,953460,863190,277702,094350,997940,857400,339492,194840,887690,564310,105121,557125,84664,96
7TETAtime evolution travel algorithm (joo)0,913620,823490,319902,057010,970960,895320,293242,159520,734620,685690,160211,580525,79764,41
8SDSmstochastic diffusion search M0,930660,854450,394762,179880,999830,892440,196192,088460,723330,611000,106701,441035,70963,44
9BOAmbilliards optimization algorithm M0,957570,825990,252352,035901,000000,900360,305022,205380,735380,525230,095631,356255,59862,19
10AAmarchery algorithm M0,917440,708760,421602,047800,925270,758020,353282,036570,673850,552000,237381,463235,54861,64
11ESGevolution of social groups (joo)0,999060,796540,350562,146161,000000,828630,131021,959650,823330,553000,047251,423585,52961,44
12SIAsimulated isotropic annealing (joo)0,957840,842640,414652,215130,982390,795860,205071,983320,686670,493000,090531,270205,46960,76
13EOmextremal_optimization_M0,761660,772420,317471,851550,999990,767510,235272,002770,747690,539690,142491,429875,28458,71
14BBObiogeography based optimization0,949120,694560,350311,993990,938200,673650,256821,868670,746150,482770,173691,402615,26558,50
15ACSartificial cooperative search0,755470,747440,304071,806981,000000,888610,224132,112740,690770,481850,133221,305835,22658,06
16DAdialectical algorithm0,861830,700330,337241,899400,981630,727720,287181,996530,703080,452920,163671,319675,21657,95
17BHAmblack hole algorithm M0,752360,766750,345831,864930,935930,801520,271772,009230,650770,516460,154721,321955,19657,73
18ASOanarchy society optimization0,848720,746460,314651,909830,961480,791500,238031,991010,570770,540620,166141,277525,17857,54
19RFOroyal flush optimization (joo)0,833610,737420,346291,917330,894240,738240,240981,873460,631540,502920,164211,298675,08956,55
20AOSmatomic orbital search M0,802320,704490,310211,817020,856600,694510,219961,771070,746150,528620,143581,418355,00655,63
21TSEAturtle shell evolution algorithm (joo)0,967980,644800,296721,909490,994490,619810,227081,841390,690770,426460,135981,253225,00455,60
22BSAbacktracking_search_algorithm0,973090,545340,290981,809410,999990,585430,217471,802890,847690,369530,129781,347004,95955,10
23DEdifferential evolution0,950440,616740,303081,870260,953170,788960,166521,908650,786670,360330,029531,176534,95555,06
24SRAsuccessful restaurateur algorithm (joo)0,968830,634550,292171,895550,946370,555060,191241,692670,749230,440310,125261,314804,90354,48
25BObonobo_optimizer0,775650,638050,329081,742780,880880,763440,255731,900050,610770,498460,142461,251694,89554,38
26CROchemical reaction optimisation0,946290,661120,298531,905930,879060,584220,211461,674730,758460,426460,126861,311784,89254,36
27BIOblood inheritance optimization (joo)0,815680,653360,308771,777810,899370,653190,217601,770160,678460,476310,139021,293784,84253,80
28DOAdream_optimization_algorithm0,855560,700850,372801,929210,734210,489050,241471,464730,772310,473540,185611,431464,82553,62
29BSAbird swarm algorithm0,893060,649000,262501,804550,924200,711210,249391,884790,693850,326150,100121,120124,80953,44
30DEAdolphin_echolocation_algorithm0,759950,675720,341711,777380,895820,642230,239411,777460,615380,440310,151151,206844,76252,91
31HSharmony search0,865090,687820,325271,878180,999990,680020,095901,775920,620000,422670,054581,097254,75152,79
32SSGsaplings sowing and growing0,778390,649250,395431,823080,859730,624670,174291,658690,646670,441330,105981,193984,67651,95
33BCOmbacterial chemotaxis optimization M0,759530,622680,314831,697040,893780,613390,225421,732590,653850,420920,144351,219124,64951,65
34ABOafrican buffalo optimization0,833370,622470,299641,755480,921700,586180,197231,705110,610000,431540,132251,173784,63451,49
35(PO)ES(PO) evolution strategies0,790250,626470,429351,846060,876160,609430,195911,681510,590000,379330,113221,082554,61051,22
36FBAfractal-based Algorithm0,790000,651340,289651,730990,871580,568230,188771,628580,610770,460620,123981,195374,55550,61
37TSmtabu search M0,877950,614310,291041,783300,928850,518440,190541,637830,610770,382150,121571,114494,53650,40
38BSObrain storm optimization0,937360,576160,296881,810410,931310,558660,235371,725340,552310,290770,119140,962224,49849,98
39WOAmwale optimization algorithm M0,845210,562980,262631,670810,931000,522780,163651,617430,663080,411380,113571,188034,47649,74
40AEFAartificial electric field algorithm0,877000,617530,252351,746880,927290,726980,180641,834900,666150,116310,095080,877544,45949,55
41AEOartificial ecosystem-based optimization algorithm0,913800,467130,264701,645630,902230,437050,214001,553270,661540,308000,285631,255174,45449,49
42CAmcamel algorithm M0,786840,560420,351331,698590,827720,560410,243361,631490,648460,330920,134181,113564,44449,37
43ACOmant colony optimization M0,881900,661270,303771,846930,858730,586800,150511,596040,596670,373330,024720,994724,43849,31
44CMAEScovariance_matrix_adaptation_evolution_strategy0,762580,720890,000001,483470,820560,796160,000001,616720,758460,490770,000001,249234,34948,33
45DA_duelistduelist_algorithm0,927820,537780,277921,743520,869570,475360,181931,526860,621530,335690,117151,074374,34548,28
ECOcecological_cycle_optimizer0,703000,371220,338041,412260,485640,294830,198720,979190,589230,368300,357361,314893,70641,18
RWrandom walk0,487540,321590,257811,066940,375540,219440,158770,753750,279690,149170,098470,527342,34826,09


Выводы

Алгоритм ECO можно рекомендовать для задач, где важна стабильность сходимости и допустимы умеренные вычислительные затраты. Для задач, требующих максимальной эффективности, следует рассмотреть алгоритмы из верхней части нашего рейтинга. Оригинальная и интуитивно понятная концепция, основанная на экологических взаимодействиях. Адаптивный коэффициент хищничества G, обеспечивающий плавный переход от глобального исследования к локальной эксплуатации. Механизм жадного отбора (ревизии), гарантирующий монотонное улучшение лучшего решения. Три режима декомпозиции, вносящие разнообразие в поисковые стратегии. Высокая вычислительная сложность из-за множества операций копирования и сортировки на каждой итерации. 

tab

Рисунок 2. Цветовая градация алгоритмов по соответствующим тестам

chart

Рисунок 3. Гистограмма результатов тестирования алгоритмов (по шкале от 0 до 100, чем больше, тем лучше, где 100 — максимально возможный теоретический результат, в архиве скрипт для расчета рейтинговой таблицы)

Плюсы и минусы алгоритма ECOc:

Плюсы:

  1. Хорошо справляется с некоторым типом задач.

Минусы:

  1. Труднее справляется с  дискретными функциями.

К статье прикреплён архив с актуальными версиями кодов алгоритмов. Автор статьи не несёт ответственности за абсолютную точность в описании канонических алгоритмов, во многие из них были внесены изменения для улучшения поисковых возможностей. Выводы и суждения, представленные в статьях, основываются на результатах проведённых экспериментов.



Программы, используемые в статье

#ИмяТипОписание
1#C_AO.mqh
Включаемый файл
Родительский класс популяционных алгоритмов оптимизации
2#C_AO_enum.mqh
Включаемый файл
Перечисление популяционных алгоритмов оптимизации
3TestFunctions.mqh
Включаемый файл
Библиотека тестовых функций
4
TestStandFunctions.mqh
Включаемый файл
Библиотека функций тестового стенда
5
Utilities.mqh
Включаемый файл
Библиотека вспомогательных функций
6
CalculationTestResults.mqh
Включаемый файл
Скрипт для расчета результатов в сравнительную таблицу
7
Testing AOs.mq5
СкриптЕдиный испытательный стенд для всех популяционных алгоритмов оптимизации
8
Simple use of population optimization algorithms.mq5
Скрипт
Простой пример использования популяционных алгоритмов оптимизации без визуализации
9
Test_AO_ECOc.mq5
СкриптИспытательный стенд для ECO
Прикрепленные файлы |
ECOc.zip (385.3 KB)
Объединяем 3D-бары, квантовые вычисления и машинное обучение в единую торговую систему Объединяем 3D-бары, квантовые вычисления и машинное обучение в единую торговую систему
Представлена полная интеграция модуля 3D-баров в квантово-усиленную торговую систему для прогнозирования движения валютных пар. Система объединяет стационарные четырёхмерные признаки, квантовый энкодер на 8 кубитах и градиентный бустинг CatBoost с 52+ признаками. Система реализована на Python с использованием MetaTrader 5, Qiskit, CatBoost и опциональной интеграцией LLM Llama 3.2 для интерпретации прогнозов.
Знакомство с языком MQL5 (Часть 21): Автоматическое обнаружение паттернов Гартли Знакомство с языком MQL5 (Часть 21): Автоматическое обнаружение паттернов Гартли
Узнайте, как обнаружить и отобразить гармонический паттерн Гартли в MetaTrader 5 с использованием языка MQL5. В этой статье объясняется каждый шаг данного процесса: от выявления точек свинга до применения коэффициентов Фибоначчи и графического построения паттерна на графике целиком для четкого визуального подтверждения.
Нейросети в трейдинге: Сеточная аппроксимация событийного потока как инструмент анализа ценовых паттернов (Окончание) Нейросети в трейдинге: Сеточная аппроксимация событийного потока как инструмент анализа ценовых паттернов (Окончание)
В статье представлена адаптация фреймворка EEMFlow для построения высокоэффективных торговых моделей средствами MQL5. Рассматриваются алгоритмы оценки MeshFlow с расширенной корреляцией признаков, позволяющие точно анализировать динамику рынка и прогнозировать ценовые потоки. Тестирование подтвердило положительное математическое ожидание, умеренные просадки и высокую эффективность принятия решений.
Нейросети в трейдинге: Сеточная аппроксимация событийного потока как инструмент анализа ценовых паттернов (CDC-модуль) Нейросети в трейдинге: Сеточная аппроксимация событийного потока как инструмент анализа ценовых паттернов (CDC-модуль)
В статье представлен промежуточный этап реализации фреймворка EEMFlow средствами MQL5. Основное внимание уделено построению и интеграции CDC-модуля, включающего Self-Corrector, механизм Self-Attention для скорректированного потока и взвешенное объединение сигналов через маску доверия. Рассмотрены принципы архитектуры, порядок прямого и обратного проходов, а также особенности работы с локальными и глобальными признаками движения.