English Русский 日本語
preview
Algorithmen zur Optimierung mit Populationen: Künstliche multisoziale Suchobjekte (MSO)

Algorithmen zur Optimierung mit Populationen: Künstliche multisoziale Suchobjekte (MSO)

MetaTrader 5Tester | 19 Juni 2024, 14:33
54 0
Andrey Dik
Andrey Dik

Inhalt

1. Einführung
2. Der Algorithmus
3. Testergebnisse


1. Einführung

Im vorigen Artikel haben wir die Entwicklung von sozialen Gruppen betrachtet, die sich frei im Suchraum bewegen. Ich schlage jedoch vor, dieses Konzept zu ändern und davon auszugehen, dass sich Gruppen zwischen den Sektoren bewegen und von einem zum anderen springen. Alle Gruppen haben ihre eigenen Zentren, die bei jeder Iteration des Algorithmus aktualisiert werden. Außerdem führen wir das Konzept des Gedächtnisses sowohl für die Gruppe als Ganzes als auch für jedes einzelne Partikels in ihr ein. Mit diesen Änderungen ermöglicht unser Algorithmus nun, dass Gruppen auf der Grundlage von Informationen über die besten Lösungen von Sektor zu Sektor wechseln.

Diese neue Modifikation eröffnet neue Möglichkeiten zur Untersuchung der Entwicklung sozialer Gruppen. Die Umstellung auf Sektoren ermöglicht es den Gruppen, Informationen und Erfahrungen innerhalb jedes Sektors auszutauschen, was zu einer effektiveren Suche und Anpassung führen kann. Die Einführung des Gedächtnisses ermöglicht es den Gruppen, Informationen über frühere Bewegungen zu behalten und sie für Entscheidungen über zukünftige Bewegungen zu nutzen.

In diesem Artikel werden wir eine Reihe von Experimenten durchführen, um zu untersuchen, wie diese neuen Konzepte die Suchleistung eines Algorithmus beeinflussen. Wir werden die Interaktion zwischen Gruppen, ihre Fähigkeit zur Kooperation und Koordination sowie ihre Lern- und Anpassungsfähigkeit analysieren. Unsere Erkenntnisse können die Evolution sozialer Systeme erhellen und zu einem besseren Verständnis dafür beitragen, wie sich Gruppen bilden, entwickeln und an eine sich verändernde Umwelt anpassen.

Abschließend werden die Möglichkeiten zur weiteren Verbesserung des modifizierten Algorithmus und seine Anwendung in verschiedenen Bereichen erörtert. Die in dieser Arbeit vorgenommenen Änderungen ermöglichen es uns, den Lösungsraum effizienter zu erkunden und optimale Werte zu finden. Dies kann für Forscher und Praktiker, die auf dem Gebiet der Optimierung und Lösungssuche arbeiten, von Nutzen sein.


2. Der Algorithmus

Das ultimative Ziel des Algorithmus, der die Prinzipien sozialer Gruppen integriert, ist es, ein effektives System der Koordination und Kooperation zwischen Gruppenmitgliedern zu schaffen. Hier sind die allgemeinen Grundsätze, die in einen solchen Algorithmus integriert werden können:

  • Der Bewegungsalgorithmus ermöglicht es der Partei, sich zwischen verschiedenen Sektoren oder Gebieten zu bewegen. Dies wird es der Gruppe ermöglichen, eine Vielzahl von Ressourcen und Erfahrungen zu erkunden und nicht nur Informationen über einzelne Koordinaten, sondern auch Metadaten in Form von Sektoren mit anderen Gruppen auszutauschen.
  • Rollentrennung und Spezialisierung ermöglichen es den Gruppenmitgliedern, sich auf bestimmte Bereiche zu spezialisieren. Dies wird die Gruppe in die Lage versetzen, ihre Ressourcen und Fähigkeiten effektiv zu nutzen, um gemeinsame Ziele zu erreichen. Dies kann besonders nützlich sein, wenn es um die Lösung von Problemen mit mehrdimensionalen Räumen geht, in denen es gleichzeitig Flächen von Funktionen mit unterschiedlichen Eigenschaften gibt (sowohl glatte als auch diskrete).
  • Kooperation und Interaktion ermöglichen es den Gruppenmitgliedern, zusammenzuarbeiten und miteinander zu interagieren. Dazu kann es gehören, Informationen auszutauschen, Ideen zu diskutieren und in unbekannte Bereiche zu interpolieren und zu extrapolieren.
  • Konflikt und Konfliktlösung - Mechanismen zur Lösung von Konflikten innerhalb der Gruppe. Dies kann die Festlegung von Regeln und Verfahren, die Mediation und den Dialog zur Beilegung von Meinungsverschiedenheiten und Streitigkeiten umfassen. Zum Beispiel, um zu verhindern, dass die Partikel um dieselben Gebiete konkurrieren, und um wertvolle Iterationen des Algorithmus zu sparen.
  • Führung und Organisation - die Möglichkeit, dass es in der Gruppe Führungspersönlichkeiten gibt, die für die Organisation, Koordination und Entscheidungsfindung zuständig sind. Leiter sollten in der Lage sein, die Gruppe zu motivieren und zu führen, um Ziele zu erreichen.
  • Der Wissens- und Erfahrungsaustausch ermöglicht es der Gruppe, aktiv Wissen und Erfahrungen zwischen den Teilnehmern auszutauschen. Dies wird der Gruppe helfen, von anderen zu lernen, sich an neue Situationen anzupassen und fundiertere Entscheidungen zu treffen. Die Fähigkeit, komplexe logische Verbindungen zwischen Koordinaten herzustellen und nicht nur stochastische Raumforschung zu betreiben.
  • Das Gruppengedächtnis ermöglicht es der Gruppe, Informationen über frühere Bewegungen, Rollen, Spezialisierungen, Zusammenarbeit und Konfliktlösung zu speichern. Dies wird es der Gruppe ermöglichen, ihre Erfahrungen zu nutzen, um fundiertere Entscheidungen über künftige Bewegungen und Interaktionen zu treffen.

Die Integration dieser allgemeinen Grundsätze in den Algorithmus wird ein effizienteres soziales System schaffen, das zur Zusammenarbeit, zur Koordinierung, zum Informationsaustausch und zur Anpassung an ein sich veränderndes Umfeld fähig ist.

Erläutern wir die Bedeutung des Sektors zum besseren Verständnis im Zusammenhang mit dem Algorithmus. Ein Sektor ist Teil des Definitionsbereichs des optimierten Parameters (Koordinatenachsen des mehrdimensionalen Raums). Die Einteilung der Achsen in Sektoren ist für alle Gruppen gleich. Zwei Gruppen G0 und G1 können z. B. auf Sektoren der entsprechenden Koordinaten angeordnet werden:

G0 (X) |---V---|-------|-------|-------|-------|

G0 (Y) |-------|---V---|-------|-------|-------|

G0 (Z) |-------|-------|-------|-------|---V---|

-----------------------------------------------------

G1 (X) |-------|-------|---V---|-------|-------|

G1 (Y) |---V---|-------|-------|-------|-------|

G1 (Z) |-------|-------|-------|---V---|-------|

Einer der Hauptgedanken des Algorithmus besteht darin, den Gruppen die Möglichkeit zu geben, Wissen über erfolgreiche Sektoren auszutauschen, während gleichzeitig ein gewisses Maß an Stochastizität bei der freien Wahl der Sektoren beibehalten wird.

Lassen Sie uns nun zur Beschreibung des ersten Konzepts unseres Algorithmus übergehen. Betrachten wir zunächst einen Algorithmus mit zufälliger Bewegung von Gruppen über Sektoren hinweg, ohne Berücksichtigung des Gedächtnisses für die besten Lösungen.

Der Pseudocode des Algorithmus lautet wie folgt:

1. Sektoren nach dem Zufallsprinzip für Gruppen auswählen
2. Punkte gleichmäßig auf die Sektoren verteilen
3. Berechnung der Fitnessfunktion
4. Aktualisierung der globalen Lösung (beste Populationspartikel)
5. Ermittlung des Werts des besten Partikels in der Gruppe in der aktuellen Iteration
6. Aktualisierung des Gedächtnisses für die besten Lösungen in den Sektoren für jede Gruppe
7. Aktualisierung des Gedächtnisses für die besten Lösungen in den Sektoren für jedes Partikel
8. Aktualisierung der besten Lösung nach den Gruppen
9. Eine Gruppe fragt eine andere Gruppe, ob ihre Lösung für jede Koordinate besser ist:
9. a) wenn ja: dann Verwendung seines Sektors
9. b) wenn nicht: Auswahl eines anderen Sektors mit einer gewissen Wahrscheinlichkeit
10. Partikel nach Wahrscheinlichkeiten erstellen:
10. a) wenn ja: Verteilung gleichmäßig über den Sektor
10. b) wenn nicht: Klärung der Entscheidung der Gruppe
11. Wiederholung ab S.4

Die interne Architektur der Gruppe und die Kennzeichnung der Koordinaten nach Sektoren können wie folgt dargestellt werden:

Group  [groups]|
                        |-----------------------------------------
                        |fB
                        |-----------------------------------------
                        |fBLast
                        |-----------------------------------------
                        |cB              [coords]
                        |-----------------------------------------
                        |cLast         [coords]
                        |-----------------------------------------
                        |centre       [coords]
                        |-----------------------------------------
                        |secInd       [coords]
                        |-----------------------------------------
                        |secIndLast [coords]
                        |-----------------------------------------
                        |p                [groupSize]|
                        |                                    |-------------------
                        |                                    |c   [coords]
                        |                                    |f   

m [coords]|
                 |--------------
                 |min [sectNumb]
                 |max [sectNumb]

Kommen wir nun zur Beschreibung des Codes.

Um den Suchraum in Sektoren einzuteilen, müssen wir die Grenzen der Sektoren festlegen. Um dies zu erreichen, schreiben wir die Struktur S_Min_Max. Schlüsseln wir das Stück für Stück auf:

Die Struktur S_Min_Max hat zwei Datenfelder: „min“ und „max“, die die linke Sektorgrenze und mit „max“ - die rechte Sektorgrenzen darstellen. Die Größe der beiden Arrays entspricht der Anzahl der Sektoren, die durch den Parameter „sectNumb“ angegeben wird.

Die Struktur definiert auch die Funktion Init, die die Arrays „min“ und „max“ initialisiert. Sie akzeptiert einen Parameter „sectNumb“, der die Anzahl der Sektoren angibt. Innerhalb der Init-Funktion wird die Größe der Arrays „min“ und „max“ entsprechend dem übergebenen Parameter „sectNumb“ geändert. Daher bietet diese Struktur eine Möglichkeit, Sektorgrenzen zu speichern und sie mit der Funktion Init zu initialisieren.

//——————————————————————————————————————————————————————————————————————————————
struct S_Min_Max
{
  void Init (int sectNumb)
  {
    ArrayResize (min, sectNumb);
    ArrayResize (max, sectNumb);
  }
  double min []; //sector border on the left, size - number of sectors
  double max []; //sector border on the right, size - number of sectors
};
//——————————————————————————————————————————————————————————————————————————————

Um ein Partikel zu beschreiben, das ein Mitglied der Gruppe ist, schreiben wir die Struktur S_Particle, die zwei Felder enthält: „c“ und „f“.

  • „c“ - Array zum Speichern von Partikelkoordinaten. Die Größe des Arrays wird durch den Parameter „coords“ bestimmt, der an die Init-Funktion übergeben wird.
  • „f“ ist der Wert der Partikelfitnessfunktion, die mit dem Wert „-DBL_MAX“ in der Init-Funktion initialisiert wurde.

Diese Struktur bietet also einen Container für die Speicherung der Koordinaten eines Partikels und des zugehörigen Funktionswertes.

//——————————————————————————————————————————————————————————————————————————————
struct S_Particle
{
  void Init (int coords, int sectNumb)
  {
    ArrayResize (c, coords);

    f = -DBL_MAX;
  }

  double c  [];
  double f;
};
//——————————————————————————————————————————————————————————————————————————————

Wir kombinieren eine Gruppe von Partikeln in der Datenstruktur S_Group. Die Struktur S_Group enthält mehrere Datenfelder:

  • „p“ steht für das Array von S_Particle-Strukturen, die zur Speicherung von Gruppenpartikeln verwendet werden. Die Größe des Arrays „p“ wird durch den Parameter „groupSize“ bestimmt, der an die Funktion Init übergeben wird. Innerhalb der „for“-Schleife wird jedes Partikel mit der Funktion Init aus der Struktur S_Particle initialisiert.
  • „secInd“ und „secIndLast“ - die Arrays speichern Sektorindizes für jede Koordinate. Die Größe der Arrays „secInd“ und „secIndLast“ wird durch den Parameter „coords“ bestimmt.
  • „cB“ und „cBLast“ - in diesen Feldern werden die besten Koordinaten der Gruppe bzw. die vorherigen besten Koordinaten gespeichert. Die Größe der Arrays „cB“ und „cBLast“ wird ebenfalls durch den Parameter „coords“ bestimmt.
  • „fB“ und „fBLast“ - die Variablen speichern das beste Ergebnis bzw. das vorherige beste Ergebnis in der Gruppe.
  • „centre“ - das Feld speichert das Zentrum. Die Größe des Arrays „centre“ wird ebenfalls durch den Parameter „coords“ bestimmt und dient der Ermittlung der besten Sektorkoordinaten für die gesamte Gruppe.

Die Init-Funktion initialisiert alle Arrays und Variablen in der S_Group-Struktur. Sie benötigt drei Parameter: „coords“ - die Anzahl der Koordinaten, „groupSize“ - die Größe der Gruppe, „sectNumb“ - die Anzahl der Sektoren.

Diese Struktur bietet also einen Container zur Speicherung von Informationen über eine Gruppe von Partikeln. Die Partikel gehorchen den Gruppenregeln und interagieren nicht mit Partikeln anderer Gruppen. Die Interaktion erfolgt durch die indirekte Weitergabe von Informationen über die Sektoren auf Gruppenebene.

//——————————————————————————————————————————————————————————————————————————————
struct S_Group
{
  void Init (int coords, int groupSize, int sectNumb)
  {
    ArrayResize     (p,             groupSize);
    ArrayResize     (secInd,        coords);
    ArrayResize     (cB,            coords);
    ArrayResize     (cBLast,        coords);
    ArrayResize     (secIndLast,    coords);
    ArrayResize     (centre,        coords);
    for (int i = 0; i < groupSize; i++)  p [i].Init (coords, sectNumb);

    fB     = -DBL_MAX;
    fBLast = -DBL_MAX;
  }

  S_Particle p          [];
  int        secInd     []; //sector index on the coordinate, size is the number of coordinates
  int        secIndLast []; //previous index of the sector on the coordinate, the size is the number of coordinates

  double     cB         []; //the best coord's in the group
  double     cBLast     []; //the previous best coord's in the group
  double     fB;            //the best result in the group
  double     fBLast;        //the previous best result in the group
  double     centre [];
};
//——————————————————————————————————————————————————————————————————————————————

Beschreiben wir den Optimierungsagenten mit der S_Agent-Struktur, durch die Informationen von Gruppenpartikeln zur Berechnung der Fitnessfunktion übertragen werden. Die Struktur S_Agent enthält zwei Felder:

  • „c“ - das Array speichert die Koordinaten des Agenten.
  • „f“ - speichert die Fitnessfunktion des Agenten.

Die Funktion Init initialisiert das Array „c“ und die Variable „f“ in der Struktur S_Agent. Sie benötigt einen Parameter „coords“, der die Größe des Arrays „c“ angibt.

//——————————————————————————————————————————————————————————————————————————————
struct S_Agent
{
  void Init (const int coords)
  {
    ArrayResize (c, coords);
    f = -DBL_MAX;
  }

  double c []; //coordinates
  double f;    //fitness
};
//——————————————————————————————————————————————————————————————————————————————

Beschreiben wir den Multi-Social-Algorithmus anhand der Klasse C_AO_MSO. Die Klasse enthält mehrere Datenfelder und Methoden:

  • „cB“ - das Feld speichert die besten Koordinaten.
  • „fB“ - die Variable speichert die Fitness der besten Koordinaten.
  • „a“ - das Array von S_Agent-Strukturen, in dem Agenten gespeichert werden.
  • „rangeMax“, „rangeMin“ und „rangeStep“ - die Arrays speichern den maximalen und minimalen Suchbereich bzw. Schritt.

Die Klasse enthält auch mehrere Methoden:

  • Init initialisiert alle Datenelemente der Klasse. Es akzeptiert die folgenden Parameter: coordinatesNumberP - Anzahl der Koordinaten, populationSizeP - Populationsgröße, groupsP - Anzahl der Koordinaten, sectorsNumberP - Anzahl der Sektoren pro Koordinate, probRNSectorP - zufällige Sektorwahrscheinlichkeit, probUniformSectorP - Gleichverteilungswahrscheinlichkeit für ein Partikel, probClgroupP - Wahrscheinlichkeit der Verfeinerung des Gruppenergebnisses und powerP - Potenz für die Potenzgesetz-Verteilungsfunktion.
  • Moving und Revision - die Methoden zur Durchführung grundlegender Operationen mit Gruppen und Gruppenpartikeln.

Im Allgemeinen handelt es sich bei der Klasse C_AO_MSO um eine Implementierung eines Optimierungsalgorithmus mit Mehrfachsuche und optimaler Verteilung der Agenten. Sie enthält Daten und Methoden zur Verwaltung von Agenten, Gruppen und Sektoren sowie zur Durchführung von Suchvorgängen und zur Verfeinerung des Ergebnisses.

//——————————————————————————————————————————————————————————————————————————————
class C_AO_MSO
{
  //----------------------------------------------------------------------------
  public: double cB [];         //best coordinates
  public: double fB;            //FF of the best coordinates
  public: S_Agent a [];         //agents

  public: double rangeMax  []; //maximum search range
  public: double rangeMin  []; //manimum search range
  public: double rangeStep []; //step search

  public: void Init (const int    coordinatesNumberP,  //coordinates number
                     const int    populationSizeP,     //population size
                     const int    groupsP,             //number of groups
                     const int    sectorsNumberP,      //sectors number
                     const double probRNSsectorP,      //probability random sector
                     const double probUniformSectorP,  //probability uniform distribution
                     const double probClgroupP,        //probability of clarifying the group's result
                     const double powerP);             //power

  public: void Moving   ();
  public: void Revision ();

  //----------------------------------------------------------------------------
  private: int    coords;                //coordinates number
  private: int    popSize;               //population size

  private: int    sectNumb;              //sectors number
  private: double sectorSpace [];        //sector space

  private: S_Group    gr [];             //groups
  private: S_Min_Max  min_max_Sector []; //sector boundary by coordinates

  private: int    groups;                //number of groups
  private: int    sectorsNumber;         //sectors number
  private: double probRNSsector;         //probability random sector
  private: double probUniformSector;     //probability uniform distribution
  private: double probClgroup;           //probability of clarifying the group's result
  private: double power;                 //power

  private: bool   revision;

  private: double SeInDiSp  (double In, double InMin, double InMax, double Step);
  private: double RNDfromCI (double min, double max);
  private: double Scale     (double In, double InMIN, double InMAX, double OutMIN, double OutMAX,  bool revers);
  private: double PowerDistribution (const double In, const double outMin, const double outMax, const double power);
};
//——————————————————————————————————————————————————————————————————————————————

Die Methode Init initialisiert ein Objekt der Klasse C_AO_MSO mit den angegebenen Parametern. Lassen Sie uns diesen Code Stück für Stück aufschlüsseln:

Zu Beginn der Funktion werden die Variablen und Datenelemente der Klasse initialisiert. Der Zufallszahlengenerator wird anhand der aktuellen Zeit in Mikrosekunden zurückgesetzt. Dann wird die Variable „fB“ auf den kleinstmöglichen Doppelwert „-DBL_MAX“ und die Variable „revision“ auf „false“ gesetzt.

Die an die Funktion übergebenen Parameter werden dann den entsprechenden Feldern der Klasse zugewiesen.

Um die Partikel einer Population in Gruppen aufzuteilen, wird das Array „partInSwarms“ erstellt. Sie speichert die Anzahl der Partikel in jeder Gruppe. Die Größe des Arrays ist gleich der Anzahl der Gruppen. Die Variable „particles“ berechnet dann die Anzahl der Partikel in jeder Gruppe, indem die Gesamtpopulationsgröße „popSize“ durch die Anzahl der „groups“ geteilt wird.

Wenn ein Rest "verloren" geht, wird er auf die Gruppen verteilt. Der Zyklus wird so lange durchgeführt, bis der Rest 0 ist.

Anschließend werden die Array-Größen geändert und die Objekte initialisiert.

//——————————————————————————————————————————————————————————————————————————————
void C_AO_MSO::Init (const int    coordinatesNumberP,  //coordinates number
                     const int    populationSizeP,     //population size
                     const int    groupsP,             //number of groups
                     const int    sectorsNumberP,      //sectors number
                     const double probRNSsectorP,      //probability random sector
                     const double probUniformSectorP,  //probability uniform distribution
                     const double probClgroupP,        //probability of clarifying the group's result
                     const double powerP)              //power
{
  MathSrand ((int)GetMicrosecondCount ()); // reset of the generator
  fB       = -DBL_MAX;
  revision = false;

  coords            = coordinatesNumberP;
  popSize           = populationSizeP;
  groups            = groupsP;
  sectNumb          = sectorsNumberP;
  probRNSsector     = probRNSsectorP;
  probUniformSector = probUniformSectorP;
  probUniformSector = probClgroupP;
  power             = powerP;

  //----------------------------------------------------------------------------
  int partInSwarms [];
  ArrayResize (partInSwarms, groups);

  int particles = popSize / groups;
  ArrayInitialize (partInSwarms, particles);

  int lost = popSize - particles * groups;

  if (lost > 0)
  {
    int pos = 0;

    while (true)
    {
      partInSwarms [pos]++;
      lost--;
      pos++;
      if (pos >= groups) pos = 0;
      if (lost == 0) break;
    }
  }

  //----------------------------------------------------------------------------
  ArrayResize (rangeMax,  coords);
  ArrayResize (rangeMin,  coords);
  ArrayResize (rangeStep, coords);
  ArrayResize (cB,        coords);

  ArrayResize (gr,        groups);
  for (int s = 0; s < groups; s++) gr [s].Init (coords, partInSwarms [s], sectNumb);

  ArrayResize (sectorSpace, coords);

  ArrayResize (a, popSize);
  for (int i = 0; i < popSize; i++) a [i].Init (coords);
}
//——————————————————————————————————————————————————————————————————————————————

Die Moving-Methode ist für die Bewegung der Partikel in der ersten Iteration verantwortlich und hat die Aufgabe, die Gruppen und ihre Partikel mit ihrer Anfangsposition zu initialisieren.

Zu Beginn der Funktion wird der Wert der Variablen „revision“ überprüft, um sicherzustellen, dass sie nur einmal ausgeführt wird, und wenn er „false“ ist.

Der erste Teil des Codes ist für die Aufteilung des Raums in Sektoren und die Initialisierung des Arrays „min_max_Sector“ zuständig. Für jede Koordinate „c“ wird die Sektorgröße „sectorSpace[c]“ als Differenz zwischen „rangeMax[c]“ und „rangeMin[c]“, geteilt durch die Anzahl der Sektoren „sectNumb“, berechnet. Die „Min“- und „Max“-Werte werden dann im Array „min_max_Sector“ für jede Koordinate und jeden Sektor initialisiert.

Anschließend werden die Partikel im Suchraum angeordnet. Für jede „s“-Gruppe werden Zufallssektoren für jede Koordinate ausgewählt. Sektorindexwerte werden für jede Gruppe im Array „secInd“ gespeichert. Anschließend werden die Partikel der Gruppe nach dem Zufallsprinzip auf die ausgewählten Sektoren verteilt. Für jedes Partikel „p“ und jede Koordinate „c“ wird ein Zufallswert „cd“ innerhalb des Minimal- und Maximalwerts des Sektors ausgewählt und dieser Wert in den Partikelkoordinaten gespeichert.

Der letzte Codeblock ist für das Senden von Partikeln an Agenten zuständig. Der Zähler „cnt“ wird erstellt, der zur Nummerierung der Agenten verwendet wird. Dann werden für jede Gruppe „s“ und jedes Partikel „p“ die Partikelkoordinatenwerte in das Array „a[cnt].c“ kopiert, wobei „cnt“ nach jeder Kopie inkrementiert wird.

Die Methode ist also für die zufällige Anfangsplatzierung der Partikel im Optimierungsalgorithmus verantwortlich, teilt den Raum in Sektoren auf, wählt zufällig Sektoren für jede Gruppe aus und verteilt die Partikel innerhalb der ausgewählten Sektoren. Die Partikel werden dann an Agenten zur weiteren Verarbeitung weitergeleitet.

//——————————————————————————————————————————————————————————————————————————————
void C_AO_MSO::Moving ()
{
  if (!revision)
  {
    //marking up sectors--------------------------------------------------------
    ArrayResize (min_max_Sector, coords);

    for (int c = 0; c < coords; c++)
    {
      sectorSpace [c] = (rangeMax [c] - rangeMin [c]) / sectNumb;
      min_max_Sector [c].Init (sectNumb);

      for (int sec = 0; sec < sectNumb; sec++)
      {
        min_max_Sector [c].min [sec] = rangeMin [c] + sectorSpace [c] * sec;
        min_max_Sector [c].max [sec] = min_max_Sector [c].min [sec] + sectorSpace [c];
      }
    }

    //--------------------------------------------------------------------------
    int    sect    = 0;   //sector
    double sectMin = 0.0; //sector's min
    double sectMax = 0.0; //sector's max
    int    ind     = 0;   //index
    double cd      = 0.0; //coordinate

    for (int s = 0; s < groups; s++)
    {
      //select random sectors for the group-------------------------------------
      for (int c = 0; c < coords; c++)
      {
        ind = (int)(RNDfromCI (0, sectNumb));
        if (ind >= sectNumb) ind = sectNumb - 1;

        gr [s].secInd     [c] = ind;
        gr [s].secIndLast [c] = ind;
      }

      //random distribute the particles of the group within the sectors---------
      for (int p = 0; p < ArraySize (gr [s].p); p++)
      {
        for (int c = 0; c < coords; c++)
        {
          sect               = gr [s].secInd [c];
          cd                 = RNDfromCI (min_max_Sector [c].min [sect], min_max_Sector [c].max [sect]);
          gr [s].p [p].c [c] = SeInDiSp (cd, rangeMin [c], rangeMax [c], rangeStep [c]);
        }
      }
    }

    //--------------------------------------------------------------------------
    //send particles to agents
    int cnt = 0;

    for (int s = 0; s < groups; s++)
    {
      for (int p = 0; p < ArraySize (gr [s].p); p++)
      {
        ArrayCopy (a [cnt].c, gr [s].p [p].c, 0, 0, WHOLE_ARRAY);
        cnt++;
      }
    }

    revision = true;
  }
}
//——————————————————————————————————————————————————————————————————————————————

Die wichtigsten Operationen zur Bewegung von Gruppen und ihren Partikeln durch den Suchraum werden mit der Revisionsmethode durchgeführt:

  • Aktualisierung der global besten Lösung durch Vergleich der Fitnessfunktionswerte für jedes Partikel mit dem aktuell besten Wert. Wenn der Zielfunktionswert für das aktuelle Partikel größer ist als der aktuelle beste Wert, wird er zum neuen besten Wert und seine Koordinaten werden in die Variable „cB“ kopiert.
  • Übertragung der Ergebnisse von Agenten auf Partikel und Bestimmung des besten Partikels in jeder Gruppe. Der Wert der Fitnessfunktion jedes Partikels wird gleich dem Wert der Zielfunktion des Agenten gesetzt, der diesem Partikel entspricht. Wenn der Wert einer Partikelfitnessfunktion größer ist als der aktuell beste Wert in der Gruppe, wird er zum neuen besten Wert und seine Koordinaten werden in die Variable „cB“ der Gruppe kopiert.
  • Aktualisierung der besten Lösung für jede Gruppe. Wenn der neue beste Wert in der Gruppe größer ist als der vorherige, wird er zum aktuellen besten Wert und seine Koordinaten werden in die Variablen „cBLast“ und „secIndLast“ der Gruppe kopiert.
  • Für jede Koordinate jeder Gruppe wird geprüft, ob es eine andere Gruppe mit einer besseren Lösung gibt. Wenn eine solche Gruppe existiert, werden der Sektor und der Mittelpunkt der aktuellen Gruppe mit den Werten des Sektors und des Mittelpunkts der Gruppe mit der besten Lösung aktualisiert. Ansonsten bleiben der Sektor und das Zentrum unverändert.
  • Schaffung neuer Partikel auf der Grundlage von Wahrscheinlichkeiten. Für jede Gruppe und jedes Partikel in der Gruppe werden auf der Grundlage von Wahrscheinlichkeiten neue Koordinatenwerte erzeugt. Die Wahrscheinlichkeit, eine Gleichverteilung oder eine Verteilung mit der Funktion PowerDistribution zu wählen, wird durch die Parameter „probUniformSector“ und „power“ bestimmt.
  • Verschieben der erzeugten Partikel zu Agenten zur weiteren Verwendung in der nächsten Iteration des Optimierungsalgorithmus.

Die Methode aktualisiert die Lösungen bei jeder Iteration, wobei Informationen über die besten Lösungen in den Gruppen und Wahrscheinlichkeiten verwendet werden, um neue Partikel zu erstellen.

//——————————————————————————————————————————————————————————————————————————————
void C_AO_MSO::Revision ()
{
  //----------------------------------------------------------------------------
  //Update the best global 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);
    }
  }

  //----------------------------------------------------------------------------
  //Transfer the results from the agents to the particles
  //and get the value of the best particle in the group at the current iteration
  int cnt = 0;
  for (int s = 0; s < groups; s++)
  {
    gr [s].fB = -DBL_MAX;

    for (int p = 0; p < ArraySize (gr [s].p); p++)
    {
      gr [s].p [p].f = a [cnt].f;

      if (a [cnt].f > gr [s].fB)
      {
        gr [s].fB = a [cnt].f;
        ArrayCopy (gr [s].cB, a [cnt].c, 0, 0, WHOLE_ARRAY);
      }

      cnt++;
    }
  }

  int sector = 0;

  //----------------------------------------------------------------------------
  //Update the best solution for the group
  for (int s = 0; s < groups; s++)
  {
    if (gr [s].fB > gr [s].fBLast)
    {
      gr [s].fBLast = gr [s].fB;
      ArrayCopy (gr [s].cBLast, gr [s].cB, 0, 0, WHOLE_ARRAY);
      ArrayCopy (gr [s].secIndLast, gr [s].secInd, 0, 0, WHOLE_ARRAY);
    }

    ArrayCopy (gr [s].centre, gr [s].cBLast);
  }


  //----------------------------------------------------------------------------
  int    sect    = 0;     //sector
  double sectMin = 0.0;   //sector's min
  double sectMax = 0.0;   //sector's max
  int    ind     = 0;     //index
  double cd      = 0.0;   //coordinate

  for (int s = 0; s < groups; s++)
  {
    for (int c = 0; c < coords; c++)
    {
      if (RNDfromCI (0.0, 1.0) < 0.6)
      {
        ind = (int)(RNDfromCI (0, groups));
        if (ind >= groups) ind = groups - 1;

        if (ind == s) ind++;
        if (ind > groups - 1) ind = 0;

        if (gr [ind].fBLast > gr [s].fBLast)
        {
          gr [s].secInd [c] = gr [ind].secIndLast [c];
          gr [s].centre [c] = gr [ind].cBLast [c];
        }
      }
      else
      {
        if (RNDfromCI (0.0, 1.0) < probRNSsector)
        {
          ind = (int)(RNDfromCI (0, sectNumb));
          if (ind >= sectNumb) ind = sectNumb - 1;

          gr [s].secInd [c] = ind;
          sect = gr [s].secInd [c];

          cd = RNDfromCI (min_max_Sector [c].min [sect], min_max_Sector [c].max [sect]);
          gr [s].centre [c] = SeInDiSp (cd, rangeMin [c], rangeMax [c], rangeStep [c]);
        }
        else gr [s].secInd [c] = gr [s].secIndLast [c];
      }
    }
  }

  //----------------------------------------------------------------------------
  for (int s = 0; s < groups; s++)
  {
    for (int p = 0; p < ArraySize (gr [s].p); p++)
    {
      for (int c = 0; c < coords; c++)
      {
        sect = gr [s].secInd [c];

        if (RNDfromCI (0.0, 1.0) < probUniformSector)
        {
          cd = RNDfromCI (min_max_Sector [c].min [sect], min_max_Sector [c].max [sect]);
        }
        else
        {
           cd = PowerDistribution (gr [s].centre [c], min_max_Sector [c].min [sect], min_max_Sector [c].max [sect], power);
        }

        gr [s].p [p].c [c] = SeInDiSp (cd, rangeMin [c], rangeMax [c], rangeStep [c]);
      }
    }
  }
  //----------------------------------------------------------------------------
  cnt = 0;

  for (int s = 0; s < groups; s++)
  {
    for (int p = 0; p < ArraySize (gr [s].p); p++)
    {
      ArrayCopy (a [cnt].c, gr [s].p [p].c, 0, 0, WHOLE_ARRAY);
      cnt++;
    }
  }
}
//——————————————————————————————————————————————————————————————————————————————

Als Nächstes betrachten wir denselben Algorithmus, jedoch mit zusätzlichem Gedächtniss für die Gruppe und ihre Partikel sowie einigen anderen Änderungen in der Logik der Suchstrategie.

Wir werden den Pseudocode des Algorithmus ändern und dabei die Verfügbarkeit von Gedächtnis für Gruppen und Partikel berücksichtigen:

  • 1. Sektoren nach dem Zufallsprinzip für Gruppen auswählen
  • 2. Punkte gleichmäßig auf die Sektoren verteilen
  • 4. FF berechnen
  • 5. Aktualisierung der globalen Lösung (beste Populationspartikel)
  • 6. Ermittlung des Werts des besten Partikels in der Gruppe in der aktuellen Iteration
  • 7. Aktualisierung des Gedächtnisses für die besten Lösungen in den Sektoren für jede Gruppe
  • 8. Aktualisierung des Gedächtnisses für die besten Lösungen in den Sektoren für jedes Partikel
  • 9. Aktualisierung der besten Lösung nach den Gruppen
  • 10. Eine Gruppe fragt eine andere Gruppe, ob ihre Lösung für jede Koordinate besser ist:
  • 10. a) wenn ja: dann verwende seinen Sektor
  • 10. b) wenn nicht: wählen mit einer gewissen Wahrscheinlichkeit einen anderen Sektor
  • 11. Partikel nach Wahrscheinlichkeiten erstellen:
  • 11. a) wenn ja: gleichmäßig über den Sektor verteilt
  • 11. b) wenn nicht: (Wahrscheinlichkeit ? (Kläre die Entscheidung der Gruppe) : (Kläre Ihre Entscheidung))
  • 12. Wiederholung ab S.4

Durch die Hinzufügung des Gedächtnisses könnte die Gruppe theoretisch Informationen über frühere Bewegungen speichern und diese für Entscheidungen über zukünftige Bewegungen nutzen. Dies kann Gruppen helfen, sich besser an ein sich veränderndes Umfeld anzupassen und den Lösungsraum effektiver zu erkunden.

Wir nehmen folgende Änderungen an der internen Architektur der Gruppe vor:

Swarm [groups]|
                        |-----------------------------------------
                        |fB
                        |-----------------------------------------
                        |fBLast
                        |-----------------------------------------
                        |cB               [coords]
                        |-----------------------------------------
                        |cBLast        [coords]
                        |-----------------------------------------
                        |secInd        [coords]
                        |-----------------------------------------
                        |secIndLast [coords]
                        |-----------------------------------------
                        |sMemory    [coords]|
                        |                               |---------------
                        |                               |cB      [sectNumb]
                        |                               |fB      [sectNumb]
                        |-----------------------------------------
                        |p         [groupSize] |
                        |                              |-------------------
                        |                              |c       [coords]
                        |                              |f
                        |                              |pMemory [coords]|
                        |                                                            |--------
                        |                                                            |cB [sectNumb]
                        |                                                            |fB [sectNumb]

Wir fügen die Struktur S_Memory hinzu, die das Gedächtnis beschreibt. Für Gruppen und Partikel sieht das Gedächtnis gleich aus und enthält zwei Arrays „cB“ und „fB“, in denen Informationen über die besten Koordinaten und eine Fitnessfunktion für diese Koordinaten gespeichert werden.

//——————————————————————————————————————————————————————————————————————————————
struct S_Memory
{
  void Init (int sectNumb)
  {
    ArrayResize     (cB, sectNumb);
    ArrayResize     (fB, sectNumb);
    ArrayInitialize (fB, -DBL_MAX);
  }
  double cB []; //the best sector coordinate, size is the number of sectors
  double fB []; //FF is the best coordinate on a sector, size is the number of sectors
};
//——————————————————————————————————————————————————————————————————————————————

Wir fügen dementsprechend Gedächtnisdeklarationen zu den Strukturen von Partikeln und Gruppen hinzu:

//——————————————————————————————————————————————————————————————————————————————
struct S_Particle
{
  <..............code is hidden.................>

  S_Memory pMemory []; //particle memory, size - the number of coordinates
};
//——————————————————————————————————————————————————————————————————————————————

//——————————————————————————————————————————————————————————————————————————————
struct S_Group
{
  <..............code is hidden.................>

  S_Memory sMemory []; //group memory, size - number of coordinates 
}; 
//——————————————————————————————————————————————————————————————————————————————

Die Änderungen betrafen auch die Revisionsmethode:

  • Aktualisierung der besten Sektorkoordinaten im Schwarmgedächtnis. Alle Sektoren werden für jede Gruppe und jede Koordinate aufgezählt. Wenn der „fB“-Wert einer Gruppe in einem Sektor größer ist als der „fB“-Wert im Sektorspeicher, werden „fB“ und „cB“ im Gedächtnis aktualisiert.
  • Aktualisierung der besten Positionen im Gedächtnis der Partikel. Wenn der Wert der Partikelfitnessfunktion größer ist als der Wert im Partikelgedächtnis, werden „fB“ und „cB“ im Gedächtnis aktualisiert.
//——————————————————————————————————————————————————————————————————————————————
void C_AO_MSO::Revision ()
{
  //----------------------------------------------------------------------------
  //Update the best global 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);
    }
  }

  //----------------------------------------------------------------------------
  //Transfer the results from the agents to the particles
  //and get the value of the best particle in the group at the current iteration
  int cnt = 0;
  for (int s = 0; s < groups; s++)
  {
    gr [s].fB = -DBL_MAX;

    for (int p = 0; p < ArraySize (gr [s].p); p++)
    {
      gr [s].p [p].f = a [cnt].f;

      if (a [cnt].f > gr [s].fB)
      {
        gr [s].fB = a [cnt].f;
        ArrayCopy (gr [s].cB, a [cnt].c, 0, 0, WHOLE_ARRAY);
      }

      cnt++;
    }
  }

  //----------------------------------------------------------------------------
  //Update the best sector coordinates in the swarm's memory
  int sector = 0;
  for (int s = 0; s < groups; s++)
  {
    for (int c = 0; c < coords; c++)
    {
      sector = gr [s].secInd [c];

      if (gr [s].fB > gr [s].sMemory [c].fB [sector])
      {
        gr [s].sMemory [c].fB [sector] = gr [s].fB;
        gr [s].sMemory [c].cB [sector] = gr [s].cB [c];
      }
    }
  }

  //----------------------------------------------------------------------------
  //Update in the memory of the particles their best positions by sector
  sector  = 0;
  for (int s = 0; s < groups; s++)
  {
    for (int p = 0; p < ArraySize (gr [s].p); p++)
    {
      for (int c = 0; c < coords; c++)
      {
        sector = gr [s].secInd [c];

        if (gr [s].p [p].f > gr [s].p [p].pMemory [c].fB [sector])
        {
          gr [s].p [p].pMemory [c].fB [sector] = gr [s].p [p].f;
          gr [s].p [p].pMemory [c].cB [sector] = gr [s].p [p].c [c];
        }
      }
    }
  }

  //----------------------------------------------------------------------------
  //Update the best solution for the group
  for (int s = 0; s < groups; s++)
  {
    if (gr [s].fB > gr [s].fBLast)
    {
      gr [s].fBLast = gr [s].fB;
      ArrayCopy (gr [s].cBLast, gr [s].cB, 0, 0, WHOLE_ARRAY);
      ArrayCopy (gr [s].secIndLast, gr [s].secInd, 0, 0, WHOLE_ARRAY);
    }
  }

  //----------------------------------------------------------------------------
  int    sect    = 0;     //sector
  double sectMin = 0.0;   //sector's min
  double sectMax = 0.0;   //sector's max
  int    ind     = 0;     //index
  double cd      = 0.0;   //coordinate

  for (int s = 0; s < groups; s++)
  {
    for (int c = 0; c < coords; c++)
    {
      ind = (int)(RNDfromCI (0, groups));
      if (ind >= groups) ind = groups - 1;

      if (ind == s) ind++;
      if (ind > groups - 1) ind = 0;

      if (RNDfromCI (0.0, 1.0) < 0.6)
      {
        if (gr [ind].fBLast > gr [s].fBLast)                                       
        {
          gr [s].secInd [c] = gr [ind].secIndLast [c];
        }
      }
      else                                                                      
      {
        if (RNDfromCI (0.0, 1.0) < probRNSsector)
        {
          ind = (int)(RNDfromCI (0, sectNumb));
          if (ind >= sectNumb) ind = sectNumb - 1;

          gr [s].secInd [c] = ind;
          sect = gr [s].secInd [c];

          if (gr [s].sMemory [c].fB [sect] == -DBL_MAX)
          {
            cd = RNDfromCI (min_max_Sector [c].min [sect], min_max_Sector [c].max [sect]);
            gr [s].sMemory [c].cB [sect] = SeInDiSp (cd, rangeMin [c], rangeMax [c], rangeStep [c]);
          }
        }
        else gr [s].secInd [c] = gr [s].secIndLast [c];
      }
    }
  }

  //----------------------------------------------------------------------------
  for (int s = 0; s < groups; s++)
  {
    for (int p = 0; p < ArraySize (gr [s].p); p++)
    {
      for (int c = 0; c < coords; c++)
      {
        sect = gr [s].secInd [c];

        if (RNDfromCI (0.0, 1.0) < probUniformSector)
        {
          cd = RNDfromCI (min_max_Sector [c].min [sect], min_max_Sector [c].max [sect]);
        }
        else
        {
          if (RNDfromCI (0.0, 1.0) < probClgroup)
          {
            cd = PowerDistribution (gr [s].sMemory [c].cB [sect], min_max_Sector [c].min [sect], min_max_Sector [c].max [sect], power);
          }
          else
          {
            cd = PowerDistribution (gr [s].p [p].pMemory [c].cB [sect], min_max_Sector [c].min [sect], min_max_Sector [c].max [sect], power);
          }
        }

        gr [s].p [p].c [c] = SeInDiSp (cd, rangeMin [c], rangeMax [c], rangeStep [c]);
      }
    }
  }

  //----------------------------------------------------------------------------
  //send the particles to the agents
  cnt = 0;

  for (int s = 0; s < groups; s++)
  {
    for (int p = 0; p < ArraySize (gr [s].p); p++)
    {
      ArrayCopy (a [cnt].c, gr [s].p [p].c, 0, 0, WHOLE_ARRAY);
      cnt++;
    }
  }
}
//——————————————————————————————————————————————————————————————————————————————


3. Testergebnisse

Die Algorithmentests ohne Berücksichtigung des Partikelgedächtnisses liefern recht gute Ergebnisse. Der Algorithmus rangiert in der Bewertungstabelle unter den ersten zehn. Es ist wichtig, darauf hinzuweisen, dass dieser Algorithmus nur ein Beispiel für eine Logik ist, und wenn er hervorragende Ergebnisse gezeigt hätte, hätte ich ihn in die Tabelle aufgenommen. Es gibt auch viele Möglichkeiten für die weitere Umsetzung und Änderung dieses Algorithmus.

Obwohl die Ergebnisse nicht herausragend sind, hat der Algorithmus gute Suchfähigkeiten bei der Erkundung verschiedener Bereiche des Suchraums gezeigt.

C_AO_MSO|60|30|9|0.05|0.05|10.0
=============================
5 Hilly's; Func runs: 10000; result: 0.9313358190790157
25 Hilly's; Func runs: 10000; result: 0.6649184286250989
500 Hilly's; Func runs: 10000; result: 0.3282041522365852
=============================
5 Forest's; Func runs: 10000; result: 0.9522099605531393
25 Forest's; Func runs: 10000; result: 0.5542256622730999
500 Forest's; Func runs: 10000; result: 0.08984352753493675
=============================
5 Megacity's; Func runs: 10000; result: 0.7899999999999998
25 Megacity's; Func runs: 10000; result: 0.33533333333333326
500 Megacity's; Func runs: 10000; result: 0.042983333333333325
=============================
All score: 4.68905 (52.1%)

Diese Ergebnisse beziehen sich auf die sozialen Gruppen mit Gedächtnis. Es ist eine leichte Verschlechterung der Gesamtergebnisse des Algorithmus festzustellen. Dennoch nimmt dieser Algorithmus seinen rechtmäßigen Platz an der Spitze der Bewertungstabelle ein. Dies zeigt das Potenzial des Algorithmus und seine Fähigkeit, zufriedenstellende Ergebnisse zu erzielen. Die Idee, das Konzept der gemeinsamen Nutzung des Gedächtnisses nicht nur zwischen Gruppen, sondern auch zwischen ihren Partikeln zu berücksichtigen, ist ein logischer Schritt zur Verbesserung des Algorithmus. Die Einführung dieser zusätzlichen Interaktion kann zu neuen Ideen und Strategien führen. Wie bereits erwähnt, werden in diesem Artikel verschiedene Szenarien der Interaktion zwischen sozialen Gruppen beschrieben, von denen ich nur einen Teil aufgenommen habe. Das bedeutet, dass es viel Spielraum für Änderungen und Verbesserungen des Algorithmus gibt.

C_AO_MSOm|60|30|9|0.1|0.9|0.1|10.0
=============================
5 Hilly's; Func runs: 10000; result: 0.9468984351872132
25 Hilly's; Func runs: 10000; result: 0.5865441453580522
500 Hilly's; Func runs: 10000; result: 0.3186653673403949
=============================
5 Forest's; Func runs: 10000; result: 0.9064162754293653
25 Forest's; Func runs: 10000; result: 0.43175851113448455
500 Forest's; Func runs: 10000; result: 0.06865408175918558
=============================
5 Megacity's; Func runs: 10000; result: 0.6783333333333333
25 Megacity's; Func runs: 10000; result: 0.213
500 Megacity's; Func runs: 10000; result: 0.03310000000000002
=============================
All score: 4.18337 (46.4%)

Hilly

  MSO mit der Testfunktion Hilly

Forest

  MSO mit der Testfunktion Forest

Megacity

  MSO mit der Testfunktion Megacity


Zusammenfassung

Unter Berücksichtigung der bisherigen Überlegungen und Ergebnisse kann ich Folgendes hinzufügen:

Bei den Experimenten wurde festgestellt, dass der Algorithmus mit Speicher im Vergleich zum Algorithmus ohne Gedächtnis etwas schlechtere Ergebnisse lieferte. Das bedeutet jedoch nicht, dass der gedächtnisbasierte Algorithmus weniger vielversprechend ist. Höchstwahrscheinlich muss das Konzept des Gedächtnisaustauschs zwischen Gruppen und Partikeln geändert werden, um seine Ergebnisse zu verbessern.

Darüber hinaus ist es erwähnenswert, dass die Einbeziehung anderer Prinzipien der Interaktion zwischen sozialen Gruppen die Effizienz des Erinnerungsalgorithmus erheblich verbessern kann. Die Einführung von Mechanismen für die Zusammenarbeit, die Koordinierung und das Lernen zwischen Gruppen kann zu erheblichen Leistungsverbesserungen führen und den Algorithmus auf einen der vorderen Plätze in unserer Bewertungstabelle bringen.

Abschließend wird in der Studie ein neues Konzept für die Entwicklung sozialer Gruppen vorgeschlagen, das auf der Bewegung zwischen Sektoren und der Nutzung des Gedächtnisses beruht. Diese Konzepte eröffnen neue Möglichkeiten zur Untersuchung sozialer Systeme und ihrer Fähigkeit zur Kooperation, Koordination und Anpassung. Ich hoffe, dass die Ergebnisse dazu beitragen werden, besser zu verstehen, wie soziale Gruppen in einem komplexen sozialen Umfeld funktionieren und sich entwickeln, und dass sie eine Gelegenheit für weitere Forschungen in diesem Bereich bieten werden.

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

Beigefügte Dateien |
Entwicklung eines Expertenberaters für mehrere Währungen (Teil 3): Überarbeitung der Architektur Entwicklung eines Expertenberaters für mehrere Währungen (Teil 3): Überarbeitung der Architektur
Wir haben bereits einige Fortschritte bei der Entwicklung eines Mehrwährungs-EAs mit mehreren parallel arbeitenden Strategien gemacht. In Anbetracht der gesammelten Erfahrungen sollten wir die Architektur unserer Lösung überprüfen und versuchen, sie zu verbessern, bevor wir zu weit vorpreschen.
Wie Sie mit der Erfüllung von Händleraufträgen im Freelance-Service Geld verdienen können Wie Sie mit der Erfüllung von Händleraufträgen im Freelance-Service Geld verdienen können
MQL5 Freelance ist ein Online-Dienst, bei dem Entwickler für die Erstellung von Handelsanwendungen für Händler als Kunden bezahlt werden. Der Dienst existiert seit 2010 sehr erfolgreich und hat bis heute über 100.000 Projekte im Gesamtwert von 7 Millionen Dollar abgeschlossen. Wie wir sehen, geht es hier um eine beträchtliche Menge Geld.
Verwendung von Optimierungsalgorithmen zur Konfiguration von EA-Parametern im laufenden Betrieb Verwendung von Optimierungsalgorithmen zur Konfiguration von EA-Parametern im laufenden Betrieb
Der Artikel behandelt die praktischen Aspekte der Verwendung von Optimierungsalgorithmen, um die besten EA-Parameter im laufenden Betrieb zu finden, sowie die Virtualisierung von Handelsoperationen und EA-Logik. Der Artikel kann als Anleitung für die Implementierung von Optimierungsalgorithmen in einen EA verwendet werden.
Entwicklung eines Expertenberaters für mehrere Währungen (Teil 2): Übergang zu virtuellen Positionen von Handelsstrategien Entwicklung eines Expertenberaters für mehrere Währungen (Teil 2): Übergang zu virtuellen Positionen von Handelsstrategien
Lassen Sie uns mit der Entwicklung eines Multiwährungs-EAs mit mehreren parallel arbeitenden Strategien fortfahren. Versuchen wir, die gesamte mit der Eröffnung von Marktpositionen verbundene Arbeit von der Strategieebene auf die Ebene des EA zu verlagern, der die Strategien verwaltet. Die Strategien selbst werden nur virtuell gehandelt, ohne Marktpositionen zu eröffnen.