English Русский 中文 Español Português
preview
Extremaloptimierung (EO)

Extremaloptimierung (EO)

MetaTrader 5Handel |
30 0
Andrey Dik
Andrey Dik

Inhalt

  1. Einführung
  2. Implementierung des Algorithmus
  3. Testergebnisse


Einführung

Viele reale Probleme, insbesondere Handelsaufgaben, sind durch komplexe diskrete Zielfunktionslandschaften mit mehreren lokalen Extrema, Unstetigkeiten und nicht differenzierbaren Bereichen gekennzeichnet, wodurch klassische gradientenbasierte Methoden nicht anwendbar sind. Zahlreiche metaheuristische Algorithmen wurden entwickelt, um solche Probleme zu lösen, und jeder Ansatz hat seine eigenen Vor- und Nachteile bei der Ausbalancierung von Exploration und Exploitation des Suchraums.

Extremaloptimierung (EO) ist ein metaheuristischer Optimierungsalgorithmus, der vom Bak-Sneppen-Modell inspiriert ist. Der Algorithmus wurde 1999 von Stefan Boettcher und Allon Percus als eine Methode entwickelt, die vom Konzept der selbstorganisierten Kritikalität inspiriert ist, wonach sich komplexe Systeme auf natürliche Weise in Richtung eines kritischen Zustands entwickeln, in dem lawinenartige Veränderungen unterschiedlicher Skalen auftreten. Eine populationsbasierte Variante von EO wurde für die kontinuierliche Optimierung mithilfe iterativer Aktualisierungen auf Populationsebene entwickelt.


Implementierung des Algorithmus

Das Bak-Sneppen-Modell wurde entwickelt, um die Evolution von Ökosystemen zu beschreiben und das Phänomen der selbstorganisierten Kritikalität zu demonstrieren. Dies ist ein einfaches Koevolutionsmodell, das zeigt, wie lokale Interaktionen zu globalen kritischen Ereignissen führen können.

Prinzipien des Bak-Sneppen-Modells

Ökosystem von Arten:

  • N Arten sind in einer Kette (oder auf einem Gitter) angeordnet
  • Jeder Art i wird ein Fitnesswert fi ∈ [0,1] zugewiesen
  • Fitness repräsentiert die Anpassungsfähigkeit einer Art an ihre Umgebung.

Dynamik der Evolution

Bei jedem Zeitschritt:
1. Ermittle die Art mit der geringsten Fitness: fmin = min{fi}
2. Ersetze die Fitness dieser Art und ihrer Nachbarn durch neue Zufallswerte
3. Wiederhole den Vorgang
Selbstorganisierte Kritikalität
  • Das System organisiert sich selbst in einen kritischen Zustand
  • Es stellt sich ein Schwellenwert von fc ≈ 0,67 ein
  • Arten mit einer Fitness < fc sterben in lawinenartigen Ereignissen aus
  • Lawinengrößen folgen einem Potenzgesetz

In Abwesenheit externer Steuerung organisiert sich das System selbst: Auf lange Phasen relativer Stagnation folgen plötzlich lawinenartige Veränderungen unterschiedlicher Größenordnung. Die Größen der Lawinen folgen einem Potenzgesetz: P(s) ~ s^(-τ), wobei die Lebensdauern von Arten einem Potenzgesetz in Abwesenheit einer charakteristischen Skala gehorchen. Veränderungen bei einer Art wirken sich auf benachbarte Arten aus. Globale Dynamiken entstehen aus lokalen Interaktionen.

Boettcher und Percus adaptierten die Prinzipien des Bak-Sneppen-Modells, um einen Optimierungsalgorithmus zu erstellen. Anstatt das Beste zu verbessern, verbessern wir das Schlechteste. Die Konzentration auf die schlechtesten Elemente ist kontraintuitiv, aber effektiv, um aus lokalen Optima auszubrechen. Im Bak-Sneppen-Modell erfolgt die Evolution durch ein punktuiertes Gleichgewicht – lange Perioden der Stasis, die durch plötzliche Veränderungen unterbrochen werden. EO nutzt dieses Prinzip: Wenn nur schlechte Komponenten geändert werden und das Ändern einer Komponente die Lösung drastisch verbessert, kann die Verbesserung einer Komponente andere Komponenten schlecht machen.

Extremaloptimierung wendet die Prinzipien der selbstorganisierten Kritikalität – ursprünglich in Ökosystemmodellen untersucht – auf die Optimierung an. Die entscheidende Innovation ist die Nutzung der natürlichen Tendenz komplexer Systeme zur Selbstorganisation, um die Exploration und Exploitation des Suchraums automatisch auszubalancieren. Wir werden diese Behauptung an praktischen Problemen testen. Lassen Sie uns nun den Algorithmus in Pseudocode skizzieren.

Initialisierung:

  1. Erstelle eine Population aus popSize Agenten 
  2. Initialisiere die Parameter
  3. Erstelle die Arrays für das Ranking von Agenten und Komponenten

Erster Durchlauf (Initialisierung der Population):

  1. Für jeden Agenten in der Population:
    • Für jede Komponente (Koordinaten):
      • Weise einen Zufallswert innerhalb des zulässigen Bereichs zu
      • Wende eine Diskretisierung an, falls erforderlich

Grundlegende Optimierungsschleife:

Führe für jeden Agenten in der Population aus:

  1. Agenten-Ranking:
    • Erstelle eine Liste aller Agenten mit ihrer Fitness
    • Sortiere die Agenten nach ihrer Fitness (die schlechtesten zuerst bei Maximierung)
  2. Wähle einen Zielagenten:
    • Verwende die Potenzgesetz-Verteilung P(n) ∝ n^(-τ)
    • Wähle einen Rang gemäß dieser Verteilung
    • Definiere den Agenten mit dem gewählten Rang als Zielagenten
  3. Komponenten-Ranking des Zielagenten:
    • Berechne die Fitness für jede Komponente:
      • Fitness = 1 - (normalisierte Abweichung vom besten bekannten Wert)
    • Sortiere die Komponenten nach der Fitness (die schlechtesten zuerst)
  4. Komponentenauswahl und Mutation:
    • Verwende eine Potenzgesetz-Verteilung, um den Komponentenrang zu wählen
    • Ersetze die gewählte Komponente durch einen neuen Zufallswert
    • Prüfe die Grenzen und wende eine Diskretisierung an

Ergebnisaktualisierung:

  1. Sortiere die gesamte Population nach der Fitness (die besten am Anfang)
  2. Aktualisiere die global beste Lösung, wenn eine Verbesserung gefunden wird

Implementieren wir den Algorithmus nun im Code. Wir schreiben eine Klasse, die die Implementierung des EO-Algorithmus darstellt, basierend auf der Optimierungsmethode unter Verwendung des Prinzips der Entfernung der schlechtesten Elemente, um bessere Lösungen zu finden. Die Klasse erbt von der Basisklasse C_AO und enthält zusätzlich algorithmusspezifische Parameter und Methoden. Konstruktor und Destruktor: Initialisierung der Parameter beziehungsweise Freigabe der Ressourcen. Wichtigste Parameter

  • popSize – Populationsgröße, Anzahl der Agenten in der Population;
  • tau – Potenzgesetzverteilung, die die Wahrscheinlichkeiten für die Auswahl von Elementen bestimmt;
  • greedyStart – Anteil der Agenten mit greedy-basierter Initialisierung
  • eliteUpdate – Anteil der Agenten, die pro Iteration am Update teilnehmen.
Das Parameter-Array params enthält Einstellungen und kopiert die Werte der ursprünglichen Parameter zur Integration mit der Benutzeroberfläche oder externen Steuerung. Methoden:
  • SetParams – aktuelle Parameterwerte aus dem Array extrahieren und anwenden;
  • Init – Population unter Berücksichtigung der Parameterbereiche und der Anzahl der Epochen initialisieren;
  • Moving – einen Schritt des Algorithmus ausführen und den Zustand der Population aktualisieren;
  • Revision – Bewertungen aktualisieren oder auf die nächste Stufe vorbereiten. 
Interne Strukturen:
  • RankedComponent – Struktur zum Speichern des Rankings von Agentenkomponenten nach ihrer Qualität (Fitness);
  • RankedAgent – Struktur zum Speichern des Rankings der Agenten selbst gemäß ihrer Gesamtfitness.
Interne Variablen und Parameter:
  • compRanks und agentRanks – Arrays von Strukturen zum Speichern sortierter Komponenten und Agenten;
  • tau, greedyStart, eliteUpdate steuern das Verhalten des Algorithmus
Interne Methoden:
  • ApplyExtremalOptimization – grundlegender Mechanismus zur Auswahl und Aktualisierung von Elementen basierend auf ihren Rängen unter Berücksichtigung der Potenzgesetzverteilung.
  • CalculateComponentFitness – berechnet die Fitness der Agentenkomponente.
  • SelectRankByPowerLaw – wählt den Rang einer Komponente oder eines Agenten unter Verwendung einer Potenzgesetzverteilung aus, was eine Fokussierung auf die schlechtesten Elemente ermöglicht.

Die Klasse ist für die Anwendung des Extremaloptimierungsalgorithmus vorgesehen, insbesondere bei Problemen, die die Suche nach einer qualitativ hochwertigen Lösung durch sukzessive Eliminierung der am schlechtesten angepassten Komponenten in der Population erfordern.

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

  //------------------------------------------------------------------
  ArrayResize (compRanks, coords);
  ArrayResize (agentRanks, popSize);

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

Die Initialisierungsmethode der EO-Klasse ist für die Vorbereitung der Anfangsbedingungen für den weiteren Ablauf verantwortlich. Sie akzeptiert Parameter für die minimalen und maximalen Wertebereiche der Variablen sowie Schrittweiten für deren Änderung und bei Bedarf die Anzahl der Epochen (Iterationen).

Die Methode ruft zuerst das Standard-Initialisierungsverfahren auf, das grundlegende Parameter konfiguriert und gemeinsame Datenstrukturen vorbereitet. Wenn dieses Verfahren fehlschlägt, wird die Initialisierung abgebrochen.

Wenn die Initialisierung erfolgreich ist, ändert die Methode die Größe der Arrays, die zum Speichern der rangierten Komponenten und Agenten verwendet werden. Die Größe des Komponenten-Arrays wird entsprechend der Anzahl der Koordinaten oder Variablen des Problems festgelegt, und das Array der Agenten wird entsprechend der angegebenen Populationsgröße festgelegt. Sobald diese Schritte abgeschlossen sind, gibt die Methode true zurück.

//————————————————————————————————————————————————————————————————————
//--- Main loop of the algorithm
void C_AO_EO::Moving ()
{
  // Initial population setup
  if (!revision)
  {
    int greedyCount = (int)(popSize * greedyStart);

    for (int i = 0; i < popSize; i++)
    {
      // Random initialization for the rest
      for (int c = 0; c < coords; c++)
      {
        a [i].c [c] = u.RNDfromCI (rangeMin [c], rangeMax [c]);
        a [i].c [c] = u.SeInDiSp (a [i].c [c], rangeMin [c], rangeMax [c], rangeStep [c]);
      }
    }

    revision = true;
    return;
  }

  // Apply Extremal Optimization ---------------------------------
  ApplyExtremalOptimization ();
}
//————————————————————————————————————————————————————————————————————

Die Methode ApplyExtremalOptimization implementiert die Hauptschleife des EO-Algorithmus zur Aktualisierung der Agentenpopulation. Ihr Ziel ist es, Lösungen durch Modifizierung von Agentenkomponenten basierend auf EO-Prinzipien zu verbessern. Die Anzahl der pro Iteration zu aktualisierenden Agenten wird unter Berücksichtigung des Parameters eliteUpdate (der Anteil der zu aktualisierenden Agenten) und der Populationsgröße bestimmt. Agenten werden basierend auf ihrer Fitness sortiert. Der Algorithmus ordnet Agenten vom schlechtesten zum besten, sodass der Algorithmus für eine Maximierung ausgelegt ist. Unter Verwendung einer Potenzgesetz-Wahrscheinlichkeitsverteilung wird der Agent ausgewählt, der geändert werden soll.

Für den ausgewählten Agenten werden seine Komponenten rangiert. Jeder Komponente wird ein Fitnesswert zugewiesen, um ihren Beitrag zur Agentenfitness zu bewerten. Die Komponenten werden basierend auf ihrer Fitness vom schlechtesten zum besten sortiert. Eine Potenzgesetz-Wahrscheinlichkeitsverteilung wird verwendet, um eine der Komponenten des Agenten zur Modifikation auszuwählen. Dies geschieht, um die Wahrscheinlichkeit zu erhöhen, dass Komponenten mit dem schlechtesten Rang ausgewählt werden.

Die ausgewählte Agentenkomponente wird durch einen Zufallswert innerhalb des zulässigen Bereichs ersetzt, der durch die Parameter rangeMin und rangeMax spezifiziert ist. Der resultierende Wert wird auf Gültigkeit geprüft, um sicherzustellen, dass er den spezifizierten Grenzen und Schrittweiten entspricht.

    Die Methode wiederholt diese Schritte für jeden zu aktualisierenden Agenten und implementiert die Schlüssellogik des EO-Algorithmus: Auswahl von Komponenten mit der schlechtesten Leistung und deren zufällige Ersetzung, um die Fitness der Lösungen zu verbessern.

    //————————————————————————————————————————————————————————————————————
    //--- Apply Extremal Optimization
    void C_AO_EO::ApplyExtremalOptimization ()
    {
      // Number of agents to update in this iteration
      int numUpdates = MathMax (1, (int)(popSize * eliteUpdate));
    
      // Update selected agents based on EO principle
      //for (int update = 0; update < numUpdates; update++)
      for (int update = 0; update < popSize; update++)
      {
        // Step 1: Select an agent to modify
        // Use ranking by overall fitness
        int targetAgent;
    
        // Rank agents by fitness (from worst to best for maximization)
        for (int i = 0; i < popSize; i++)
        {
          agentRanks [i].idx = i;
          agentRanks [i].fitness = a [i].f;
        }
    
        // Sort (worst first to maximize)
        for (int i = 0; i < popSize - 1; i++)
        {
          for (int j = i + 1; j < popSize; j++)
          {
            if (agentRanks [i].fitness > agentRanks [j].fitness)
            {
              RankedAgent temp = agentRanks [i];
              agentRanks [i] = agentRanks [j];
              agentRanks [j] = temp;
            }
          }
        }
    
        // Select an agent according to the power-law distribution
        int rank    = SelectRankByPowerLaw (popSize);
        targetAgent = agentRanks [rank].idx;
    
        // Step 2: Rank the components of the selected agent
        for (int c = 0; c < coords; c++)
        {
          compRanks [c].agentIdx     = targetAgent;
          compRanks [c].componentIdx = c;
          compRanks [c].fitness      = CalculateComponentFitness (targetAgent, c);
        }
    
        // Sort components (worst first)
        for (int i = 0; i < coords - 1; i++)
        {
          for (int j = i + 1; j < coords; j++)
          {
            if (compRanks [i].fitness > compRanks [j].fitness)
            {
              RankedComponent temp = compRanks [i];
              compRanks [i] = compRanks [j];
              compRanks [j] = temp;
            }
          }
        }
    
        // Step 3: Select a component to change according to P(n) ∝ n^(-τ)
        int compRank = SelectRankByPowerLaw (coords);
        int compIdx  = compRanks [compRank].componentIdx;
    
        // Step 4: Replace the selected component with a new random value
        // This is the key principle of EO - unconditional replacement with random
        a [targetAgent].c [compIdx] = u.RNDfromCI (rangeMin [compIdx], rangeMax [compIdx]);
    
        // Check boundaries
        a [targetAgent].c [compIdx] = u.SeInDiSp (a [targetAgent].c [compIdx],
                                                  rangeMin [compIdx],
                                                  rangeMax [compIdx],
                                                  rangeStep [compIdx]);
      }
    }
    //————————————————————————————————————————————————————————————————————
    

    Die Methode CalculateComponentFitness berechnet den Fitnesswert für eine einzelne Komponente des Agenten. Diese Funktion spielt eine wichtige Rolle im Extremal-Optimierungs-Algorithmus (EO) und bewertet den Beitrag jeder Komponente zur Fitness der Lösung. Der Algorithmus verwendet eine einfache Metrik, die auf der Berechnung der Fitness als relativer Beitrag einer Komponente zur Fitness basiert.

    Anfangs wird die Fitness auf null initialisiert. Als Nächstes wird der Bereich der Komponentenwerte (range) berechnet. Wenn dieser Bereich größer als null ist, wird die normalisierte Abweichung berechnet. Die Abweichung wird als Absolutwert der Differenz zwischen dem Agentenkomponentenwert und dem Basiswert von cB berechnet, normalisiert durch den Bereich der Komponentenwerte. Die Fitness wird berechnet, indem die Abweichung von 1.0 subtrahiert wird. Dies macht die Fitness umgekehrt proportional zur Abweichung: Je kleiner die Abweichung einer Komponente vom Zielwert ist, desto höher ist ihre Fitness.

    Somit gibt die Funktion einen Fitnesswert für eine bestimmte Komponente zurück, der angibt, wie gut der aktuelle Wert der Komponente mit dem Zielwert übereinstimmt, was für die weitere Rangfolge der Komponenten erforderlich ist.

    //————————————————————————————————————————————————————————————————————
    //--- Calculate the fitness component
    double C_AO_EO::CalculateComponentFitness (int agentIdx, int componentIdx)
    {
      // For the general optimization problem we use a simple metric
      // λi = relative contribution of the component to the fitness
    
      double fitness = 0.0;
    
      double range = rangeMax [componentIdx] - rangeMin [componentIdx];
      if (range > 0)
      {
        // Normalized deviation
        double deviation = MathAbs (a [agentIdx].c [componentIdx] - cB [componentIdx]) / range;
        fitness =1.0 - deviation;// Invert so that bigger = better
      }
    
      return fitness;
    }
    //————————————————————————————————————————————————————————————————————
    

    Die Methode SelectRankByPowerLaw implementiert die Auswahl der Position (Rang) eines Elements aus einer Liste basierend auf einer Wahrscheinlichkeitsverteilung nach einem Potenzgesetz. Diese Methode ist der Schlüssel zum EO-Algorithmus, da durch sie die Auswahl von Agenten und Komponenten für die Modifikation erfolgt. Die Methode nimmt maxRank als Eingabe entgegen, was den maximalen Rang des Elements definiert.

    Die Methode basiert auf dem Prinzip der inversen Transformation zur Gewinnung eines Zufallswertes gemäß dem Potenzgesetz P(n) ∝ n^(-τ), wobei n der Rang des Elements ist und τ (Tau) der Parameter, der die Form der Potenzgesetzverteilung bestimmt.

    Abhängig vom Wert des tau-Parameters werden zwei Szenarien realisiert:

    1. Allgemeiner Fall (τ ≠ 1.0):

      • ein Normalisierungsfaktor norm wird berechnet, der die korrekte Skalierung der Wahrscheinlichkeiten sicherstellt;
      • eine Zufallszahl r im Bereich [0, 1) wird unter Verwendung von u.RNDprobab() generiert;
      • die Formel der inversen Transformation wird verwendet, um den Rang basierend auf r, norm und τ zu berechnen;
      • der Rang wird auf [0, maxRank - 1] begrenzt, um Array-Indexüberschreitungen zu vermeiden.
    2. Spezialfall (τ = 1.0):

      • der Normalisierungsfaktor norm wird für den Fall τ = 1.0 berechnet;
      • eine spezielle Formel wird zur Berechnung des Rangs verwendet;
      • der Rang wird auf den Bereich [0, maxRank - 1] begrenzt.

    Als Ergebnis gibt die Methode einen ganzzahligen Rang zurück, der die ausgewählte Position des Elements in der Rangliste angibt. Diese Auswahl ist probabilistisch, das heißt, Elemente mit niedrigerem Rang (schlechter) haben eine höhere Wahrscheinlichkeit, ausgewählt zu werden, in Übereinstimmung mit den Prinzipien von EO.

    //————————————————————————————————————————————————————————————————————
    //--- Select a rank according to a power-law distribution
    int C_AO_EO::SelectRankByPowerLaw (int maxRank)
    {
      // P(n) ∝ n^(-τ), where n is a rank from 1 to maxRank
      // Use the inverse transformation method
    
      double r = u.RNDprobab ();
    
      if (tau != 1.0)
      {
        // General case: inverse transform for P(n) ∝ n^(-τ)
        double norm = (1.0 - MathPow (maxRank + 1.0, 1.0 - tau)) / (1.0 - tau);
        double x = r * norm;
        int rank = (int)MathPow ((1.0 - tau) * x + 1.0, 1.0 / (1.0 - tau)) - 1;
    
        if (rank >= maxRank) rank = maxRank - 1;
        if (rank < 0) rank = 0;
    
        return rank;
      }
      else
      {
        // Special case τ = 1: P(n) ∝ 1/n
        double norm = MathLog (maxRank + 1.0);
        int rank = (int)(MathExp (r * norm) - 1.0);
    
        if (rank >= maxRank) rank = maxRank - 1;
        if (rank < 0) rank = 0;
    
        return rank;
      }
    }
    //————————————————————————————————————————————————————————————————————
    

    Die Methode Revision dient dazu, Informationen über die besten Lösungen während der Ausführung des EO-Algorithmus zu aktualisieren. Ihre Aufgabe ist es, die aktuell beste Lösung zu bestimmen und globale Variablen zu aktualisieren, die Informationen darüber speichern. Ein temporäres Array aT wird erstellt, um die sortierten Agenten zu speichern. Die a-Population von Agenten wird mithilfe der integrierten Funktion u.Sorting sortiert. Die Sortierung erfolgt zur Maximierung, das heißt, die besten Agenten (diejenigen mit dem höchsten Wert der f-Fitnessfunktion) werden am Anfang des a-Arrays (der Hauptdatenstruktur) platziert, das Informationen über die Agenten enthält, einschließlich der Werte ihrer c-Komponenten und des Wertes der f-Fitnessfunktion.

    Nach der Sortierung wird geprüft, ob der Wert der f-Fitnessfunktion des besten Agenten (d. h. a[0]) größer ist als der aktuelle beste fB-Wert (der den Wert der Fitnessfunktion der bisher besten gefundenen Lösung speichert). Wenn der aktuell beste Agent besser ist als die global beste Lösung, werden die Werte der Komponenten des besten Agenten (a[0].c) in das cB-Array kopiert, das wahrscheinlich die Komponenten der besten Lösung speichert, und fB wird auf den Wert der Fitnessfunktion des besten Agenten (a[0].f) aktualisiert.

    Somit aktualisiert die Funktion Revision die Informationen über die beste Lösung, bewahrt deren Komponenten sowie den Wert der Fitnessfunktion und sortiert die Population so, dass die besten Lösungen immer am Anfang des Arrays verfügbar sind. 

    //————————————————————————————————————————————————————————————————————
    //--- Update the best solutions
    void C_AO_EO::Revision ()
    {
      // Sort the population for MAXIMIZATION
      static S_AO_Agent aT [];
      ArrayResize (aT, popSize);
    
      // Use the built-in sorting function
      u.Sorting (a, aT, popSize);
    
      // Update the global best solution
      if (a [0].f > fB)
      {
        ArrayCopy (cB, a [0].c, 0, 0, WHOLE_ARRAY);
        fB = a [0].f;
      }
    }
    //————————————————————————————————————————————————————————————————————
    


    Testergebnisse

    Nach dem Testen zeigte der Algorithmus keine guten Ergebnisse. Daher entschied ich mich, alle ursprünglichen Methoden zu überprüfen und eine modifizierte Version zu erstellen, die auf die Verbesserung der Konvergenz des Algorithmus abzielt.

    EO|Extremal Optimization (Boettcher-Percus)|50.0|1.4|0.5|0.3|
    =============================
    5 Hilly's; Func runs: 10000; result: 0.5146369337195529
    25 Hilly's; Func runs: 10000; result: 0.29089804555433085
    500 Hilly's; Func runs: 10000; result: 0.25192095557138877
    =============================
    5 Forest's; Func runs: 10000; result: 0.367128650332966
    25 Forest's; Func runs: 10000; result: 0.19477408852361866
    500 Forest's; Func runs: 10000; result: 0.15367465708144543
    =============================
    5 Megacity's; Func runs: 10000; result: 0.2584615384615384
    25 Megacity's; Func runs: 10000; result: 0.12707692307692314
    500 Megacity's; Func runs: 10000; result: 0.09413846153846227
    =============================
    All score: 2.25271 (25.03%)

    Nachfolgend finden Sie meine eigene Interpretation dieser Optimierungsmethode. Wir implementieren eine neue Klasse, die von der Basis-Optimierungsklasse erbt. 

    Der Konstruktor legt die Anfangsparameter des Algorithmus fest: Populationsgröße, die Anzahl der zu verbessernden schlechtesten Lösungen, die Mutationswahrscheinlichkeit sowie die Verteilungsgrade für Selektion und Mutation. Die Parameter werden zur weiteren Modifikation und Anpassung in einem Array von Strukturen gespeichert.

    Die Methode SetParams aktualisiert die internen Variablen der Klasse basierend auf den Werten im Parameter-Array. Es werden Methoden deklariert, um den Algorithmus zu initialisieren, Bewegungsschritte auszuführen (Aktualisierung des Zustands) und eine Revision durchzuführen (Neubewertung von Lösungen oder Vorbereitung der nächsten Iteration). Der private Teil der Klasse speichert Variablen für die aktuelle Epoche und die Gesamtzahl der Epochen der Algorithmusausführung. Es wird eine Methode zur Mutation einer spezifischen Komponente einer Lösung in einer Population definiert, was einen wesentlichen Teil des implementierten Algorithmus darstellt. 

    //————————————————————————————————————————————————————————————————————
    class C_AO_EOm : public C_AO
    {
      public: //----------------------------------------------------------
      ~C_AO_EOm () { }
      C_AO_EOm ()
      {
        ao_name = "EOm";
        ao_desc = "Extremal Optimization M";
        ao_link = "https://www.mql5.com/en/articles/18755";
    
        popSize        = 50;      // Population size
        popRaising     = 3;       // Boost the worst agents
        mutationRate   = 0.1;     // Mutation probability
        powCh          = 2.0;     // Selection power-law exponent
        powMut         = 8.0;     // Mutation power-law exponent 
    
        ArrayResize (params, 5);
    
        params [0].name = "popSize";        params [0].val = popSize;
        params [1].name = "popRaising";     params [1].val = popRaising;
        params [2].name = "mutationRate";   params [2].val = mutationRate;
        params [3].name = "powCh";          params [3].val = powCh;
        params [4].name = "powMut";         params [4].val = powMut;
      }
    
      void SetParams ()
      {
        popSize        = (int)params [0].val;
        popRaising     = (int)params [1].val;
        mutationRate   = params      [2].val;
        powCh          = params      [3].val;
        powMut         = params      [4].val;
      }
    
      bool Init (const double &rangeMinP  [],
                 const double &rangeMaxP  [],
                 const double &rangeStepP [],
                 const int     epochsP = 0);
    
      void Moving   ();
      void Revision ();
    
      //------------------------------------------------------------------
      int    popRaising;       // Boost the worst agents
      double mutationRate;     // Mutation probability
      double powCh;            // Selection power-law exponent
      double powMut;           // Mutation power-law exponent
    
      private: //---------------------------------------------------------
      int    currentEpoch;     // current epoch
      int    totalEpochs;      // total number of epochs
    
      void MutateComponent (int agentIdx, int componentIdx);
    };
    //————————————————————————————————————————————————————————————————————
    

    Die Methode Init ist für die Initialisierung des Algorithmus zuständig. Die Funktion nimmt als Eingabe Arrays mit Minimal- und Maximalwerten sowie die Schrittweite für Optimierungsparameter entgegen, ebenso wie die Gesamtzahl der Epochen (Zyklen) des Algorithmusbetriebs.

    Innerhalb der Methode wird zuerst die Funktion StandardInit aus der Basisklasse C_AO aufgerufen. Diese Funktion führt eine allgemeine Initialisierung, Speicherzuweisung oder die Einrichtung grundlegender Parameter in Bezug auf Bereiche und Schritte für Optimierungsparameter durch.

    Wenn StandardInit fehlschlägt, wird auch die Funktion Init beendet und gibt false zurück. Wenn StandardInit erfolgreich ist, initialisiert die Methode die Variablen currentEpoch (aktuelle Epoche) auf 0 und totalEpochs (Gesamtzahl der Epochen) auf den im Parameter epochsP erhaltenen Wert.

    Am Ende gibt die Methode true zurück, was eine erfolgreiche Initialisierung signalisiert. Somit bereitet die Methode den Algorithmus durch das Festlegen der Anfangsparameter und des Epochenzählers auf den Einsatz vor.

    //————————————————————————————————————————————————————————————————————
    //--- Initialization
    bool C_AO_EOm::Init (const double &rangeMinP  [],
                         const double &rangeMaxP  [],
                         const double &rangeStepP [],
                         const int epochsP = 0)
    {
      if (!StandardInit (rangeMinP, rangeMaxP, rangeStepP)) return false;
    
      //------------------------------------------------------------------
      currentEpoch = 0;
      totalEpochs  = epochsP;
    
      return true;
    }
    //————————————————————————————————————————————————————————————————————
    

    Die Methode Moving stellt den Hauptzyklus des extremalen Optimierungsalgorithmus dar. Sie ist für die Evolution der Lösungspopulation bei der Suche nach der optimalen Lösung verantwortlich. Epochen-Inkrement: der Zähler currentEpoch wird inkrementiert. Populationsinitialisierung (nur erste Epoche): Wenn das Flag revision (das die Notwendigkeit einer Neubewertung der Lösungen anzeigt) gleich false ist (d. h. im ersten Zyklus des Algorithmus), wird die Population initialisiert.

    Für jeden Agenten (Lösung) in der Population wird für jede Koordinate (Lösungsparameter) ein Zufallswert in einem gegebenen Bereich (rangeMin, rangeMax) für die aktuelle Koordinate generiert. Die SeInDiSp-Diskretisierung wird verwendet, um sicherzustellen, dass die Parameterwerte den angegebenen Schritten entsprechen. Nach der Initialisierung wird revision auf true gesetzt, sodass dieser Codeblock nur einmal ausgeführt wird. Die Methode wird beendet. 

    Anwendung der extremalen Optimierung in nachfolgenden Epochen: ein temporäres Array aT wird erstellt, um neue (mutierte) Lösungen zu speichern. Für jeden Agenten in der Population wird die Struktur aT[i] initialisiert. Für jede Lösungskoordinate wird eine Zufallszahl generiert und mit der Potenz powCh potenziert. Dies wird verwendet, um den Ausgangsagenten auszuwählen.

    Die Zufallszahl wird skaliert, um den Elternindex in der Population ind auszuwählen. Der Mutationstyp wird bestimmt: Wenn die Zufallszahl kleiner als mutationRate ist (die Mutation wird mit der Wahrscheinlichkeit mutationRate aktiviert), dann wird die Mutation gemäß dem Potenzgesetz PowerDistribution auf den Wert der Elternkoordinate angewendet. Andernfalls erfolgt eine gerichtete Bewegung in Richtung der besten Lösung unter Hinzufügung von Zufallsrauschen. Der neue Wert wird als Summe aus dem Wert der Elternkoordinate, einer Zufallszahl und der Differenz zwischen cB[c] (der gefundenen besten Koordinate) und der Elternkoordinate berechnet. Die SeInDiSp-Diskretisierung wird verwendet. Nach der Mutation werden alle Koordinaten aus dem temporären Array aT in das Hauptpopulations-Array a kopiert.

    Somit implementiert die Methode einen Evolutionszyklus, bei dem die Lösungen in jedem Schritt (Epoche) mutieren (sich ändern), wobei Mechanismen der Selektion, der zufälligen Mutation und der gerichteten Suche verwendet werden, mit dem Ziel, ihre Werte zu verbessern (Minimierung oder Maximierung der Zielfunktion), um letztendlich die optimale Lösung zu finden.

    //————————————————————————————————————————————————————————————————————
    //--- Main loop of the algorithm
    void C_AO_EOm::Moving ()
    {
      currentEpoch++;
    
      // Initial population setup
      if (!revision)
      {
        for (int i = 0; i < popSize; i++)
        {
          for (int c = 0; c < coords; c++)
          {
            a [i].c [c] = u.RNDfromCI (rangeMin [c], rangeMax [c]);
            a [i].c [c] = u.SeInDiSp (a [i].c [c], rangeMin [c], rangeMax [c], rangeStep [c]);
          }
        }
    
        revision = true;
        return;
      }
    
      //Apply Extremal Optimization---------------------------------------
      static S_AO_Agent aT []; ArrayResize (aT, popSize);
    
      for (int i = 0; i < popSize; i++)
      {
        aT [i].Init (coords);
    
        for (int c = 0; c < coords; c++)
        {
          double rnd = u.RNDprobab (); rnd = pow (rnd, powCh);
          int ind = (int)u.Scale (rnd, 0.0, 1.0, 0, popSize - 1);
    
          // Select the mutation type
          double mutType = u.RNDprobab ();
    
          if (mutType < mutationRate)
          {
            aT [i].c [c] = u.PowerDistribution (a [ind].c [c], rangeMin [c], rangeMax [c], powMut);
          }
          else
          {
            // Directed movement towards the better with noise
            aT [i].c [c] = a [ind].c [c] + u.RNDprobab () * (cB [c] - a [ind].c [c]);
          }
    
          // Check boundaries
          aT [i].c [c] = u.SeInDiSp (aT [i].c [c], rangeMin [c], rangeMax [c], rangeStep [c]);
        }
      }
    
      for (int i = 0; i < popSize; i++) ArrayCopy (a [i].c, aT [i].c);
    }
    //————————————————————————————————————————————————————————————————————
    

    Die Methode ist für die Aktualisierung von Informationen über die besten Lösungen während des Betriebs des Algorithmus verantwortlich. 

    Sortierung der Population: Ein temporäres Array aT wird erstellt, um eine Kopie der Population zu speichern. Die Population a wird nach dem Wert der Zielfunktion sortiert. Die Methode u.Sorting wird für die Sortierung verwendet. 

    Aktualisierung der global besten Lösung: Es wird geprüft, ob der Wert der Zielfunktion f des ersten Elements der Population (d. h. der besten Lösung) besser ist als der aktuelle globale Bestwert fB. Wenn die aktuelle Lösung besser ist, wird cB aus den Koordinaten des ersten Elements a[0].c kopiert und fB mit dem Wert f der besseren Lösung aktualisiert. 

    Aktualisierung der schlechtesten Lösung: fW wird mit dem Funktionswert des letzten Elements der Population aktualisiert. 

    Anheben der schlechtesten Lösungen: In einer Schleife, die popRaising-mal ausgeführt wird, werden die schlechtesten Lösungen in der Population angehoben: Für die popRaising schlechtesten Agenten (die sich am Ende des sortierten Arrays a befinden) wird der Wert der Zielfunktion f als Zufallswert neu berechnet, der zwischen fW (dem schlechtesten aktuellen Ergebnis) und fB (dem besten aktuellen Ergebnis) liegt. Dies geschieht, um Vielfalt einzuführen oder die schlechtesten Lösungen in Richtung der besseren zu verschieben. 

    Neusortierung der Population: Die Population a wird mithilfe der Methode u.Sorting neu sortiert. Dies ist notwendig, um die Population nach Änderungen der f-Werte wieder in Ordnung zu bringen.

    //————————————————————————————————————————————————————————————————————
    //--- Update the best solutions
    void C_AO_EOm::Revision ()
    {
      // Sort the population  --------------------------------------------
      static S_AO_Agent aT []; ArrayResize (aT, popSize);
      u.Sorting (a, aT, popSize);
    
      // Update the global best solution
      if (a [0].f > fB)
      {
        ArrayCopy (cB, a [0].c, 0, 0, WHOLE_ARRAY);
        fB = a [0].f;
      }
    
      fW = a [popSize - 1].f;
    
      //------------------------------------------------------------------
      for (int i = 0; i < popRaising; i++)
      {
        a [popSize - 1 - i].f = u.RNDfromCI (fW, fB);
      }
    
      u.Sorting (a, aT, popSize);
    }
    //————————————————————————————————————————————————————————————————————
    

    Nun verwendet der Algorithmus (der in gewissem Sinne die Ideen von EO erbt, wenn auch auf modifizierte Weise) eine Potenzverteilung, um Ausgangslösungen auszuwählen (nicht notwendigerweise schlechte).

    a [popSize - 1 - i].f = u.RNDfromCI (fW, fB);

    Ich habe eine Funktion hinzugefügt, die in EO-Beschreibungen nicht vorkommt: Der Algorithmus gibt den schlechtesten Agenten gewissermaßen neues Potenzial, indem er ihnen eine zufällige Fitness im Bereich vom schlechtesten bis zum besten Wert in der Population zuweist. PowerDistribution für Mutation ist eine Interpretation der Power-Law-Distributionsmutation. Gezielte Bewegung in Richtung des Besseren (für mutType >= mutationRate ) – Ergänzung zur Beschleunigung der Konvergenz.

    Nun können wir uns die Ergebnisse der modifizierten Version ansehen. Wir können die folgenden Ergebnisse in unsere Bewertungstabelle aufnehmen.

    EOm|Extremal Optimization Mod|50.0|3.0|0.1|2.0|8.0|
    =============================
    5 Hilly's; Func runs: 10000; result: 0.7616651321732368
    25 Hilly's; Func runs: 10000; result: 0.7724295992586084
    500 Hilly's; Func runs: 10000; result: 0.3174703398632668
    =============================
    5 Forest's; Func runs: 10000; result: 0.9999936711143977
    25 Forest's; Func runs: 10000; result: 0.7675163269928252
    500 Forest's; Func runs: 10000; result: 0.23527203643380376
    =============================
    5 Megacity's; Func runs: 10000; result: 0.7476923076923077
    25 Megacity's; Func runs: 10000; result: 0.5396923076923076
    500 Megacity's; Func runs: 10000; result: 0.14249230769230903
    =============================
    All score: 5.28422 (58.71%)

    Die Visualisierung zeigt eine große Streuung der Ergebnisse für niedrigdimensionale Funktionen (grüne Linien).

    Hilly

    EOm mit der Testfunktion Hilly

    Forest

    EOm mit der Testfunktion Forest

    Megacity

    EOm mit der Testfunktion Megacity

    Nach dem Test belegt der EOm-Algorithmus den 12. Platz in unserer Rangliste.

    # AO Beschreibung 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)
    1ANSSuche über die gesamte Nachbarschaft0.949480.847760.438572.235811.000000.923340.399882.323230.709230.634770.230911.574916.13468.15
    2CLACode-Lock-Algorithmus (joo)0.953450.871070.375902.200420.989420.917090.316422.222940.796920.693850.193031.683806.10767.86
    3AMOmOptimierung der Tiermigration M0.903580.843170.462842.209590.990010.924360.465982.380340.567690.591320.237731.396755.98766.52
    4(P+O)ES(P+O) Evolutionsstrategien0.922560.881010.400212.203790.977500.874900.319452.171850.673850.629850.186341.490035.86665.17
    5CTAKometenschweif-Algorithmus (joo)0.953460.863190.277702.094350.997940.857400.339492.194840.887690.564310.105121.557125.84664.96
    6TETAZeit-Evolutions-Reise-Algorithmus (Joo)0.913620.823490.319902.057010.970960.895320.293242.159520.734620.685690.160211.580525.79764.41
    7SDSmstochastische Diffusionssuche M0.930660.854450.394762.179880.999830.892440.196192.088460.723330.611000.106701.441035.70963.44
    8BOAmBillard-Optimierungsalgorithmus M0.957570.825990.252352.035901.000000.900360.305022.205380.735380.525230.095631.356255.59862.19
    9AAmAlgorithmus für das Bogenschießen M0.917440.708760.421602.047800.925270.758020.353282.036570.673850.552000.237381.463235.54861.64
    10ESGEntwicklung sozialer Gruppen (joo)0.999060.796540.350562.146161.000000.828630.131021.959650.823330.553000.047251.423585.52961.44
    11SIASimuliertes isotropes Glühen (Joo)0.957840.842640.414652.215130.982390.795860.205071.983320.686670.493000.090531.270205.46960.76
    12EOmextremal_optimization_M0.761660.772420.317471.851550.999990.767510.235272.002770.747690.539690.142491.429875.28458.71
    13BBObiogeografisch basierte Optimierung0.949120.694560.350311.993990.938200.673650.256821.868670.746150.482770.173691.402615.26558.50
    14ACSkünstliche, kooperative Suche0.755470.747440.304071.806981.000000.888610.224132.112740.690770.481850.133221.305835.22658.06
    15DAdialektischer Algorithmus0.861830.700330.337241.899400.981630.727720.287181.996530.703080.452920.163671.319675.21657.95
    16BHAmAlgorithmus für schwarze Löcher M0.752360.766750.345831.864930.935930.801520.271772.009230.650770.516460.154721.321955.19657.73
    17ASOAnarchische Gesellschaftsoptimierung0.848720.746460.314651.909830.961480.791500.238031.991010.570770.540620.166141.277525.17857.54
    18RFOOptimierung des Royal Flush (joo)0.833610.737420.346291.917330.894240.738240.240981.873460.631540.502920.164211.298675.08956.55
    19AOSmSuche nach atomaren Orbitalen M0.802320.704490.310211.817020.856600.694510.219961.771070.746150.528620.143581.418355.00655.63
    20TSEASchildkrötenpanzer-Evolutionsalgorithmus (joo)0.967980.644800.296721.909490.994490.619810.227081.841390.690770.426460.135981.253225.00455.60
    21BSABacktracking-Suchalgorithmus0.973090.545340.290981.809410.999990.585430.217471.802890.847690.369530.129781.347004.95955.10
    22DEdifferentielle Evolution0.950440.616740.303081.870260.953170.788960.166521.908650.786670.360330.029531.176534.95555.06
    23SRAAlgorithmus für erfolgreiche Gastronomen (joo)0.968830.634550.292171.895550.946370.555060.191241.692670.749230.440310.125261.314804.90354.48
    24CROOptimierung chemischer Reaktionen0.946290.661120.298531.905930.879060.584220.211461.674730.758460.426460.126861.311784.89254.36
    25BIOOptimierung der Blutvererbung (joo)0.815680.653360.308771.777810.899370.653190.217601.770160.678460.476310.139021.293784.84253.80
    26BSAVogelschwarm-Algorithmus0.893060.649000.262501.804550.924200.711210.249391.884790.693850.326150.100121.120124.80953.44
    27DEAAlgorithmus zur Echoortung bei Delfinen0.759950.675720.341711.777380.895820.642230.239411.777460.615380.440310.151151.206844.76252.91
    28HSHarmoniesuche0.865090.687820.325271.878180.999990.680020.095901.775920.620000.422670.054581.097254.75152.79
    29SSGSetzen, Säen und Wachsen0.778390.649250.395431.823080.859730.624670.174291.658690.646670.441330.105981.193984.67651.95
    30BCOmOptimierung mit der bakteriellen Chemotaxis M0.759530.622680.314831.697040.893780.613390.225421.732590.653850.420920.144351.219124.64951.65
    31ABOOptimierung des afrikanischen Büffels0.833370.622470.299641.755480.921700.586180.197231.705110.610000.431540.132251.173784.63451.49
    32(PO)ES(PO) Evolutionsstrategien0.790250.626470.429351.846060.876160.609430.195911.681510.590000.379330.113221.082554.61051.22
    33FBAFraktal-basierter Algorithmus0.790000.651340.289651.730990.871580.568230.188771.628580.610770.460620.123981.195374.55550.61
    34TSmTabu-Suche M0.877950.614310.291041.783300.928850.518440.190541.637830.610770.382150.121571.114494.53650.40
    35BSOBrainstorming-Optimierung0.937360.576160.296881.810410.931310.558660.235371.725340.552310.290770.119140.962224.49849.98
    36WOAmWal-Optimierungsalgorithmus M0.845210.562980.262631.670810.931000.522780.163651.617430.663080.411380.113571.188034.47649.74
    37AEFAAlgorithmus für künstliche elektrische Felder0.877000.617530.252351.746880.927290.726980.180641.834900.666150.116310.095080.877544.45949.55
    38AEOAlgorithmus zur Optimierung auf der Grundlage künstlicher Ökosysteme0.913800.467130.264701.645630.902230.437050.214001.553270.661540.308000.285631.255174.45449.49
    39CAmKamel-Algorithmus M0.786840.560420.351331.698590.827720.560410.243361.631490.648460.330920.134181.113564.44449.37
    40ACOmAmeisen-Kolonie-Optimierung M0.881900.661270.303771.846930.858730.586800.150511.596040.596670.373330.024720.994724.43849.31
    41CMAESAnpassung der Kovarianzmatrix mittels Evolutionsstrategie0.762580.720890.000001.483470.820560.796160.000001.616720.758460.490770.000001.249234.34948.33
    42BFO-GAOptimierung der bakteriellen Futtersuche – ga0.891500.551110.315291.757900.969820.396120.063051.428990.726670.275000.035251.036924.22446.93
    43SOAeinfacher Optimierungsalgorithmus0.915200.469760.270891.655850.896750.374010.169841.440600.695380.280310.108521.084224.18146.45
    44ABHAAlgorithmus für künstliche Bienenstöcke0.841310.542270.263041.646630.878580.477790.171811.528180.509230.338770.103970.951974.12745.85
    45ACMOOptimierung atmosphärischer Wolkenmodelle0.903210.485460.304031.692700.802680.378570.191781.373030.623080.244000.107950.975034.04144.90
    RWRandom Walk0.487540.321590.257811.066940.375540.219440.158770.753750.279690.149170.098470.527342.34826.09


    Zusammenfassung

    Die vorgestellte kompakte modifizierte Implementierung von EOm zeigt ein interessantes Beispiel auf dem Gebiet der metaheuristischen Optimierung: eine signifikante Abweichung von theoretischen Prinzipien kann zu verbesserten praktischen Ergebnissen führen. Der Algorithmus, der unter 45 populationsbasierten Methoden den 12. Platz belegte, ist eigentlich ein Hybrid, der nur die Kernidee der Potenzgesetzverteilung aus dem ursprünglichen EO beibehält. 

    Der Auferstehungs-Mechanismus der schlechtesten Agenten verhindert eine vorzeitige Konvergenz, erhält die Populationsvielfalt aufrecht und schafft zusätzliche Möglichkeiten zur Exploration. Vereinfachung der Berechnungsstruktur: Der Verzicht auf eine komponentenweise Auswertung reduziert die Rechenkomplexität, und das direkte Arbeiten mit Lösungen beschleunigt die Konvergenz.

    Der Erfolg der modifizierten Version von EO bestätigt ein wichtiges Prinzip beim Entwurf von Metaheuristiken: die Effizienz eines Algorithmus wird nicht durch seine Treue zur ursprünglichen Idee bestimmt, sondern durch das Gleichgewicht zwischen Exploration und Exploitation des Suchraums. Die vorgestellte Implementierung zeigt trotz ihrer Abkehr von den klassischen Prinzipien der Extremaloptimierung eine hohe Konvergenzgeschwindigkeit, wettbewerbsfähige Ergebnisse sowie eine einfache Implementierung und Konfiguration.

    Dies macht EOm zu einem nützlichen Werkzeug im Arsenal der Populationsoptimierungsmethoden, insbesondere für Probleme, bei denen das Gleichgewicht zwischen Lösungsqualität und Rechenaufwand wichtig ist.

    Tabelle

    Abbildung 1. Farbskala der Algorithmen nach den entsprechenden Tests

    Tabelle

    Abbildung 2. Histogramm der Algorithmus-Testergebnisse (Skala von 0 bis 100, je höher, desto besser, wobei 100 das maximal mögliche theoretische Ergebnis ist; im Archiv befindet sich ein Skript zur Berechnung der Bewertungstabelle)

    Vor- und Nachteile von EOm:

    Vorteile:

    1. Einfache Umsetzung
    2. Schnell und effizient
    3. Gute Ergebnisse bei diskreten Problemen

    Nachteile:

    1. Große Streuung der Ergebnisse bei niedrigdimensionalen Funktionen
    2. Durchschnittliche Ergebnisse bei glatten niedrigdimensionalen Problemen

    Dem Artikel ist ein Archiv mit den aktuellen Versionen der Algorithmuscodes beigefügt. Der Autor des Artikels übernimmt keine Verantwortung für die absolute Richtigkeit der Beschreibung der kanonischen Algorithmen. An vielen von ihnen wurden Änderungen vorgenommen, um die Suchmöglichkeiten zu verbessern. Die in den Artikeln dargelegten Schlussfolgerungen und Urteile beruhen auf den Ergebnissen der Experimente.


    Im Artikel verwendete Programme

    #NameTypBeschreibung
    1#C_AO.mqh
    Include
    Übergeordnete Klasse von Populationsoptimierungsalgorithmen
    2#C_AO_enum.mqh
    Include
    Enumeration der Algorithmen zur Populationsoptimierung
    3TestFunctions.mqh
    Include
    Bibliothek mit Testfunktionen
    4
    TestStandFunctions.mqh
    Include
    Bibliothek mit Funktionen für die Testumgebung
    5
    Utilities.mqh
    Include
    Bibliothek mit Hilfsfunktionen
    6
    CalculationTestResults.mqh
    Include
    Skript zur Berechnung der Ergebnisse in der Vergleichstabelle
    7
    Testing AOs.mq5
    SkriptDie einheitliche Testumgebung für alle Algorithmen zur Populationsoptimierung
    8
    Simple use of population optimization algorithms.mq5
    Skript
    Ein einfaches Beispiel für die Verwendung von Algorithmen zur Populationsoptimierung ohne Visualisierung
    9
    Test_AO_EOm.mq5
    SkriptEOm-Testumgebung

    Übersetzt aus dem Russischen von MetaQuotes Ltd.
    Originalartikel: https://www.mql5.com/ru/articles/18755

    Beigefügte Dateien |
    EOm.zip (247.28 KB)
    Die Übertragung der Trading-Signale in einem universalen Expert Advisor. Die Übertragung der Trading-Signale in einem universalen Expert Advisor.
    In diesem Artikel wurden die verschiedenen Möglichkeiten beschrieben, um die Trading-Signale von einem Signalmodul des universalen EAs zum Steuermodul der Positionen und Orders zu übertragen. Es wurden die seriellen und parallelen Interfaces betrachtet.
    Neuronale Netze im Trading: Skill-Hierarchie für das Verhalten adaptiver Agenten (letzter Teil) Neuronale Netze im Trading: Skill-Hierarchie für das Verhalten adaptiver Agenten (letzter Teil)
    Der Artikel erörtert die praktische Implementierung des HiSSD-Frameworks bei algorithmischen Handelsaufgaben. Er erklärt, wie die Skill-Hierarchie und die adaptive Architektur genutzt werden können, um stabile Handelsstrategien aufzubauen.
    Eine alternative Log-datei mit der Verwendung der HTML und CSS Eine alternative Log-datei mit der Verwendung der HTML und CSS
    In diesem Artikel werden wir eine sehr einfache, aber leistungsfähige Bibliothek zur Erstellung der HTML-Dateien schreiben, dabei lernen wir auch, wie man eine ihre Darstellung einstellen kann (nach seinem Geschmack) und sehen wir, wie man es leicht in seinem Expert Advisor oder Skript hinzufügen oder verwenden kann.
    Benutzerdefinierte Symbole in MQL5: Erstellung eines 3D-Bar-Symbols Benutzerdefinierte Symbole in MQL5: Erstellung eines 3D-Bar-Symbols
    Der Artikel bietet eine detaillierte Anleitung zur Erstellung des innovativen Indikators 3DBarCustomSymbol.mq5, der benutzerdefinierte Symbole in MetaTrader 5 generiert, die Kurs, Zeit, Volumen und Volatilität in einer einzigen dreidimensionalen Darstellung kombinieren. Die mathematischen Grundlagen, die Systemarchitektur, praktische Aspekte der Implementierung und die Anwendung in Handelsstrategien werden behandelt.