Chaos-Optimierungsalgorithmus (COA)
Inhalt
Einführung
Bei modernen rechnergestützten Problemstellungen, insbesondere auf den Finanzmärkten und im algorithmischen Handel, spielen effiziente Optimierungsmethoden eine entscheidende Rolle. Unter den zahlreichen globalen Optimierungsalgorithmen nehmen von Naturphänomenen inspirierte Ansätze einen besonderen Platz ein. Der Chaos-Optimierungs-Algorithmus (COA) ist eine solche innovative Lösung, die Chaostheorie und globale Optimierungsmethoden kombiniert.
In diesem Artikel stelle ich einen verbesserten chaotischen Optimierungsalgorithmus vor, der grundlegende Eigenschaften chaotischer Systeme ausnutzt – Ergodizität, Empfindlichkeit gegenüber Anfangsbedingungen und quasi-stochastisches Verhalten. Der Algorithmus verwendet verschiedene chaotische Abbildungen, um den Suchraum effizient zu erkunden und lokale Optima zu vermeiden, ein Problem, das bei Optimierungsmethoden häufig auftritt.
Eine Besonderheit des vorgeschlagenen Algorithmus ist, dass er die chaotische Suche mit der gewichteten Gradientenmethode und adaptiven Mechanismen kombiniert, die eine dynamische Anpassung der Suchparameter ermöglichen. Durch die Verwendung verschiedener Arten von chaotischen Abbildungen – die logistische Abbildung, die Sinusabbildung und die Tent-Abbildung – zeigt der Algorithmus eine gute Widerstandsfähigkeit gegen Stagnation und die Fähigkeit, globale Optima in komplexen multimodalen Funktionen zu finden. Wie üblich werden wir den gesamten Algorithmus analysieren und dann seine Fähigkeiten mit unseren inzwischen standardisierten Testfunktionen testen.
Implementierung des Algorithmus
Der Algorithmus besteht aus drei Hauptphasen:
- Chaotische Suche mit der ersten Carrier-Wave, bei der zunächst die chaotischen Anfangsvariablen initialisiert, anschließend ihre Folgewerten über eine logistische Abbildung erzeugt, auf den Optimierungsbereich projiziert und die beste gefundene Lösung gespeichert werden;
- Suche entlang der Richtung des gewichteten Gradienten;
- chaotische Suche mit einer zweiten Carrier-Wave, bei der eine lokale Suche um die beste Lösung herum durchgeführt wird, mit einem fraktalen Ansatz zur Implementierung der Schrittweite.
In der nachstehenden Abbildung habe ich versucht, das Wesen des chaotischen Optimierungsalgorithmus zu veranschaulichen, dessen Hauptidee darin besteht, das Chaos als nützliches Optimierungsinstrument und nicht als Zufallsprozess zu nutzen. Das globale Optimum (hellgelb leuchtend in der Mitte) ist das Ziel, das wir finden wollen. Die blau leuchtenden Partikel sind Suchagenten, die sich entlang chaotischer Trajektorien bewegen. Diese Bahnen werden durch leuchtende Linien dargestellt, die die nichtlineare Natur der Bewegung zeigen.
Die Abbildung veranschaulicht die Schlüsseleigenschaften chaotischen Verhaltens: Determinismus (Trajektorien sind glatt, nicht zufällig), Ergodizität (Partikel erkunden den gesamten Raum), Empfindlichkeit gegenüber Anfangsbedingungen (verschiedene Partikel bewegen sich auf unterschiedlichen Bahnen). Die Suchdynamik wird durch ein Leuchten unterschiedlicher Intensität dargestellt, das die „Energie“ der Suche in verschiedenen Bereichen visualisiert, wobei konzentrische Kreise um das Optimum Anziehungsbereiche symbolisieren und Unschärfen sowie Farbverläufe die Kontinuität des Suchraums vermitteln. Die wichtigsten Phasen des Algorithmus:
- breite Suche vom Zentrum weg (entfernte Teilchen),
- schrittweise Annäherung an vielversprechende Gebiete (mittlere Trajektorien),
- lokale Suche in der Nähe des Optimums (Partikel in der Nähe des Zentrums).
Das sich daraus ergebende Bild kann als ein „Porträt“ der chaotischen Optimierung betrachtet werden, in dem das Chaos nicht als Unordnung, sondern als kontrollierter Prozess der Erkundung des Lösungsraums dargestellt wird.

Abbildung 1. Visualisierung der chaotischen Optimierung
Das nachstehende visuelle Diagramm des Algorithmus spiegelt drei Hauptphasen wider:
- Die erste Carrier-Wave-Suche (blauer Block) verwendet eine chaotische Abbildung für die globale Suche und transformiert die chaotischen Variablen in den Suchraum,
- Die gewichtete Gradientensuche (orangefarbener Block) ist ein gewichtetes Gradientenverfahren, bei dem auch Nebenbedingungen über Gewichtsverhältnisse berücksichtigt werden,
- Zweite Carrier-Wave-Suche (violetter Block) – lokale Suche nach der besten Lösung und adaptive Abstimmung des Parameters α.

Abbildung 2. Ablaufschema des chaotischen Optimierungsalgorithmus
Das Diagramm zeigt die grundlegende dreistufige Struktur des COA-Algorithmus (CHAOS). In meiner Implementierung (und davon gab es mehrere) entschied ich mich für eine fortgeschrittenere und praktischere Version des Algorithmus, erweiterte die Agentenstruktur, fügte einen Bewegungszähler, einen Stagnationszähler und chaotische Variablen für jede Dimension hinzu. Es war auch wichtig, die chaotischen Abbildungen zu variieren; die Autoren verwendeten ausschließlich die logistische Abbildung, während meine Version Sinus- und Tent-Abbildungen hinzugefügt hat. Diese Implementierung beinhaltet die automatische Anpassung der Strafparameter, die Anpassung der Suchparameter, je nach Erfolg mit Trägheitsanpassung. Zusätzlich wurde eine komplexere Initialisierung unter Verwendung des Latin Hypercube hinzugefügt.
Beginnen wir mit dem Schreiben des Pseudocodes für den Algorithmus:
Initialisierung des Algorithmus
- Einstellung der Algorithmusparameter:
- Populationsgröße (popSize)
- Anzahl der Iterationen der ersten Phase (S1)
- Anzahl der Iterationen der zweiten Phase (S2)
- Strafparameter (sigma)
- Anpassungsquote (t3)
- kleine Konstante für Gewichtsverhältnisse (eps)
- Trägheitsparameter (Trägheit)
- Parameter für den sozialen Einfluss (socialFactor)
- Mutationswahrscheinlichkeit (mutationRate)
- Initialisierung der Agenten:
- Für jeden Agenten in der Population:
- chaotische Variablen (Gamma) mit verschiedenen Anfangswerten initialisieren
- Geschwindigkeitsvektoren zurücksetzen (Geschwindigkeit)
- den Stagnationszähler auf 0 setzen
- Für jeden Agenten in der Population:
- Initialisierung der Suchparameter (alpha):
- Anpassung der Parameter je nach Größe des Suchraums
- alpha[c] = 0,1 * (rangeMax[c] – rangeMin[c]) / sqrt(coords)
Phase 1: Ausgangspopulation mit chaotischer Verteilung
- Erstellung einer Ausgangspopulation mithilfe eines Latin Hypercube:
- Werte für jede Dimension erzeugen
- die Werte mischen, um eine gleichmäßige Verteilung sicherzustellen
- die Werte auf den Variablenbereich abbilden.
- Es werden verschiedene Strategien zur Initialisierung der Agenten verwendet:
- für das erste Quartal der Agenten: gleichmäßige Verteilung
- für das zweite Quartal: Clusterbildung um mehrere Punkte
- für das dritte Quartal: zufällige Positionen mit einer Verschiebung zu den Rändern
- für das letzte Quartal: chaotische Positionen mit verschiedenen Abbildungen
Phase 2: Chaotische Suche mit der ersten Carrier-Wave
- Für jede Iteration bis zu S1:
- Für jeden Agenten in der Population:
- wenn die Mutationswahrscheinlichkeit ausgelöst wird, die Mutation anwenden
- ansonsten für jede Koordinate:
- Aktualisiere die chaotischen Variablen über die gewählte Abbildung (logistische, Sinus- oder Tent-Abbildung).
- Bestimme die Strategie (globale oder lokale Suche) auf der Grundlage der Optimierungsphase.
- Für die globale Suche: verwende chaotische Werte zur Bestimmung der neuen Position.
- für die lokale Suche: kombiniere die Anziehungskraft auf die besten Lösungen mit chaotischer Störung.
- Aktualisiere die Geschwindigkeit unter Berücksichtigung der Trägheit.
- Berücksichtige die Geschwindigkeits- und Positionsgrenzen.
- Prüfe auf Verstöße gegen Beschränkungen und nimm Korrekturen vor.
- Bewertung und Aktualisierung:
- Berechne die Straffunktion für jeden Agenten.
- Aktualisiere die besten persönlichen und globalen Lösungen.
- Aktualisiere dynamisch die Strafparameter.
- Passe den Suchparameter (Alpha) je nach Erfolg an.
- Für jeden Agenten in der Population:
Phase 3: Chaotische Suche mit der zweiten Carrier-Wave
- Für jede Iteration von S1 bis S1+S2:
- Prüfe auf Konvergenz
- für jeden Agenten in der Population:
- Wenn Konvergenz festgestellt wird, wende eine zufällige Mutation bei einigen Agenten an.
- ansonsten für jede Koordinate:
- die chaotische Variable aktualisieren
- Schränke den Suchradius adaptiv ein.
- Wähle einen Basispunkt aus, wobei die besten Lösungen Vorrang haben.
- Füge chaotische Störungen und Lévy-Rauschen hinzu, um zufällige weite Sprünge zu ermöglichen.
- Aktualisierung von Geschwindigkeit und Position mit Trägheit
- Positionsbeschränkungen anwenden
- Bewertung und Aktualisierung:
- Berechne die Straffunktion für jeden Agenten.
- Aktualisiere die besten persönlichen und globalen Lösungen.
- Aktualisiere die Geschichte der besten globalen Lösung, um die Konvergenz zu bestimmen.
- Setze festsitzende Agenten bei Bedarf zurück.
Hilfsfunktionen
- Chaotische Abbildungen:
- LogisticMap(x): x[n+1] = rx[n](1-x[n]) mit Validierung
- SineMap(x): x[n+1] = sin(π*x[n]) mit Normierung
- TentMap(x): x[n+1] = μ*min(x[n], 1-x[n]) mit Validierung
- SelectChaosMap(x, type): Auswahl einer Abbildung anhand des Typs
- Umgang mit Beschränkungen und Sanktionen:
- CalculateConstraintValue(agent, coord): Berechnung der Verletzung einer Nebenbedingung
- CalculateConstraintGradient(agent, coord): Berechnung des Gradienten der Nebenbedingung.
- CalculateWeightedGradient(agent, coord): Berechnung des gewichteten Gradienten
- CalculatePenaltyFunction(agent): Berechnung des Wertes der Straffunktion
- Umgang mit Stagnation und Konvergenz:
- IsConverged(): Überprüfung der Konvergenz anhand der Historie der besten Lösungen
- ResetStagnatingAgents(): Zurücksetzen von stagnierenden Agenten.
- ApplyMutation(agent): Anwendung verschiedener Arten von Mutationen
- UpdateSigma(): Dynamische Aktualisierung des Strafparameters
- UpdateBestHistory(newBest): Aktualisierung der Historie der besten Werte
Nun können wir mit der Beschreibung der Implementierung des COA-Algorithmus (CHAOS) fortfahren. In diesem Artikel werden wir alle wichtigen Implementierungsmethoden untersuchen, und im nächsten Artikel werden wir direkt zu den Tests und den Leistungsergebnissen des Algorithmus übergehen. Implementieren wir die Struktur S_COA_Agent und die Strukturfelder:
- gamma [] – Satz chaotischer Variablen des Pseudo-Zufallstyps, die verwendet werden, um Elemente des Zufalls und der Vielfalt in das Verhalten des Agenten einzuführen,
- velocity [] – Array von Geschwindigkeiten, erlaubt es dem Agenten, sich dynamischer durch den Raum zu bewegen und dabei die Trägheit zu berücksichtigen,
- stagnationCounter – Zähler, der sich erhöht, wenn der Agent keine Verbesserung seiner Lösung zeigt; er hilft bei der Implementierung von Mechanismen zum Neustart von Strategien im Falle einer Stagnation.
Mit der Methode Init() werden die Anfangswerte von Arrays erstellt und festgelegt. Für gamma[] wird eine gleichmäßige Verteilung zwischen 0,1 und 0,9 verwendet, um Abwechslung in die Anfangsbedingungen der chaotischen Variablen zu bringen. Die Geschwindigkeiten in velocity [] beginnen bei Null, der Stagnationszähler wird auf Null gesetzt.
//—————————————————————————————————————————————————————————————————————————————— // Improved agent structure with additional fields struct S_COA_Agent { double gamma []; // chaotic variables double velocity []; // movement velocity (to increase inertia) int stagnationCounter; // stagnation counter void Init (int coords) { ArrayResize (gamma, coords); ArrayResize (velocity, coords); // Uniform distribution of gamma values for (int i = 0; i < coords; i++) { // Use different initial values for better variety gamma [i] = 0.1 + 0.8 * (i % coords) / (double)MathMax (1, coords - 1); // Initialize velocity with zeros velocity [i] = 0.0; } stagnationCounter = 0; } }; //——————————————————————————————————————————————————————————————————————————————
Die Klasse C_AO_COA_chaos ist von der Basisklasse C_AO abgeleitet und ist eine Implementierung des COA(CHAOS)-Algorithmus. Sie enthält die für den Betrieb erforderlichen Methoden und Parameter sowie zusätzliche Funktionen zur Steuerung des Verhaltens der Agenten, die auf den Konzepten der chaotischen Suche basieren. Komponenten der Klasse:
- SetParams () – Methode zur Einstellung der Algorithmusparameter,
- Init () – Initialisierungsmethode, die Bereiche und Parameter für den Betrieb des Algorithmus annimmt,
- Moving () – Methode, die für das Verschieben von Agenten im Lösungsraum zuständig ist,
- Revision () – Methode zur Überprüfung bzw. Korrektur der Agentenpositionen.
- S1, S2 – Anzahl der Iterationen in zwei Phasen des Algorithmus.
- sigma, t3, eps, inertia, socialFactor, mutationRate – Parameter, die das Verhalten der Agenten und den Algorithmus als Ganzes beeinflussen.
- alpha [] – Array von Parametern, die für die Suche verwendet werden.
- agent [] – Array von Agenten, aus denen die Population des Algorithmus besteht.
- Methoden zur Berechnung von Gradienten, Nebenbedingungen und Straffunktionen sowie zur Überprüfung der Durchführbarkeit von Lösungen (IsFeasible),
- Methoden für chaotische Abbildungen (LogisticMap, SineMap, TentMap, SelectChaosMap).
- Variablen, die Informationen über die aktuelle Epoche (epochs, epochNow) und den dynamischen Strafterm (currentSigma) speichern,
- globalBestHistory [] – Array zur Speicherung der global besten Werte über mehrere Iterationen,
- Index der Historie (historyIndex) zur Verfolgung der Position im Array der besten Werte,
- Die Methoden zur Verwaltung der Agentenpopulation (InitialPopulation), zur Durchführung der verschiedenen Suchphasen (FirstCarrierWaveSearch, SecondCarrierWaveSearch), zur Mutation von Agenten (ApplyMutation), zur Aktualisierung des Strafterms (UpdateSigma) und zur Überprüfung der Konvergenz (IsConverged) sowie zum Zurücksetzen stagnierender Agenten (ResetStagnatingAgents).
Die Klasse C_AO_COA_chaos ist also eine komplexe Komponente eines Optimierungssystems, das Agenten zur Lösungsfindung einsetzt. Es integriert die Parameter, Methoden und Logik, die zur Steuerung von Agenten innerhalb eines Algorithmus benötigt werden, einschließlich deterministischer und chaotischer Strategien.
//—————————————————————————————————————————————————————————————————————————————— class C_AO_COA_chaos : public C_AO { public: //-------------------------------------------------------------------- ~C_AO_COA_chaos () { } C_AO_COA_chaos () { ao_name = "COA(CHAOS)"; ao_desc = "Chaos Optimization Algorithm"; ao_link = "https://www.mql5.com/de/articles/16729"; // Internal parameters (not externally configurable) inertia = 0.7; socialFactor = 1.5; mutationRate = 0.05; // Default parameters popSize = 50; S1 = 30; S2 = 20; sigma = 2.0; t3 = 1.2; eps = 0.0001; // Initialize the parameter array for the C_AO interface ArrayResize (params, 6); params [0].name = "popSize"; params [0].val = popSize; params [1].name = "S1"; params [1].val = S1; params [2].name = "S2"; params [2].val = S2; params [3].name = "sigma"; params [3].val = sigma; params [4].name = "t3"; params [4].val = t3; params [5].name = "eps"; params [5].val = eps; } void SetParams () { // Update internal parameters from the params array popSize = (int)params [0].val; S1 = (int)params [1].val; S2 = (int)params [2].val; sigma = params [3].val; t3 = params [4].val; eps = params [5].val; } bool Init (const double &rangeMinP [], // minimum search range const double &rangeMaxP [], // maximum search range const double &rangeStepP [], // search step const int epochsP = 0); // number of epochs void Moving (); void Revision (); //---------------------------------------------------------------------------- // External algorithm parameters int S1; // first phase iterations int S2; // second phase iterations double sigma; // penalty parameter double t3; // alpha correction ratio double eps; // small number for weighting ratios // Internal algorithm parameters double inertia; // inertia parameter for movement (internal) double socialFactor; // social influence parameter (internal) double mutationRate; // mutation probability (internal) S_COA_Agent agent []; // array of agents private: //------------------------------------------------------------------- int epochNow; double currentSigma; // Dynamic penalty parameter double alpha []; // search parameters double globalBestHistory [10]; // History of global best solution values int historyIndex; // Auxiliary methods double CalculateWeightedGradient (int agentIdx, int coordIdx); double CalculateConstraintValue (int agentIdx, int coordIdx); double CalculateConstraintGradient (int agentIdx, int coordIdx); double CalculatePenaltyFunction (int agentIdx); // Method for checking the solution feasibility bool IsFeasible (int agentIdx); // Chaotic maps double LogisticMap (double x); double SineMap (double x); double TentMap (double x); double SelectChaosMap (double x, int type); void InitialPopulation (); void FirstCarrierWaveSearch (); void SecondCarrierWaveSearch (); void ApplyMutation (int agentIdx); void UpdateSigma (); void UpdateBestHistory (double newBest); bool IsConverged (); void ResetStagnatingAgents (); }; //——————————————————————————————————————————————————————————————————————————————
Die Init-Methode der Klasse C_AO_COA ist für die anfängliche Einrichtung und Vorbereitung des Algorithmus für den Betrieb zuständig. Sie führt mehrere wichtige Aufgaben aus: Zunächst führt sie eine grundlegende Initialisierung mit der Methode StandardInit() durch, die Bereiche, Schritte und andere Parameter einrichtet. Wenn dies nicht gelingt, schlägt die Initialisierung fehl.
Als Nächstes werden die Parameter für die Anzahl der Epochen, die aktuelle Epoche (epochNow) und den Strafterm (currentSigma) festgelegt. Eine Historie der besten Lösungen wird initialisiert, um den Fortschritt zu verfolgen. Die Größe der Arrays der zu suchenden Mindest- und Höchstwertbereiche wird überprüft. Wenn die Größen nicht übereinstimmen oder nicht angegeben sind, wird die Initialisierung abgebrochen.
Anschließend werden Arrays initialisiert, in denen Agenten, Alpha-Verhältnisse und die besten gefundenen Lösungen gespeichert werden. Jeder Agent erhält eine Ausgangsposition, die auf verschiedenen Strategien basiert:
- Ein Teil der Agenten verteilt sich gleichmäßig über den gesamten Bereich,
- Eine andere Gruppierung um mehrere Punkte innerhalb eines Bereichs.
- Andere werden nach dem Zufallsprinzip unter Berücksichtigung der Grenzen positioniert,
- Die übrigen verwenden chaotische Abbildungsfunktionen, um Ausgangslösungen zu erhalten.
Die Init-Methode der Klasse C_AO_COA_chaos setzt die Anfangsparameter und Arrays, die für die Suche nach der optimalen Lösung erforderlich sind. Der Prozess umfasst die Überprüfung der Korrektheit der Eingabedaten, die Einrichtung von Suchbereichen, die Initialisierung eines Arrays von Agenten mit verschiedenen Startpositionsstrategien und die Festlegung der Werte globaler Variablen wie der besten gefundenen Lösung. Während der Ausführung des Verfahrens werden die für den weiteren iterativen Optimierungsprozess notwendigen Datenstrukturen angelegt und Parameter gesetzt, die das Verhalten der Agenten und des Algorithmus insgesamt regeln.
//—————————————————————————————————————————————————————————————————————————————— bool C_AO_COA_chaos::Init (const double &rangeMinP [], const double &rangeMaxP [], const double &rangeStepP [], const int epochsP = 0) { if (!StandardInit (rangeMinP, rangeMaxP, rangeStepP)) return false; //---------------------------------------------------------------------------- epochNow = 0; currentSigma = sigma; historyIndex = 0; // Initialize the history of best values for (int i = 0; i < 10; i++) globalBestHistory [i] = -DBL_MAX; // Check and initialize the main arrays int arraySize = ArraySize (rangeMinP); if (arraySize <= 0 || arraySize != ArraySize (rangeMaxP) || arraySize != ArraySize (rangeStepP)) { return false; } ArrayResize (agent, popSize); ArrayResize (alpha, coords); // Adaptive alpha initialization depending on the search range for (int c = 0; c < coords; c++) { // alpha depends on the size of the search space double range = rangeMax [c] - rangeMin [c]; alpha [c] = 0.1 * range / MathSqrt (MathMax (1.0, (double)coords)); } // Initialize of agents with various strategies for (int i = 0; i < popSize; i++) { agent [i].Init (coords); for (int c = 0; c < coords; c++) { double position; // Different initialization strategies if (i < popSize / 4) { // Uniform distribution in space position = rangeMin [c] + (i * (rangeMax [c] - rangeMin [c])) / MathMax (1, popSize / 4); } else if (i < popSize / 2) { // Clustering around multiple points int cluster = (i - popSize / 4) % 3; double clusterCenter = rangeMin [c] + (cluster + 1) * (rangeMax [c] - rangeMin [c]) / 4.0; position = clusterCenter + u.RNDfromCI (-0.1, 0.1) * (rangeMax [c] - rangeMin [c]); } else if (i < 3 * popSize / 4) { // Random positions with an offset towards the boundaries double r = u.RNDprobab (); if (r < 0.5) position = rangeMin [c] + 0.2 * r * (rangeMax [c] - rangeMin [c]); else position = rangeMax [c] - 0.2 * (1.0 - r) * (rangeMax [c] - rangeMin [c]); } else { // Chaotic positions using different maps int mapType = i % 3; double chaosValue = SelectChaosMap (agent [i].gamma [c], mapType); position = rangeMin [c] + chaosValue * (rangeMax [c] - rangeMin [c]); } a [i].cB [c] = u.SeInDiSp (position, rangeMin [c], rangeMax [c], rangeStep [c]); } } return true; } //——————————————————————————————————————————————————————————————————————————————
Die Methode LogisticMap implementiert die logistische Abbildung, die zur Erzeugung chaotischer Sequenzen verwendet wird. Diese Funktion wird in dem Algorithmus verwendet, um Zufälligkeit und Abwechslung in die Lösungssuche zu bringen. Die Hauptidee der Methode ist die Berechnung eines neuen Zustandswertes auf der Grundlage des aktuellen Zustands unter Verwendung der logistischen Abbildungsgleichung mit einem Parameter, der leicht variiert wird, um das chaotische Verhalten zu verbessern.
Vor der Berechnung wird der Eingabewert auf Gültigkeit und Bereich geprüft; stimmt er nicht überein, wird er durch eine Zufallszahl innerhalb des angegebenen Bereichs ersetzt. Nach der Berechnung des neuen Wertes wird dieser ebenfalls auf einen akzeptablen Bereich überprüft und gegebenenfalls durch eine Zufallszahl ersetzt, um die Stabilität der Funktion zu gewährleisten. Dadurch stellt die interne Logik sicher, dass der nächste Zustand generiert wird, ohne dass die Grenzen überschritten werden.
//—————————————————————————————————————————————————————————————————————————————— // Improved chaotic maps double C_AO_COA_chaos::LogisticMap (double x) { // Protection against incorrect inputs if (x < 0.0 || x > 1.0 || MathIsValidNumber (x) == false) { x = 0.2 + 0.6 * u.RNDprobab (); } // x(n+1) = r*x(n)*(1-x(n)) double r = 3.9 + 0.1 * u.RNDprobab (); // Slightly randomized parameter to avoid loops double result = r * x * (1.0 - x); // Additional validation if (result < 0.0 || result > 1.0 || MathIsValidNumber (result) == false) { result = 0.2 + 0.6 * u.RNDprobab (); } return result; } //——————————————————————————————————————————————————————————————————————————————
Die Methode SineMap implementiert eine chaotische Abbildung auf der Grundlage der Sinusfunktion. Sie nimmt den aktuellen Zustand, prüft seine Gültigkeit und ersetzt ihn durch einen Zufallswert in diesem Bereich, wenn er falsch ist oder außerhalb des Bereichs [0, 1] liegt. Anschließend wird ein neuer Wert mithilfe der Sinusfunktion berechnet, normalisiert, sodass er wieder im Bereich [0, 1] liegt, und eine weitere Prüfung durchgeführt.
Liegt der endgültige Wert außerhalb der Grenzen oder ist er ungültig, wird er erneut durch eine Zufallszahl im Bereich [0,2, 0,8] ersetzt. Als Ergebnis liefert die Methode einen neuen Zustand, der auf der Grundlage des aktuellen Zustands mithilfe der chaotischen Abbildung ermittelt wird.
//—————————————————————————————————————————————————————————————————————————————— double C_AO_COA_chaos::SineMap (double x) { // Protection against incorrect inputs if (x < 0.0 || x > 1.0 || MathIsValidNumber (x) == false) { x = 0.2 + 0.6 * u.RNDprobab (); } // x(n+1) = sin(π*x(n)) double result = MathSin (M_PI * x); // Normalize the result to the range [0, 1] result = (result + 1.0) / 2.0; // Additional validation if (result < 0.0 || result > 1.0 || MathIsValidNumber (result) == false) { result = 0.2 + 0.6 * u.RNDprobab (); } return result; } //——————————————————————————————————————————————————————————————————————————————
Die TentMap-Methode implementiert eine Tent-Abbildung zur Erzeugung einer chaotischen Sequenz. Die Methode nimmt einen Eingabewert „x“, der zwischen 0 und 1 liegen sollte, prüft „x“ auf Gültigkeit und ersetzt ihn gegebenenfalls durch einen Zufallswert innerhalb des zulässigen Bereichs. Anschließend wird unter Verwendung eines „mu“-Parameters nahe 2 ein neuer Wert auf der Grundlage einer für die „Tent“-Abbildung charakteristischen stückweisen linearen Funktion berechnet.
Nach der Berechnung wird eine weitere Prüfung durchgeführt, um sicherzustellen, dass der Wert gültig ist, und, falls erforderlich, wird er mit einer Zufallszahl normalisiert. Die Methode gibt dann einen neuen, zufällig generierten Wert zurück.
//—————————————————————————————————————————————————————————————————————————————— double C_AO_COA_chaos::TentMap (double x) { // Protection against incorrect inputs if (x < 0.0 || x > 1.0 || MathIsValidNumber (x) == false) { x = 0.2 + 0.6 * u.RNDprobab (); } // Tent map: x(n+1) = μ*min(x(n), 1-x(n)) double mu = 1.99; // Parameter close to 2 for chaotic behavior double result; if (x <= 0.5) result = mu * x; else result = mu * (1.0 - x); // Additional validation if (result < 0.0 || result > 1.0 || MathIsValidNumber (result) == false) { result = 0.2 + 0.6 * u.RNDprobab (); } return result; } //——————————————————————————————————————————————————————————————————————————————
Die Methode SelectChaosMap dient der Auswahl und Anwendung einer chaotischen Abbildungsfunktion in Abhängigkeit vom angegebenen Typ. Sie nimmt einen „x“-Wert und einen „type“-Parameter an, der die spezifische Art der chaotischen Abbildung angibt. Die Grundidee der Methode besteht darin, den Rest der Division des Typs durch 3 zu verwenden, um die Abbildungsoption zu bestimmen, die eine zyklische Auswahl zwischen drei verschiedenen chaotischen Abbildungen bietet: logistische, Sinus- oder Tent-Abbildung. Je nach Ergebnis wird die entsprechende Funktion aufgerufen, die den Eingabewert von „x“ unter Verwendung der gewählten chaotischen Dynamik in einen neuen Wert umwandelt.
Fällt der Typ aus irgendeinem Grund nicht in den erwarteten Bereich (0, 1, 2), wird standardmäßig die logistische Abbildung angewendet. Jede dieser Abbildungen simuliert chaotisches Verhalten und wird verwendet, um verschiedene und unvorhersehbare Zahlen als Teil der Optimierung zu erzeugen.
//—————————————————————————————————————————————————————————————————————————————— double C_AO_COA_chaos::SelectChaosMap (double x, int type) { // Select a chaotic map based on type switch (type % 3) { case 0: return LogisticMap (x); case 1: return SineMap (x); case 2: return TentMap (x); default: return LogisticMap (x); } } //——————————————————————————————————————————————————————————————————————————————
Die InitialPopulation-Methode dient der Initialisierung der Ausgangspopulation des Optimierungsalgorithmus unter Verwendung der Latin Hypercube Sampling (LHS)-Technik. LHS ist ein geschichtetes Stichprobenverfahren, das im Vergleich zu Zufallsstichproben eine gleichmäßigere Abdeckung des mehrdimensionalen Suchraums ermöglicht und dadurch die Qualität der Ausgangspopulation verbessert.
Die Methode beginnt mit der Deklaration von Arrays für die Latin-Hypercube-Werte und temporäre Werte, die bei der Generierung helfen sollen. Die Methode versucht, Speicher für die erforderlichen Arrays zuzuweisen, und wenn die Speicherzuweisung fehlschlägt, wird ein Backup-Szenario durchgeführt, bei dem die anfängliche Population zufällig erstellt wird. Dadurch wird sichergestellt, dass das Programm nicht wegen Speichermangels abstürzt.
Die Methode erzeugt dann Werte für den Latin Hypercube. Für jede Koordinate wird eine geordnete Reihe von Werten erstellt, die dann nach dem Zufallsprinzip gemischt wird. Die gemischten Werte werden dem Hypercube-Array zugewiesen. Die Werte des Latin Hypercubes werden in Koordinaten von Individuen im Suchraum umgewandelt. Die Berechnung wird unter Verwendung der angegebenen Bereiche durchgeführt, und die erhaltenen Werte werden auf den erforderlichen Bereich und Schritt begrenzt.
Am Ende setzt die Methode ein Kennzeichen, das anzeigt, dass die Ausgangspopulation geändert oder neu erstellt wurde. Der Vorteil dieses Ansatzes besteht darin, dass er eine diversifiziertere Ausgangspopulation schafft.
//—————————————————————————————————————————————————————————————————————————————— void C_AO_COA_chaos::InitialPopulation () { // Create Latin Hypercube for the initial population double latinCube []; // One-dimensional array for storing hypercube values double tempValues []; // Temporary array for storing and shuffling values ArrayResize (latinCube, popSize * coords); ArrayResize (tempValues, popSize); // Generate a Latin hypercube for (int c = 0; c < coords; c++) { // Create ordered values for (int i = 0; i < popSize; i++) { tempValues [i] = (double)i / popSize; } // Shuffle the values for (int i = popSize - 1; i > 0; i--) { int j = (int)(u.RNDprobab () * (i + 1)); if (j < popSize) { double temp = tempValues [i]; tempValues [i] = tempValues [j]; tempValues [j] = temp; } } // Assign the mixed values for (int i = 0; i < popSize; i++) { latinCube [i * coords + c] = tempValues [i]; } } // Convert the Latin hypercube values to coordinates for (int i = 0; i < popSize; i++) { for (int c = 0; c < coords; c++) { double x = rangeMin [c] + latinCube [i * coords + c] * (rangeMax [c] - rangeMin [c]); a [i].c [c] = u.SeInDiSp (x, rangeMin [c], rangeMax [c], rangeStep [c]); } } } //——————————————————————————————————————————————————————————————————————————————
Die FirstCarrierWaveSearch-Methode implementiert eine Suchphase in den Algorithmus, die ein Gleichgewicht zwischen der globalen Erkundung des Raums und der lokalen Ausnutzung bekannter guter Lösungen herstellen soll. Seine Hauptaufgabe besteht darin, die Positionen und Geschwindigkeiten der Agenten zu aktualisieren, um weiterhin mögliche Lösungen zu finden und zu verbessern. Zu Beginn der Methode wird ein Verhältnis definiert, das den Grad der Erkundung in der aktuellen Suchepoche steuert. Dieses Verhältnis nimmt mit fortschreitenden Epochen quadratisch ab, was eine allmähliche Verlagerung des Schwerpunkts von globalen Suchvorgängen auf lokale Verbesserungen gewährleistet. Dann wird für jeden Agenten in der Population ein Mutationstest durchgeführt – mit einer gewissen Wahrscheinlichkeit wird eine Mutation durchgeführt, um die Vielfalt der Lösungen zu erhöhen. Anschließend wird für jede Suchrichtung (Koordinaten):
- der Typ der chaotischen Abbildung ausgewählt, der zur Erzeugung neuer potenzieller Lösungen verwendet wird,
- die Suchstrategie festgelegt: entweder global oder lokal.
Bei der globalen Suche aktualisiert der Agent seine Position mithilfe einer chaotischen Komponente, und die Geschwindigkeit wird angepasst, um die Trägheit und die Bewegungsrichtung zu berücksichtigen. Bei der lokalen Suche konzentriert sich der Agent auf die besten gefundenen Lösungen und zieht diese mit einer kleinen Zufallsvariation an, um Schleifenbildung zu vermeiden. In beiden Fällen ist die Geschwindigkeit begrenzt, um zu vermeiden, dass die Grenzen des Suchraums zu weit überschritten werden. Die Positionen der Agenten werden unter Berücksichtigung der Nebenbedingungen des Suchraums aktualisiert, und wenn nötig, werden Korrekturen vorgenommen, wenn Verletzungen der Nebenbedingungen festgestellt werden. In diesem Fall werden die Positionen angepasst und die Geschwindigkeiten reduziert, um die nachfolgenden Schritte zu glätten.
//—————————————————————————————————————————————————————————————————————————————— void C_AO_COA_chaos::FirstCarrierWaveSearch () { // Adaptive balance between exploration and exploitation double globalPhase = (double)epochNow / S1; double explorationRate = 1.0 - globalPhase * globalPhase; // Quadratic decrease // For each agent for (int i = 0; i < popSize; i++) { // Apply mutations with some probability to increase diversity if (u.RNDprobab () < mutationRate * (1.0 + explorationRate)) { ApplyMutation (i); continue; } for (int c = 0; c < coords; c++) { // Select a chaotic map with uniform distribution int mapType = ((i + c + epochNow) % 3); // Safely check access to the gamma array if (c < ArraySize (agent [i].gamma)) { agent [i].gamma [c] = SelectChaosMap (agent [i].gamma [c], mapType); } else { continue; // Skip if the index is invalid } // Determine the relationship between global and local search double strategy = u.RNDprobab (); double x; if (strategy < explorationRate) { // Global search with a chaotic component x = rangeMin [c] + agent [i].gamma [c] * (rangeMax [c] - rangeMin [c]); // Add a velocity component to maintain the movement direction agent [i].velocity [c] = inertia * agent [i].velocity [c] + (1.0 - inertia) * (x - a [i].c [c]); } else { // Local search around the best solutions double personalAttraction = u.RNDprobab (); double globalAttraction = u.RNDprobab (); // Balanced attraction to the best solutions double attractionTerm = //personalAttraction * (agent [i].cPrev [c] - a [i].c [c]) + personalAttraction * (a [i].cB [c] - a [i].c [c]) + socialFactor * globalAttraction * (cB [c] - a [i].c [c]); // Chaotic disturbance to prevent being stuck double chaosRange = alpha [c] * explorationRate; double chaosTerm = chaosRange * (2.0 * agent [i].gamma [c] - 1.0); // Update velocity with inertia agent [i].velocity [c] = inertia * agent [i].velocity [c] + (1.0 - inertia) * (attractionTerm + chaosTerm); } // Limit the velocity to prevent too large steps double maxVelocity = 0.1 * (rangeMax [c] - rangeMin [c]); if (MathAbs (agent [i].velocity [c]) > maxVelocity) { agent [i].velocity [c] = maxVelocity * (agent [i].velocity [c] > 0 ? 1.0 : -1.0); } // Apply the velocity to the position x = a [i].c [c] + agent [i].velocity [c]; // Apply search space restrictions a [i].c [c] = u.SeInDiSp (x, rangeMin [c], rangeMax [c], rangeStep [c]); // Check the constraints and apply a smooth correction double violation = CalculateConstraintValue (i, c); if (violation > eps) { double gradient = CalculateWeightedGradient (i, c); double correction = -gradient * violation * (1.0 - globalPhase); a [i].c [c] = u.SeInDiSp (a [i].c [c] + correction, rangeMin [c], rangeMax [c], rangeStep [c]); // Reset the velocity when correcting violations agent [i].velocity [c] *= 0.5; } } } } //——————————————————————————————————————————————————————————————————————————————
Die Methode SecondCarrierWaveSearch ist eine Optimierungsstufe, die sich nach der ersten Suche entwickelt und darauf abzielt, die gefundenen Lösungen zu vertiefen und zu verfeinern. Das Hauptziel dieser Methode ist die Verbesserung der im vorherigen Schritt erzielten Ergebnisse durch die Anwendung ausgefeilterer Suchstrategien und die Anpassung der Parameter.
Die Methode beginnt mit der Berechnung eines Parameters, der die lokale Suchphase widerspiegelt, die sich mit der Zeit intensiviert. Dadurch kann der Algorithmus schrittweise von einer breiten Suche zu einer detaillierteren und präziseren Erkundung des Bereichs bereits bekannter Lösungen übergehen. Zu Beginn der Methode wird geprüft, ob die Konvergenz erreicht ist. Wenn der Algorithmus einen stabilen Zustand erreicht hat, werden einige Agenten einer Mutation unterzogen, um die Vielfalt der Lösungen zu erhöhen und lokale Extreme zu vermeiden.
Für jeden Agenten wird eine sequentielle Suche nach neuen Lösungen in seinem Raum durchgeführt. Es werden chaotische Abbildungen definiert, die dazu beitragen, Elemente des Zufalls einzuführen. Der Suchparameter wird kleiner, je näher wir der optimalen Lösung kommen. Dies ermöglicht einen engeren Fokus bei der Suche in der Nähe der derzeit besten Lösungen. Bei der Aktualisierung der einzelnen Positionen werden die bisherigen Leistungen der Agenten berücksichtigt. Es wird ein Basispunkt bestimmt, der entweder das absolute globale Optimum oder die bisherigen persönlichen Leistungen des Agenten sein kann, was dazu beiträgt, sowohl die individuellen als auch die allgemeinen Ergebnisse der gesamten Population zu berücksichtigen.
Bei der Positionsaktualisierung werden sowohl chaotische Verzerrungen als auch Zufallsrauschen (z. B. Lévy-Rauschen) verwendet, was ein Element der Zufälligkeit hinzufügt und die Suche nach neuen, potenziell besseren Lösungen erleichtert. Die Methode berücksichtigt die Trägheit bei der Aktualisierung der Agentengeschwindigkeiten, was sanftere Änderungen ermöglicht und aggressive Bewegungen verhindert. Infolgedessen werden die aktualisierten Positionen durch die festgelegten Grenzen begrenzt, wodurch sichergestellt wird, dass die Problembedingungen erfüllt sind.
Die Methode SecondCarrierWaveSearch zielt auf eine genauere und tiefgreifendere Optimierung bestehender Lösungen ab.
//—————————————————————————————————————————————————————————————————————————————— void C_AO_COA_chaos::SecondCarrierWaveSearch () { // Refining local search with adaptive parameters double localPhase = (double)(epochNow - S1) / S2; double intensificationRate = localPhase * localPhase; // Quadratic increase in intensification // Check the algorithm convergence bool isConverged = IsConverged (); // For each agent for (int i = 0; i < popSize; i++) { // If convergence is detected, add a random mutation to some agents if (isConverged && i % 3 == 0) { ApplyMutation (i); continue; } for (int c = 0; c < coords; c++) { // Select a chaotic map with uniform distribution int mapType = ((i * c + epochNow) % 3); agent [i].gamma [c] = SelectChaosMap (agent [i].gamma [c], mapType); // Adaptive search radius with narrowing towards the end of optimization double adaptiveAlpha = alpha [c] * (1.0 - 0.8 * intensificationRate); // Select a base point with priority to the best solutions double basePoint; if (a [i].f > a [i].fB) { basePoint = a [i].c [c]; // The current position is better } else { double r = u.RNDprobab (); if (r < 0.7 * (1.0 + intensificationRate)) // Increase attraction to the global best { basePoint = cB [c]; // Global best } else { basePoint = a [i].cB [c]; // Personal best } } // Local search with a chaotic component double chaosOffset = adaptiveAlpha * (2.0 * agent [i].gamma [c] - 1.0); // Add Levy noise for random long jumps (heavy tailed distribution) double levyNoise = 0.0; if (u.RNDprobab () < 0.1 * (1.0 - intensificationRate)) { // Simplified approximation of Levy noise double u1 = u.RNDprobab (); double u2 = u.RNDprobab (); if (u2 > 0.01) // Protection against division by very small numbers { levyNoise = 0.01 * u1 / MathPow (u2, 0.5) * adaptiveAlpha * (rangeMax [c] - rangeMin [c]); } } // Update the velocity with inertia agent [i].velocity [c] = inertia * (1.0 - 0.5 * intensificationRate) * agent [i].velocity [c] + (1.0 - inertia) * (chaosOffset + levyNoise); // Apply the velocity to the position double x = basePoint + agent [i].velocity [c]; // Limit the position a [i].c [c] = u.SeInDiSp (x, rangeMin [c], rangeMax [c], rangeStep [c]); } } } //——————————————————————————————————————————————————————————————————————————————
Im nächsten Artikel werden wir die übrigen Methoden des Algorithmus weiter untersuchen, Tests durchführen und die Ergebnisse zusammenfassen.
Übersetzt aus dem Russischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/ru/articles/16729
Warnung: Alle Rechte sind von MetaQuotes Ltd. vorbehalten. Kopieren oder Vervielfältigen untersagt.
Dieser Artikel wurde von einem Nutzer der Website verfasst und gibt dessen persönliche Meinung wieder. MetaQuotes Ltd übernimmt keine Verantwortung für die Richtigkeit der dargestellten Informationen oder für Folgen, die sich aus der Anwendung der beschriebenen Lösungen, Strategien oder Empfehlungen ergeben.
Winkelanalyse von Preisbewegungen: Ein hybrides Modell zur Prognose von Finanzmärkten
Anwendung des L1-Trendfilters in MetaTrader 5
Eine alternative Log-datei mit der Verwendung der HTML und CSS
Neuronale Netze im Trading: Anomalieerkennung im Frequenzbereich (CATCH)
- Freie Handelsapplikationen
- Über 8.000 Signale zum Kopieren
- Wirtschaftsnachrichten für die Lage an den Finanzmärkte
Sie stimmen der Website-Richtlinie und den Nutzungsbedingungen zu.