Dream Optimization Algorithm (DOA)
Contents
Introduction
As part of my extensive research into optimal optimization methods, I was drawn to a completely new and unusual approach inspired by a highly controversial and little-studied phenomenon: the mechanism of dreams.
In March 2025, Y. Lang and Y. Gao presented to the scientific community an innovative metaheuristic optimization algorithm — Dream Optimization Algorithm (DOA) published in the Computer Methods in Applied Mechanics and Engineering journal (Volume 436). This algorithm, inspired by the unique characteristics of human dreams, opens up new perspectives for solving complex optimization problems, including tuning trading system parameters.
DOA simulates three key aspects of the sleep process: partial memory retention, selective forgetting with subsequent replenishment of information, and the exchange of "dreams" between agents in the population. In the context of algorithmic trading, these mechanisms allow for a balance between exploring new areas of parametric space and exploiting the optimal solutions found, which is critical when optimizing trading strategies in the context of non-stationary financial markets.
In this article, we will examine in detail the mathematical basis of the algorithm, implement it in MQL5, and conduct a comparative analysis with other population-based optimization methods.
Algorithm implementation
When we sleep, our brain does three important things: remembering important information from the day, forgetting unnecessary details, and combining different memories into new ideas.
DOA uses these same principles to find optimal solutions. After initialization, the entire population is divided into several teams. Each team gets its own "memory style" - from the first group with the best memory to the group with the greatest forgetfulness, where each group changes a different number of dimensions (k) depending on the group number and the overall dimensionality of the problem (D).
For most of its runtime, the algorithm is in the exploration phase. First, each group applies a memory strategy, returning all its agents to the best position found by the group, then, with a certain probability, a forgetting and addition strategy is applied. In this case, 'k' randomly selected dimensions are modified using cosine modulation according to the formula cos((i+T/10)π/T), providing large steps at the beginning and gradually decreasing them. With the remaining probability, the dream exchange strategy works, copying 'k' dimensions from a random agent in the population.
At the final stage of the process, the algorithm enters the exploitation phase, where all agents are reset to the globally best solution and perform fine-tuning with minimal steps, thanks to the cosine function cos(iπ/T), which tends to zero at the end of the optimization, which creates a balance between exploration of the search space through the group memory mechanism and short-term but precise final optimization.

Figure 1. DOA algorithm in action
The image above shows the structural diagram of the DOA algorithm. At the top, the central element is a thought cloud labeled "Dream-Inspired Search". Three lines diverge from it, leading to the three main strategies of the algorithm: the blue block Remember Best reflects the memory strategy, in the center is the pink block Forget Explore, symbolizing the strategy of forgetting and exploration, on the right is the green block Share Dreams, representing the strategy of exchanging experience between agents.
Below these three strategies is the Two Phases section, which shows the algorithm time distribution as a horizontal progress bar, with the green portion occupying 99% and labeled Explore and the red bar on the right occupying the remaining 1%, visually highlighting the extreme disproportion between the exploration and exploitation phases.
At the very bottom of the illustration, the key mathematical formula of the algorithm "Position += Random × Cosine_Wave(iteration)" is presented, highlighting the technical nature and importance of cosine modulation in the operation of the DOA algorithm. Let us move on to writing the pseudocode.
Initialization
START of the DOA algorithm
SET parameters:
- Population size = 60 agents
- Number of groups = 6
- Exploration share = 99% of total time
- Probability of forgetting = 30%
CREATE 60 agents with random positions in the search space
DIVIDE the agents into 6 equal groups (10 in each)
INITIALIZE the best solution of each group as the worst possible one
Main optimization loop
FOR each iteration from 1 to maximum:
IF iteration <= 99% of total iterations:
EXECUTE the exploration phase
OTHERWISE:
EXECUTE the exploitation phase
Exploration
FOR each group m from 1 to 6:
FIND the best agent in the m group
UPDATE best group solution
CALCULATE the number of dimensions to change:
k_minimum = ceiling(D / 8 / m)
k_maximum = ceiling(D / 3 / m)
k = random_number between k_minimum and k_maximum
Note: Group 1 changes more dimensions (better memory),
Group 6 changes fewer dimensions (forgets more)
FOR each agent j in group m:
STEP 1 - Memory Strategy:
COPY the position of the best agent of the group to the current agent
(all agents of the group "remember" the best solution found)
STEP 2 - Select k random dimensions to modify
STEP 3 - Forgetting or sharing strategy:
IF random_number < 0.3 (30% probability):
// Strategy of forgetting and addition
FOR each of the k selected dimensions:
new_value = current + random × cosine_wave
where cosine_wave = (cos((iteration + T/10) × π / T) + 1) / 2
Note: cosine provides larger steps at the beginning,
small steps towards the end of the study
OTHERWISE (70% probability):
// Dream exchange strategy
FOR each of the k selected dimensions:
COPY the value from a random agent in the population
(the agent "dreams" of another agent's solution)
CHECK and correct boundaries for all dimensions
Exploitation
FOR each agent j among all 60 agents:
STEP 1 - Reset to global best:
COPY the globally best solution to the current agent
(all agents gather at the found "peak")
STEP 2 - Fine-tuning:
CALCULATE the number of dimensions to change:
k = random_number between 2 and maximum(2, ceiling(D/3))
SELECT k random dimensions
FOR each of the k selected dimensions:
new_value = current + random × cosine_wave
where cosine_wave = (cos(iteration × π / T) + 1) / 2
Note: at the end of the algorithm, the cosine is almost = 0,
which provides very small steps
CHECK and correct boundaries
Updating results
AFTER each change of positions:
CALCULATE the value of the objective function for each agent
UPDATE globally best solution:
IF a better solution than the current global one is found:
SAVE it as new global best
In the exploration phase also:
UPDATE the best solutions of each group
END of iteration
Let's start writing the algorithm code. The class will implement the DOA optimization algorithm and inherit from the C_AO base class (interface for various optimization algorithms). The constructor and destructor are standard, without any additional actions in the destructor. The constructor specifies the main parameters of the algorithm and their values, and also links them to the "params" parameter array, which allows for easy management of the parameters from the outside.
Main parameters- popSize — population size, the number of possible solutions in each iteration;
- numGroups — number of groups the population is divided into for parallel exchange of information;
- explorationRate — proportion of iterations allocated to the exploration phase, in which the algorithm searches for new areas of space;
- forgettingProb — probability of using the "forgetting" strategy, which allows avoiding getting stuck in local minima.
- SetParams () — sets class parameters from the "params" array;
- Init () — initialization of the algorithm, specifying the search ranges and the number of epochs;
- Moving () — performs one optimization step;
- Revision () — revises and updates the current state of the solution.
- currentIteration, totalIterations, explorationIters — iteration counters and phase boundaries;
- groupBest [] — array storing the best solutions of each group, which helps in information sharing and solution evolution.
- ExplorationPhase () — responsible for the exploratory search mode, expanding the search horizons;
- ExploitationPhase () — phase of using already discovered good solutions to improve them;
- UpdateGroupBest () — update the best solution in a specific group;
- GetGroupStartIndex (), GetGroupEndIndex () — help determine the ranges of solution indices within each group.
This class implements a DOA algorithm, in which the population is split into a fixed number of groups. During iterations, the algorithm divides its time between the exploration phase (searching for new solutions) and the exploitation phase (improving the best solutions already found). The "forgetting" strategy allows the algorithm to avoid local optima. The general idea is to ensure a balance between exploring new areas and carefully improving already discovered solutions, which promotes effective global optimization.
//———————————————————————————————————————————————————————————————————— class C_AO_DOA_dream : public C_AO { public: //---------------------------------------------------------- ~C_AO_DOA_dream () { } C_AO_DOA_dream () { ao_name = "DOA"; ao_desc = "Dream Optimization Algorithm"; ao_link = "https://www.mql5.com/en/articles/19177"; popSize = 60; // population size numGroups = 6; // number of groups (fixed in the original) explorationRate = 0.99; // iteration rate for the exploration phase (9/10 in the original) forgettingProb = 0.3; // probability of using the main forgetting strategy ArrayResize (params, 4); params [0].name = "popSize"; params [0].val = popSize; params [1].name = "numGroups"; params [1].val = numGroups; params [2].name = "explorationRate"; params [2].val = explorationRate; params [3].name = "forgettingProb"; params [3].val = forgettingProb; } void SetParams () { popSize = (int)params [0].val; numGroups = (int)params [1].val; explorationRate = params [2].val; forgettingProb = params [3].val; } bool Init (const double &rangeMinP [], const double &rangeMaxP [], const double &rangeStepP [], const int epochsP = 0); void Moving (); void Revision (); //------------------------------------------------------------------ int numGroups; // number of groups double explorationRate; // iteration rate for the exploration phase double forgettingProb; // probability of applying the main strategy private: //--------------------------------------------------------- int currentIteration; // current iteration int totalIterations; // total number of iterations int explorationIters; // number of exploration iterations S_AO_Agent groupBest []; // best solutions in each group void ExplorationPhase (); void ExploitationPhase (); void UpdateGroupBest (int groupNum); int GetGroupStartIndex (int groupNum); int GetGroupEndIndex (int groupNum); }; //————————————————————————————————————————————————————————————————————
The initialization method of the C_AO_DOA_dream class performs preparatory operations to run the optimization algorithm. It sets the initial parameters and establishes the internal states required for further iterations.
First, a common initialization method is called, which checks and sets the search ranges and steps, ensuring that the parameters are set correctly. If this check or setup fails, initialization is terminated.
Then the counters are set: the current iteration is reset to "0", the total number of iterations is set from the passed parameters, and the number of iterations allocated for exploration is calculated as a fraction of the total number, taking into account the specified proportion (explorationRate).
Next, an array of the best group solutions (groupBest) is initialized, the size of which is equal to the number of groups. For each group, an initial solution is created using the Init method, and the quality function value of this solution is set to the minimum possible number to ensure proper comparison and updating in the future.
As a result, after executing this method, the algorithm is ready to start the optimization with the set parameters, counters and initial group solutions.
//———————————————————————————————————————————————————————————————————— //--- Initialization bool C_AO_DOA_dream::Init (const double &rangeMinP [], const double &rangeMaxP [], const double &rangeStepP [], const int epochsP = 0) { if (!StandardInit (rangeMinP, rangeMaxP, rangeStepP)) return false; //------------------------------------------------------------------ currentIteration = 0; totalIterations = epochsP; explorationIters = (int)(totalIterations * explorationRate); ArrayResize (groupBest, numGroups); for (int i = 0; i < numGroups; i++) { groupBest [i].Init (coords); groupBest [i].f = -DBL_MAX; // Initialize with the worst value } return true; } //————————————————————————————————————————————————————————————————————
The Moving method is the main iteration step of the DOA algorithm. It implements the logic of the algorithm progress from one iteration to the next. First, the currentIteration counter is incremented, tracking the progress of the algorithm.
Initial initialization (first run only). The "revision" flag is checked; if it is "false" (that is, the algorithm is being run for the first time), the initialization of the population is performed, then for each agent in the population and for each agent coordinate:
- a random coordinate value is generated within the given range (rangeMin and rangeMax) using the u.RNDfromCI() function;
- an adjustment of this value is applied taking into account the step (rangeStep) using the u.SeInDiSp() function, which brings the value to the nearest acceptable value (multiple of the step);
- after initialization, the "revision" flag is set to 'true' to avoid reinitialization in future iterations;
- at this point, the method completes its work.
- checks whether the current iteration is in the exploration phase (currentIteration <= explorationIters);
- if the iteration is in the exploration phase, the ExplorationPhase() method is called;
- otherwise (if the iteration is in the exploitation phase), the ExploitationPhase() method is called.
Thus, the Moving method controls the optimization process by providing an initial population initialization and then switching between the exploration and exploitation phases based on an iteration counter. The initialization occurs only once, after which the algorithm goes into a loop that determines which phase to execute in the current iteration.
//———————————————————————————————————————————————————————————————————— //--- The main step of the algorithm void C_AO_DOA_dream::Moving () { currentIteration++; // Initial population setup 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; } //------------------------------------------------------------------ // Determine the phase of the algorithm if (currentIteration <= explorationIters) { ExplorationPhase (); } else { ExploitationPhase (); } } //————————————————————————————————————————————————————————————————————
The ExplorationPhase method implements the exploration phase of the DOA algorithm. In this phase, solutions for agent groups are updated and diversified in order to find new possible areas of the search space. For each group of agents, the best solution in the group is updated to reflect the current best result found. Next, the number of dimensions (dimensionality) for the forgetting procedure is determined based on the current group number and the total number of coordinates. For each group, the indices of the initial and final agents included in it are calculated.
Then, for each agent within the group, the best solution of the entire group is copied to the current solution of the agent (the Memory strategy), which provides some "old" good solution to return to. A list of dimensions (coordinates) is created that will be subject to the "forgetting" and "replenishment" operation. The array of dimensions is shuffled to randomly select which ones will be changed.
For each agent in the group, a strategy for updating the selected dimensions is determined with a probability specified by the forgettingProb parameter; a "forgetting" strategy with cosine modulation is applied.
A random offset within the range is generated for the selected dimensions. Cosine modulation depends on the current iteration and the total number of iterations, allowing control over the degree of change over time. After updating, the measurement value is brought to a valid range taking into account the steps. Or, if the "forgetting" scenario is not selected, the "dream sharing" strategy is applied. The measurement values are copied from a random other agent, meaning that information is exchanged between agents.
As a result, this phase promotes exploration of the search space, increasing the diversity of solutions and helping to avoid local traps through random changes and information exchange between agents.
//———————————————————————————————————————————————————————————————————— //--- Exploration phase void C_AO_DOA_dream::ExplorationPhase () { // Handle each group for (int m = 0; m < numGroups; m++) { // Update the best solution in the group UpdateGroupBest (m); // Calculate the number of dimensions to forget int kMin = (int)MathCeil ((double)coords / 8.0 / (m + 1)); int kMax = (int)MathCeil ((double)coords / 3.0 / (m + 1)); int k = u.RNDintInRange (kMin, kMax); // Handle agents in the group int startIdx = GetGroupStartIndex (m); int endIdx = GetGroupEndIndex (m); for (int j = startIdx; j <= endIdx; j++) { // Memory strategy - reset to the best group solution ArrayCopy (a [j].c, groupBest [m].c, 0, 0, WHOLE_ARRAY); // Select random dimensions to forget int dims []; ArrayResize (dims, coords); for (int i = 0; i < coords; i++) dims [i] = i; // Shuffle the array of dimensions for (int i = coords - 1; i > 0; i--) { int idx = u.RNDintInRange (0, i); int temp = dims [i]; dims [i] = dims [idx]; dims [idx] = temp; } // Strategy of forgetting and replenishment if (u.RNDprobab () < forgettingProb) { // Basic strategy with cosine modulation for (int h = 0; h < k; h++) { int dim = dims [h]; double range = rangeMax [dim] - rangeMin [dim]; double randomValue = u.RNDprobab () * range + rangeMin [dim]; double cosineModulation = (MathCos ((1.0 * currentIteration + totalIterations / 10.0) * M_PI / totalIterations) + 1.0) / 2.0; a [j].c [dim] = a [j].c [dim] + randomValue * cosineModulation; a [j].c [dim] = u.SeInDiSp (a [j].c [dim], rangeMin [dim], rangeMax [dim], rangeStep [dim]); } } else { // Dream sharing - copying from a random agent for (int h = 0; h < k; h++) { int dim = dims [h]; int donor = u.RNDintInRange (0, popSize - 1); a [j].c [dim] = a [donor].c [dim]; } } } } } //————————————————————————————————————————————————————————————————————
The ExploitationPhase method implements the exploitation phase of the optimization algorithm. Its main task is to guide the search towards the best found solution in order to improve current results.
For each agent in the population, the agent's solution is restored to the global best solution found so far, allowing one to focus on the most promising areas of the search space. Next, the number of dimensions (dimensionality) to be modified is determined. Typically, no less than two and no more than a certain value are selected, related to the number of coordinates. A list of all dimensions (coordinates) is created and then randomly shuffled to randomly select which ones will be changed. For each selected dimension:
- the range of variation of this measurement is calculated;
- a random value is generated within this range;
- this value is modulated using a cosine function that depends on the current iteration number and the total number of iterations, allowing control over the degree of impact of changes over time;
- as a result, the measurement value changes taking into account the generated value and cosine modulation;
- after this, the value is brought to the acceptable range taking into account the discretization step so that the solution remains valid.
The goal of this method is to refine the good solutions already found using random and controlled modifications, which helps to enter a more optimal region of the search space and obtain better solutions.
//———————————————————————————————————————————————————————————————————— //--- Exploitation phase void C_AO_DOA_dream::ExploitationPhase () { // In the exploitation phase, all agents move towards the global best for (int j = 0; j < popSize; j++) { // Reset to global best solution ArrayCopy (a [j].c, cB, 0, 0, WHOLE_ARRAY); // Calculate the number of dimensions to modify int km = MathMax (2, (int)MathCeil ((double)coords / 3.0)); int k = u.RNDintInRange (2, km); // Select random dimensions int dims []; ArrayResize (dims, coords); for (int i = 0; i < coords; i++) dims [i] = i; // Shuffle the array of dimensions for (int i = coords - 1; i > 0; i--) { int idx = u.RNDintInRange (0, i); int temp = dims [i]; dims [i] = dims [idx]; dims [idx] = temp; } // Apply the forgetting and addition strategy for (int h = 0; h < k; h++) { int dim = dims [h]; double range = rangeMax [dim] - rangeMin [dim]; double randomValue = u.RNDprobab () * range + rangeMin [dim]; double cosineModulation = (MathCos (currentIteration * M_PI / totalIterations) + 1.0) / 2.0; a [j].c [dim] = a [j].c [dim] + randomValue * cosineModulation; a [j].c [dim] = u.SeInDiSp (a [j].c [dim], rangeMin [dim], rangeMax [dim], rangeStep [dim]); } } } //————————————————————————————————————————————————————————————————————
The UpdateGroupBest method is designed to determine the best solution within a specific group of agents. Its main actions are as follows:
- obtaining the indices of the starting and ending positions of agents included in a given group;
- loop through all agents in the specified group;
- for each agent, the value of the evaluation function (the solution quality metric) is compared with the current best value stored for the group;
- if an agent finds a solution with the best fitness function value, it updates the record of the best solution in the group, replacing it with the most efficient one.
Thus, the method provides up-to-date information about the best solution within each group, which is important for further steps of the algorithm, such as the search strategy and solution updating.
//———————————————————————————————————————————————————————————————————— //--- Update the best solution in the group void C_AO_DOA_dream::UpdateGroupBest (int groupNum) { int startIdx = GetGroupStartIndex (groupNum); int endIdx = GetGroupEndIndex (groupNum); for (int i = startIdx; i <= endIdx; i++) { if (a [i].f > groupBest [groupNum].f) { groupBest [groupNum].f = a [i].f; ArrayCopy (groupBest [groupNum].c, a [i].c, 0, 0, WHOLE_ARRAY); } } } //————————————————————————————————————————————————————————————————————
The GetGroupStartIndex method is used to calculate the starting index of elements included in the specified group in the array of decisions or agents. It is based on calculations that assume a uniform distribution of groups throughout the array. The basic idea is to determine the position of the first agent (or element) in a particular group based on the group number, the total number of groups, and the total population size.
This is done by multiplying the group number by the total population size and dividing by the number of groups, which gives the index of the first element within a given group. This approach ensures uniform division of data into groups and is conveniently used for further operations related to grouping of solutions.
//———————————————————————————————————————————————————————————————————— //--- Get the starting index of the group int C_AO_DOA_dream::GetGroupStartIndex (int groupNum) { return (int)((double)groupNum * popSize / numGroups); } //————————————————————————————————————————————————————————————————————
The GetGroupEndIndex method calculates the ending index of the elements included in the specified group. It determines the last element in a group based on the group number, the total population size, and the number of groups. The calculation is done by multiplying the group number plus one by the total population size and dividing by the number of groups. The resulting value is then decremented by one to determine the index of the last element in the group.
An additional check is necessary to prevent array out-of-bounds: if the calculated index exceeds the population size, it is adjusted to the value of the last valid index. This approach ensures that the boundaries of each group of agents in the population are correctly defined.
//———————————————————————————————————————————————————————————————————— //--- Get the ending index of the group int C_AO_DOA_dream::GetGroupEndIndex (int groupNum) { int endIdx = (int)((double)(groupNum + 1) * popSize / numGroups) - 1; if (endIdx >= popSize) endIdx = popSize - 1; return endIdx; } //————————————————————————————————————————————————————————————————————
The Revision method is designed to update information about the best solution found during the algorithm's operation. First, it iterates over all solutions in the current population. Inside the loop, for each solution, the value of its objective function is checked and if this value is greater than the current best value, then fB is updated to take the value of the objective function of the current solution, and the current solution becomes the best solution.
The method then checks whether the current iteration is in the "exploration" phase (explorationIters), if so, in addition to updating the global best solution, the method also considers the best solutions found within each group. To do this, the loop iterates over all groups, and for each group, the objective function value of the best solution in that group is compared with the current best value.
If the solution within the group is better, then fB is updated and the solution from groupBest is copied to the global buffer cB. Thus, the Revision method constantly monitors and updates information about the best solution found depending on the current phase of the algorithm (exploration or exploitation), ensuring that the best solution found at the current moment is preserved.
//———————————————————————————————————————————————————————————————————— //--- Update the best and worst solutions void C_AO_DOA_dream::Revision () { // Update the global best solution 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); } } // Update the best solutions of groups in the exploration phase if (currentIteration <= explorationIters) { for (int m = 0; m < numGroups; m++) { if (groupBest [m].f > fB) { fB = groupBest [m].f; ArrayCopy (cB, groupBest [m].c, 0, 0, WHOLE_ARRAY); } } } } //————————————————————————————————————————————————————————————————————
Test results
Now that we have implemented the DOA algorithm, we can move on directly to testing on test functions. As you can see, the DOA algorithm scored 53.62% and will be included in our rating table.
=============================
5 Hilly's; Func runs: 10000; result: 0.8555594031110225
25 Hilly's; Func runs: 10000; result: 0.7008493263471764
500 Hilly's; Func runs: 10000; result: 0.37279821121874124
=============================
5 Forest's; Func runs: 10000; result: 0.7342194493052585
25 Forest's; Func runs: 10000; result: 0.48905397049976357
500 Forest's; Func runs: 10000; result: 0.24146681094197792
=============================
5 Megacity's; Func runs: 10000; result: 0.7723076923076921
25 Megacity's; Func runs: 10000; result: 0.4735384615384616
500 Megacity's; Func runs: 10000; result: 0.18561538461538593
=============================
All score: 4.82541 (53.62%)
The visualization of the DOA algorithm's performance on small dimensions (green lines) shows a scatter of results, especially for the "Forest" and "Megacity" functions.

DOA on the Hilly test function

DOA on the Forest test function

DOA on the Megacity test function
Based on the test results, the DOA algorithm ranks 26th in the overall ranking of population optimization algorithms.
| # | 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 optimization | 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 | DOA | dream_optimization_algorithm | 0.85556 | 0.70085 | 0.37280 | 1.92921 | 0.73421 | 0.48905 | 0.24147 | 1.46473 | 0.77231 | 0.47354 | 0.18561 | 1.43146 | 4.825 | 53.62 |
| 27 | 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 |
| 28 | 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 |
| 29 | 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 |
| 30 | 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 |
| 31 | 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 |
| 32 | 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 |
| 33 | (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 |
| 34 | 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 |
| 35 | 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 |
| 36 | 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 |
| 37 | 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 |
| 38 | 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 |
| 39 | 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 |
| 40 | 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 |
| 41 | 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 |
| 42 | 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 |
| 43 | 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 |
| 44 | 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 |
| 45 | 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 |
| 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 | |
Summary
Dream Optimization Algorithm demonstrates reasonable performance, scoring 53.62% out of 100% possible in the tests conducted, placing it in our ranking table.
The analysis of the results reveals a pattern characteristic of many metaheuristic algorithms: a significant performance decline with increasing problem dimension. For low-dimensional problems, DOA shows results in the range of 73-86%, but when moving to high-dimensional problems, efficiency drops to 18-37% over a finite number of iterations.
Overall, the algorithm is a true "average" among other optimization methods. Those interested can experiment with the algorithm settings; perhaps there is still potential for achieving better results.

Figure 2. Color gradation of algorithms across the corresponding tests

Figure 3. Histogram of algorithm testing results (scale from 0 to 100, the higher the better, where 100 is the maximum possible theoretical result, in the archive there is a script for calculating the rating table)
DOA pros and cons:
Pros:
- Simple implementation.
- Fast.
Cons:
- High variance on low-dimensional test functions.
An archive with the latest versions of the algorithm code is attached to the article. The author of the article is not responsible for the absolute accuracy in the description of canonical algorithms. Changes have been made to many of them to improve search capabilities. The conclusions and judgments presented in the articles are based on the results of the experiments.
Programs used in the article
| # | Name | Type | Description |
|---|---|---|---|
| 1 | #C_AO.mqh | Include | Parent class of population optimization algorithms |
| 2 | #C_AO_enum.mqh | Include | Enumeration of population optimization algorithms |
| 3 | TestFunctions.mqh | Include | Library of test functions |
| 4 | TestStandFunctions.mqh | Include | Test stand function library |
| 5 | Utilities.mqh | Include | Library of auxiliary functions |
| 6 | CalculationTestResults.mqh | Include | Script for calculating results in the comparison table |
| 7 | Testing AOs.mq5 | Script | The unified test stand for all population optimization algorithms |
| 8 | Simple use of population optimization algorithms.mq5 | Script | A simple example of using population optimization algorithms without visualization |
| 9 | Test_AO_DOA.mq5 | Script | DOA test stand |
Translated from Russian by MetaQuotes Ltd.
Original article: https://www.mql5.com/ru/articles/19177
Warning: All rights to these materials are reserved by MetaQuotes Ltd. Copying or reprinting of these materials in whole or in part is prohibited.
This article was written by a user of the site and reflects their personal views. MetaQuotes Ltd is not responsible for the accuracy of the information presented, nor for any consequences resulting from the use of the solutions, strategies or recommendations described.
Building an Internal and External Market Structure Indicator
Creating an EMA Crossover Forward Simulation (Culmination): Interactive Synthetic Candles
Building Volatility Models in MQL5 (Part IV): Implementing Long Memory Volatility Processes, FIGARCH, and HARCH
MQL5 Wizard Techniques you should know (Part 100): Sliding Window Median and Bidirectional LSTM for a Custom Trailing Stop
- Free trading apps
- Over 8,000 signals for copying
- Economic news for exploring financial markets
You agree to website policy and terms of use