Популяционные алгоритмы оптимизации: строим защиту от читеров
Содержание
Введение
В предыдущей статье мы обнаружили, что отдельные алгоритмы способны получать завышенные оценки не за счёт качества поиска, а за счёт случайного совпадения своей внутренней механики с геометрией тестовых функций. Мы выявили природу явления, сформулировали критерии диагностики и скорректировали тестовые функции Forest и Megacity. Это устранило возможность выигрыша вследствие перемещения поисковых агентов по «диагонали» в двумерной плоскости. Статья завершилась планом: прогнать все алгоритмы на обновлённом стенде и пересчитать рейтинг.
Данная статья — выполнение этого плана. Все 45 алгоритмов из рейтинговой таблицы были протестированы заново на скорректированных тестовых функциях. Помимо пересчёта, разработан составной тест на «читерство». Вместо одной функции с повторяющимися координатами агент одновременно оптимизирует пять различных функций с разными ландшафтами. Алгоритм с искусственным направленным смещением не способен одновременно «угадать» оптимум на пяти разных поверхностях, тогда как честный поисковый механизм покажет очень близкие результаты как на обновлённых тестовых функциях, так и на новой мульти-функции. Его задача — быстро и однозначно определить, обладает ли алгоритм реальной поисковой способностью, до запуска полного тестового стенда. Это своего рода входной фильтр, отсеивающий «пустышки» на раннем этапе. Речь идёт не о пересмотре методологии, а об устранении нескольких исключений, которые эксплуатировали конкретное расположение экстремумов.
По итогам прочтения трейдер получит обновлённую рейтинговую таблицу, очищенную от алгоритмов с ложно завышенными результатами, и готовый скрипт для самостоятельной проверки любого нового алгоритма перед тем, как доверить ему оптимизацию своей стратегии.
Результаты тестов
Приведём результаты тестирования первых 10 алгоритмов из нашей старой рейтинговой таблицы на новом стенде.
ANS (72.73%) — уверенно занимает первое место, показав максимально возможный результат 1.0 на Forest и почти идеальный на Hilly при 5 функциях. Стабильно высокие результаты по всем трём функциям.
ANS|Across Neighbourhood Search|50.0|100.0|8.0|1.0|0.6|
=============================
5 Hilly's; Func runs: 10000; result: 0.9999999999875436
25 Hilly's; Func runs: 10000; result: 0.8822811736388573
500 Hilly's; Func runs: 10000; result: 0.40137720364864543
=============================
5 Forest's; Func runs: 10000; result: 1.0
25 Forest's; Func runs: 10000; result: 0.9528121725014275
500 Forest's; Func runs: 10000; result: 0.2809183267906096
=============================
5 Megacity's; Func runs: 10000; result: 0.9466666666666669
25 Megacity's; Func runs: 10000; result: 0.8573333333333336
500 Megacity's; Func runs: 10000; result: 0.2238933333333332
=============================
All score: 6.54528 (72.73%)
CLA (71.17%) — третий результат в новом рейтинге. Высокие показатели на первых тестах всех функций (0.951, 0.993, 0.936), уверенное масштабирование на средних размерностях.
CLA|Code Lock Algorithm|100.0|8.0|0.8|0.03|
=============================
5 Hilly's; Func runs: 10000; result: 0.9513916030211934
25 Hilly's; Func runs: 10000; result: 0.8619898090237819
500 Hilly's; Func runs: 10000; result: 0.37878768991969275
=============================
5 Forest's; Func runs: 10000; result: 0.9934937994742749
25 Forest's; Func runs: 10000; result: 0.9350030299784114
500 Forest's; Func runs: 10000; result: 0.264969743691552
=============================
5 Megacity's; Func runs: 10000; result: 0.9359999999999999
25 Megacity's; Func runs: 10000; result: 0.8426666666666668
500 Megacity's; Func runs: 10000; result: 0.24059999999999984
=============================
All score: 6.40490 (71.17%)
AMOm (71.95%) — вторая позиция нового рейтинга с очень ровным профилем: ни на одной функции нет ни аномального взлёта, ни провала. Особенно хорош на высоких размерностях — 0.468 на Hilly-500 и 0.364 на Forest-500, одни из лучших показателей в таблице.
AMOm|Animal Migration Optimization M|50.0|8.0|10.0|
=============================
5 Hilly's; Func runs: 10000; result: 0.9162371105304754
25 Hilly's; Func runs: 10000; result: 0.8360339347175263
500 Hilly's; Func runs: 10000; result: 0.46789660023174695
=============================
5 Forest's; Func runs: 10000; result: 0.9848161468170084
25 Forest's; Func runs: 10000; result: 0.9200997377060082
500 Forest's; Func runs: 10000; result: 0.3639111656785071
=============================
5 Megacity's; Func runs: 10000; result: 0.9173333333333332
25 Megacity's; Func runs: 10000; result: 0.8170666666666667
500 Megacity's; Func runs: 10000; result: 0.2517733333333329
=============================
All score: 6.47517 (71.95%)
(P+O)ES (69.63%) — лучший результат на Hilly-25 среди всей десятки (0.895). Сбалансированный алгоритм без слабых мест, хорошо справляется с задачами разного характера.
=============================
5 Hilly's; Func runs: 10000; result: 0.8657144873317885
25 Hilly's; Func runs: 10000; result: 0.8953901738038004
500 Hilly's; Func runs: 10000; result: 0.39739528286050285
=============================
5 Forest's; Func runs: 10000; result: 0.9776075492446766
25 Forest's; Func runs: 10000; result: 0.8981952542170181
500 Forest's; Func runs: 10000; result: 0.2687849185074435
=============================
5 Megacity's; Func runs: 10000; result: 0.9213333333333333
25 Megacity's; Func runs: 10000; result: 0.8024000000000001
500 Megacity's; Func runs: 10000; result: 0.23952000000000004
=============================
All score: 6.26634 (69.63%)
CTA (65.14%) — делит 9–10 место с ESG в новом рейтинге. Лучший в десятке результат на Megacity-5 (0.955), но самое резкое падение с ростом размерности: от 0.955 до 0.110 на Megacity. Алгоритм силён на компактных задачах, но хуже масштабируется.
CTA|Comet Tail Algorithm|80.0|40.0|4.0|-1.0|0.2|1.0|0.5|0.1|15.0|
=============================
5 Hilly's; Func runs: 10000; result: 0.9243464383277585
25 Hilly's; Func runs: 10000; result: 0.8678611260832623
500 Hilly's; Func runs: 10000; result: 0.2783803821000941
=============================
5 Forest's; Func runs: 10000; result: 0.9903857592716669
25 Forest's; Func runs: 10000; result: 0.8457126196030522
500 Forest's; Func runs: 10000; result: 0.19448478585260007
=============================
5 Megacity's; Func runs: 10000; result: 0.9546666666666669
25 Megacity's; Func runs: 10000; result: 0.6968000000000002
500 Megacity's; Func runs: 10000; result: 0.11008000000000102
=============================
All score: 5.86272 (65.14%)
TETA (65.21%) — почти идеальный результат на Forest-5 (0.997) и сильный на Megacity-25 (0.822), но слабее показатели на высоких размерностях: Forest-500 (0.144) и Megacity-500 (0.104) — самые низкие в десятке.
TETA|Time Evolution Travel Algorithm (joo)|50.0|
=============================
5 Hilly's; Func runs: 10000; result: 0.9145203656820382
25 Hilly's; Func runs: 10000; result: 0.8636891042289963
500 Hilly's; Func runs: 10000; result: 0.2557893068727686
=============================
5 Forest's; Func runs: 10000; result: 0.9965389719633986
25 Forest's; Func runs: 10000; result: 0.9129125157050326
500 Forest's; Func runs: 10000; result: 0.14394284935691087
=============================
5 Megacity's; Func runs: 10000; result: 0.8546666666666669
25 Megacity's; Func runs: 10000; result: 0.8221333333333336
500 Megacity's; Func runs: 10000; result: 0.10442666666666756
=============================
All score: 5.86862 (65.21%)
SDSm (68.63%) — сильные результаты на первых тестах всех функций (выше 0.92), но заметное снижение на высоких размерностях, особенно на Forest-500 (0.221) и Megacity-500 (0.214).
SDSm|Stochastic Diffusion Search M|100.0|100.0|0.05|
=============================
5 Hilly's; Func runs: 10000; result: 0.9519471636297065
25 Hilly's; Func runs: 10000; result: 0.8494376697764915
500 Hilly's; Func runs: 10000; result: 0.3624897619727907
=============================
5 Forest's; Func runs: 10000; result: 0.9806113591666786
25 Forest's; Func runs: 10000; result: 0.8845675590592755
500 Forest's; Func runs: 10000; result: 0.2211247219431563
=============================
5 Megacity's; Func runs: 10000; result: 0.9226666666666669
25 Megacity's; Func runs: 10000; result: 0.7901333333333336
500 Megacity's; Func runs: 10000; result: 0.21379999999999993
=============================
All score: 6.17678 (68.63%)
ECBO (62.97%) — почти идеальный результат на Forest-5 (0.995) и сильный на Hilly-5 (0.940), но падение на высоких размерностях: Forest-500 всего 0.131.
ECBO|Enhanced Colliding Bodies Optimization|50.0|20.0|0.7|
=============================
5 Hilly's; Func runs: 10000; result: 0.9402415265522688
25 Hilly's; Func runs: 10000; result: 0.7236308766253738
500 Hilly's; Func runs: 10000; result: 0.3235591845134633
=============================
5 Forest's; Func runs: 10000; result: 0.9947663805080049
25 Forest's; Func runs: 10000; result: 0.8029133468157632
500 Forest's; Func runs: 10000; result: 0.13055914998929397
=============================
5 Megacity's; Func runs: 10000; result: 0.8760000000000001
25 Megacity's; Func runs: 10000; result: 0.7016000000000002
500 Megacity's; Func runs: 10000; result: 0.17433333333333365
=============================
All score: 5.66760 (62.97%)
BOAm (60.41%) — единственный алгоритм в десятке, у которого Hilly-5 ниже 0.8 (0.762), зато самый стабильный по средним размерностям: разрыв между Hilly-25 (0.724) и Forest-25 (0.820) минимальный. Хороший результат на Forest-500 (0.289) — второй в десятке после AMOm, но провал на Megacity-500 (0.098) — самый низкий в таблице.
BOAm|Billiards Optimization Algorithm M|50.0|10.0|
=============================
5 Hilly's; Func runs: 10000; result: 0.7617749675007237
25 Hilly's; Func runs: 10000; result: 0.7242063623901942
500 Hilly's; Func runs: 10000; result: 0.2527483917912686
=============================
5 Forest's; Func runs: 10000; result: 0.9089006604555031
25 Forest's; Func runs: 10000; result: 0.819600230097181
500 Forest's; Func runs: 10000; result: 0.2885341267767846
=============================
5 Megacity's; Func runs: 10000; result: 0.8373333333333333
25 Megacity's; Func runs: 10000; result: 0.7461333333333333
500 Megacity's; Func runs: 10000; result: 0.09762666666666744
=============================
All score: 5.43686 (60.41%)
AAm (66.16%) — выделяется лучшим в десятке результатом на Hilly-500 (0.426) и Megacity-500 (0.287). Алгоритм лучше других масштабируется на высокие размерности, но уступает лидерам на малых.
AAm|Archery Algorithm M|50.0|0.3|
=============================
5 Hilly's; Func runs: 10000; result: 0.8468452965108316
25 Hilly's; Func runs: 10000; result: 0.7332044456299903
500 Hilly's; Func runs: 10000; result: 0.42589593336440623
=============================
5 Forest's; Func runs: 10000; result: 0.9670855014018752
25 Forest's; Func runs: 10000; result: 0.7783747648133637
500 Forest's; Func runs: 10000; result: 0.27788504722761453
=============================
5 Megacity's; Func runs: 10000; result: 0.8613333333333332
25 Megacity's; Func runs: 10000; result: 0.7770666666666668
500 Megacity's; Func runs: 10000; result: 0.28711999999999954
=============================
All score: 5.95481 (66.16%)
Результаты прогона алгоритмов на обновлённом стенде получены и готовы к внесению в рейтинговую таблицу. Однако перед этим есть смысл сделать ещё один шаг, о котором речь пойдёт далее.
В ходе наших исследований было обнаружено, что некоторые алгоритмы оптимизации могут показывать завышенные результаты на отдельных тестовых функциях не за счёт качества поиска, а за счёт случайного совпадения внутренней механики алгоритма с геометрией ландшафта функции. Например, если алгоритм генерирует траектории преимущественно вдоль диагонали пространства поиска, а глобальный максимум расположен на этой диагонали, то оптимум будет находиться легче. Это не отражает реальную поисковую способность алгоритма.
HHO продемонстрировал подозрительно высокий результат на функции Forest — свыше 93% при том, что на Hilly той же размерности показывал лишь около 58%. Такой разрыв выходил за рамки обычного разброса и потребовал детального расследования. Анализ внутренней механики алгоритма выявил, что скалярные множители в формулах HHO порождают преимущественно диагональные траектории поиска, а глобальный максимум Forest располагался как раз вблизи диагонали пространства. Алгоритм не столько искал оптимум, сколько систематически «наезжал» на него за счёт совпадения направления движения с геометрией ландшафта. Мы назвали это явление «читерством».
Стандартный тестовый стенд запускает каждую из трёх тестовых функций (Hilly, Forest, Megacity) независимо, с тремя уровнями размерности: 10, 50 и 1000 координат одной и той же функции. При этом все пары координат агента оптимизируют одну и ту же поверхность. Алгоритм с систематическим смещением в определённом направлении может эксплуатировать эту однородность.
Для предварительного выявления такого поведения был разработан составной тест. Принцип прост: вместо 10 координат одной функции (5 пар) мы используем 5 разных функций — Hilly, Forest, Megacity, Peaks и Skin. Каждой функции назначается одна пара координат. Каждая пара живёт в собственном ландшафте и индивидуальном допустимом диапазоне: Hilly оптимизируется в [-3, 3], Forest в [-42.5, -37] × [-45, -39.8], Megacity в [-10, -2] × [-10.5, 10] и так далее. Итоговый fitness агента вычисляется как среднее значение Core() по всем пяти функциям.
Ключевое свойство теста: алгоритм не может «обмануть» его тем же способом, что и одиночную функцию. Любой читерский приём, к примеру, применимый для Forest, бесполезен для Hilly или Megacity с их совершенно другой геометрией и другими диапазонами координат. Чтобы получить высокий результат на составном тесте, алгоритм должен действительно уметь искать оптимум в каждом из пяти различных ландшафтов независимо.
Интерпретация результатов проста. Если алгоритм «честный», его результат на составном тесте будет примерно соответствовать среднему результату первого теста (5 функций) стандартного стенда по тем же функциям, с небольшим отклонением. Если же алгоритм завышает результат на какой-либо одной функции за счёт геометрического совпадения, на составном тесте это преимущество исчезнет, и разница между стандартным и составным тестом будет значительной. Чем больше это расхождение — тем сильнее алгоритм эксплуатирует особенности конкретной функции вместо реального поиска.
Составной тест
Скрипт Test_AO_AntiCheat построен максимально просто и не требует визуализации — только вывод результатов в журнал.
При запуске алгоритм оптимизации выбирается из выпадающего списка через параметр AOexactly_P, что позволяет быстро переключаться между любыми алгоритмами без перекомпиляции. Два оставшихся параметра задают количество вычислений функции (NumbTestFuncRuns_P) и число повторных прогонов (NumberRepetTest_P).
В начале работы скрипт создаёт пять объектов тестовых функций: Hilly, Forest, Megacity, Peaks и Skin. Далее формируются массивы rangeMin и rangeMax длиной 10 элементов (5 пар координат). Каждая пара получает границы поиска от своей функции: элементы 0-1 заполняются доменом Hilly, элементы 2-3 — доменом Forest, и так далее. Массив rangeStep заполняется нулями, поскольку дискретизация аргументов не используется.
Число эпох вычисляется стандартным способом — общее количество вычислений делится на размер популяции. Далее запускается основной цикл повторных прогонов. В каждом прогоне алгоритм инициализируется заново, и внутренний цикл по эпохам выполняет стандартную последовательность: вызов Moving(), расчёт fitness, вызов Revision().
Расчёт fitness — единственное отличие от стандартного скрипта. Вместо вызова f.CalcFunc(ao.a[set].c), который передаёт все координаты одной функции, здесь для каждого агента выполняется цикл по пяти функциям. Каждая функция получает свою пару координат через прямой вызов Core(x, y), результаты суммируются и делятся на пять. Поскольку все функции возвращают нормализованные значения в диапазоне [0, 1], итоговый fitness тоже лежит в [0, 1].
После каждого прогона в журнал выводится достигнутый результат ao.fB. По завершении всех прогонов выводится среднее значение и его процентное выражение. Этот процент — индикатор. Достаточно сравнить его со средним значением первого теста стандартного стенда, чтобы оценить «честность» алгоритма.
//+------------------------------------------------------------------+ void OnStart() { C_AO *AO = SelectAO(AOexactly_P); if(AO == NULL) { Print("AO is not selected..."); return; } Print(AO.GetName(), "|", AO.GetDesc(), "|", AO.GetParams()); //--- создаём 5 функций #define NFUNCS 5 C_Function *funcs [NFUNCS]; funcs [0] = new C_Hilly(); funcs [1] = new C_Forest(); funcs [2] = new C_Megacity(); funcs [3] = new C_Peaks(); funcs [4] = new C_Skin(); //--- 10 координат: пара 0-1 = Hilly, 2-3 = Forest, 4-5 = Megacity, // 6-7 = Peaks, 8-9 = Skin int params = NFUNCS * 2; double rangeMin []; double rangeMax []; double rangeStep []; ArrayResize(rangeMin, params); ArrayResize(rangeMax, params); ArrayResize(rangeStep, params); for(int i = 0; i < NFUNCS; i++) { rangeMin [i * 2] = funcs [i].GetMinRangeX(); rangeMax [i * 2] = funcs [i].GetMaxRangeX(); rangeStep [i * 2] = 0.0; rangeMin [i * 2 + 1] = funcs [i].GetMinRangeY(); rangeMax [i * 2 + 1] = funcs [i].GetMaxRangeY(); rangeStep [i * 2 + 1] = 0.0; } //--- запуск тестов int epochCount = NumbTestFuncRuns_P / (int)AO.params [0].val; double aveResult = 0.0; Print("============================="); Print("Composite test: Hilly + Forest + Megacity + Peaks + Skin"); Print("Coordinates: ", params, "; Epochs: ", epochCount, "; Repeats: ", NumberRepetTest_P); Print("============================="); for(int test = 0; test < NumberRepetTest_P; test++) { if(!AO.Init(rangeMin, rangeMax, rangeStep, epochCount)) break; for(int epochCNT = 1; epochCNT <= epochCount && !IsStopped(); epochCNT++) { AO.Moving(); //--- расчёт fitness для каждого агента for(int set = 0; set < ArraySize(AO.a); set++) { double sum = 0.0; for(int i = 0; i < NFUNCS; i++) { sum += funcs [i].Core(AO.a [set].c [i * 2], AO.a [set].c [i * 2 + 1]); } AO.a [set].f = sum / NFUNCS; } AO.Revision(); } Print("Run ", test + 1, "/", NumberRepetTest_P, ": ", AO.fB); aveResult += AO.fB; } aveResult /= (double)NumberRepetTest_P; Print("============================="); Print("Average result: ", DoubleToString(aveResult, 10), " (", DoubleToString(aveResult * 100.0, 2), "%)"); Print("============================="); //--- освобождение for(int i = 0; i < NFUNCS; i++) delete funcs [i]; delete AO; } //+------------------------------------------------------------------+
Теперь можем перейти к распечатке результатов. Результаты очень показательные и хорошо демонстрируют работу теста.
DOAm (53.68%) и HHO (53.18%) показали практически одинаковый результат на составном тесте. Однако на стандартном стенде их общие оценки заметно различались: DOAm — 73.63%, HHO — 68.32%. Особенно бросается в глаза поведение на Forest: оба алгоритма показывали на этой функции аномально высокие результаты (DOAm — 94.1%, HHO — 92.9% на первом тесте с 5 функциями), значительно превышающие их результаты на Hilly. Составной тест это преимущество «отрезал» — когда Forest стоит рядом с четырьмя другими функциями с совершенно разными доменами и ландшафтами, эксплуатировать геометрию одной конкретной функции уже невозможно. Падение с ~73% и ~68% до ~53% — это существенное расхождение, указывающее на то, что часть результата на стандартном стенде была «незаслуженной».
DOAm|Dingo Optimization Algorithm M|50.0|0.5|0.7|
=============================
Composite test: Hilly + Forest + Megacity + Peaks + Skin
Coordinates: 10; Epochs: 200; Repeats: 10
=============================
Run 1/10: 0.4239956151778058
Run 2/10: 0.6031577198849927
Run 3/10: 0.472651762215779
Run 4/10: 0.44242763860374995
Run 5/10: 0.393561526388916
Run 6/10: 0.58159034825664
Run 7/10: 0.58159034825664
Run 8/10: 0.6044791403615191
Run 9/10: 0.6682691450306482
Run 10/10: 0.5960407868510031
=============================
Average result: 0.5367764031 (53.68%)
=============================
HHO|Harris Hawks Optimization|50.0|1.5|
=============================
Composite test: Hilly + Forest + Megacity + Peaks + Skin
Coordinates: 10; Epochs: 200; Repeats: 10
=============================
Run 1/10: 0.5647280120475809
Run 2/10: 0.5866885383601005
Run 3/10: 0.510840192697806
Run 4/10: 0.510840192697806
Run 5/10: 0.5801540782975321
Run 6/10: 0.5801540782975321
Run 7/10: 0.6101617039102479
Run 8/10: 0.4505520166668432
Run 9/10: 0.4505520166668432
Run 10/10: 0.4732281103689847
=============================
Average result: 0.5317898940 (53.18%)
=============================
ANS|Across Neighbourhood Search|50.0|100.0|8.0|1.0|0.6|
=============================
Composite test: Hilly + Forest + Megacity + Peaks + Skin
Coordinates: 10; Epochs: 200; Repeats: 10
=============================
Run 1/10: 0.9866666666663436
Run 2/10: 0.9866666666666667
Run 3/10: 0.9999999999999998
Run 4/10: 0.9994983755015288
Run 5/10: 0.9069704495992525
Run 6/10: 0.9861650421661512
Run 7/10: 0.98612941584339
Run 8/10: 0.9999999999999993
Run 9/10: 0.9866666666666623
Run 10/10: 0.999498375502054
=============================
Average result: 0.9838261659 (98.38%)
=============================
CLA (96.70%) подтвердил аналогичную картину — стабильно высокие результаты на всех прогонах, практически все выше 98% (с двумя выбросами около 90%, что нормально для стохастического процесса). Это тоже «честный» алгоритм.
CLA|Code Lock Algorithm (joo)|100.0|8.0|0.8|0.03|
=============================
Composite test: Hilly + Forest + Megacity + Peaks + Skin
Coordinates: 10; Epochs: 100; Repeats: 10
=============================
Run 1/10: 0.9814189578704682
Run 2/10: 0.9839805249712157
Run 3/10: 0.9847263113568381
Run 4/10: 0.9849091877632024
Run 5/10: 0.9064307824513899
Run 6/10: 0.9848008598052127
Run 7/10: 0.8930626122526194
Run 8/10: 0.9856223196479059
Run 9/10: 0.9795896538911133
Run 10/10: 0.9854045893497755
=============================
Average result: 0.9669945799 (96.70%)
Итог: тест чётко разделил алгоритмы на две группы. ANS и CLA показали, что их поисковый механизм работает универсально. DOAm и HHO потеряли около 20 процентных пунктов — это и есть та доля их стандартного результата, которая приходилась на «везение» с геометрией отдельных функций, а не на реальную поисковую способность.
Поэтому DOAm и HHO не будут присутствовать в нашей рейтинговой таблице, поскольку включение таких алгоритмов в рейтинг исказило бы общую картину и ввело бы в заблуждение относительно их реальной эффективности.
После обновления тестовых функций (максимума Megacity и корректировки Forest) рейтинговая таблица была полностью пересчитана. Сравнение старых и новых результатов показало, что большинство алгоритмов сохранили свои позиции с незначительными отклонениями. Несколько алгоритмов улучшили результат на 4–6 пунктов: SSG (+5.8), AMOm (+5.4), SDSm (+5.2), (PO)ES (+5.0), SIA (+4.7). У некоторых наблюдалось небольшое снижение: BOAm (−1.8), BSA backtracking (−1.9), CSO (−1.6). Ряд алгоритмов — CTA, ECBO, DOA, FBA — изменились менее чем на 1 процентный пункт. В целом расхождения не выходили за рамки ожидаемого: изменение геометрии тестовых функций естественным образом перераспределяет результаты, одним алгоритмам новый ландшафт подходит чуть лучше, другим — чуть хуже.
Однако один алгоритм вызвал вопросы — HS (Harmony Search). Его общий результат вырос с 52.79% до 60.60%, что составляет 7.8 процентных пунктов — заметно больше, чем у остальных. Причём весь прирост пришёлся на одну функцию: результат первого теста Megacity вырос с 0.620 до 0.917, а суммарный балл по Megacity — с 1.097 до 1.698. На Hilly и Forest результаты HS практически не изменились. Столь резкий скачок на одной конкретной функции потребовал проверки: действительно ли HS стал лучше искать, или же его механика случайно совпала с новой геометрией Megacity?
Для ответа на этот вопрос мы прогнали HS через составной тест. HS чист. 92.45% — это примерно уровень ANS (98.38%) и CLA (96.70%) на том же составном тесте.
HS|Harmony Search|50.0|0.9|0.1|0.1|
=============================
Composite test: Hilly + Forest + Megacity + Peaks + Skin
Coordinates: 10; Epochs: 200; Repeats: 10
=============================
Run 1/10: 0.8521718129502356
Run 2/10: 0.8521718129502356
Run 3/10: 0.9800589497283483
Run 4/10: 0.9800589497283483
Run 5/10: 0.9949839619589923
Run 6/10: 0.9949839619589923
Run 7/10: 0.9949839619589923
Run 8/10: 0.8064827441874302
Run 9/10: 0.8064827441874302
Run 10/10: 0.9828288881157536
=============================
Average result: 0.9245207788 (92.45%)
=============================
Для сравнения, алгоритмы, уличённые в «читерстве» (DOAm и HHO), на том же тесте набрали лишь 53.68% и 53.18%. Разница очевидна: HS действительно умеет искать оптимум на разных ландшафтах одновременно.
Теперь наша рейтинговая таблица завершена и выглядит следующим образом:
| cc | 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 | 1,00000 | 0,88228 | 0,40138 | 2,28366 | 1,00000 | 0,95281 | 0,28092 | 2,23373 | 0,94667 | 0,85733 | 0,22389 | 2,02789 | 6,545 | 72,72 |
| 2 | AMOm | animal migration optimization M | 0,91624 | 0,83603 | 0,46790 | 2,22017 | 0,98482 | 0,92010 | 0,36391 | 2,26883 | 0,91733 | 0,81707 | 0,25177 | 1,98617 | 6,475 | 71,94 |
| 3 | CLA | code lock algorithm (joo) | 0,95139 | 0,86199 | 0,37879 | 2,19217 | 0,99349 | 0,93500 | 0,26497 | 2,19346 | 0,93600 | 0,84267 | 0,24060 | 2,01927 | 6,405 | 71,17 |
| 4 | (P+O)ES | (P+O) evolution strategies | 0,86571 | 0,89539 | 0,39740 | 2,15850 | 0,97761 | 0,89820 | 0,26878 | 2,14459 | 0,92133 | 0,80240 | 0,23952 | 1,96325 | 6,266 | 69,62 |
| 5 | SDSm | stochastic diffusion search M | 0,95195 | 0,84944 | 0,36249 | 2,16388 | 0,98061 | 0,88457 | 0,22112 | 2,08630 | 0,92267 | 0,79013 | 0,21380 | 1,92660 | 6,177 | 68,63 |
| 6 | AAm | archery algorithm M | 0,84685 | 0,73320 | 0,42590 | 2,00595 | 0,96709 | 0,77837 | 0,27789 | 2,02335 | 0,86133 | 0,77707 | 0,28712 | 1,92552 | 5,955 | 66,17 |
| 7 | SIA | simulated isotropic annealing (joo) | 0,93543 | 0,86504 | 0,38483 | 2,18530 | 0,94069 | 0,80609 | 0,23835 | 1,98513 | 0,86400 | 0,66160 | 0,19536 | 1,72096 | 5,891 | 65,46 |
| 8 | TETA | time evolution travel algorithm (joo) | 0,91452 | 0,86369 | 0,25579 | 2,03400 | 0,99654 | 0,91291 | 0,14394 | 2,05339 | 0,85467 | 0,82213 | 0,10443 | 1,78123 | 5,869 | 65,21 |
| 9 | ESG | evolution of social groups (joo) | 0,98111 | 0,79857 | 0,31167 | 2,09135 | 0,98954 | 0,82270 | 0,15032 | 1,96256 | 0,92133 | 0,73440 | 0,15315 | 1,80888 | 5,863 | 65,14 |
| 10 | CTA | comet tail algorithm (joo) | 0,92435 | 0,86786 | 0,27838 | 2,07059 | 0,99039 | 0,84571 | 0,19448 | 2,03058 | 0,95467 | 0,69680 | 0,11008 | 1,76155 | 5,863 | 65,14 |
| 11 | ECBO | enhanced colliding bodies optimization | 0,94024 | 0,72363 | 0,32356 | 1,98743 | 0,99477 | 0,80291 | 0,13056 | 1,92824 | 0,87600 | 0,70160 | 0,17433 | 1,75193 | 5,668 | 62,98 |
| 12 | DA | dialectical algorithm | 0,93117 | 0,75400 | 0,26205 | 1,94722 | 0,98925 | 0,81375 | 0,08662 | 1,88962 | 0,92667 | 0,68107 | 0,11315 | 1,72089 | 5,558 | 61,76 |
| 13 | BBO | biogeography based optimization | 0,95876 | 0,70609 | 0,35752 | 2,02237 | 0,92981 | 0,70660 | 0,16970 | 1,80611 | 0,87467 | 0,63013 | 0,20813 | 1,71293 | 5,541 | 61,57 |
| 14 | BHAm | black hole algorithm M | 0,79558 | 0,76207 | 0,34682 | 1,90447 | 0,99836 | 0,75798 | 0,13826 | 1,89460 | 0,85067 | 0,64427 | 0,17020 | 1,66514 | 5,464 | 60,71 |
| 15 | HS | harmony search | 0,91420 | 0,69049 | 0,29924 | 1,90393 | 0,97627 | 0,73373 | 0,14193 | 1,85193 | 0,91733 | 0,62720 | 0,15364 | 1,69817 | 5,454 | 60,60 |
| 16 | RFO | royal flush optimization (joo) | 0,80989 | 0,74481 | 0,34546 | 1,90016 | 0,95251 | 0,77926 | 0,15185 | 1,88362 | 0,80400 | 0,66427 | 0,19071 | 1,65898 | 5,443 | 60,48 |
| 17 | BOAm | billiards optimization algorithm M | 0,76177 | 0,72421 | 0,25275 | 1,73873 | 0,90890 | 0,81960 | 0,28853 | 2,01703 | 0,83733 | 0,74613 | 0,09763 | 1,68109 | 5,437 | 60,41 |
| 18 | ASO | anarchy society optimization | 0,73070 | 0,73713 | 0,31195 | 1,77978 | 0,99732 | 0,87700 | 0,17619 | 2,05051 | 0,72000 | 0,68773 | 0,18988 | 1,59761 | 5,428 | 60,31 |
| 19 | EOm | extremal optimization_M | 0,76527 | 0,75205 | 0,31908 | 1,83640 | 0,99999 | 0,76426 | 0,12437 | 1,88862 | 0,84133 | 0,64133 | 0,15247 | 1,63513 | 5,360 | 59,56 |
| 20 | ACS | artificial cooperative search | 0,75545 | 0,77162 | 0,31653 | 1,84360 | 1,00000 | 0,80488 | 0,10705 | 1,91193 | 0,76933 | 0,60800 | 0,14157 | 1,51890 | 5,274 | 58,60 |
| 21 | SSG | saplings sowing and growing | 0,75436 | 0,63206 | 0,35935 | 1,74577 | 0,91907 | 0,69694 | 0,19755 | 1,81356 | 0,81867 | 0,60533 | 0,21347 | 1,63747 | 5,197 | 57,74 |
| 22 | AOSm | atomic orbital search M | 0,76184 | 0,68435 | 0,31344 | 1,75963 | 0,90015 | 0,80044 | 0,11501 | 1,81560 | 0,82800 | 0,63280 | 0,15696 | 1,61776 | 5,193 | 57,70 |
| 23 | TSEA | turtle shell evolution algorithm (joo) | 0,95809 | 0,64852 | 0,29571 | 1,90232 | 0,99522 | 0,58104 | 0,10542 | 1,68168 | 0,92133 | 0,52160 | 0,14567 | 1,58860 | 5,173 | 57,48 |
| 24 | DE | differential evolution | 0,96398 | 0,62346 | 0,26089 | 1,84833 | 0,98482 | 0,77018 | 0,11459 | 1,86959 | 0,93067 | 0,36213 | 0,11000 | 1,40280 | 5,121 | 56,90 |
| 25 | BIO | blood inheritance optimization (joo) | 0,72580 | 0,66522 | 0,31228 | 1,70330 | 0,99995 | 0,68125 | 0,11540 | 1,79660 | 0,85467 | 0,59333 | 0,15364 | 1,60164 | 5,102 | 56,69 |
| 26 | (PO)ES | (PO) evolution strategies | 0,73972 | 0,58190 | 0,38896 | 1,71058 | 0,91199 | 0,59975 | 0,21262 | 1,72436 | 0,82400 | 0,56240 | 0,23432 | 1,62072 | 5,056 | 56,18 |
| 27 | BO | bonobo optimizer | 0,75555 | 0,64366 | 0,32657 | 1,72578 | 0,94332 | 0,70442 | 0,13999 | 1,78773 | 0,73467 | 0,61440 | 0,16728 | 1,51635 | 5,030 | 55,89 |
| 28 | SRA | successful restaurateur algorithm (joo) | 0,89010 | 0,63359 | 0,29115 | 1,81484 | 0,96634 | 0,55285 | 0,08914 | 1,60833 | 0,89333 | 0,52800 | 0,13911 | 1,56044 | 4,984 | 55,38 |
| 29 | CRO | chemical reaction optimisation | 0,91281 | 0,65681 | 0,29866 | 1,86828 | 0,90513 | 0,56020 | 0,10939 | 1,57472 | 0,82800 | 0,50133 | 0,14149 | 1,47082 | 4,914 | 54,60 |
| 30 | BCOm | bacterial chemotaxis optimization M | 0,82589 | 0,61733 | 0,31584 | 1,75906 | 0,95296 | 0,63718 | 0,11984 | 1,70998 | 0,76533 | 0,51653 | 0,15800 | 1,43986 | 4,909 | 54,54 |
| 31 | DOA | dream optimization algorithm | 0,78522 | 0,78121 | 0,36036 | 1,92679 | 0,61584 | 0,42117 | 0,12254 | 1,15955 | 0,86667 | 0,72587 | 0,21127 | 1,80381 | 4,890 | 54,33 |
| 32 | ABO | african buffalo optimization | 0,92295 | 0,62528 | 0,29885 | 1,84708 | 0,92992 | 0,57468 | 0,09372 | 1,59832 | 0,73333 | 0,51333 | 0,14324 | 1,38990 | 4,835 | 53,72 |
| 33 | BSA | bird swarm algorithm | 0,94432 | 0,67941 | 0,26401 | 1,88774 | 0,91649 | 0,65619 | 0,12054 | 1,69322 | 0,80933 | 0,33547 | 0,10652 | 1,25132 | 4,832 | 53,69 |
| 34 | TSm | tabu search M | 0,87806 | 0,61040 | 0,28993 | 1,77839 | 0,98116 | 0,52165 | 0,08544 | 1,58825 | 0,82667 | 0,49547 | 0,13552 | 1,45766 | 4,824 | 53,60 |
| 35 | BSA | backtracking search algorithm | 0,87128 | 0,53190 | 0,28675 | 1,68993 | 0,92408 | 0,51602 | 0,09153 | 1,53163 | 0,96000 | 0,47253 | 0,13760 | 1,57013 | 4,792 | 53,24 |
| 36 | WOAm | whale optimization algorithm M | 0,93893 | 0,59477 | 0,26695 | 1,80065 | 0,98036 | 0,53873 | 0,07112 | 1,59021 | 0,78667 | 0,47600 | 0,11892 | 1,38159 | 4,772 | 53,02 |
| 37 | CSO | competitive swarm optimizer | 0,85151 | 0,60786 | 0,29896 | 1,75833 | 0,84085 | 0,58491 | 0,11974 | 1,54550 | 0,80000 | 0,48560 | 0,14184 | 1,42744 | 4,731 | 52,57 |
| 38 | FBA | fractal-based algorithm | 0,69419 | 0,64267 | 0,28955 | 1,62641 | 0,99812 | 0,54905 | 0,08705 | 1,63422 | 0,76133 | 0,51253 | 0,13689 | 1,41075 | 4,671 | 51,90 |
| 39 | ECOi | eco-inspired evolutionary algorithm | 0,78817 | 0,54402 | 0,29360 | 1,62579 | 0,88996 | 0,46592 | 0,09747 | 1,45335 | 0,78533 | 0,45173 | 0,14295 | 1,38001 | 4,459 | 49,54 |
| 40 | BSO | brain storm optimization | 0,92207 | 0,57625 | 0,29732 | 1,79564 | 0,80764 | 0,42508 | 0,09448 | 1,32720 | 0,77200 | 0,36533 | 0,13065 | 1,26798 | 4,391 | 48,79 |
| 41 | CAm | camel algorithm M | 0,71534 | 0,56917 | 0,35985 | 1,64436 | 0,84094 | 0,47174 | 0,10850 | 1,42118 | 0,70400 | 0,41947 | 0,19563 | 1,31910 | 4,385 | 48,72 |
| 42 | ACOm | ant colony optimization_M | 0,71885 | 0,48410 | 0,30990 | 1,51285 | 0,75792 | 0,48639 | 0,11871 | 1,36302 | 0,83600 | 0,48667 | 0,16148 | 1,48415 | 4,360 | 48,44 |
| 43 | BSO | brain storm optimization | 0,91331 | 0,55813 | 0,29705 | 1,76849 | 0,85329 | 0,44038 | 0,09447 | 1,38814 | 0,72267 | 0,32880 | 0,13325 | 1,18472 | 4,341 | 48,23 |
| 44 | AEFA | artificial electric field algorithm | 0,88798 | 0,65769 | 0,25276 | 1,79843 | 0,95550 | 0,63602 | 0,03946 | 1,63098 | 0,60800 | 0,16000 | 0,09845 | 0,86645 | 4,296 | 47,73 |
| 45 | SOA | simple optimization algorithm | 0,91664 | 0,47040 | 0,27095 | 1,65799 | 0,88264 | 0,31546 | 0,06044 | 1,25854 | 0,82933 | 0,31733 | 0,11579 | 1,26245 | 4,179 | 46,43 |
| RW | random walk | 0,49970 | 0,32333 | 0,25791 | 1,08094 | 0,30754 | 0,11470 | 0,04400 | 0,46624 | 0,36133 | 0,17013 | 0,10244 | 0,63390 | 2,181 | 24,23 | |
Выводы
В данной статье мы завершили работу, начатую в предыдущей: от диагностики проблемы перешли к её полному устранению. Основные результаты:
- Все 45 алгоритмов были протестированы на обновлённых тестовых функциях с пересчётом рейтинговой таблицы. Подавляющее большинство алгоритмов показали результаты, близкие к прежним — отклонения составили от долей процента до 5–6 пунктов, что укладывается в естественный разброс при изменении ландшафта. Это подтвердило надёжность тестового стенда как инструмента: его методология работает корректно, а выявленная проблема касалась лишь нескольких алгоритмов-исключений.
- Алгоритмы HHO и DOAm были идентифицированы как «читеры» и исключены из рейтинговой таблицы. Составной тест показал для них результат около 53% — уровень, несопоставимый с их прежними оценками на стандартном стенде (68% и 73%). Для сравнения, алгоритмы из верхней части таблицы — ANS, CLA, HS — на том же составном тесте показали 96–99%, подтвердив универсальность своего поискового механизма.
- Разработан скрипт составного теста на устойчивость к геометрическому смещению. Пять различных функций (Hilly, Forest, Megacity, Peaks, Skin) с разными доменами и ландшафтами объединены в одну задачу с 10 координатами. Один запуск этого скрипта занимает несколько секунд и даёт однозначный ответ: если результат значительно ниже, чем среднее первого теста стандартного стенда — алгоритм эксплуатирует геометрию, а не ищет. Рекомендуется использовать этот скрипт как входной фильтр перед полным прогоном на тестовом стенде.
Для практикующего трейдера всё это имеет прямое значение. Алгоритмы оптимизации используются в торговле повсеместно — для подбора параметров торговых стратегий, настройки индикаторов, оптимизации портфеля. Если алгоритм завышает результаты на тестовых задачах из‑за случайного совпадения с их геометрией, то на реальных задачах он даст далёкие от оптимума параметры и создаст ложное ощущение качества оптимизации. Наш инструментарий для выявления «читерства» помогает отсеять такие алгоритмы ещё на этапе выбора и использовать только те, которые действительно обладают качественным поисковым механизмом.
Практическая рекомендация для трейдера: перед тем как использовать новый алгоритм оптимизации для подбора параметров торговой стратегии, прогоните его через составной тест. Если результат составного теста существенно расходится с результатами стандартного стенда — не доверяйте этому алгоритму, такой алгоритм не справится с реальной задачей так же, как пасует перед составным тестом. Все описанные инструменты — скрипт составного теста, обновлённые тестовые функции и 3D-панель визуализации — прилагаются к статье и готовы к использованию.

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

Рисунок 2. Гистограмма результатов (0–100; больше — лучше, 100 — теоретический максимум). В архиве — скрипт для расчёта рейтинговой таблицы.
К статье прикреплён архив с актуальными версиями кодов алгоритмов. Автор не несёт ответственности за абсолютную точность в описании канонических алгоритмов, во многие из них были внесены изменения для улучшения поисковых возможностей. Выводы и суждения, представленные в статьях, основываются на результатах проведённых экспериментов.
Программы, используемые в статье
| # | Имя | Тип | Описание |
|---|---|---|---|
| 1 | #C_AO.mqh | Включаемый файл | Родительский класс популяционных алгоритмов оптимизации |
| 2 | #C_AO_enum.mqh | Включаемый файл | Перечисление популяционных алгоритмов оптимизации |
| 3 | TestFunctions.mqh | Включаемый файл | Библиотека тестовых функций |
| 4 | TestStandFunctions.mqh | Включаемый файл | Библиотека функций тестового стенда |
| 5 | TestStand3D.mqh | Включаемый файл | 3D-панель визуализации для тестового стенда |
| 6 | Utilities.mqh | Включаемый файл | Библиотека вспомогательных функций |
| 7 | Test_AO_All.mq5 | Скрипт | Единый испытательный стенд для всех популяционных алгоритмов оптимизации |
| 8 | Verify_Extremes.mq5 | Скрипт | Поиск RAW-экстремумов + 2D-тепловая карта функции |
| 9 | Test_AO_AntiCheat.mq5 | Скрипт | Тест на читерство алгоритмов оптимизации |
Предупреждение: все права на данные материалы принадлежат MetaQuotes Ltd. Полная или частичная перепечатка запрещена.
Данная статья написана пользователем сайта и отражает его личную точку зрения. Компания MetaQuotes Ltd не несет ответственности за достоверность представленной информации, а также за возможные последствия использования описанных решений, стратегий или рекомендаций.
Моделирование рынка: Первые шаги на SQL в MQL5 (I)
Разработка инструментария для анализа Price Action (Часть 33): Инструмент на основе теории свечного диапазона
Статистический арбитраж на основе коинтегрированных акций (Часть 7): Система оценки 2
Как создать и оптимизировать торговую систему на основе циклов (Detrended Price Oscillator — DPO)
- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования