Династический алгоритм — Dynastic Optimization Algorithm (DOA)
Содержание
Введение
Выбор алгоритма оптимизации — не академический вопрос: от него напрямую зависит, найдёт ли оптимизатор рабочую область параметров за отведённые тысячи прогонов или сожжёт их впустую. Как понять, стоит ли за очередным названием работающий инструмент? Ответ прост: взять и проверить на стенде с фиксированным бюджетом, равными условиями и ростом размерности, то есть в условиях, максимально близких к реальной задаче оптимизации торговой системы.
Сегодняшний гость — Династический алгоритм оптимизации. Dynastic Optimization Algorithm (DOA) был предложен в 2020 году авторами Massan, Wagan, Shaikh в журнале Applied Soft Computing (том 90, статья 106176).
Метафора алгоритма — социальная динамика исторических человеческих династий. Общество в модели делится на три касты: правители (rulers), которые удерживают лучшие найденные позиции; работники (workers), которые трудятся в окрестности правителей; и исследователи (explorers), которые странствуют по всему пространству в поисках новых земель. Смена поколений — это переранжирование общества: любой работник или исследователь, превзошедший правителя, занимает его место на троне. По исчерпании отведённого времени лучший из правителей объявляется императором — он и есть ответ алгоритма.
С доступностью первоисточников ситуация непростая. Основная статья с математической моделью и псевдокодом закрыта платным доступом. Открыто доступны два сопутствующих источника: короткая статья тех же авторов в журнале 3C Tecnología (2020) с параметрами алгоритма и результатами на двух тестовых функциях. Что оказалось самым ценным — статья тех же авторов AIDOA (Adam Inspired DOA, журнал MURJET, 2025), в которой раздел с описанием базового DOA переизложен полностью. Реализация в настоящей статье собрана по этим двум открытым источникам; все места, которые первоисточники не оговаривают, перечислены и закрыты собственными решениями с их документированием.
План таков: реализуем алгоритм в рамках фреймворка C_AO, прогоним на стандартном стенде, разберёмся с результатами, а они окажутся неожиданными в обе стороны. В итоге получим и вердикт по канонической версии, и работоспособную модификацию, пригодную в том числе для задач с дискретными параметрами, столь характерными для торговых систем.
Реализация алгоритма
Модель DOA описывается несколькими простыми правилами. Популяция размера popSize делится на три касты фиксированными долями: правители rr, работники rw, исследователи re, причём rr + rw + re = 1. Авторские значения: rr = 0.05, rw = 0.55, re = 0.4 при popSize = 100. Правители — верхние rr·popSize особей по фитнесу. Их позиции зафиксированы: между итерациями правители не двигаются.
Работники генерируются заново на каждой итерации в окрестности правителей: по каждой координате позиция работника отстоит от позиции назначенного ему правителя не более чем на radw·range, где radw — параметр (авторское значение 0.4), а range — ширина диапазона поиска по данной координате. Привязка работника к правителю в тексте описана через евклидову меру близости (вокруг ближайших правителей).
Исследователи генерируются заново равномерно случайно по всему пространству поиска. В конце итерации вся популяция ранжируется по фитнесу, верхние rr·popSize особей становятся правителями следующего поколения, цикл повторяется. Ответ — лучший правитель за всю историю.

Рисунок 1. Касты в пространстве поиска и цикл одной эпохи
Слева — пространство поиска: правители (короны) удерживают лучшие позиции, вокруг каждого в пределах пунктирного радиуса radW·range генерируются работники, исследователи разбросаны по всему пространству. Справа — цикл одной эпохи: двор правителей с запомненным фитнесом порождает кандидатов (наследники и работники — вокруг правителей, исследователи — случайно), кандидаты оцениваются, и из объединённого пула: свежие кандидаты + действующие правители, верхние nR занимают двор следующей эпохи. Лучшее найденное решение фиксируется как император (cB/fB).
Псевдокод алгоритма:
инициализация: popSize случайных особей, оценка фитнеса повторять до исчерпания бюджета: ранжировать популяцию по фитнесу правители <- верхние nR особей (позиции фиксированы) работники <- nW новых точек в радиусе radw вокруг правителей исследователи <- nE новых случайных точек в пространстве поиска оценить фитнес работников и исследователей вернуть лучшего правителя (императора)
Модель подкупает простотой, но при внимательном чтении обнаруживается, что несколько ключевых мест первоисточник не специфицирует, и их приходится закрывать решениями для реализации.
Привязка работника к правителю. Вокруг ближайших правителей, однако у заново генерируемого работника нет собственной позиции до генерации, поэтому ближайший осмыслен только относительно позиции с прошлой итерации, которая в модели никак не используется. В реализации принята равномерная привязка по кругу: работники распределяются между правителями поровну.
Распределение внутри радиуса. Не указано, равномерное оно или сосредоточенное у правителя. В канонической реализации принят равномерный куб: смещение по каждой координате U(-1, 1)·radw·range. Забегая вперёд — именно эта деталь окажется решающей.
Судьба правителей при стагнации. Механизма принудительного обновления элиты нет: правитель покидает трон только уступив по фитнесу.
Отметим и то, чего в модели нет вовсе: никакой адаптации по ходу поиска. Ни радиус работников, ни доли каст не меняются от итерации к итерации.
Селекция трона выполняется из объединённого пула: действующие правители плюс все свежеоценённые кандидаты. Верхние nRulers пула занимают двор следующей эпохи. Такая схема даёт элитизм по построению — правитель теряет место только тому, кто его фактически превзошёл. Лучшие найденные решения не теряются никогда. На первом проходе фитнес правителей инициализирован значением -DBL_MAX, поэтому они честно проигрывают любому оценённому кандидату и отдельная ветка первичной инициализации в селекции не нужна.
Все данные алгоритма хранятся в массивах структур: S_DOA_Ind ruler[] — двор (позиции и фитнес правителей), S_DOA_Ind pool[] — буфер пула селекции размера popSize + nRulers.
Реализация в рамках C_AO. Интеграция в стенд потребовала одного нестандартного решения, связанного с экономией бюджета фитнес-функции. Стенд оценивает ровно popSize кандидатов за эпоху, но правители в DOA неподвижны — переоценивать их каждую эпоху означало бы выбрасывать rr = 5% бюджета на вычисление уже известных значений (функция детерминирована). Поэтому правители хранятся в классе отдельно, с запомненным фитнесом. Освободившиеся nRulers слотов заполняются наследниками: по одному дополнительному работнику вокруг каждого правителя. Структурные доли каст сохранены, бюджет используется полностью.
Селекция трона выполняется из объединённого пула: действующие правители плюс все свежеоценённые кандидаты. Верхние nRulers пула занимают двор следующей эпохи. Такая схема даёт элитизм по построению — правитель теряет место только тому, кто его фактически превзошёл, и лучшие найденные решения не теряются никогда. На первом проходе фитнес правителей инициализирован значением -DBL_MAX, поэтому они честно проигрывают любому оценённому кандидату и отдельная ветка первичной инициализации в селекции не нужна.
Все данные алгоритма хранятся в массивах структур: S_DOA_Ind ruler[] — двор (позиции и фитнес правителей), S_DOA_Ind pool[] — буфер пула селекции размера popSize + nRulers. Структура особи:
//+------------------------------------------------------------------+ //| Structure | //+------------------------------------------------------------------+ struct S_DOA_Ind { double c []; // координаты (валидные, прогнаны через SeInDiSp) double f; // фитнес void Init(int coords) { ArrayResize(c, coords); f = -DBL_MAX; } };
Класс содержит шесть внешних параметров: popSize, rulerRatio, workerRatio (доля исследователей вычисляется как остаток), radW, radWmin (конечный радиус линейного затухания; при radWmin = radW радиус постоянный — каноническая версия) и distrPower (степень концентрации распределения работника; 0 — равномерный куб, каноническая версия). Значения по умолчанию воспроизводят каноническую версию бит-в-бит.
//+------------------------------------------------------------------+ //| Class | //+------------------------------------------------------------------+ class C_AO_DOAm_dynastic : public C_AO { public: ~C_AO_DOAm_dynastic() {} C_AO_DOAm_dynastic() { ao_name = "DOAm(Dynastic)"; ao_desc = "Dynastic Optimization Algorithm"; ao_link = "https://www.mql5.com/ru/articles/23504"; popSize = 100; // размер популяции rulerRatio = 0.05; // доля правителей rr workerRatio = 0.55; // доля работников rw (исследователи re = 1-rr-rw) radW = 0.4; // стартовый радиус работников, доля диапазона radWmin = 0.4; // конечный радиус (== radW -> постоянный, каноника) distrPower = 0.0; // степень концентрации у правителя (0 -> равномерно, каноника) ArrayResize(params, 6); params [0].name = "popSize"; params [0].val = popSize; params [1].name = "rulerRatio"; params [1].val = rulerRatio; params [2].name = "workerRatio"; params [2].val = workerRatio; params [3].name = "radW"; params [3].val = radW; params [4].name = "radWmin"; params [4].val = radWmin; params [5].name = "distrPower"; params [5].val = distrPower; } void SetParams() { popSize = (int)params [0].val; rulerRatio = params [1].val; workerRatio = params [2].val; radW = params [3].val; radWmin = params [4].val; distrPower = params [5].val; //--- предохранители if(popSize < 3) popSize = 3; // минимум по одному на касту if(rulerRatio <= 0.0) rulerRatio = 0.01; if(rulerRatio > 0.5) rulerRatio = 0.5; if(workerRatio < 0.0) workerRatio = 0.0; if(rulerRatio + workerRatio >= 1.0) workerRatio = 1.0 - rulerRatio - 0.01; // исследователям должно что-то остаться if(workerRatio < 0.0) workerRatio = 0.0; if(radW <= 0.0) radW = 0.01; if(radW > 1.0) radW = 1.0; if(radWmin <= 0.0) radWmin = 0.0001; if(radWmin > radW) radWmin = radW; if(distrPower < 0.0) distrPower = 0.0; } bool Init(const double &rangeMinP [], const double &rangeMaxP [], const double &rangeStepP [], const int epochsP = 0); void Moving(); void Revision(); //--- видимые параметры double rulerRatio; // rr double workerRatio; // rw double radW; // стартовый радиус работников (доля диапазона) double radWmin; // конечный радиус (линейное затухание по эпохам) double distrPower; // степень PowerDistribution (0 -> равномерный куб) private: int nRulers; // число правителей int nWorkers; // число «рядовых» работников (без наследников) int nExplorers; // число исследователей int epochs; // всего эпох (от стенда) int epochNow; // текущая эпоха double radNow; // актуальный радиус этой эпохи S_DOA_Ind ruler []; // [nRulers] — двор: позиции и фитнес S_DOA_Ind pool []; // [popSize + nRulers] — пул для селекции трона int ord []; // [popSize + nRulers] — индексы для сортировки //--- вспомогательные void MakeWorker(int slot, int rulerIdx); void MakeExplorer(int slot); };
Метод Init() выполняет разовую подготовку алгоритма к прогону. После стандартной инициализации базового класса (StandardInit) из долевых параметров вычисляются абсолютные размеры каст. Число правителей nRulers = MathRound(rulerRatio · popSize) ограничивается снизу единицей — двор не может быть пустым, а сверху величиной popSize − 2. Это необходимо, чтобы при любых входных долях в популяции оставалось место хотя бы для одного работника и одного исследователя. Число работников nWorkers вычисляется аналогично из workerRatio и при необходимости урезается так, чтобы как минимум один исследователь существовал всегда. Остаток популяции и составляет касту исследователей nExplorers. Такой каскад предохранителей гарантирует корректную раскладку каст при любых сочетаниях popSize, rulerRatio и workerRatio без дополнительных проверок в рабочем цикле.
Далее инициализируется расписание радиуса: число эпох epochs берётся из параметра epochsP, который стенд передаёт в Init (при нулевом значении устанавливается 1 для защиты от деления), счётчик текущей эпохи epochNow обнуляется, актуальный радиус radNow получает стартовое значение radW.
В завершение выделяются буферы — массивы структур: ruler[] размером nRulers под двор и pool[] размером popSize + nRulers под пул селекции, вместе со вспомогательным массивом индексов ord[] той же длины. Каждая структура инициализируется фитнесом -DBL_MAX — как уже говорилось. Именно это значение позволяет правителям на первом проходе честно проиграть любому оценённому кандидату и обойтись без отдельной ветки первичного заполнения двора.
//+------------------------------------------------------------------+ //| Init | //+------------------------------------------------------------------+ bool C_AO_DOAm_dynastic::Init(const double &rangeMinP [], const double &rangeMaxP [], const double &rangeStepP [], const int epochsP = 0) { if(!StandardInit(rangeMinP, rangeMaxP, rangeStepP)) return false; //--- расчёт каст: rr и rw от popSize, остаток — исследователи nRulers = (int)MathRound(rulerRatio * popSize); if(nRulers < 1) nRulers = 1; if(nRulers > popSize - 2) nRulers = popSize - 2; nWorkers = (int)MathRound(workerRatio * popSize); if(nWorkers < 0) nWorkers = 0; if(nRulers + nWorkers > popSize - 1) nWorkers = popSize - 1 - nRulers; // хотя бы один исследователь nExplorers = popSize - nRulers - nWorkers; //--- расписание радиуса epochs = epochsP; if(epochs < 1) epochs = 1; epochNow = 0; radNow = radW; //--- буферы (массивы структур) ArrayResize(ruler, nRulers); ArrayResize(pool, popSize + nRulers); ArrayResize(ord, popSize + nRulers); for(int i = 0; i < nRulers; i++) ruler [i].Init(coords); for(int i = 0; i < popSize + nRulers; i++) pool [i].Init(coords); return true; }
Метод MakeWorker() — ядро алгоритма: генерация одного работника в слот slot вокруг правителя rulerIdx. Работа идёт покоординатно и полностью независимо по координатам — никакой связи между осями оператор не создаёт (что и подтверждает античит-тест). Для каждой координаты сначала вычисляется абсолютный радиус r как доля radNow от ширины диапазона этой координаты. Затем — в зависимости от distrPower — новая позиция строится одним из двух способов. При distrPower = 0 (каноническая версия) смещение от правителя равномерно: U(−1, 1) · r, то есть работник равновероятно попадает в любую точку куба со стороной 2r. При distrPower > 0 (модификация) позиция генерируется через u.PowerDistribution в тех же границах [правитель − r, правитель + r], но с концентрацией у центра. Чем выше степень, тем больше доля координат, практически совпадающих с координатами правителя, и тем реже случаются далёкие смещения — режим разреженной мутации клона. Полученное значение прогоняется через u.SeInDiSp, которая приводит его к допустимому диапазону и сетке шага — в массив a[] попадают только валидные координаты.
Существенно, что обе ветви используют один и тот же радиус и одни и те же границы. Каноническая версия и модификация различаются исключительно формой распределения внутри неизменной окрестности, что делает сравнение версий методологически чистым.
//+------------------------------------------------------------------+ //| MakeWorker — кандидат в окрестности radNow вокруг правителя. | //| distrPower = 0 -> равномерный куб (каноника); | //| distrPower > 0 -> степенная концентрация у правителя (DOAm) | //+------------------------------------------------------------------+ void C_AO_DOAm_dynastic::MakeWorker(int slot, int rulerIdx) { double x, r; for(int c = 0; c < coords; c++) { r = radNow * (rangeMax [c] - rangeMin [c]); if(distrPower <= 0.0) x = ruler [rulerIdx].c [c] + u.RNDfromCI(-1.0, 1.0) * r; else x = u.PowerDistribution(ruler [rulerIdx].c [c], ruler [rulerIdx].c [c] - r, ruler [rulerIdx].c [c] + r, distrPower); a [slot].c [c] = u.SeInDiSp(x, rangeMin [c], rangeMax [c], rangeStep [c]); } }
Метод MakeExplorer() реализует касту исследователей и одновременно служит генератором стартовой популяции (Moving на первом проходе заполняет им все слоты). Каждая координата — независимый равномерный сэмпл по всему допустимому диапазону через u.RNDfromCI с последующей валидацией u.SeInDiSp. Никакой информации о текущем состоянии поиска исследователь не использует — это чистый рестарт, единственный источник глобальной разведки в канонической версии. В модификации эту роль частично перенимает тяжёлый хвост степенного распределения работников, и, как показал анализ параметров, доля исследователей перестаёт быть критичной.
//+------------------------------------------------------------------+ //| MakeExplorer — кандидат равномерно по всему пространству | //+------------------------------------------------------------------+ void C_AO_DOAm_dynastic::MakeExplorer(int slot) { for(int c = 0; c < coords; c++) a [slot].c [c] = u.SeInDiSp(u.RNDfromCI(rangeMin [c], rangeMax [c]), rangeMin [c], rangeMax [c], rangeStep [c]); }
Метод Moving() раскладывает эпоху по кастам: сначала наследники (по одному работнику вокруг каждого правителя, в слоты, освобождённые неоцениваемыми правителями). Затем работники с равномерной привязкой по кругу, остаток — исследователи:
//+------------------------------------------------------------------+ //| Moving | //| Слоты a[i].c — только свежие кандидаты (работники и исследо- | //| ватели); правители живут в ruler[] и стендом не переоцениваются| //+------------------------------------------------------------------+ void C_AO_DOAm_dynastic::Moving() { //--- первый прогон: вся популяция случайна if(!revision) { for(int i = 0; i < popSize; i++) MakeExplorer(i); return; } //--- линейное затухание радиуса от radW к radWmin по эпохам // (radWmin == radW -> радиус постоянный, каноника) epochNow++; if(epochNow > epochs) epochNow = epochs; radNow = radW + (radWmin - radW) * ((double)epochNow / (double)epochs); int slot = 0; //--- 1) наследники: по одному работнику вокруг «своего» правителя // (заполняют слоты, освобождённые неоцениваемыми правителями) for(int r = 0; r < nRulers; r++) { MakeWorker(slot, r); slot++; } //--- 2) работники: равномерная привязка к правителям по кругу for(int j = 0; j < nWorkers; j++) { MakeWorker(slot, j % nRulers); slot++; } //--- 3) исследователи: случайный рестарт в незанятом пространстве for(; slot < popSize; slot++) MakeExplorer(slot); }Метод Revision() обновляет глобальный лучший, собирает пул (старые правители + свежие кандидаты) и частичной сортировкой методом выбора извлекает новый двор — сортировать весь пул целиком не нужно, достаточно верхних nRulers позиций:
//+------------------------------------------------------------------+ //| Revision | //| Селекция трона: объединённый пул «старые правители + свежие | //| кандидаты», верхние nRulers занимают двор. Правитель уступает | //| место только тому, кто его превзошёл (элитизм по построению). | //+------------------------------------------------------------------+ void C_AO_DOAm_dynastic::Revision() { //--- глобальный лучший («император») for(int i = 0; i < popSize; i++) { if(a [i].f > fB) { fB = a [i].f; ArrayCopy(cB, a [i].c, 0, 0, coords); } } //--- пул селекции: свежие кандидаты... for(int i = 0; i < popSize; i++) { ArrayCopy(pool [i].c, a [i].c, 0, 0, coords); pool [i].f = a [i].f; } //--- ...плюс действующие правители (на первом проходе их f=-DBL_MAX, // и они честно проигрывают любому оценённому кандидату) for(int r = 0; r < nRulers; r++) { ArrayCopy(pool [popSize + r].c, ruler [r].c, 0, 0, coords); pool [popSize + r].f = ruler [r].f; } //--- частичная сортировка выбором: нужны только верхние nRulers int poolSize = popSize + nRulers; for(int i = 0; i < poolSize; i++) ord [i] = i; for(int i = 0; i < nRulers; i++) { int bi = i; for(int j = i + 1; j < poolSize; j++) if(pool [ord [j]].f > pool [ord [bi]].f) bi = j; int t = ord [i]; ord [i] = ord [bi]; ord [bi] = t; } //--- новый двор for(int r = 0; r < nRulers; r++) { ArrayCopy(ruler [r].c, pool [ord [r]].c, 0, 0, coords); ruler [r].f = pool [ord [r]].f; } revision = true; }
Результаты тестов
Каноническая версия: результаты, диагноз и потолок настройки. Каноническая конфигурация — авторские параметры (popSize = 100, rr = 0.05, rw = 0.55, radw = 0.4, равномерный куб):
DOA|Dynastic Optimization Algorithm|100.0|0.05|0.55|0.4|0.4|0.0|
=============================
5 Hilly's; Func runs: 10000; result: 0.4863038555276861
25 Hilly's; Func runs: 10000; result: 0.3197909963827993
500 Hilly's; Func runs: 10000; result: 0.256978832669765
=============================
5 Forest's; Func runs: 10000; result: 0.2829948767552311
25 Forest's; Func runs: 10000; result: 0.1197676703581283
500 Forest's; Func runs: 10000; result: 0.04143826207438861
=============================
5 Megacity's; Func runs: 10000; result: 0.33999999999999997
25 Megacity's; Func runs: 10000; result: 0.16373333333333343
500 Megacity's; Func runs: 10000; result: 0.10161333333333415
=============================
All score: 2.11262 (23.47%)
23.47% — уровень случайного поиска. Для трейдера это означало бы: оптимизатор, который за 10 000 бэктестов находит параметры не лучше, чем 10 000 случайных наборов. И это не ошибка реализации, а прямое следствие модели, в чём легко убедиться, разобрав её по механизмам.
У канонического DOA нет ни одного механизма сжатия поиска. Радиус работников постоянен и равен 0.4·range — локальная окрестность правителя покрывает 80% диапазона по диаметру, то есть де-факто работник — это почти глобальный случайный сэмпл со слабым смещением. Исследователи — 40% бюджета — чистые случайные точки по определению. Правители неподвижны.
Почему этого не увидели авторы? Ответ в конфигурации авторской валидации: DOA тестировался на двух двумерных функциях (Booth и Bohachevsky) при 10 000 итераций популяцией 100 — миллион вычислений фитнес-функции на 2D-задаче. В такой постановке даже чистый случайный поиск доползает до окрестности оптимума, и отличить работающий алгоритм от неработающего невозможно в принципе. Это хороший пример того, зачем нужен стенд с фиксированным скромным бюджетом и ростом размерности: слабость модели, невидимая на миллионе оценок в 2D, вскрывается за один прогон. В переводе на язык трейдинга: алгоритм, доказавший себя на миллионе прогонов двухпараметрической задачи, ничего не говорит о том, как он справится с экспертом на двадцать входов при реалистичном бюджете тестера.
Потолок настроенной каноники. Прежде чем модифицировать алгоритм, необходимо честно ответить на вопрос: может быть, дело просто в неудачных авторских параметрах? Проверка на стенде — канонический равномерный оператор с настроенными параметрами (popSize = 50, radW = 0.1, что даёт вдвое больше эпох селекции и адекватный радиус локального поиска):
=============================
5 Hilly's; Func runs: 10000; result: 0.5619911683130899
25 Hilly's; Func runs: 10000; result: 0.3579458154505299
500 Hilly's; Func runs: 10000; result: 0.25830717084436966
=============================
5 Forest's; Func runs: 10000; result: 0.42142023073906776
25 Forest's; Func runs: 10000; result: 0.16533823804791856
500 Forest's; Func runs: 10000; result: 0.05230889735727588
=============================
5 Megacity's; Func runs: 10000; result: 0.404
25 Megacity's; Func runs: 10000; result: 0.19013333333333332
500 Megacity's; Func runs: 10000; result: 0.10401333333333421
=============================
All score: 2.51546 (27.95%)
27.95%. Настройка оживляет алгоритм лишь частично: подрастают функции малой размерности (Hilly 5: 0.49 → 0.56, Forest 5: 0.28 → 0.42, Megacity 5: 0.34 → 0.40), но колонки 500× не сдвигаются вовсе — при полноразмерном равномерном возмущении никакой радиус не спасает высокую размерность. Итого +4.5 процентного пункта — это и есть потолок равномерного оператора. Вывод: слабость канонической модели не сводится к неудачным авторским параметрам, она заложена в самой форме оператора работника.
Модификация DOAm. Логика модификации следует из диагноза. Проблема канонического оператора — полноразмерное возмущение: работник отличается от правителя сразу по всем координатам, и с ростом размерности вероятность улучшения падает к нулю. Нужен оператор, который наследует правителя почти целиком и возмущает лишь малую часть координат — но при этом сохраняет шанс крупного скачка для выхода из локальных экстремумов.
Ровно это даёт замена равномерного куба на степенное распределение с большой степенью. При distrPower = 100 смещение по координате равно ±r·|u|^100, где u — равномерная величина на [0, 1]. Медиана |u|^100 — порядка 10^-30: подавляющее большинство координат работника после дискретизации SeInDiSp совпадают с координатами правителя побитово. Лишь малая доля координат получает заметный сдвиг, и изредка случается крупный прыжок в пределах радиуса. Работник превращается из случайной точки в огромном кубе в клона правителя с разреженной мутацией. Для задачи с 1000 координат это означает десятки значимых мутаций на кандидата вместо одновременной встряски всех координат — качественно другой режим поиска.
Разница между двумя операторами наглядно показана на рисунке 2.

Рисунок 2. Распределение в канонической версии против модификации
Вверху — плотности распределения смещения работника относительно правителя: у каноники (слева) любое смещение в пределах ±r равновероятно, и при r = 0.4·range это фактически глобальный сэмпл; у DOAm (справа) распределение имеет острый пик в нуле и тяжёлые хвосты — координата чаще всего копируется, но изредка совершает крупный прыжок. Внизу — как это выглядит на уровне одного кандидата при 40 координатах: каноническая версия возмущает все координаты сразу (вероятность улучшить инкумбента падает к нулю с ростом размерности), DOAm выдаёт клона правителя с двумя-тремя точечными мутациями.
У степенного оператора есть и второе полезное свойство: он многомасштабен сам по себе. Тяжёлый хвост распределения совмещает в одном операторе тонкую доводку (типичные микросдвиги) и разведку (редкие крупные прыжки).
Итоговая конфигурация DOAm отличается от авторской двумя позициями: формой распределения работника (distrPower = 100 вместо равномерного куба — ключевое изменение) и размером популяции (50 вместо 100). Это даёт больше эпох селекции на тот же бюджет и вклад этого изменения близок к уровню шума. Доли каст и радиус остались авторскими.
Результаты DOAm (popSize = 50, rr = 0.05, rw = 0.55, radW = 0.4, distrPower = 100):
DOAm(Dynastic)|Dynastic Optimization Algorithm|50.0|0.05|0.55|0.4|0.4|100.0|
=============================
5 Hilly's; Func runs: 10000; result: 0.6320237322869958
25 Hilly's; Func runs: 10000; result: 0.5800326780139757
500 Hilly's; Func runs: 10000; result: 0.31943562728259933
=============================
5 Forest's; Func runs: 10000; result: 0.7694779896193158
25 Forest's; Func runs: 10000; result: 0.6273031170351832
500 Forest's; Func runs: 10000; result: 0.12425120438372103
=============================
5 Megacity's; Func runs: 10000; result: 0.7413333333333333
25 Megacity's; Func runs: 10000; result: 0.5952000000000002
500 Megacity's; Func runs: 10000; result: 0.1655066666666671
=============================
All score: 4.55456 (50.61%)
Итоговая трёхступенчатая картина:
| Версия | Конфигурация | All score |
|---|---|---|
| DOA, авторские параметры | 100 / 0.05 / 0.55 / radW 0.4, равномерный куб | 23.47% |
| DOA, настроенная каноника | 50 / 0.05 / 0.55 / radW 0.1, равномерный куб | 27.95% |
| DOAm | 50 / 0.05 / 0.55 / radW 0.4, distrPower 100 | 50.61% |
Все три ступени сведены на рисунке 3.

Рисунок 3. Сводная диаграмма результатов
Слева — общий счёт трёх версий: настройка параметров в рамках канонического оператора даёт +4.5 п.п., замена формы распределения — +27 п.п. при тех же кастах и радиусе. Справа — детализация по всем тестам: каноническая версия и её настройка различимы только на малых размерностях, DOAm уходит в отрыв на всех тестах, а колонки 500× остаются слабым местом всех трёх версий. Соотношение вкладов говорит само за себя: работоспособность алгоритма определяется в большей мере оператором, а не параметрами.
Профиль результатов DOAm закономерен для клонирующего оператора с разреженной мутацией: сильные Forest и Megacity малой и средней размерности (0.77 и 0.74 на пяти функциях — точечные мутации хорошо работают на острых пиках и плато, элитизм не даёт растерять найденное), приличная Hilly, и ожидаемо слабые колонки: на 1000 координатах пропускной способности разреженной мутации при бюджете 10 000 физически не хватает. Отдельно отметим дискретную Megacity: 0.74 на малой размерности — хороший показатель именно для того класса задач, к которому относится оптимизация торговых систем с дискретными параметрами (периоды индикаторов, стопы и тейки в пунктах).
Анализ параметров. Поведение DOAm при варьировании параметров оказалось интереснее, чем виделось на первых прогонах, и заслуживает подробного разбора — тем более что первые выводы пришлось по ходу исследования уточнять.
Важная оговорка: представленная конфигурация DOAm — результат ручного исследования параметров, а не исчерпывающей оптимизации, и потенциал алгоритма ею, по-видимому, не исчерпан. Каждая итерация расширения сетки (радиус на полный диапазон, отжиг, уменьшение популяции) приносила плюс. Направления для экспериментов читателю: совместная настройка глубины отжига и p, а также параметризация не степени, а целевого числа мутируемых координат m с вычислением p из размерности задачи в Init — оптимальная плотность мутаций, зависит от размерности, и фиксированное p задаёт разную плотность на 10 и на 1000 координатах.
Уровень соответствует ожиданию. Для дополнительного контроля используется композитный античит-тест: 10 координат разбиваются на 5 пар, каждая пара принадлежит своей функции (Hilly, Forest, Megacity, Peaks, Skin) со своим диапазоном и геометрией оптимума, фитнес — среднее по пяти функциям. Любой геометрический чит даёт выигрыш максимум на одной паре из пяти и на общем счёте не виден.
По построению DOA читерских механизмов содержать не должен: как разобрано в описании MakeWorker и MakeExplorer, все операторы покоординатны и независимы, скаляра-на-вектор и связи между осями нигде нет. Результат композита для DOAm:
DOA|Dynastic Optimization Algorithm|50.0|0.05|0.55|0.4|0.4|100.0|
=============================
Composite anti-cheat test: Hilly + Forest + Megacity + Peaks + Skin
Coordinates: 10; Epochs: 200; Repeats: 10
=============================
Run 1/10: 0.7175156173476314
Run 2/10: 0.7508279225003711
Run 3/10: 0.7153487384316153
Run 4/10: 0.8177209947847637
Run 5/10: 0.7103793683564248
Run 6/10: 0.7977221039766244
Run 7/10: 0.710968819274466
Run 8/10: 0.7215798981864271
Run 9/10: 0.7774164879690602
Run 10/10: 0.9860488357796182
=============================
Average result: 0.7705528787 (77.06%)
Результат штатный. Ожидание для честного алгоритма на этом композите — уровень его же результатов на 10-координатных тестах основного стенда с поправкой на то, что каждая функция представлена одной парой координат. Peaks и Skin проще основной тройки: это даёт коридор примерно 0.75–0.85. Фактические 77.06% лежат в середине коридора — ни аномального превышения (флаг геометрического чита), ни провала (флаг скрытой зависимости от согласованности диапазонов: разные диапазоны пяти функций алгоритм переварил без деградации). Разброс прогонов также типичен для мультимодального композита с элитистской селекцией: восемь прогонов плотно в 0.71–0.82 и два верхних выброса, где разреженная мутация удачно дожала трудную пару.
Визуализация работы алгоритма DOAm на стандартных функциях и двух последних — произвольных.

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

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

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

DOAm на тестовой функции Ackley

DOAm на тестовой функции Griewank
По результатам тестирования алгоритм DOAm занимает 43 место в нашей таблице лучших популяционных методов оптимизации.
| 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 | COA | coyote_optimization_algorithm | 0,88909 | 0,70681 | 0,32718 | 1,92308 | 0,99467 | 0,85358 | 0,15152 | 1,99977 | 0,88533 | 0,71040 | 0,18981 | 1,78554 | 5,708 | 63,43 |
| 12 | 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 |
| 13 | 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 |
| 14 | 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 |
| 15 | 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 |
| 16 | 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 |
| 17 | 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 |
| 18 | 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 |
| 19 | 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 |
| 20 | 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 |
| 21 | 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 |
| 22 | 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 |
| 23 | 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 |
| 24 | 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 |
| 25 | 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 |
| 26 | 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 |
| 27 | (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 |
| 28 | 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 |
| 29 | 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 |
| 30 | 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 |
| 31 | 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 |
| 32 | 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 |
| 33 | 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 |
| 34 | 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 |
| 35 | 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 |
| 36 | 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 |
| 37 | BEA | bacterial_evolutionary_algorithm | 0,92170 | 0,59615 | 0,29340 | 1,81125 | 0,96906 | 0,44500 | 0,08233 | 1,49639 | 0,90533 | 0,43173 | 0,13676 | 1,47382 | 4,781 | 53,13 |
| 38 | BWOm | beluga_whale_optimization_M | 0,78488 | 0,56872 | 0,29557 | 1,64917 | 0,91370 | 0,61760 | 0,12988 | 1,66118 | 0,81333 | 0,49946 | 0,15004 | 1,46283 | 4,773 | 53,04 |
| 39 | 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 |
| 40 | ACA | andean_condor_algorithm | 0,78444 | 0,53260 | 0,33108 | 1,64812 | 0,79071 | 0,44960 | 0,10685 | 1,34716 | 0,92266 | 0,67733 | 0,17613 | 1,77612 | 4,771 | 53,02 |
| 41 | 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 |
| 42 | 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 |
| 43 | DOAm | dynastic_optimization_algorithm | 0,63202 | 0,58003 | 0,31943 | 1,53148 | 0,76947 | 0,62730 | 0,12425 | 1,52102 | 0,74133 | 0,59520 | 0,16550 | 1,50203 | 4,555 | 50,61 |
| 44 | 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 |
| 45 | 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 |
| 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 | |
Выводы
Подведём итог тому, что читатель получает на выходе — и как инструмент, и как знание. Династический алгоритм — характерный представитель метафорических метаэвристик прикладного происхождения: простая и наглядная социальная модель, разработанная под инженерную задачу и провалидированная в конфигурации, не способной выявить её слабости. На честном стенде с фиксированным бюджетом каноническая версия при авторских параметрах неотличима от случайного поиска (23.47%), а настройка параметров в рамках канонического оператора поднимает её лишь до 27.95%. В модели отсутствует механизм сжатия поиска, и полноразмерное равномерное возмущение не лечится никаким радиусом.
При этом каркас алгоритма — касты, неподвижная элита, селекция из объединённого пула — оказался вполне жизнеспособным носителем для правильного оператора. Замена равномерного куба на степенное распределение с большой степенью (разреженная мутация клона правителя) при авторских долях каст и радиусе поднимает композит до 50.61%. Соотношение вкладов — 4.5 п.п. от настройки против 27 п.п. от замены оператора — главный количественный результат статьи.
Отсюда практическое правило для трейдера: заявленным результатам метаэвристики можно доверять ровно настолько, насколько условия её проверки похожи на реальную задачу — фиксированный скромный бюджет прогонов и размерность, сопоставимая с числом параметров торговой системы.К статье приложен готовый класс C_AO_DOA, совместимый со всей инфраструктурой серии: обе версии — каноническая и модифицированная — в одном классе, переключение параметрами, дефолты воспроизводят канонику. Для практической оптимизации торговых систем интерес представляет именно DOAm (50.61%): его сильная сторона — задачи малой и средней размерности, в том числе дискретные (Megacity 0.74 на 10 координатах) — а это ровно профиль типичной задачи оптимизации эксперта: до пары десятков параметров, значительная часть которых дискретна. Настройка проста: главный параметр — distrPower (плотность мутаций, рабочий диапазон 25–200). Радиус имеет ясную роль дальнобойности мутаций и хорошо работает в режиме отжига: полный диапазон → точечная полировка (1.0 → 0.01), доли каст в разумной зоне не критичны. Чего от DOAm ждать не стоит — чудес на задачах с сотнями параметров: на 1000 координат при бюджете 10 000 пропускной способности разреженной мутации не хватает. И отдельно отметим: представленная конфигурация — не предел. Сетка параметров исследована вручную, и каждое её расширение приносило улучшение, так что поле для экспериментов читателю оставлено.

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

Рисунок 5. Гистограмма результатов тестирования алгоритмов (по шкале от 0 до 100: чем больше, тем лучше, где 100 — максимально возможный теоретический результат), в архиве скрипт для расчёта рейтинговой таблицы
Плюсы и минусы алгоритма DOAm:
Плюсы:
- Простая структура и понятная параметризация: главный параметр distrPower с ясным смыслом (плотность мутаций), радиус с ясной ролью (дальнобойность мутаций и её отжиг).
- Сильные результаты на функциях малой и средней размерности, особенно на острой Forest и дискретной Megacity — профиль, близкий к задачам оптимизации торговых систем.
- Элитизм по построению; доли каст и размер популяции в разумной зоне не критичны; античит-тест пройден штатно (77.06% на композите); потенциал настройки не исчерпан.
Минусы:
- Слабые результаты на высокой размерности: разреженной мутации не хватает пропускной способности на бюджете 10 000.
- Каноническая версия в исходном виде неработоспособна на фиксированном бюджете при любых параметрах; вся эффективность привнесена модификацией.
К статье прикреплён архив с актуальными версиями кодов алгоритмов. Автор статьи не несёт ответственности за абсолютную точность в описании канонических алгоритмов, во многие из них внесены изменения для улучшения поисковых возможностей. Выводы и суждения, представленные в статьях, основываются на результатах проведённых экспериментов.
Программы, используемые в статье
| # | Имя | Тип | Описание |
|---|---|---|---|
| 1 | #C_AO.mqh | Включаемый файл | Родительский класс популяционных алгоритмов оптимизации |
| 2 | #C_AO_enum.mqh | Включаемый файл | Перечисление популяционных алгоритмов оптимизации |
| 3 | TestFunctions.mqh | Включаемый файл | Библиотека тестовых функций |
| 4 | TestStandFunctions.mqh | Включаемый файл | Библиотека функций тестового стенда |
| 5 | TestStand3D.mqh | Включаемый файл | 3D-панель визуализации для тестового стенда |
| 6 | Utilities.mqh | Включаемый файл | Библиотека вспомогательных функций |
| 7 | CalculationTestResults.mqh | Включаемый файл | Скрипт для расчёта результатов в сравнительную таблицу |
| 8 | Test_AO_All.mq5 | Скрипт | Единый испытательный стенд для всех популяционных алгоритмов оптимизации |
| 9 | Test_AO_AntiCheat | Скрипт | Тест на читерство алгоритмов оптимизации |
| 10 | Simple use of population optimization algorithms.mq5 | Скрипт | Простой пример использования популяционных алгоритмов оптимизации без визуализации |
| 11 | Test_AO_DOAm.mq5 | Скрипт | Испытательный стенд для DOAm |
Предупреждение: все права на данные материалы принадлежат MetaQuotes Ltd. Полная или частичная перепечатка запрещена.
Данная статья написана пользователем сайта и отражает его личную точку зрения. Компания MetaQuotes Ltd не несет ответственности за достоверность представленной информации, а также за возможные последствия использования описанных решений, стратегий или рекомендаций.
От начального до среднего уровня: Очереди, списки и деревья (I)
Возможности Мастера MQL5, которые вам нужно знать (Часть 80): Использование паттернов Ишимоку и ADX Уайлдера в обучении с подкреплением TD3
Анализ CSV-данных (Часть 4): Разработка автоматизированного Python-решения для сравнительного анализа и валидации стратегий MQL5
Разработка самовосстанавливающегося советника в MQL5 (Часть 2): Виртуальная защита сделок, устойчивая к перезапуску
- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования