
Алгоритм дуэлянта — Duelist Algorithm
Содержание
Введение
В алгоритмической торговле каждая миллисекунда означает прибыль или убыток, поэтому поиск оптимальных параметров для торговой стратегии становится критически важной задачей. Современные трейдеры обращаются к методам искусственного интеллекта и эволюционным алгоритмам для настройки своих торговых систем.
Сегодня рассмотрим новый подход к оптимизации — Duelist Algorithm (Алгоритм Дуэлянта), который черпает вдохновение из древнего искусства поединков. Алгоритм был разработан в 2015 г. группой индонезийских ученых под руководством Biyanto как альтернатива традиционным эволюционным алгоритмам с целью минимизировать "слепой" характер операторов мутации и кроссовера через дифференцированный подход к победителям и проигравшим. В статье мы детально рассмотрим математическую основу Duelist Algorithm, сделаем реализацию на языке MQL5, и проведем сравнительный анализ с другими популяционными методами оптимизации.
Реализация алгоритма
Представьте торговую площадку как арену, где различные стратегии постоянно соревнуются друг с другом. Одни стратегии побеждают в определенных рыночных условиях, другие терпят поражение. Но что делает успешного трейдера? Способность учиться как на своих победах, так и на поражениях, постоянно адаптируя и совершенствуя свой подход.
Именно эту концепцию воплощает Duelist Algorithm. В отличие от классических генетических алгоритмов, где все особи обрабатываются одинаково, алгоритм дуэлянта признает фундаментальное различие между победителями и проигравшими. Проигравшие учатся — они анализируют стратегии победителей и перенимают их успешные элементы, а победители склонны к инновациям — они экспериментируют с новыми подходами, зная, что их базовая стратегия уже доказала свою эффективность. Чемпионы наставляют — лучшие стратегии передаются дальше.
Рисунок 1. Иллюстрация работы алгоритма DA_duelist
Визуализация основных этапов алгоритма демонстрирует все ключевые моменты работы Duelist Algorithm: начальная популяция — все дуэлянты стартуют с равными шансами, определение чемпионов — лучшие дуэлянты выделяются золотым цветом. Дуэли — представлен процесс поединка с определением победителя и проигравшего. Обучение и инновации — два разных пути развития для проигравших и победителей. Тренировка новых дуэлянтов, когда чемпионы передают свои навыки новому поколению и элиминация — худшие дуэлянты удаляются из популяции.
Иллюстрация также включает циклическую стрелку, показывающую итеративную природу алгоритма, финальный результат с чемпионом-победителем, а также подробную легенду с объяснением всех элементов и ключевых параметров. Визуализация помогает быстро понять основную концепцию алгоритма.
Теперь, после подробного разбора, напишем псевдокод алгоритма.
ВХОДНЫЕ ПАРАМЕТРЫ:
- popSize: размер популяции дуэлянтов
- luckCoefficient: коэффициент удачи в дуэлях
- learningProbability: вероятность обучения проигравшего
- innovationProbability: вероятность инновации победителя
- championsCount: количество чемпионов
ИНИЦИАЛИЗАЦИЯ:
1. Проверить и скорректировать championsCount:
- Если < 1, установить = 1
- Если >= popSize, установить = popSize / 4
2. Создать пустые массивы winners, losers
3. Создать массив champions размером championsCount
ОСНОВНОЙ ЦИКЛ (Moving):
ЕСЛИ первая итерация:
ДЛЯ каждого дуэлянта i от 0 до popSize:
ДЛЯ каждой координаты j:
Инициализировать случайным значением в допустимых границах
Установить флаг revision = true
ВЫХОД из функции
ИНАЧЕ (последующие итерации):
1. РАСШИРЕНИЕ ПОПУЛЯЦИИ:
- Увеличить массив дуэлянтов до размера (popSize + championsCount)
- Инициализировать структуры новых дуэлянтов
2. ОПРЕДЕЛЕНИЕ ЧЕМПИОНОВ:
- Отсортировать дуэлянтов по убыванию fitness (пузырьковая сортировка)
- Первые championsCount дуэлянтов становятся чемпионами
3. ТРЕНИРОВКА НОВЫХ ДУЭЛЯНТОВ:
ДЛЯ каждого чемпиона i:
Вызвать TrainNewDuelist (i, popSize + i):
ДЛЯ каждой координаты c:
новый_дуэлянт [c] = чемпион [c] + GaussDistribution ()
Применить ограничения диапазона
4. ПРОВЕДЕНИЕ ДУЭЛЕЙ:
Очистить массивы winners и losers
ДЛЯ каждого дуэлянта i от championsCount до totalDuelists:
Выбрать случайного противника opponent
ЕСЛИ opponent != i:
DetermineWinnerAndLoser(i, opponent):
A_Luck = fitness [A] * (luckCoef + random () * luckCoef)
B_Luck = fitness [B] * (luckCoef + random () * luckCoef)
ЕСЛИ (fitness [A] + A_Luck) >= (fitness [B] + B_Luck):
A - победитель, B - проигравший
ИНАЧЕ:
B - победитель, A - проигравший
Добавить в массивы winners и losers
5. ПРОЦЕСС УЛУЧШЕНИЯ:
a) Обучение проигравших:
ДЛЯ каждой пары (проигравший, победитель):
LearningProcess (loser, winner):
ДЛЯ каждой координаты c:
ЕСЛИ random () < learningProbability:
loser [c] = winner [c]
b) Инновации победителей:
ДЛЯ каждого победителя:
InnovationProcess (winner):
ДЛЯ каждой координаты c:
ЕСЛИ random () < innovationProbability:
winner [c] = случайное_значение_в_диапазоне
6. ЭЛИМИНАЦИЯ:
- Отсортировать всех дуэлянтов по убыванию fitness
- Оставить только первые popSize дуэлянтов
ОБНОВЛЕНИЕ (Revision):
ДЛЯ каждого дуэлянта i:
ЕСЛИ fitness [i] > глобальный_лучший:
Обновить глобальный_лучший = fitness [i]
Сохранить координаты лучшего решения
ПОВТОРЯТЬ основной цикл до достижения критерия останова
Хотелось бы выделить ключевые особенности данного алгоритма, которые заключаются в том, что чемпионы не участвуют в дуэлях, а тренируют новых дуэлянтов, и элемент случайности через коэффициент удачи делает дуэли непредсказуемыми. Дифференцированный подход: проигравшие учатся, а победители ищут инновационные решения. Популяция остается постоянного размера через элиминацию худших. Теперь можем перейти к реализации кода алгоритма DA_duelist.
Напишем класс "C_AO_DA_duelist", который является наследником класса "C_AO" и инициализирует массив параметров (params) и присваивает им названия и значения по умолчанию.
- SetParams () — изменяет значения внутренних переменных (popSize, luckCoefficient, и т.д.) на основе значений, хранящихся в массиве "params".
- Init () — метод инициализации алгоритма. Он принимает массивы для определения диапазонов и шагов для параметров, а также количество эпох.
- Moving ()— метод, который содержит основную логику перемещения "дуэлянтов" (поиска оптимальных параметров).
- Revision () — отвечает за анализ результатов и внесение корректив в процесс.
- luckCoefficient — коэффициент удачи;
- learningProbability — вероятность обучения;
- innovationProbability — вероятность инновации;
- championsCount — количество чемпионов;
- winners [] — массив индексов выигравших "дуэлянтов";
- losers [] — массив индексов проигравших "дуэлянтов";
- champions [] — массив индексов "чемпионов".
- DetermineWinnerAndLoser () определяет победителя и проигравшего в "дуэли";
- LearningProcess () реализует процесс обучения для проигравшего, используя победителя;
- InnovationProcess () реализует процесс инноваций для победителя;
- TrainNewDuelist () обучает нового "дуэлянта" на основе чемпиона.
//———————————————————————————————————————————————————————————————————— class C_AO_DA_duelist : public C_AO { public: //---------------------------------------------------------- ~C_AO_DA_duelist () { } C_AO_DA_duelist () { ao_name = "DA"; ao_desc = "Duelist Algorithm"; ao_link = "https://www.mql5.com/ru/articles/19093"; popSize = 50; // количество дуэлянтов luckCoefficient = 0.01; // коэффициент удачи learningProbability = 0.2; // вероятность обучения для проигравших innovationProbability = 0.1; // вероятность инновации для победителей championsCount = 5; // количество чемпионов ArrayResize (params, 5); params [0].name = "popSize"; params [0].val = popSize; params [1].name = "luckCoefficient"; params [1].val = luckCoefficient; params [2].name = "learningProbability"; params [2].val = learningProbability; params [3].name = "innovationProbability"; params [3].val = innovationProbability; params [4].name = "championsCount"; params [4].val = championsCount; } void SetParams () { popSize = (int)params [0].val; luckCoefficient = params [1].val; learningProbability = params [2].val; innovationProbability = params [3].val; championsCount = (int)params [4].val; } bool Init (const double &rangeMinP [], const double &rangeMaxP [], const double &rangeStepP [], const int epochsP = 0); void Moving (); void Revision (); //------------------------------------------------------------------ double luckCoefficient; // коэффициент удачи double learningProbability; // вероятность обучения double innovationProbability; // вероятность инновации int championsCount; // количество чемпионов private: //--------------------------------------------------------- int winners []; // индексы победителей int losers []; // индексы проигравших int champions []; // индексы чемпионов void DetermineWinnerAndLoser (int duelistA, int duelistB); void LearningProcess (int loserIndex, int winnerIndex); void InnovationProcess (int winnerIndex); void TrainNewDuelist (int championIndex, int newDuelistIndex); }; //————————————————————————————————————————————————————————————————————
Метод "Init" класса "C_AO_DA_duelist" предназначен для подготовки алгоритма к выполнению. Его основная задача — инициализировать начальные параметры и структуры данных перед началом работы.
Метод начинает работу с вызова стандартной инициализации, которая обрабатывает диапазоны и шаги для параметров. Если эта стандартная инициализация завершилась неудачно, метод возвращает "false", что сигнализирует о невозможности продолжения. Далее метод корректирует число чемпионов: если оно меньше единицы, устанавливает его равным одному; если оно превышает или равно размеру популяции, уменьшает его до четверти от общего размера популяции. Затем происходит очистка и перераспределение массивов, хранящих индексы победителей, проигравших и чемпионов, чтобы они были пустыми и готовы к следующему этапу работы алгоритма. В конце метод возвращает "true", сигнализируя об успешной инициализации.
//———————————————————————————————————————————————————————————————————— //--- Инициализация bool C_AO_DA_duelist::Init (const double &rangeMinP [], const double &rangeMaxP [], const double &rangeStepP [], const int epochsP = 0) { if (!StandardInit (rangeMinP, rangeMaxP, rangeStepP)) return false; //------------------------------------------------------------------ if (championsCount < 1) championsCount = 1; if (championsCount >= popSize) championsCount = popSize / 4; ArrayResize (winners, 0); ArrayResize (losers, 0); ArrayResize (champions, championsCount); return true; } //————————————————————————————————————————————————————————————————————
Метод "DetermineWinnerAndLoser" класса "C_AO_DA_duelist" определяет победителя и проигравшего в дуэли между двумя особями (duelists) популяции, рассмотрим порядок действий.
- Расчёт "Удачи". Для каждого дуэлянта (A и B) вычисляется значение "Удачи" (A_Luck и B_Luck). "Удача" зависит от базового значения "f" дуэлянта (его "пригодности" или "значимости"), коэффициента "luckCoefficient", и случайного элемента, полученного с помощью "u.RNDprobab ()". Используется некоторая случайность для имитации эффекта удачи.
- Определение победителя. Сравнивается сумма пригодности "f" дуэлянта и его "удачи". Тот, у кого эта сумма больше или равна, считается победителем.
- Сохранение результатов. Индексы победителя и проигравшего добавляются в соответствующие массивы "winners" и "losers". Эти массивы используются для дальнейшего анализа и эволюции популяции.
//———————————————————————————————————————————————————————————————————— //--- Определение победителя и проигравшего в дуэли void C_AO_DA_duelist::DetermineWinnerAndLoser (int duelistA, int duelistB) { // Алгоритм из документа double A_Luck = a [duelistA].f * (luckCoefficient + u.RNDprobab () * luckCoefficient); double B_Luck = a [duelistB].f * (luckCoefficient + u.RNDprobab () * luckCoefficient); if ((a [duelistA].f + A_Luck) >= (a [duelistB].f + B_Luck)) { ArrayResize (winners, ArraySize (winners) + 1); ArrayResize (losers, ArraySize (losers) + 1); winners [ArraySize (winners) - 1] = duelistA; losers [ArraySize (losers) - 1] = duelistB; } else { ArrayResize (winners, ArraySize (winners) + 1); ArrayResize (losers, ArraySize (losers) + 1); winners [ArraySize (winners) - 1] = duelistB; losers [ArraySize (losers) - 1] = duelistA; } } //————————————————————————————————————————————————————————————————————
Метод "LearningProcess" класса "C_AO_DA_duelist" реализует процесс обучения, в котором особь, проигравшая в дуэли, "учится" у победителя. Цель этого процесса — улучшить характеристики проигравшего, передавая ему часть стратегии победителя. Посмотрим, что происходит внутри метода:
Итерация по координатам. Цикл "for" перебирает все "координаты" особи. Количество координат определяется переменной "coords".
Вероятностное копирование. Внутри цикла, происходит случайная проверка, используя "u.RNDprobab ()". Если случайное число меньше, чем "learningProbability" (вероятность обучения), происходит следующее действие.
Копирование характеристики. Проигравший (loserIndex) "заимствует" значение координаты "c" у победителя (winnerIndex). Это означает, что характеристика проигравшей особи обновляется, принимая значение соответствующей характеристики победителя. По сути, проигравший копирует часть стратегии победителя.
В итоге, метод имитирует передачу знаний или стратегии от более успешной особи к менее успешной, что является базой для эволюционного процесса.
//———————————————————————————————————————————————————————————————————— //--- Процесс обучения проигравшего у победителя void C_AO_DA_duelist::LearningProcess (int loserIndex, int winnerIndex) { for (int c = 0; c < coords; c++) { if (u.RNDprobab () < learningProbability) { // Проигравший копирует часть стратегии победителя a [loserIndex].c [c] = a [winnerIndex].c [c]; } } } //————————————————————————————————————————————————————————————————————
Метод "InnovationProcess" класса "C_AO_DA_duelist" реализует процесс "инновации" или мутации для особи, победившей в дуэли. Этот процесс вносит случайные изменения в стратегию победителя, исследуя новые возможности.
Итерация по координатам. Цикл "for" перебирает все координаты "c" особи, аналогично "LearningProcess".
Вероятностная мутация. Если случайное число, полученное с помощью "u.RNDprobab ()", меньше "innovationProbability", происходит мутация. Другими словами, с заданным шансом (установленным innovationProbability) особь пробует изменить свою стратегию.
Генерация и коррекция нового значения. Генератор случайных чисел "u.RNDfromCI ()" создает для параметра "c" случайное значение, которое находится в диапазоне от "rangeMin [c]" до "rangeMax [c]". Полученное случайное значение корректируется с помощью "u.SeInDiSp ()". Эта функция отвечает за приведение значения к дискретному набору значений с шагом "rangeStep [c]" внутри заданного диапазона (rangeMin [c], rangeMax [c]).
В результате, метод позволяет победителю "экспериментировать" с новыми стратегиями, что потенциально может привести к улучшению характеристик особи и её приспособленности к среде. Это важная часть эволюционного процесса.
//———————————————————————————————————————————————————————————————————— //--- Процесс инновации для победителя void C_AO_DA_duelist::InnovationProcess (int winnerIndex) { for (int c = 0; c < coords; c++) { if (u.RNDprobab () < innovationProbability) { // Победитель пробует новую технику (мутация) a [winnerIndex].c [c] = u.RNDfromCI (rangeMin [c], rangeMax [c]); a [winnerIndex].c [c] = u.SeInDiSp (a [winnerIndex].c [c], rangeMin [c], rangeMax [c], rangeStep [c]); } } } //————————————————————————————————————————————————————————————————————
Метод "TrainNewDuelist" класса "C_AO_DA_duelist" отвечает за создание нового дуэлянта (особи) и его первоначальную настройку путем "обучения" у текущего чемпиона. Это процесс наследования, но с элементами случайности, что позволяет вводить в популяцию генетическое разнообразие.
Итерация по координатам. Цикл "for" перебирает все характеристики (координаты) "c" нового дуэлянта (newDuelistIndex), настраивая каждую из них.
Расчет отклонения (deviation). Вычисляется "deviation", определяющее диапазон возможных изменений, относительно разброса допустимых значений.
Наследование с мутацией (Gauss Distribution). К характеристике "c" чемпиона (championIndex) добавляется случайное отклонение, полученное с использованием функции "u.GaussDistribution ()". Эта функция генерирует случайное число из нормального распределения (распределение Гаусса), что позволяет вводить случайные изменения в унаследованные характеристики. Аргументы "0", "rangeMin [c]", "rangeMax [c]", "8" задают параметры нормального распределения: среднее значение 0, минимальное и максимальное значения, и параметр, контролирующий ширину распределения (8).
Приведение к дискретному значению (SeInDiSp). Полученное значение характеристики нового дуэлянта, после мутации, приводится к дискретному набору значений с помощью функции "u.SeInDiSp ()". Эта функция обеспечивает, что параметры нового дуэлянта находятся в допустимом диапазоне и соответствуют шагу "rangeStep [c]".
В результате, новый дуэлянт получает характеристики, близкие к характеристикам чемпиона, но со случайными изменениями, что создает разнообразие в популяции и позволяет исследовать новые стратегии.
//———————————————————————————————————————————————————————————————————— //--- Чемпион тренирует нового дуэлянта void C_AO_DA_duelist::TrainNewDuelist (int championIndex, int newDuelistIndex) { for (int c = 0; c < coords; c++) { // Новый дуэлянт наследует способности чемпиона с небольшими вариациями double deviation = (rangeMax [c] - rangeMin [c]) * 0.1; a [newDuelistIndex].c [c] = a [championIndex].c [c] + u.GaussDistribution (0, rangeMin [c], rangeMax [c], 8); a [newDuelistIndex].c [c] = u.SeInDiSp (a [newDuelistIndex].c [c], rangeMin [c], rangeMax [c], rangeStep [c]); } } //————————————————————————————————————————————————————————————————————
Метод "Moving" класса "C_AO_DA_duelist" представляет собой основной шаг алгоритма эволюции дуэлянтов. Он включает в себя инициализацию (при первом запуске), размножение, отбор, дуэли, обучение (с использованием результатов дуэлей), инновации и отбраковку. Это сердце эволюционного процесса, что происходит внутри метода:
Инициализация популяции (первый запуск). Если это первый запуск (revision равно false), происходит инициализация популяции: для каждой особи "i" задаются значения для всех характеристик "j" случайным образом в соответствии с допустимым диапазоном и шагом. После инициализации "revision" устанавливается в "true", чтобы избежать повторной инициализации при последующих запусках.
Подготовка к размножению. Размер массива "a" (представляющего популяцию) увеличивается, что позволяет разместить новых дуэлянтов, созданных от чемпионов. Новые дуэлянты инициализируются (устанавливаются начальные состояния).
Отбор чемпионов. Популяция сортируется по параметру "f" (приспособленности) — для отбора лучших особей. Определяются чемпионы — лучшие "championsCount" особей. Каждый чемпион использует метод "TrainNewDuelist", чтобы создать нового дуэлянта, который наследует черты чемпиона.
Подготовка к дуэлям. Массивы "winners" и "losers" очищаются, чтобы подготовиться к новым результатам дуэлей.
Проведение дуэлей. Каждая особь, кроме чемпионов, сражается с одним случайным противником (тоже, не являющимся чемпионом). Результат каждой дуэли (кто выиграл, кто проиграл) определяется с использованием "DetermineWinnerAndLoser".
Обучение дуэлянтов (Learning). Происходит обучение проигравших у победителей. "LearningProcess" позволяет проигравшим изменить свои параметры, перенимая лучшие черты от победителей.
Инновации победителей (Innovation). Лучшие особи используют "InnovationProcess", чтобы попытаться изменить свою стратегию и исследовать новые возможности.
Повторная сортировка. Вся популяция сортируется по параметру "f" заново, чтобы обновить порядок особей после изменений, внесенных в процессе дуэлей, обучения и инноваций.
Отбраковка худших. Размер массива "a" возвращается к "popSize", удаляя худших особей, чтобы поддерживать постоянный размер популяции.
Этот цикл представляет собой один шаг эволюции, в котором происходит создание потомства, отбор лучших, обучение, обновление стратегий и поддержание размера популяции. Метод "Moving" выполняет основные эволюционные операции: размножение, мутацию, отбор и обучение.
//———————————————————————————————————————————————————————————————————— //--- Основной шаг алгоритма void C_AO_DA_duelist::Moving () { // Начальная инициализация популяции if (!revision) { for (int i = 0; i < popSize; i++) { for (int j = 0; j < coords; j++) { a [i].c [j] = u.RNDfromCI (rangeMin [j], rangeMax [j]); a [i].c [j] = u.SeInDiSp (a [i].c [j], rangeMin [j], rangeMax [j], rangeStep [j]); } } revision = true; return; } //------------------------------------------------------------------ // Временное расширение массива для новых дуэлянтов int totalDuelists = popSize + championsCount; ArrayResize (a, totalDuelists); // Инициализация новых дуэлянтов for (int i = popSize; i < totalDuelists; i++) { a [i].Init (coords); } // Сортировка для определения чемпионов (используем пузырьковую сортировку) for (int i = 0; i < popSize - 1; i++) { for (int j = 0; j < popSize - i - 1; j++) { if (a [j].f < a [j + 1].f) { S_AO_Agent temp = a [j]; a [j] = a [j + 1]; a [j + 1] = temp; } } } // Определяем чемпионов for (int i = 0; i < championsCount; i++) { champions [i] = i; // Чемпион тренирует нового дуэлянта TrainNewDuelist (i, popSize + i); } // Очистка массивов победителей и проигравших ArrayResize (winners, 0); ArrayResize (losers, 0); // Проведение дуэлей (исключая чемпионов) for (int i = championsCount; i < totalDuelists; i++) { // Каждый дуэлянт сражается с одним случайным противником int opponent = u.RNDintInRange (championsCount, totalDuelists - 1); if (opponent != i) { DetermineWinnerAndLoser (i, opponent); } } // Процесс улучшения дуэлянтов int minCount = MathMin (ArraySize (winners), ArraySize (losers)); for (int i = 0; i < minCount; i++) { // Проигравшие учатся у победителей LearningProcess (losers [i], winners [i]); } for (int i = 0; i < ArraySize (winners); i++) { // Победители инновируют InnovationProcess (winners [i]); } // Сортировка всех дуэлянтов for (int i = 0; i < totalDuelists - 1; i++) { for (int j = 0; j < totalDuelists - i - 1; j++) { if (a [j].f < a [j + 1].f) { S_AO_Agent temp = a [j]; a [j] = a [j + 1]; a [j + 1] = temp; } } } // Удаляем худших дуэлянтов ArrayResize (a, popSize); } //————————————————————————————————————————————————————————————————————
Метод "Revision" класса "C_AO_DA_duelist" служит для обновления информации о лучшем решении, найденном в текущей популяции. Он предназначен для отслеживания глобального оптимума в процессе эволюции.
Итерация по популяции. Цикл "for" проходит по каждой особи в популяции (i от 0 до popSize).
Сравнение приспособленности. Внутри цикла проверяется, является ли приспособленность "f" текущей особи лучше, чем текущая лучшая приспособленность "fB".
Обновление лучшего решения. Если (a [i].f) лучше, чем (fB), то (fB) обновляется, то есть (fB) запоминает лучшую приспособленность, найденную на данный момент. Кроме того, происходит копирование характеристик "c" текущей особи в массив "cB". Это значит, что "cB" хранит значения характеристик лучшей особи, найденной до сих пор.
В итоге, метод "Revision" сканирует текущую популяцию, находит особь с наилучшей приспособленностью и, если эта особь лучше текущего "рекорда", обновляет информацию о лучшей найденной особи (ее приспособленность и сами характеристики). Этот метод необходим для отслеживания прогресса алгоритма и нахождения глобального оптимума.
//———————————————————————————————————————————————————————————————————— //--- Обновление лучшего и худшего решений void C_AO_DA_duelist::Revision () { // Обновляем глобальное лучшее решения for (int i = 0; i < popSize; i++) { if (a [i].f > fB) { fB = a [i].f; ArrayCopy (cB, a [i].c, 0, 0, WHOLE_ARRAY); } } } //————————————————————————————————————————————————————————————————————
Результаты тестов
В целом, после проведенных исследований алгоритм дуэлянта показывает себя достаточно хорошо.DA|Duelist Algorithm|100.0|0.01|0.9|0.1|2.0|
=============================
5 Hilly's; Func runs: 10000; result: 0.9278151663330798
25 Hilly's; Func runs: 10000; result: 0.5377820196319314
500 Hilly's; Func runs: 10000; result: 0.27792394907287765
=============================
5 Forest's; Func runs: 10000; result: 0.8695700230324329
25 Forest's; Func runs: 10000; result: 0.47535947112902815
500 Forest's; Func runs: 10000; result: 0.18193288697223736
=============================
5 Megacity's; Func runs: 10000; result: 0.6215384615384616
25 Megacity's; Func runs: 10000; result: 0.3356923076923076
500 Megacity's; Func runs: 10000; result: 0.11715384615384725
=============================
All score: 4.34477 (48.28%)
На визуализации работы алгоритма виден небольшой разброс в значениях как на малых размерностях так и на больших, это говорит о хороших поисковых способностях алгоритма.
DA_duelist на тестовой функции Hilly
DA_duelist на тестовой функции Forest
DA_duelist на тестовой функции Megacity
По результатам тестирования алгоритм дуэлянта занимает 42 место в общем рейтинге алгоритмов оптимизации.
№ | 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) | ||||||||
1 | ANS | across neighbourhood search | 0,94948 | 0,84776 | 0,43857 | 2,23581 | 1,00000 | 0,92334 | 0,39988 | 2,32323 | 0,70923 | 0,63477 | 0,23091 | 1,57491 | 6,134 | 68,15 |
2 | CLA | code lock algorithm (joo) | 0,95345 | 0,87107 | 0,37590 | 2,20042 | 0,98942 | 0,91709 | 0,31642 | 2,22294 | 0,79692 | 0,69385 | 0,19303 | 1,68380 | 6,107 | 67,86 |
3 | AMOm | animal migration ptimization M | 0,90358 | 0,84317 | 0,46284 | 2,20959 | 0,99001 | 0,92436 | 0,46598 | 2,38034 | 0,56769 | 0,59132 | 0,23773 | 1,39675 | 5,987 | 66,52 |
4 | (P+O)ES | (P+O) evolution strategies | 0,92256 | 0,88101 | 0,40021 | 2,20379 | 0,97750 | 0,87490 | 0,31945 | 2,17185 | 0,67385 | 0,62985 | 0,18634 | 1,49003 | 5,866 | 65,17 |
5 | CTA | comet tail algorithm (joo) | 0,95346 | 0,86319 | 0,27770 | 2,09435 | 0,99794 | 0,85740 | 0,33949 | 2,19484 | 0,88769 | 0,56431 | 0,10512 | 1,55712 | 5,846 | 64,96 |
6 | TETA | time evolution travel algorithm (joo) | 0,91362 | 0,82349 | 0,31990 | 2,05701 | 0,97096 | 0,89532 | 0,29324 | 2,15952 | 0,73462 | 0,68569 | 0,16021 | 1,58052 | 5,797 | 64,41 |
7 | SDSm | stochastic diffusion search M | 0,93066 | 0,85445 | 0,39476 | 2,17988 | 0,99983 | 0,89244 | 0,19619 | 2,08846 | 0,72333 | 0,61100 | 0,10670 | 1,44103 | 5,709 | 63,44 |
8 | BOAm | billiards optimization algorithm M | 0,95757 | 0,82599 | 0,25235 | 2,03590 | 1,00000 | 0,90036 | 0,30502 | 2,20538 | 0,73538 | 0,52523 | 0,09563 | 1,35625 | 5,598 | 62,19 |
9 | AAm | archery algorithm M | 0,91744 | 0,70876 | 0,42160 | 2,04780 | 0,92527 | 0,75802 | 0,35328 | 2,03657 | 0,67385 | 0,55200 | 0,23738 | 1,46323 | 5,548 | 61,64 |
10 | ESG | evolution of social groups (joo) | 0,99906 | 0,79654 | 0,35056 | 2,14616 | 1,00000 | 0,82863 | 0,13102 | 1,95965 | 0,82333 | 0,55300 | 0,04725 | 1,42358 | 5,529 | 61,44 |
11 | SIA | simulated isotropic annealing (joo) | 0,95784 | 0,84264 | 0,41465 | 2,21513 | 0,98239 | 0,79586 | 0,20507 | 1,98332 | 0,68667 | 0,49300 | 0,09053 | 1,27020 | 5,469 | 60,76 |
12 | EOm | extremal_optimization_M | 0,76166 | 0,77242 | 0,31747 | 1,85155 | 0,99999 | 0,76751 | 0,23527 | 2,00277 | 0,74769 | 0,53969 | 0,14249 | 1,42987 | 5,284 | 58,71 |
13 | BBO | biogeography based optimization | 0,94912 | 0,69456 | 0,35031 | 1,99399 | 0,93820 | 0,67365 | 0,25682 | 1,86867 | 0,74615 | 0,48277 | 0,17369 | 1,40261 | 5,265 | 58,50 |
14 | ACS | artificial cooperative search | 0,75547 | 0,74744 | 0,30407 | 1,80698 | 1,00000 | 0,88861 | 0,22413 | 2,11274 | 0,69077 | 0,48185 | 0,13322 | 1,30583 | 5,226 | 58,06 |
15 | DA | dialectical algorithm | 0,86183 | 0,70033 | 0,33724 | 1,89940 | 0,98163 | 0,72772 | 0,28718 | 1,99653 | 0,70308 | 0,45292 | 0,16367 | 1,31967 | 5,216 | 57,95 |
16 | BHAm | black hole algorithm M | 0,75236 | 0,76675 | 0,34583 | 1,86493 | 0,93593 | 0,80152 | 0,27177 | 2,00923 | 0,65077 | 0,51646 | 0,15472 | 1,32195 | 5,196 | 57,73 |
17 | ASO | anarchy society optimization | 0,84872 | 0,74646 | 0,31465 | 1,90983 | 0,96148 | 0,79150 | 0,23803 | 1,99101 | 0,57077 | 0,54062 | 0,16614 | 1,27752 | 5,178 | 57,54 |
18 | RFO | royal flush optimization (joo) | 0,83361 | 0,73742 | 0,34629 | 1,91733 | 0,89424 | 0,73824 | 0,24098 | 1,87346 | 0,63154 | 0,50292 | 0,16421 | 1,29867 | 5,089 | 56,55 |
19 | AOSm | atomic orbital search M | 0,80232 | 0,70449 | 0,31021 | 1,81702 | 0,85660 | 0,69451 | 0,21996 | 1,77107 | 0,74615 | 0,52862 | 0,14358 | 1,41835 | 5,006 | 55,63 |
20 | TSEA | turtle shell evolution algorithm (joo) | 0,96798 | 0,64480 | 0,29672 | 1,90949 | 0,99449 | 0,61981 | 0,22708 | 1,84139 | 0,69077 | 0,42646 | 0,13598 | 1,25322 | 5,004 | 55,60 |
21 | BSA | backtracking_search_algorithm | 0,97309 | 0,54534 | 0,29098 | 1,80941 | 0,99999 | 0,58543 | 0,21747 | 1,80289 | 0,84769 | 0,36953 | 0,12978 | 1,34700 | 4,959 | 55,10 |
22 | DE | differential evolution | 0,95044 | 0,61674 | 0,30308 | 1,87026 | 0,95317 | 0,78896 | 0,16652 | 1,90865 | 0,78667 | 0,36033 | 0,02953 | 1,17653 | 4,955 | 55,06 |
23 | SRA | successful restaurateur algorithm (joo) | 0,96883 | 0,63455 | 0,29217 | 1,89555 | 0,94637 | 0,55506 | 0,19124 | 1,69267 | 0,74923 | 0,44031 | 0,12526 | 1,31480 | 4,903 | 54,48 |
24 | CRO | chemical reaction optimisation | 0,94629 | 0,66112 | 0,29853 | 1,90593 | 0,87906 | 0,58422 | 0,21146 | 1,67473 | 0,75846 | 0,42646 | 0,12686 | 1,31178 | 4,892 | 54,36 |
25 | BIO | blood inheritance optimization (joo) | 0,81568 | 0,65336 | 0,30877 | 1,77781 | 0,89937 | 0,65319 | 0,21760 | 1,77016 | 0,67846 | 0,47631 | 0,13902 | 1,29378 | 4,842 | 53,80 |
26 | BSA | bird swarm algorithm | 0,89306 | 0,64900 | 0,26250 | 1,80455 | 0,92420 | 0,71121 | 0,24939 | 1,88479 | 0,69385 | 0,32615 | 0,10012 | 1,12012 | 4,809 | 53,44 |
27 | DEA | dolphin_echolocation_algorithm | 0,75995 | 0,67572 | 0,34171 | 1,77738 | 0,89582 | 0,64223 | 0,23941 | 1,77746 | 0,61538 | 0,44031 | 0,15115 | 1,20684 | 4,762 | 52,91 |
28 | HS | harmony search | 0,86509 | 0,68782 | 0,32527 | 1,87818 | 0,99999 | 0,68002 | 0,09590 | 1,77592 | 0,62000 | 0,42267 | 0,05458 | 1,09725 | 4,751 | 52,79 |
29 | SSG | saplings sowing and growing | 0,77839 | 0,64925 | 0,39543 | 1,82308 | 0,85973 | 0,62467 | 0,17429 | 1,65869 | 0,64667 | 0,44133 | 0,10598 | 1,19398 | 4,676 | 51,95 |
30 | BCOm | bacterial chemotaxis optimization M | 0,75953 | 0,62268 | 0,31483 | 1,69704 | 0,89378 | 0,61339 | 0,22542 | 1,73259 | 0,65385 | 0,42092 | 0,14435 | 1,21912 | 4,649 | 51,65 |
31 | ABO | african buffalo optimization | 0,83337 | 0,62247 | 0,29964 | 1,75548 | 0,92170 | 0,58618 | 0,19723 | 1,70511 | 0,61000 | 0,43154 | 0,13225 | 1,17378 | 4,634 | 51,49 |
32 | (PO)ES | (PO) evolution strategies | 0,79025 | 0,62647 | 0,42935 | 1,84606 | 0,87616 | 0,60943 | 0,19591 | 1,68151 | 0,59000 | 0,37933 | 0,11322 | 1,08255 | 4,610 | 51,22 |
33 | FBA | fractal-based Algorithm | 0,79000 | 0,65134 | 0,28965 | 1,73099 | 0,87158 | 0,56823 | 0,18877 | 1,62858 | 0,61077 | 0,46062 | 0,12398 | 1,19537 | 4,555 | 50,61 |
34 | TSm | tabu search M | 0,87795 | 0,61431 | 0,29104 | 1,78330 | 0,92885 | 0,51844 | 0,19054 | 1,63783 | 0,61077 | 0,38215 | 0,12157 | 1,11449 | 4,536 | 50,40 |
35 | BSO | brain storm optimization | 0,93736 | 0,57616 | 0,29688 | 1,81041 | 0,93131 | 0,55866 | 0,23537 | 1,72534 | 0,55231 | 0,29077 | 0,11914 | 0,96222 | 4,498 | 49,98 |
36 | WOAm | wale optimization algorithm M | 0,84521 | 0,56298 | 0,26263 | 1,67081 | 0,93100 | 0,52278 | 0,16365 | 1,61743 | 0,66308 | 0,41138 | 0,11357 | 1,18803 | 4,476 | 49,74 |
37 | AEFA | artificial electric field algorithm | 0,87700 | 0,61753 | 0,25235 | 1,74688 | 0,92729 | 0,72698 | 0,18064 | 1,83490 | 0,66615 | 0,11631 | 0,09508 | 0,87754 | 4,459 | 49,55 |
38 | AEO | artificial ecosystem-based optimization algorithm | 0,91380 | 0,46713 | 0,26470 | 1,64563 | 0,90223 | 0,43705 | 0,21400 | 1,55327 | 0,66154 | 0,30800 | 0,28563 | 1,25517 | 4,454 | 49,49 |
39 | CAm | camel algorithm M | 0,78684 | 0,56042 | 0,35133 | 1,69859 | 0,82772 | 0,56041 | 0,24336 | 1,63149 | 0,64846 | 0,33092 | 0,13418 | 1,11356 | 4,444 | 49,37 |
40 | ACOm | ant colony optimization M | 0,88190 | 0,66127 | 0,30377 | 1,84693 | 0,85873 | 0,58680 | 0,15051 | 1,59604 | 0,59667 | 0,37333 | 0,02472 | 0,99472 | 4,438 | 49,31 |
41 | CMAES | covariance_matrix_adaptation_evolution_strategy | 0,76258 | 0,72089 | 0,00000 | 1,48347 | 0,82056 | 0,79616 | 0,00000 | 1,61672 | 0,75846 | 0,49077 | 0,00000 | 1,24923 | 4,349 | 48,33 |
42 | DA_duelist | duelist_algorithm | 0,92782 | 0,53778 | 0,27792 | 1,74352 | 0,86957 | 0,47536 | 0,18193 | 1,52686 | 0,62153 | 0,33569 | 0,11715 | 1,07437 | 4,345 | 48,28 |
43 | BFO-GA | bacterial foraging optimization - ga | 0,89150 | 0,55111 | 0,31529 | 1,75790 | 0,96982 | 0,39612 | 0,06305 | 1,42899 | 0,72667 | 0,27500 | 0,03525 | 1,03692 | 4,224 | 46,93 |
44 | SOA | simple optimization algorithm | 0,91520 | 0,46976 | 0,27089 | 1,65585 | 0,89675 | 0,37401 | 0,16984 | 1,44060 | 0,69538 | 0,28031 | 0,10852 | 1,08422 | 4,181 | 46,45 |
45 | ABHA | artificial bee hive algorithm | 0,84131 | 0,54227 | 0,26304 | 1,64663 | 0,87858 | 0,47779 | 0,17181 | 1,52818 | 0,50923 | 0,33877 | 0,10397 | 0,95197 | 4,127 | 45,85 |
RW | random walk | 0,48754 | 0,32159 | 0,25781 | 1,06694 | 0,37554 | 0,21944 | 0,15877 | 0,75375 | 0,27969 | 0,14917 | 0,09847 | 0,52734 | 2,348 | 26,09 |
Выводы
Duelist Algorithm демонстрирует достойные результаты в области метаэвристической оптимизации, занимая место в топ-45 популяционных алгоритмов. Хотя он не претендует на звание абсолютного чемпиона среди оптимизационных методов, его ключевым преимуществом является скорость.
Адаптивная стратегия обучения — в контексте оптимизации торговых систем это означает, что неудачные конфигурации параметров быстро перенимают успешные паттерны, что особенно ценно при работе с нестационарными финансовыми рядами.
Баланс эксплуатации и исследования — победители не почивают на лаврах, а продолжают искать улучшения через инновации. Это критически важно для торговых стратегий, которые должны адаптироваться к изменяющимся рыночным условиям.
Элемент контролируемой случайности — коэффициент удачи естественным образом моделирует рыночную неопределенность, где даже хорошая стратегия может временно показать плохие результаты из-за краткосрочной волатильности.
Иерархическая структура с чемпионами — гарантирует сохранение лучших решений и их распространение, что в трейдинге эквивалентно сохранению проверенных временем стратегий при одновременном поиске новых возможностей.
Duelist Algorithm представляет собой добротное решение, которое через метафору боевых искусств привносит в мир оптимизации простую, но эффективную идею: учиться у сильных, экспериментировать в позиции силы и передавать знания следующему поколению.
Рисунок 2. Цветовая градация алгоритмов по соответствующим тестам
Рисунок 3. Гистограмма результатов тестирования алгоритмов (по шкале от 0 до 100, чем больше, тем лучше, где 100 — максимально возможный теоретический результат, в архиве скрипт для расчета рейтинговой таблицы)
Плюсы и минусы алгоритма DA_duelist:
Плюсы:
- Быстрый.
- Небольшой разброс результатов на тестовых функциях.
Минусы:
- Невысокая точность сходимости.
К статье прикреплён архив с актуальными версиями кодов алгоритмов. Автор статьи не несёт ответственности за абсолютную точность в описании канонических алгоритмов, во многие из них были внесены изменения для улучшения поисковых возможностей. Выводы и суждения, представленные в статьях, основываются на результатах проведённых экспериментов.
Программы, используемые в статье
# | Имя | Тип | Описание |
---|---|---|---|
1 | #C_AO.mqh | Включаемый файл | Родительский класс популяционных алгоритмов оптимизации |
2 | #C_AO_enum.mqh | Включаемый файл | Перечисление популяционных алгоритмов оптимизации |
3 | TestFunctions.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_DA_duelist.mq5 | Скрипт | Испытательный стенд для DA_duelist |
Предупреждение: все права на данные материалы принадлежат MetaQuotes Ltd. Полная или частичная перепечатка запрещена.
Данная статья написана пользователем сайта и отражает его личную точку зрения. Компания MetaQuotes Ltd не несет ответственности за достоверность представленной информации, а также за возможные последствия использования описанных решений, стратегий или рекомендаций.




- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования