English Русский 中文 Español 日本語 Português
preview
Duellanten-Algorithmus

Duellanten-Algorithmus

MetaTrader 5 — Handel |
19 2
Andrey Dik
Andrey Dik

Inhaltsverzeichnis

  1. Einleitung
  2. Implementierung des Algorithmus
  3. Testergebnisse


Einleitung

Beim algorithmischen Handel entscheidet jede Millisekunde über Gewinn oder Verlust, weshalb die Ermittlung der optimalen Parameter für eine Handelsstrategie von entscheidender Bedeutung ist. Moderne Trader setzen auf künstliche Intelligenz und evolutionäre Algorithmen, um ihre Handelssysteme fein abzustimmen.

Heute betrachten wir einen neuen Optimierungsansatz – den Duellanten-Algorithmus –, der von der jahrhundertealten Praxis des Duellierens inspiriert ist. Den Algorithmus entwickelte 2015 eine Gruppe indonesischer Wissenschaftler unter der Leitung von Biyanto als Alternative zu traditionellen evolutionären Algorithmen. Ziel war es, den „blinden“ Charakter der Operatoren für Mutation und Kreuzung durch einen differenzierten Umgang mit Siegern und Verlierern zu minimieren. In diesem Artikel werden wir die mathematischen Grundlagen des Duellanten-Algorithmus im Detail untersuchen, ihn in MQL5 implementieren und eine vergleichende Analyse mit anderen populationsbasierten Optimierungsmethoden durchführen.


Implementierung des Algorithmus

Stellen Sie sich das Börsenparkett als Arena vor, in der verschiedene Strategien ständig miteinander konkurrieren. Manche Strategien sind unter bestimmten Marktbedingungen erfolgreich, während andere scheitern. Aber was macht einen erfolgreichen Trader aus? Die Fähigkeit, sowohl aus den eigenen Erfolgen als auch aus den eigenen Niederlagen zu lernen und die eigene Vorgehensweise ständig anzupassen und zu verfeinern.

Genau dieses Konzept verkörpert der Duellanten-Algorithmus. Im Gegensatz zu klassischen genetischen Algorithmen, bei denen alle Individuen gleich behandelt werden, erkennt der Duellanten-Algorithmus einen grundlegenden Unterschied zwischen Siegern und Verlierern. Verlierer lernen – sie analysieren die Strategien der Sieger und übernehmen deren erfolgreiche Elemente, während Sieger innovieren – sie experimentieren mit neuen Ansätzen, wohl wissend, dass sich ihre Kernstrategie bereits als effizient erwiesen hat. Champions agieren als Mentoren – die besten Strategien werden weitergegeben.

Abbildung

Abbildung 1. Der DA_duelist-Algorithmus in Aktion

Die Darstellung der wichtigsten Phasen des Algorithmus veranschaulicht alle wesentlichen Aspekte des Duellanten-Algorithmus: die Ausgangspopulation – alle Duellanten starten mit gleichen Chancen; die Bestimmung der Champions – die besten Duellanten werden goldfarben hervorgehoben. Duelle – der Ablauf eines Duells mit der Bestimmung eines Siegers und eines Verlierers wird dargestellt. Lernen und Innovation – zwei unterschiedliche Entwicklungswege für Verlierer und Sieger. Training neuer Duellanten, bei dem Champions ihre Fähigkeiten an die nächste Generation weitergeben, sowie Auslese – die schlechtesten Duellanten werden aus der Population entfernt.

Die Abbildung enthält außerdem einen Schleifenpfeil, der den iterativen Charakter des Algorithmus verdeutlicht, das Endergebnis, bei dem der Champion hervorgehoben ist, sowie eine detaillierte Legende, in der alle Elemente und wichtigen Parameter erläutert werden. Die Visualisierung hilft dem Leser, den Kerngedanken des Algorithmus schnell zu erfassen.

Nachdem wir nun eine detaillierte Analyse durchgeführt haben, wollen wir den Pseudocode für den Algorithmus schreiben.

EINGABEN:
- popSize: Größe der Duellantenpopulation
- luckCoefficient: Glückskoeffizient bei Duellen
- learningProbability: Wahrscheinlichkeit, mit der der Verlierer lernt
- innovationProbability: Wahrscheinlichkeit einer Innovation durch den Sieger
- championsCount: Anzahl der Champions

INITIALISIERUNG:
1. Überprüfe championsCount und passe den Wert an:
– Falls < 1, setze den Wert auf 1
– Falls >= popSize, setze den Wert auf popSize / 4
2. Erstelle leere Arrays „winners“ und „losers“
3. Erstelle ein Array namens „champions“ der Größe championsCount

HAUPTZYKLUS (Moving):

WENN erste Iteration:
FÜR jeden Duellanten i von 0 bis popSize:
FÜR jede Koordinate j:
Mit einem Zufallswert innerhalb der zulässigen Grenzen initialisieren
Setze das Flag „revision“ auf true
Beende die Funktion

SONST (nachfolgende Iterationen):
1. ERWEITERUNG DER POPULATION:
– Vergrößere das Array „duelists“ auf die Größe (popSize + championsCount)
– Initialisiere die Strukturen der neuen Duellanten

2. BESTIMMUNG DER CHAMPIONS:
– Sortiere die Duellanten nach Fitness-Wert (Bubble-Sort)
– Die ersten championsCount Duellanten werden zu Champions

3. TRAINING NEUER DUELLANTEN:
FÜR jeden Champion i:
Rufe TrainNewDuelist (i, popSize + i) auf:
FÜR jede Koordinate c:
new_duelist [c] = champion [c] + GaussDistribution ()
Wende die Beschränkungen des Wertebereichs an

4. DURCHFÜHRUNG DER DUELLE:
Leere die Arrays „winners“ und „losers“
FÜR jeden Duellanten i von championsCount bis totalDuelists:
Wähle einen zufälligen „opponent“ aus
WENN opponent != i:
DetermineWinnerAndLoser(i, opponent):
A_Luck = fitness [A] * (luckCoef + random () * luckCoef)
B_Luck = fitness [B] * (luckCoef + random () * luckCoef)
WENN (fitness [A] + A_Luck) >= (fitness [B] + B_Luck):
A – Sieger, B – Verlierer
ANDERNFALLS:
B – Sieger, A – Verlierer
Füge die Sieger und Verlierer den Arrays hinzu

5. VERBESSERUNG:
a) Lernphase für Verlierer:
FÜR jedes Paar (Verlierer, Sieger):
LearningProcess (Verlierer, Sieger):
FÜR jede Koordinate c:
WENN random () &lt; learningProbability:
Verlierer [c] = Sieger [c]

b) Innovationen der Sieger:
FÜR jeden Sieger:
InnovationProcess (Sieger):
FÜR jede Koordinate c:
WENN random () &lt; innovationProbability:
Sieger [c] = random_value_in_range

6. ELIMINIERUNG:
– Alle Duellanten in absteigender Reihenfolge nach „Fitness“ sortieren
– Nur die ersten popSize Duellanten behalten

AKTUALISIERUNG (Revision):
FÜR jeden Duellanten i:
WENN fitness [i] &gt; global_best:
Aktualisiere global_best = fitness [i]
Speichere die Koordinaten der besten Lösung

WIEDERHOLE die Hauptschleife, bis das Abbruchkriterium erreicht ist

Ich möchte die wichtigsten Merkmale dieses Algorithmus hervorheben: Champions nehmen nicht an Duellen teil, sondern trainieren neue Duellanten, und das Element der Zufälligkeit in Form des Glückskoeffizienten macht Duelle unvorhersehbar. Ein differenzierter Ansatz: Verlierer lernen, und Sieger suchen nach innovativen Lösungen. Die Populationsgröße bleibt durch die Eliminierung der leistungsschwächsten Duellanten konstant. Nun können wir zur Implementierung des Codes des DA_duelist-Algorithmus übergehen.

Schreiben wir die Klasse „C_AO_DA_duelist“, die von der Klasse „C_AO“ erbt, ein Parameterarray initialisiert und dessen Elementen Namen und Standardwerte zuweist.

  • SetParams () — ändert die Werte interner Variablen (popSize, luckCoefficient usw.) basierend auf den im Array „params“ gespeicherten Werten.
  • Init () — Methode zur Initialisierung des Algorithmus . Die Methode akzeptiert Arrays zur Definition von Wertebereichen und Schrittweiten für Parameter sowie die Anzahl der Epochen.
  • Moving () — eine Methode, die die Hauptlogik für die Entwicklung der „Duellanten“ enthält (Suche nach optimalen Parametern).
  • Revision () — zuständig für die Analyse der Ergebnisse und die Anpassung des Prozesses.

Variablen:

  • luckCoefficient — Glückskoeffizient;
  • learningProbability — Lernwahrscheinlichkeit;
  • innovationProbability — Innovationswahrscheinlichkeit;
  • championsCount — Anzahl der Champions;
  • winners [] — Array mit den Indizes der siegreichen „Duellanten“;
  • losers [] — Array mit den Indizes der „Verlierer“-Duellanten;
  • champions [] — Array mit den Indizes der „Champions“.
Private Methoden:
  • Die Funktion „DetermineWinnerAndLoser()“ ermittelt den Sieger und den Verlierer eines „Duells“;
  • LearningProcess () implementiert den Lernprozess für den Verlierer mithilfe des Siegers;
  • InnovationProcess () implementiert den Innovationsprozess für den Sieger;
  • TrainNewDuelist () trainiert einen neuen „Duellanten“ auf Grundlage des Champions.
//————————————————————————————————————————————————————————————————————
class C_AO_DA_duelist : public C_AO
{
  public: //----------------------------------------------------------
  ~C_AO_DA_duelist () { }
  C_AO_DA_duelist ()
  {
    ao_name = "DA";
    ao_desc = "Duelist Algorithm";
    ao_link = "https://www.mql5.com/en/articles/19093";

    popSize               = 50;    // number of duelists
    luckCoefficient       = 0.01;  // luck coefficient
    learningProbability   = 0.2;   // learning probability for losers
    innovationProbability = 0.1;   // probability of innovation for winners
    championsCount        = 5;     // number of champions

    ArrayResize (params, 5);

    params [0].name = "popSize";               params [0].val = popSize;
    params [1].name = "luckCoefficient";       params [1].val = luckCoefficient;
    params [2].name = "learningProbability";   params [2].val = learningProbability;
    params [3].name = "innovationProbability"; params [3].val = innovationProbability;
    params [4].name = "championsCount";        params [4].val = championsCount;
  }

  void SetParams ()
  {
    popSize               = (int)params [0].val;
    luckCoefficient       = params      [1].val;
    learningProbability   = params      [2].val;
    innovationProbability = params      [3].val;
    championsCount        = (int)params [4].val;
  }

  bool Init (const double &rangeMinP  [],
             const double &rangeMaxP  [],
             const double &rangeStepP [],
             const int     epochsP = 0);

  void Moving   ();
  void Revision ();

  //------------------------------------------------------------------
  double luckCoefficient;       // luck coefficient
  double learningProbability;   // learning probability
  double innovationProbability; // innovation probability
  int    championsCount;        // number of champions

  private: //---------------------------------------------------------
  int    winners [];            // winners' indices
  int    losers  [];            // losers' indices
  int    champions [];          // champions' indices

  void   DetermineWinnerAndLoser (int duelistA, int duelistB);
  void   LearningProcess         (int loserIndex, int winnerIndex);
  void   InnovationProcess       (int winnerIndex);
  void   TrainNewDuelist         (int championIndex, int newDuelistIndex);
};
//————————————————————————————————————————————————————————————————————

Die Methode „Init“ der Klasse „C_AO_DA_duelist“ dient dazu, den Algorithmus für die Ausführung vorzubereiten. Seine Hauptaufgabe besteht darin, die Anfangsparameter und Datenstrukturen vor Beginn der Ausführung zu initialisieren.

Die Methode beginnt mit dem Aufruf der Standardinitialisierung, die die Wertebereiche und Schrittweiten für die Parameter verarbeitet. Sollte diese Standardinitialisierung fehlschlagen, gibt die Methode „false“ zurück, um anzuzeigen, dass sie nicht fortfahren kann. Die Methode passt dann die Anzahl der Champions an: Ist sie kleiner als eins, wird sie auf eins gesetzt; ist sie größer oder gleich der Populationsgröße, wird sie auf ein Viertel der Gesamtpopulationsgröße reduziert. Die Arrays, in denen die Indizes der Sieger, Verlierer und Champions gespeichert sind, werden anschließend geleert und neu zugewiesen, sodass sie leer und für die nächste Stufe des Algorithmus bereit sind. Am Ende gibt die Methode „true“ zurück, was eine erfolgreiche Initialisierung signalisiert.

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

  //------------------------------------------------------------------
  if (championsCount < 1) championsCount = 1;
  if (championsCount >= popSize) championsCount = popSize / 4;

  ArrayResize (winners, 0);
  ArrayResize (losers,  0);
  ArrayResize (champions, championsCount);

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

Die Methode „DetermineWinnerAndLoser“ der Klasse „C_AO_DA_duelist“ ermittelt den Sieger und den Verlierer in einem Duell zwischen zwei Individuen (Duellanten) der Population. Betrachten wir nun die Reihenfolge der Schritte.

  1. Berechnung des „Glücks“. Für jeden Duellanten (A und B) wird der Wert „Glück“ (A_Luck und B_Luck) berechnet. Das „Glück“ hängt vom Basiswert f des Duellanten (seiner „Fitness“), vom Koeffizienten „luckCoefficient“ und von einem Zufallselement ab, das mit u.RNDprobab() ermittelt wird. Es wird ein gewisses Maß an Zufälligkeit eingesetzt, um den Einfluss des Glücks zu simulieren.
  2. Ermittlung des Siegers. Die Summe aus der Fitness f des Duellanten und seinem „Glück“ wird verglichen. Der Duellant mit dem höheren oder zumindest gleich hohen Gesamtwert gilt als Sieger.
  3. Speichern der Ergebnisse. Die Sieger- und Verliererindizes werden den entsprechenden Arrays „winners“ und „losers“ hinzugefügt. Diese Arrays werden für weitere Analysen und für die Evolution der Population verwendet.

    //————————————————————————————————————————————————————————————————————
    //--- Determine the winner and loser in a duel
    void C_AO_DA_duelist::DetermineWinnerAndLoser (int duelistA, int duelistB)
    {
      // Algorithm from the document
      double A_Luck = a [duelistA].f * (luckCoefficient + u.RNDprobab () * luckCoefficient);
      double B_Luck = a [duelistB].f * (luckCoefficient + u.RNDprobab () * luckCoefficient);
    
      if ((a [duelistA].f + A_Luck) >= (a [duelistB].f + B_Luck))
      {
        ArrayResize (winners, ArraySize (winners) + 1);
        ArrayResize (losers,  ArraySize (losers) + 1);
        winners [ArraySize (winners) - 1] = duelistA;
        losers  [ArraySize (losers) - 1] = duelistB;
      }
      else
      {
        ArrayResize (winners, ArraySize (winners) + 1);
        ArrayResize (losers,  ArraySize (losers) + 1);
        winners [ArraySize (winners) - 1] = duelistB;
        losers  [ArraySize (losers) - 1] = duelistA;
      }
    }
    //————————————————————————————————————————————————————————————————————
    

    Die Methode „LearningProcess“ der Klasse „C_AO_DA_duelist“ implementiert einen Lernprozess, bei dem ein Individuum, das ein Duell verliert, vom Sieger „lernt“. Ziel dieses Prozesses ist es, die Leistung des Verlierers zu verbessern, indem ein Teil der Strategie des Siegers auf das verlierende Individuum übertragen wird. Schauen wir uns einmal an, was innerhalb der Methode passiert:

    Durchlauf über Koordinaten. Die „for“-Schleife durchläuft alle „Koordinaten“ eines Individuums. Die Anzahl der Koordinaten wird durch die Variable „coords“ festgelegt.

    Probabilistisches Kopieren. Innerhalb der Schleife wird mithilfe von u.RNDprobab() eine zufällige Prüfung durchgeführt. Ist die Zufallszahl kleiner als learningProbability, wird die folgende Aktion ausgeführt.

    Kopieren von Merkmalen. Ein Verlierer (loserIndex) „übernimmt“ den Wert der Koordinate c vom Sieger (winnerIndex). Das bedeutet, dass das Merkmal des verlierenden Individuums so aktualisiert wird, dass es den Wert des entsprechenden Merkmals des Siegers annimmt. Im Grunde genommen übernimmt der Verlierer einen Teil der Strategie des Siegers.

    Letztendlich simuliert diese Methode den Transfer von Wissen oder Strategien von einem erfolgreicheren Individuum auf ein weniger erfolgreiches, was die Grundlage für den evolutionären Prozess bildet.

    //————————————————————————————————————————————————————————————————————
    //--- A loser learns from a winner
    void C_AO_DA_duelist::LearningProcess (int loserIndex, int winnerIndex)
    {
      for (int c = 0; c < coords; c++)
      {
        if (u.RNDprobab () < learningProbability)
        {
          // A loser copies part of a winner's strategy
          a [loserIndex].c [c] = a [winnerIndex].c [c];
        }
      }
    }
    //————————————————————————————————————————————————————————————————————
    

    Die Methode „InnovationProcess“ der Klasse „C_AO_DA_duelist“ implementiert den Prozess der „Innovation“ bzw. Mutation für das Individuum, das das Duell gewinnt. Dieser Prozess führt zufällige Änderungen an der Strategie des Siegers ein und erkundet so neue Möglichkeiten.

    Durchlauf über Koordinaten. Die „for“-Schleife durchläuft alle „c“-Koordinaten eines Individuums, ähnlich wie bei „LearningProcess“.

    Probabilistische Mutation. Wenn die von u.RNDprobab() generierte Zufallszahl kleiner als innovationProbability ist, findet eine Mutation statt. Mit anderen Worten: Ein Individuum versucht, seine Strategie mit einer bestimmten Wahrscheinlichkeit zu ändern, die durch innovationProbability festgelegt wird.

    Erzeugung und Korrektur eines neuen Werts. Der Zufallszahlengenerator u.RNDfromCI() erzeugt einen Zufallswert für den Parameter „c“, der im Wertebereich von rangeMin[c] bis rangeMax[c] liegt. Der resultierende Zufallswert wird mithilfe von u.SeInDiSp() angepasst. Diese Funktion dient dazu, einen Wert in eine diskrete Wertemenge mit der Schrittweite rangeStep[c] innerhalb eines vorgegebenen Wertebereichs (rangeMin[c], rangeMax[c]) umzuwandeln.

    Dadurch ermöglicht die Methode dem Sieger, mit neuen Strategien zu experimentieren, was potenziell zu verbesserten Eigenschaften des Individuums und seiner Anpassungsfähigkeit an die Umgebung führen kann. Dies ist ein wichtiger Teil des evolutionären Prozesses.

    //————————————————————————————————————————————————————————————————————
    //--- The innovation process for a winner
    void C_AO_DA_duelist::InnovationProcess (int winnerIndex)
    {
      for (int c = 0; c < coords; c++)
      {
        if (u.RNDprobab () < innovationProbability)
        {
          // The winner tries a new technique (mutation)
          a [winnerIndex].c [c] = u.RNDfromCI (rangeMin [c], rangeMax [c]);
          a [winnerIndex].c [c] = u.SeInDiSp (a [winnerIndex].c [c], rangeMin [c], rangeMax [c], rangeStep [c]);
        }
      }
    }
    //————————————————————————————————————————————————————————————————————
    

    Die Methode „TrainNewDuelist“ der Klasse „C_AO_DA_duelist“ ist dafür zuständig, einen neuen Duellanten (ein neues Individuum) zu erstellen und seine Ersteinrichtung durch „Training“ auf Basis des aktuellen Champions vorzunehmen. Es handelt sich um einen Vererbungsprozess, der jedoch zufällige Elemente enthält, wodurch genetische Vielfalt in die Population eingebracht werden kann.

    Iteration über Koordinaten. Die „for“-Schleife durchläuft alle „c“-Parameter (Koordinaten) des neuen Duellanten (newDuelistIndex) und setzt jeden einzelnen davon.

    Berechnung der Abweichung. Es wird die „Abweichung“ berechnet, die den Bereich möglicher Änderungen im Verhältnis zur Spannweite der zulässigen Werte bestimmt.

    Vererbung mit Mutation (Gauß-Verteilung). Dem Merkmal „c“ des Champions (championIndex) wird eine zufällige Abweichung hinzugefügt, die mit der Funktion u.GaussDistribution() ermittelt wurde. Diese Funktion generiert eine Zufallszahl aus einer Normalverteilung (Gauß-Verteilung), wodurch zufällige Schwankungen bei den vererbten Merkmalen möglich sind. Die Argumente 0, rangeMin[c], rangeMax[c] und 8 legen die Parameter der Normalverteilung fest: den Mittelwert 0, den Minimal- und den Maximalwert sowie den Parameter, der die Breite der Verteilung bestimmt (8).

    Anpassung an das diskrete Raster (SeInDiSp). Der sich nach der Mutation ergebende Wert des Merkmals des neuen Duellanten wird mithilfe der Funktion u.SeInDiSp() in eine diskrete Wertemenge umgewandelt. Diese Funktion stellt sicher, dass die Parameter des neuen Duellanten innerhalb des zulässigen Wertebereichs liegen und der Schrittweite rangeStep[c] entsprechen.

    Dadurch erhält der neue Duellant ähnliche Kennwerte wie der Champion, allerdings mit zufälligen Abweichungen, was für Vielfalt in der Population sorgt und die Exploration neuer Strategien ermöglicht.

    //————————————————————————————————————————————————————————————————————
    //--- A champion trains a new duelist
    void C_AO_DA_duelist::TrainNewDuelist (int championIndex, int newDuelistIndex)
    {
      for (int c = 0; c < coords; c++)
      {
        // The new duelist inherits the champion's abilities with slight variations
        double deviation = (rangeMax [c] - rangeMin [c]) * 0.1;
        a [newDuelistIndex].c [c] = a [championIndex].c [c] + u.GaussDistribution (0, rangeMin [c], rangeMax [c], 8);
        a [newDuelistIndex].c [c] = u.SeInDiSp (a [newDuelistIndex].c [c], rangeMin [c], rangeMax [c], rangeStep [c]);
      }
    }
    //————————————————————————————————————————————————————————————————————
    

    Die Methode „Moving“ der Klasse „C_AO_DA_duelist“ stellt den Hauptschritt des Evolutionsalgorithmus der Duellanten dar. Dazu gehören Initialisierung (beim ersten Start), Reproduktion, Selektion, Duelle, Training (unter Verwendung der Ergebnisse der Duelle), Innovation und Auslese. Dies ist der Kern des evolutionären Prozesses, der innerhalb der Methode abläuft:

    Initialisierung der Population (erster Durchlauf). Wenn es sich um den ersten Durchlauf handelt (revision ist „false“), wird die Population initialisiert: Für jedes Individuum i werden die Werte für alle Merkmale j zufällig gemäß dem zulässigen Wertebereich und der Schrittweite zugewiesen. Nach der Initialisierung wird „revision“ auf „true“ gesetzt, um eine erneute Initialisierung bei nachfolgenden Durchläufen zu vermeiden.

    Vorbereitung auf die Reproduktion. Die Größe des Arrays „a“ (das die Population darstellt) wird erhöht, um neue Duellanten aufzunehmen, die von Champions erzeugt wurden. Neue Duellanten werden initialisiert (die Anfangszustände werden festgelegt).

    Auswahl der Champions. Die Population wird nach dem Parameter f (Fitness) sortiert, um die besten Individuen auszuwählen. Die Champions werden bestimmt – die championsCount besten Individuen. Jeder Champion verwendet die Methode „TrainNewDuelist“, um einen neuen Duellanten zu erstellen, der die Eigenschaften des Champions erbt.

    Vorbereitung auf Duelle. Die Arrays „Sieger“ und „Verlierer“ werden geleert, um sie für neue Duellergebnisse vorzubereiten.

    Duelle austragen. Jedes Individuum, mit Ausnahme der Champions, tritt gegen einen zufällig ausgewählten Gegner an (ebenfalls kein Champion). Der Ausgang jedes Duells (wer Sieger ist und wer Verlierer ist) wird mithilfe von „DetermineWinnerAndLoser“ ermittelt.

    Training der Duellanten (Lernen). Verlierer lernen von Siegern. „LearningProcess“ ermöglicht es Verlierern, ihre Parameter zu ändern, indem sie die besten Eigenschaften der Sieger übernehmen.

    Innovationen der Sieger. Die Sieger nutzen InnovationProcess, um ihre Strategien anzupassen und neue Möglichkeiten auszuloten.

    Neusortierung. Die gesamte Population wird erneut nach dem Parameter „f“ sortiert, um die Reihenfolge der Individuen nach den durch Duelle, Training und Innovation vorgenommenen Änderungen zu aktualisieren.

    Auslese der Schlechtesten. Die Größe des Arrays „a“ wird auf „popSize“ zurückgesetzt, wobei die schlechtesten Individuen entfernt werden, um eine konstante Populationsgröße aufrechtzuerhalten.

    Dieser Zyklus stellt einen Evolutionsschritt dar, in dem Nachkommen erzeugt, die Besten ausgewählt, Lernprozesse durchgeführt, Strategien angepasst und die Populationsgröße aufrechterhalten wird. Die Moving-Methode führt die grundlegenden evolutionären Operationen durch: Reproduktion, Mutation, Selektion und Lernen.

    //————————————————————————————————————————————————————————————————————
    //--- The main step of the algorithm
    void C_AO_DA_duelist::Moving ()
    {
      // 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;
      }
    
      //------------------------------------------------------------------
      // Temporary array expansion for new duelists
      int totalDuelists = popSize + championsCount;
      ArrayResize (a, totalDuelists);
    
      // Initialize new duelists
      for (int i = popSize; i < totalDuelists; i++)
      {
        a [i].Init (coords);
      }
    
      // Sort to determine champions (using bubble sort)
      for (int i = 0; i < popSize - 1; i++)
      {
        for (int j = 0; j < popSize - i - 1; j++)
        {
          if (a [j].f < a [j + 1].f)
          {
            S_AO_Agent temp = a [j];
            a [j] = a [j + 1];
            a [j + 1] = temp;
          }
        }
      }
    
      // Determine the champions
      for (int i = 0; i < championsCount; i++)
      {
        champions [i] = i;
        // A champion trains a new duelist
        TrainNewDuelist (i, popSize + i);
      }
    
      // Clear the winners' and losers' arrays
      ArrayResize (winners, 0);
      ArrayResize (losers,  0);
    
      // Conduct duels (excluding champions)
      for (int i = championsCount; i < totalDuelists; i++)
      {
        // Each duelist fights one random opponent
        int opponent = u.RNDintInRange (championsCount, totalDuelists - 1);
        if (opponent != i)
        {
          DetermineWinnerAndLoser (i, opponent);
        }
      }
    
      // Improving duelists
      int minCount = MathMin (ArraySize (winners), ArraySize (losers));
      for (int i = 0; i < minCount; i++)
      {
        // Losers learn from winners
        LearningProcess (losers [i], winners [i]);
      }
    
      for (int i = 0; i < ArraySize (winners); i++)
      {
        // Winners innovate
        InnovationProcess (winners [i]);
      }
    
      // Sort all duelists
      for (int i = 0; i < totalDuelists - 1; i++)
      {
        for (int j = 0; j < totalDuelists - i - 1; j++)
        {
          if (a [j].f < a [j + 1].f)
          {
            S_AO_Agent temp = a [j];
            a [j] = a [j + 1];
            a [j + 1] = temp;
          }
        }
      }
    
      // Remove the worst duelists
      ArrayResize (a, popSize);
    }
    //————————————————————————————————————————————————————————————————————
    

    Die Methode „Revision“ der Klasse „C_AO_DA_duelist“ dient dazu, Informationen über die beste in der aktuellen Population gefundene Lösung zu aktualisieren. Sie dient dazu, während der Evolution das globale Optimum zu verfolgen.

    Iteration über die Population. Die „for“-Schleife durchläuft jedes einzelne Individuum der Population (i von 0 bis popSize).

    Fitnessvergleich. Innerhalb der Schleife prüfen wir, ob die Fitness „f“ des aktuellen Individuums besser ist als die derzeit beste Fitness „fB“.

    Aktualisierung der besten Lösung. Wenn (a[i].f) besser ist als (fB), wird (fB) aktualisiert, d. h., (fB) speichert die bisher gefundene beste Fitness. Zudem werden die „c“-Merkmale des aktuellen Individuums in das cB-Array kopiert. Das bedeutet, dass cB die Merkmalswerte des bisher gefundenen besten Individuums speichert.

    Letztendlich durchsucht die Methode „Revision“ die aktuelle Population, ermittelt das Individuum mit der besten Fitness und aktualisiert, falls dieses Individuum besser ist als der aktuelle „Rekord“, die Informationen über das bisher gefundene beste Individuum (seine Fitness und die Merkmale selbst). Diese Methode ist notwendig, um den Fortschritt des Algorithmus zu verfolgen und das globale Optimum zu finden.

    //————————————————————————————————————————————————————————————————————
    //--- Update the best and worst solutions
    void C_AO_DA_duelist::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);
        }
      }
    }mit der auf der Testfunktion
    //————————————————————————————————————————————————————————————————————
    


    Testergebnisse

    Insgesamt lässt sich nach den durchgeführten Untersuchungen feststellen, dass der Duellanten-Algorithmus recht gute Ergebnisse liefert.

    DA|Duellanten-Algorithmus|100.0|0.01|0.9|0.1|2.0|
    =============================
    5 Hilly's; Funktionsaufrufe: 10000; Ergebnis: 0.9278151663330798
    25 Hilly's; Funktionsaufrufe: 10000; Ergebnis: 0.5377820196319314
    500 Hilly's; Funktionsaufrufe: 10000; Ergebnis: 0.27792394907287765
    =============================
    5 Forest's; Funktionsaufrufe: 10000; Ergebnis: 0.8695700230324329
    25 Forest's; Funktionsaufrufe: 10000; Ergebnis: 0.47535947112902815
    500 Forest's; Funktionsaufrufe: 10000; Ergebnis: 0.18193288697223736
    =============================
    5 Megacity's; Funktionsaufrufe: 10000; Ergebnis: 0.6215384615384616
    25 Megacity's; Funktionsaufrufe: 10000; Ergebnis: 0.3356923076923076
    500 Megacity's; Funktionsaufrufe: 10000; Ergebnis: 0.11715384615384725
    =============================
    Gesamtpunktzahl: 4.34477 (48.28 %)

    Die Visualisierung der Funktionsweise des Algorithmus zeigt sowohl bei kleinen als auch bei großen Dimensionen eine geringe Streuung der Werte, was auf die guten Suchfähigkeiten des Algorithmus hindeutet.

    Hilly

    DA_duelist für die Testfunktion Hilly

    Forest

    DA_duelist für die Testfunktion Forest

    Megacity

    DA_duelist für die Testfunktion Megacity

    Auf der Grundlage der Testergebnisse belegt der Duellanten-Algorithmus unter den getesteten Optimierungsalgorithmen den 42. Platz in der Gesamtwertung.

    #AOBeschreibungHillyHilly
    Final
    ForestForest
    Final
    Megacity (diskret)Megacity
    Final
    Endgültiges
    Ergebnis
    % von
    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)
    1ANSnachbarschaftsübergreifende Suche0.949480.847760.438572.235811.000000.923340.399882.323230.709230.634770.230911.574916.13468.15
    2CLACodeschloss-Algorithmus (joo)0.953450.871070.375902.200420.989420.917090.316422.222940.796920.693850.193031.683806.10767.86
    3AMOmTiermigrationsoptimierung 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
    6TETAZeitentwicklungsreise-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
    9AAmBogenschieß-Algorithmus M0.917440.708760.421602.047800.925270.758020.353282.036570.673850.552000.237381.463235.54861.64
    10ESGEvolution sozialer Gruppen (joo)0.999060.796540.350562.146161.000000.828630.131021.959650.823330.553000.047251.423585.52961.44
    11SIAsimuliertes isotropes Annealing (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
    13BBObiogeografiebasierte 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
    16BHAmBlack-Hole-Algorithmus M0.752360.766750.345831.864930.935930.801520.271772.009230.650770.516460.154721.321955.19657.73
    17ASOOptimierung anarchischer Gesellschaften0.848720.746460.314651.909830.961480.791500.238031.991010.570770.540620.166141.277525.17857.54
    18RFORoyal-Flush-Optimierung (joo)0.833610.737420.346291.917330.894240.738240.240981.873460.631540.502920.164211.298675.08956.55
    19AOSmAtomorbital-Suche 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 des erfolgreichen Gastronomen (joo)0.968830.634550.292171.895550.946370.555060.191241.692670.749230.440310.125261.314804.90354.48
    24CROOptimierung durch chemische Reaktionen0.946290.661120.298531.905930.879060.584220.211461.674730.758460.426460.126861.311784.89254.36
    25BIOOptimierung durch 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
    27DEADelfin-Echolokationsalgorithmus0.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
    29SSGAussaat und Wachstum von Setzlingen0.778390.649250.395431.823080.859730.624670.174291.658690.646670.441330.105981.193984.67651.95
    30BCOmOptimierung durch bakterielle Chemotaxis M0.759530.622680.314831.697040.893780.613390.225421.732590.653850.420920.144351.219124.64951.65
    31ABOAfrican-Buffalo-Optimierung0.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
    33FBAfraktalbasierter 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
    35BSOBrain-Storm-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 des künstlichen elektrischen Feldes0.877000.617530.252351.746880.927290.726980.180641.834900.666150.116310.095080.877544.45949.55
    38AEOOptimierungsalgorithmus auf Basis 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
    40ACOmAmeisenkolonie-Optimierung M0.881900.661270.303771.846930.858730.586800.150511.596040.596670.373330.024720.994724.43849.31
    41CMAESKovarianzmatrix-Adaption-Evolutionsstrategie0.762580.720890.000001.483470.820560.796160.000001.616720.758460.490770.000001.249234.34948.33
    42DA_duelistDuellanten-Algorithmus0.927820.537780.277921.743520.869570.475360.181931.526860.621530.335690.117151.074374.34548.28
    43BFO-GAOptimierung durch bakterielle Nahrungssuche – GA0.891500.551110.315291.757900.969820.396120.063051.428990.726670.275000.035251.036924.22446.93
    44SOAeinfacher Optimierungsalgorithmus0.915200.469760.270891.655850.896750.374010.169841.440600.695380.280310.108521.084224.18146.45
    45ABHAKünstlicher Bienenstock-Algorithmus0.841310.542270.263041.646630.878580.477790.171811.528180.509230.338770.103970.951974.12745.85
    RWRandom Walk0.487540.321590.257811.066940.375540.219440.158770.753750.279690.149170.098470.527342.34826.09


    Zusammenfassung

    Der Duellanten-Algorithmus erzielt im Bereich der metaheuristischen Optimierung beachtliche Ergebnisse und zählt zu den 45 besten populationsbasierten Algorithmen. Auch wenn er nicht den Anspruch erhebt, der absolute Champion unter den Optimierungsmethoden zu sein, liegt sein entscheidender Vorteil in der Geschwindigkeit.

    Adaptive Lernstrategie – im Kontext der Optimierung von Handelssystemen bedeutet dies, dass erfolglose Parameterkonfigurationen schnell erfolgreiche Muster übernehmen, was insbesondere bei der Arbeit mit nicht stationären Finanzzeitreihen von großem Wert ist.

    Ein Gleichgewicht zwischen Exploitation und Exploration – Sieger ruhen sich nicht auf ihren Lorbeeren aus, sondern streben durch Innovation stets nach Verbesserung. Dies ist von entscheidender Bedeutung für Handelsstrategien, die sich an veränderte Marktbedingungen anpassen müssen.

    Das Element der kontrollierten Zufälligkeit – der Glücksfaktor – bildet auf natürliche Weise die Unsicherheit am Markt ab, wo selbst eine gute Strategie aufgrund kurzfristiger Schwankungen vorübergehend schlechte Ergebnisse erzielen kann.

    Eine hierarchische Struktur mit Champions stellt sicher, dass die besten Lösungen erhalten bleiben und weiterverbreitet werden, was im Handel gleichbedeutend ist mit der Beibehaltung bewährter Strategien bei gleichzeitiger Suche nach neuen Chancen.

    Der Duellanten-Algorithmus ist eine solide Lösung, die mithilfe der Metapher der Kampfkünste eine einfache, aber wirkungsvolle Idee in die Welt der Optimierung einbringt: von den Starken lernen, aus einer Position der Stärke heraus experimentieren und Wissen an die nächste Generation weitergeben.

    Registerkarte

    Abbildung 2. Farbabstufung der Algorithmen in den jeweiligen Tests

    Diagramm

    Abbildung 3. Histogramm der Ergebnisse der Algorithmentests (Skala von 0 bis 100; je höher, desto besser; wobei 100 das theoretisch maximal mögliche Ergebnis ist; im Archiv befindet sich ein Skript zur Berechnung der Bewertungstabelle)

    Vor- und Nachteile von DA_duelist:

    Vorteile:

    1. Schnell.
    2. Geringe Varianz über die Testfunktionen hinweg.

    Nachteile:

    1. Geringe Konvergenzgenauigkeit.

    Dem Artikel ist ein Archiv mit den neuesten Versionen des Algorithmus-Codes beigefügt. Der Autor des Artikels übernimmt keine Gewähr für die absolute Richtigkeit der Beschreibung der kanonischen Algorithmen. An vielen davon wurden Änderungen vorgenommen, um die Suchfähigkeiten zu verbessern. Die in den Artikeln dargelegten Schlussfolgerungen und Einschätzungen basieren auf den Ergebnissen der Experimente.


    In diesem Artikel verwendete Programme

    #NameTypBeschreibung
    1#C_AO.mqh
    Include
    Basisklasse für populationsbasierte Optimierungsalgorithmen
    2#C_AO_enum.mqh
    Include
    Enumeration populationsbasierter Optimierungsalgorithmen
    3TestFunctions.mqh
    Include
    Bibliothek mit Testfunktionen
    4
    TestStandFunctions.mqh
    Include
    Bibliothek mit Teststand-Funktionen
    5
    Utilities.mqh
    Include
    Bibliothek mit Hilfsfunktionen
    6
    CalculationTestResults.mqh
    Include
    Skript zur Berechnung der Ergebnisse in der Vergleichstabelle
    7
    Testing AOs.mq5
    SkriptEinheitlicher Teststand für alle populationsbasierten Optimierungsalgorithmen
    8
    Simple use of population optimization algorithms.mq5
    Skript
    Ein einfaches Beispiel für die Verwendung populationsbasierter Optimierungsalgorithmen ohne Visualisierung
    9
    Test_AO_DA_duelist.mq5
    SkriptTeststand für DA_duelist

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

    Beigefügte Dateien |
    DAvduelistk.zip (262.07 KB)
    Letzte Kommentare | Zur Diskussion im Händlerforum (2)
    Александр Бельмецов
    Александр Бельмецов | 15 Aug. 2025 in 04:00
    MetaQuotes:

    Der Artikel „Der Duelist-Algorithmus – Duelist Algorithm“ wurde veröffentlicht:

    Autor: Andrey Dik

    Duellanten, die sich im Ring bekämpfen. Der Markt ist kein Ring, sondern ein Gelände. Mal ist man bis zur Hüfte im Sumpf versunken. Auf dem Eis gewinnt der Eiskunstläufer, aber im Sumpf … Und was für ein Krieger wird am Ende daraus?
    lynxntech
    lynxntech | 15 Aug. 2025 in 04:21
    Александр Бельмецов #:
    Duellanten, die sich im Ring bekämpfen. Der Markt ist kein Ring, sondern ein Gelände. Mal ist man bis zur Hüfte im Sumpf. Auf dem Eis gewinnt der Eiskunstläufer, aber im Sumpf … Und was für ein Krieger kommt am Ende dabei heraus?

    Das könnt ihr selbst im Internet nachsehen, das hat sich der Verfasser des Themas nicht ausgedacht.

    Neuronale Netze im Trading: Das Temporal-Query-Modell (TQNet) Neuronale Netze im Trading: Das Temporal-Query-Modell (TQNet)
    Das TQNet-Framework eröffnet durch die Kombination von Modularität, Flexibilität und hoher Leistungsfähigkeit neue Möglichkeiten für die Modellierung und Prognose von Finanzzeitreihen. Der Artikel untersucht die Möglichkeit, komplexe Mechanismen zur Verarbeitung globaler Korrelationen zu implementieren, darunter auch fortgeschrittene Methoden zur Parameterinitialisierung.
    Marktsimulation: Positionsanzeige (VI) Marktsimulation: Positionsanzeige (VI)
    In diesem Artikel werden wir eine Reihe von Verbesserungen vornehmen, um sicherzustellen, dass der Positionsindikator den tatsächlichen Zustand auf dem Handelsserver in Bezug auf offene Positionen und ihren aktuellen Zustand genau widerspiegelt. Ich möchte darauf hinweisen, dass die hier gezeigten Anwendungen keineswegs dazu gedacht sind, eines der in MetaTrader 5 verfügbaren Elemente zu ersetzen. Sie sollten zudem nicht ohne die gebotene Vorsicht und ohne Augenmaß verwendet werden, da ihr Zweck darin besteht, Lehrcode bereitzustellen – also Code, der ausschließlich dazu dient, die Funktionsweise des Systems zu erlernen. Ich bezeichne diesen Code als „Lehrcode“, weil die Verwendung von Nachrichten in manchen Fällen nicht die beste Methode ist, um bestimmte Funktionen zu implementieren.
    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.
    Neuronale Netze im Trading: Zerlegen statt Skalieren (Fazit) Neuronale Netze im Trading: Zerlegen statt Skalieren (Fazit)
    Wir laden Sie ein, einen Algorithmus kennenzulernen, mit dem eine Zeitreihe in aussagekräftige Schichten zerlegt und daraus ein sparsames Modell aufgebaut wird. Wir stellen systematisch die Architektur, die praktische Umsetzung in MQL5/OpenCL sowie Praxistests unter Verwendung historischer Marktdaten vor.