English Русский 中文 Español 日本語 Português
preview
Entwicklung eines Replay Systems — Marktsimulation (Teil 14): Die Geburt des SIMULATORS (IV)

Entwicklung eines Replay Systems — Marktsimulation (Teil 14): Die Geburt des SIMULATORS (IV)

MetaTrader 5Tester | 5 Dezember 2023, 09:00
231 0
Daniel Jose
Daniel Jose

Einführung

Im vorherigen Artikel „Entwicklung eines Replay-Systems - Marktsimulation (Teil 13): Die Geburt des SIMULATORs (III)“ habe ich die Änderungen an der Servicedatei zur besseren Darstellung von Ticks und deren Verarbeitung gezeigt. Das Hauptziel des vorherigen Artikels war es, zu zeigen, wie dies geschehen kann und wo der Code geändert und hinzugefügt werden muss, um Daten vom Dienst zu erhalten. So können wir diese Daten an einen anderen Ort, in diesem Fall in eine Datei, verschieben. Mit dieser Datei in der Hand können wir das Programm verwenden, in diesem Fall habe ich gezeigt, wie man EXCEL verwendet, um die Daten zu analysieren, die der Simulator erzeugt.

Diese Art von Aufgabe, auch wenn sie trivial erscheinen mag, ist für das, was wir in diesem Artikel tun werden, von größter Bedeutung. Wenn wir nicht wissen, wie wir die vom Simulator erzeugten Daten analysieren können, werden wir nicht verstehen, was implementiert werden muss; aber vor allem werden wir nicht verstehen, warum es so implementiert wird, wie ich es zeigen werde. Neben dem Hauptthema des vorangegangenen Artikels haben wir auch einige Punkte erläutert, die im Code geändert werden mussten, damit der Balken in etwa 1 Minute erstellt werden kann, und zwar mit guter Genauigkeit, sodass alles sehr realitätsnah ist. Trotz alledem müssen wir, um zu verstehen, was wir in diesem Artikel tun werden, eine weitere Sache berücksichtigen. Da im vorherigen Artikel bereits viele Informationen enthalten waren, habe ich beschlossen, hier noch ein letztes Detail zu erläutern. Sie können es im beigefügten Code sehen.


Testen Sie den kostenlosen Random Walk

Unten sehen Sie die einfachste Version der Routine, mit der versucht wird, den freien Random Walk zu erzeugen.

inline void Simulation(const MqlRates &rate, MqlTick &tick[])
                        {
#define macroRandomLimits(A, B) (int)(MathMin(A, B) + (((rand() & 32767) / 32767.0) * MathAbs(B - A)))

                                long il0, max;
                                double v0, v1;
                                int p0;
                                
                                ArrayResize(m_Ticks.Rate, (m_Ticks.nRate > 0 ? m_Ticks.nRate + 3 : def_BarsDiary), def_BarsDiary);
                                m_Ticks.Rate[++m_Ticks.nRate] = rate;                           
                                max = rate.tick_volume - 1;     
                                v0 = 4.0;
                                v1 = (60000 - v0) / (max + 1.0);
                                for (int c0 = 0; c0 <= max; c0++, v0 += v1)
                                {
                                        tick[c0].last = 0;
                                        tick[c0].flags = 0;
                                        il0 = (long)v0;
                                        tick[c0].time = rate.time + (datetime) (il0 / 1000);
                                        tick[c0].time_msc = il0 % 1000;
                                        tick[c0].volume_real = 1.0;
                                }
                                tick[0].last = rate.open;
                                tick[max].last = rate.close;
                                for (int c0 = (int)(rate.real_volume - rate.tick_volume); c0 > 0; c0--)
                                        tick[macroRandomLimits(0, max)].volume_real += 1.0;
                                for (int c0 = 1; c0 < max; c0++)
                                        tick[c0].last = macroRandomLimits(rate.low, rate.high);                                 
                                il0 = (long)(max * (0.3));
                                tick[macroRandomLimits(il0, il0 * 2)].last = rate.low;
                                tick[macroRandomLimits(max - il0, max)].last = rate.high;                                         
                                for (int c0 = 0; c0 <= max; c0++)
                                {
                                        ArrayResize(m_Ticks.Info, (m_Ticks.nTicks + 1), def_MaxSizeArray);
                                        m_Ticks.Info[m_Ticks.nTicks++] = tick[c0];
                                }
                        }
                        
#undef macroRandomLimits

Es ist sehr wichtig, den obigen Code zu verstehen, um zu verstehen, was wir als nächstes tun werden. Wenn Sie genau diesen Code ausführen, erhalten Sie ein sehr verwirrendes Diagramm. Es ist wichtig zu wissen, wie diese sehr grundlegende Funktion funktioniert, damit Sie verstehen können, wie komplexere Funktionen funktionieren. Beginnen wir mit der Makrodefinition. Frage: Was bewirkt dieses Makro? Sie werden sich vielleicht fragen: Was ist das für ein Wahnsinn? Brauchen wir wirklich etwas so Seltsames? Die Antwort auf diese Frage lautet JA und NEIN.

JA, denn der Zufallswert muss innerhalb eines ganz bestimmten Bereichs erzeugt werden. Zu diesem Zweck müssen wir eine Art von Einschränkung festlegen. Und NEIN, denn um einen RANDOM WALK zu erzeugen, brauchen wir diese Berechnung selbst nicht. Aber auch hier gilt: Wir müssen verstehen, wie dieses einfachere System funktioniert, um andere, komplexere Systeme zu verstehen.

Bei der UND-Verknüpfung schränken wir den Wert also auf einen Bereich ein. Dies ist der erste Punkt. Wenn wir diesen Wert durch die obere Grenze des Bereichs teilen, erhalten wir einen Wert, der im Bereich von 0 bis 1 liegt. Dieser Wert, der zwischen 0 und 1 liegt, wird dann mit der Differenz zwischen der oberen und unteren Grenze multipliziert. Auf diese Weise erhalten wir einen Wert, der im Bereich von 0 bis zum Maximalwert liegt, der unser Bereich sein wird. Wenn wir nun diesen Bereich zum Mindestwert addieren, erhalten wir den Wert, den wir tatsächlich benötigen. Dies ist der Wert, der verwendet werden sollte. Auf diese Weise müssen wir uns nicht um weitere Prüfungen kümmern: Das Makro selbst stellt sicher, dass der Wert innerhalb akzeptabler Grenzen liegt. Haben Sie die Idee hinter diesem verrückten Makro verstanden? Das ist reine Mathematik, nichts weiter.

Kommen wir nun zur ersten der vier FOR-Schleifen, die sich innerhalb der Funktion befinden. Bevor wir in die eigentliche Schleife einsteigen, müssen wir ein paar einfache Berechnungen durchführen, die uns beim Rest der Funktion helfen werden. Zunächst einmal müssen wir wissen, wie viele Ticks wir tatsächlich simulieren wollen. Als Nächstes müssen wir wissen, wie lang jedes Häkchen sein wird, oder genauer gesagt, wann es erscheinen soll. Der Einfachheit halber verwenden wir eine konstante Zeit zwischen ihnen. Jetzt können wir in die Schleife einsteigen und die Ticks innerhalb des 1-Minuten-Balkenbereichs verteilen. In einigen Fällen liegen die Ticks weiter auseinander, in anderen näher beieinander. Aber das spielt jetzt keine Rolle mehr. Was wir brauchen und wollen, ist das, was für uns wirklich wichtig ist. Das bedeutet, dass jedes Tick existiert und einzigartig ist. Dies kann durch die Platzierung von Ticks zu verschiedenen Zeitpunkten erreicht werden.

Sie haben vielleicht bemerkt, dass ich für jeden simulierten Tick einen Mindestvolumenwert festgelegt habe. Dieser Punkt ist auch für den nächsten Schritt wichtig. Jetzt kommen wir in die nächste Schleife. An dieser Stelle wird es interessant, denn als Erstes bestimmen wir den Eröffnungs- und den Schlusskurs eines 1-Minuten-Balkens. Wirklich interessant ist, was innerhalb der Schleife passiert. Wir subtrahieren das Gesamtvolumen von der Anzahl der Ticks, die verwendet werden. Damit erhalten wir einen Wert, der das noch nicht zugewiesene Volumen darstellt. Wir könnten dieses Volumen direkt beim letzten Tick oder bei einem anderen Tick zuweisen. Dies würde jedoch zu einer starken Veränderung des Volumens führen, was auf dem realen Markt nicht oft vorkommt. Daher benötigen wir eine andere Methode, um die verbleibenden Ticks so zu verteilen, dass das sich ergebende Volumen in Bezug auf den Wert des 1-Minuten-Balkens ausgedrückt wird. Um diese Verteilung so glatt und zufällig wie möglich zu gestalten, werden wir unser Makro verwenden. Jedes Mal, wenn das Makro aufgerufen wird, erzeugt es einen Wert, der innerhalb bestimmter Grenzen liegt. Und in diesem Moment erhöht sich der Wert des Bandes um 1. Mit anderen Worten: Das Gesamtvolumen wird zufällig und gleichmäßig verteilt, sodass der Eindruck entsteht, dass die Daten denen des realen Marktes ähneln.

Betrachten wir abschließend die letzten beiden Schleifen, von denen die erste das Zufallsprinzip in unserem Tick-System erzeugt. Wir müssen uns nicht anstrengen: Wir sagen dem System lediglich, welchen Mindest- und welchen Höchstpreis es verwenden soll. Jeder Tick hat also einen zufällig ausgewählten Preis. Beachten Sie, dass wir für diese Auswahl ein Makro verwenden. Danach müssen wir sicherstellen, dass sowohl der Maximalwert als auch der Minimalwert vorhanden sind. Der Grund dafür ist, dass sie bei der Zufallsgenerierung möglicherweise nicht erstellt wurden und die Position, an der diese Punkte gefunden werden, ebenfalls zufällig gewählt wird.

Was die letzte Schleife betrifft, so werden die Werte einfach an das Tick-System weitergegeben, so als ob es sich um echte Ticks handeln würde. Sie können das Ergebnis sehen und verstehen, wenn Sie die Ausgabe in einer Datei speichern und diese dann als Daten für ein Diagramm verwenden. Normalerweise tun wir dies in einem Programm, wie z. B. Excel. Dies kann jedoch auch direkt im MetaTrader 5 unter Verwendung eines nutzerdefinierten Symbols erfolgen. Auf diese Details wollen wir jetzt aber nicht eingehen. Es ist wichtig zu verstehen, dass die Simulation tatsächlich wie erwartet abläuft.

Ausgehend von der Erklärung, die wir im vorigen Artikel begonnen haben, können Sie sehen, dass wir jetzt der Randomisierung von Bewegungen Priorität einräumen. Im Gegensatz zu anderen Artikeln, die eine Methode verwenden, die der des Strategietesters sehr ähnlich ist, um die Simulation zu erstellen, haben wir eine Zickzack-Bewegung verwendet, die der in der Abbildung unten sehr ähnlich ist:

Während dies eine großartige Idee für die Verwendung in einem Strategietester ist, ist dieser Ansatz für ein Replay/Simulationssystem nicht ganz angemessen. Es ist ein anderer Ansatz erforderlich, der etwas kreativer, aber auch komplexer ist. So entstand das System, das ich gerade erklärt habe. Dort beginnen wir ganz einfach, Bewegungen innerhalb eines 1-Minuten-Balkens zu „randomisieren“. Aber dieser Ansatz ist nicht ganz angemessen, wenn wir einen Bewegungsstil anstreben, der der Bewegung eines in einer Flüssigkeit schwebenden Objekts sehr ähnlich ist. Damit Sie verstehen, wie dies geschieht, ist es wichtig zu wissen, wie man eine Datenreihe in ein Diagramm umwandelt. Am einfachsten ist es, wenn Sie EXCEL für die Umrechnung verwenden. Auch hier ist es wichtig, dass Sie wissen, wie man das macht.

Der vorherige Artikel „Entwicklung eines Replay Systems — Marktsimulation (Teil 13): Die Geburt des SIMULATORS (III)“ hatte ein Video mit einer Erklärung. Es ist sehr wichtig, dass Sie wissen, wie man das macht, wenn Sie wirklich verstehen wollen, was in diesem Artikel passieren wird. Das liegt daran, dass wir hier eine Bewegungssimulation erstellen werden, die wie ein RANDOM WALK aussieht. Wenn Sie sich die vom Simulator erstellten Charts ansehen, werden Sie sofort feststellen, dass die Bewegung sehr ähnlich zu der Bewegung ist, die während der Symbolhandelsphase beobachtet wird. Ich werde in diesem Artikel keine mathematischen Formeln oder ähnliches aufführen, da ich keinen Nutzen in einem solchen Ansatz sehe. Was alle wirklich interessiert, ist der Code selbst und was er produziert. Die verwendeten mathematischen Formeln bringen überhaupt nichts und sind für viele nicht erkenntnisfördernd, da viele die abstrakten Sachverhalte nicht verstehen, um die es geht. Dies wird die Angelegenheit also eher verkomplizieren als erklären. Aber sicherlich wird jeder die erzielten Ergebnisse verstehen.

In diesem Artikel erfahren Sie, wie Sie die Zahl 01 am einfachsten in die Zahl 02 umwandeln können:                   

                       

Abbildung 01 - Zufällige Bewegung in Sprüngen



Abbildung 02 - Zufällige, schrittweise Bewegung


Beide Zahlen werden mit der gleichen Datenbank erstellt:


Abbildung 03 - Die in beiden Bewegungen verwendete Datenbank


ABER es gibt Probleme, die sich von einem völlig zufälligen System unterscheiden und die wir korrigieren müssen. Selbst dann werden wir in mehr als 99 % der Fälle nicht sofort ein wirklich adäquates System haben, während das verbleibende 1 % auf einen gewissen Zufall zurückzuführen ist, was die Simulation ideal macht. Aber es wird etwas Seltenes sein. Daher müssen wir einige Tricks anwenden, um alle anderen Fälle, d. h. 99 %, zu lösen.

Schauen wir uns an, wie das System tatsächlich funktioniert. Aber, falls Sie den vorherigen Artikel „Entwicklung eines Replay-Systems — Marktsimulation (Teil 13) Die Geburt des SIMULATORS (III)“ noch nicht gelesen haben, empfehle ich Ihnen dringend, den vorherigen Artikel zuerst zu lesen. Der Grund dafür ist, dass wir uns hier nur auf die notwendigen Änderungen und deren Umsetzung konzentrieren werden. Wir werden die Erklärungen, die im vorherigen Artikel gegeben wurden, nicht wiederholen. Daher ist es wichtig, den vorangehenden Inhalt zu verstehen. Insbesondere der Teil, der die Umwandlung von Daten in Diagramme in Excel beinhaltet.

Lassen Sie uns nun zum Thema Umsetzung übergehen.


Durchführung des RANDOM WALK mit absolut freier Bewegung

Um das zufällige Springen in ein zufälliges Treten umzuwandeln, müssen wir lediglich die Arbeitsweise der Simulationsfunktion ändern. Schauen wir uns dazu seinen Code an:

inline void Simulation(const MqlRates &rate, MqlTick &tick[])
                        {
#define macroRandomLimits(A, B) (int)(MathMin(A, B) + (((rand() & 32767) / 32767.0) * MathAbs(B - A)))

                                long il0, max;
                                double v0, v1;
                                
                                ArrayResize(m_Ticks.Rate, (m_Ticks.nRate > 0 ? m_Ticks.nRate + 3 : def_BarsDiary), def_BarsDiary);
                                m_Ticks.Rate[++m_Ticks.nRate] = rate;
                                max = rate.tick_volume - 1;     
                                v0 = 4.0;
                                v1 = (60000 - v0) / (max + 1.0);
                                for (int c0 = 0; c0 <= max; c0++, v0 += v1)
                                {
                                        tick[c0].last = 0;
                                        tick[c0].flags = 0;
                                        il0 = (long)v0;
                                        tick[c0].time = rate.time + (datetime) (il0 / 1000);
                                        tick[c0].time_msc = il0 % 1000;
                                        tick[c0].volume_real = 1.0;
                                }
                                tick[0].last = rate.open;
                                tick[max].last = rate.close;
                                for (int c0 = (int)(rate.real_volume - rate.tick_volume); c0 > 0; c0--)
                                        tick[macroRandomLimits(0, max)].volume_real += 1.0;
                                for (int c0 = 1; c0 < max; c0++)
                                        tick[c0].last = macroRandomLimits(rate.low, rate.high);
                                        tick[c0].last = tick[c0 - 1].last + (m_PointsPerTick * ((rand() & 1) == 1 ? 1 : -1));
                                il0 = (long)(max * (0.3));
                                tick[macroRandomLimits(il0, il0 * 2)].last = rate.low;
                                tick[macroRandomLimits(max - il0, max)].last = rate.high;
                                for (int c0 = 0; c0 <= max; c0++)
                                {
                                        ArrayResize(m_Ticks.Info, (m_Ticks.nTicks + 1), def_MaxSizeArray);
                                        m_Ticks.Info[m_Ticks.nTicks++] = tick[c0];
                                }
#undef macroRandomLimits
                        }                       

Vorsicht, wir ändern nur die Funktionsweise der Funktion, aber wir behalten die gleiche Last. Auf diese Weise werden wir die gleiche Anzahl von Ticks verwenden. Achten Sie auf den hervorgehobenen Teil. Und nun beachten Sie Folgendes: Der gelöschte Code muss gelöscht und der hervorgehobene Code muss an seiner Stelle eingefügt werden. Wenn wir nur diese Änderung vornehmen, können wir einen RANDOM WALK erstellen, aber das ist kein richtiger Schritt. Noch nicht, denn selbst wenn es in einem seltenen Moment eine Bewegung gibt, die innerhalb des 1-Minuten-Balkens bleibt, mit anderen Worten, wenn das Hoch und das Tief getroffen und innerhalb dieser Amplitude gehalten werden, dann haben wir mit diesem Code kein Vertrauen oder keine Kontrolle darüber. Dies kann man sehen, wenn man es ausführt und das Ergebnisdiagramm betrachtet.

Wenn Sie die beigefügten Dateien verwenden und die Konfigurationsdatei nicht ändern, funktioniert der Wiedergabe-/Simulationsdienst nur im ersten Bereich, und der Bereich, der im Bild unten hervorgehoben ist, wird verwendet:



Beachten Sie die Grenzen: OBERGRENZE => 108375 und UNTERE GRENZE => 107850. Und das sind nicht die Grenzen, die in der Grafik zu sehen sind. Schon ein kurzer Blick genügt, um festzustellen, dass diese Grenzen nicht eingehalten werden. Schauen Sie sich das unten abgebildete Datendiagramm einer der Ausführungen an.


Abbildung 04 - Diagramm eines völlig freien RANDOM WALK


Wie Sie sehen können, wird die Untergrenze bei weitem nicht eingehalten. Auch hier kann es passieren, dass an einem ganz bestimmten Punkt die Grenzen respektiert werden. Es gibt noch ein weiteres Problem mit isolierten Punkten, das im obigen Schaubild zu sehen ist, aber lassen Sie uns allmählich fortfahren. Diese Punkte stellen ein weiteres Problem dar, das wir lösen müssen. Lassen Sie uns jedoch zunächst die Grenzen ausloten. Nun, einige Dinge mögen akzeptabel sein, wenn wir Simulationen von Bewegungen erstellen. Aber hier werden wir sie nicht akzeptieren. Der Grund dafür ist, dass wir Simulationen auf der Grundlage von Daten durchführen, die wir zuvor erhalten haben, und wir müssen das respektieren, was uns zur Verfügung gestellt wird.

Um dieses Problem der Grenzen zu lösen, müssen wir ein freies System in ein begrenztes System umwandeln. Obwohl viele Menschen diesen Ansatz nicht gutheißen, haben wir keine andere Wahl, als eine Art Kontrolle zu schaffen, um die Grenzwerte um jeden Preis einzuhalten. Daher ist es wichtig, den vorhergehenden Artikel zu lesen, um zu verstehen, wie man EXCEL oder ein anderes Programm verwendet, um die vom Simulationssystem erzeugte Grafik zu analysieren. Verlassen Sie sich nicht einfach auf Daten und halten Sie sie für richtig. Man muss sie sich wirklich in einem Diagramm ansehen.

Anders als bei einem völlig zufälligen, auf Sprüngen basierenden System, wie in Abbildung 01 dargestellt, bei dem die Verwendung des MetaTrader 5-Grafiksystems völlig unmöglich ist, geschieht das Gleiche nicht, wenn wir das erhalten, was in Abbildung 02 oder sogar in Abbildung 04 dargestellt ist. Allerdings gibt es in beiden Fällen das Problem der isolierten Punkte im Diagramm, die einen seltsamen Balken erzeugen. Wenn Sie die Simulationsdaten jedoch nicht in EXCEL übertragen möchten, können Sie einige Änderungen am Code vornehmen, damit jeder Tick direkt im MetaTrader 5-Chart angezeigt wird. Dadurch wird das Chart jedoch aufgrund der Menge an Informationen, die es enthält, schwerer zu verstehen sein. Denken Sie daran: Sie müssen Tick für Tick auf dem Chart platzieren, nicht auf den Balken. Wenn Sie nicht wissen, wie man das macht, lesen Sie diesen Artikel: „Einen handelnden Expert Advisor von Grund auf neu entwickeln (Teil 13): Time And Trade (II)“, denn darin erkläre ich, wie man die Ticks, die wir hier im Simulator erzeugen, zeichnen kann. Obwohl Times And Trade sich auf die Anzeige von realen Symbolticks konzentriert, können wir damit auch im Simulator generierte Ticks anzeigen. Es geht darum, den für Times And Trade angezeigten Code anzupassen.

Das ist keine allzu schwierige Aufgabe, aber sie erfordert Änderungen, die dann wieder rückgängig gemacht werden müssen. Ich werde also nicht zeigen, wie man es macht. Ziel ist es, auf sehr einfache Weise zu zeigen, wie man das System dazu bringt, eine Bewegung zu generieren, sodass wir eine Simulation der möglichen Bewegung innerhalb eines 1-Minuten-Taktes haben, aber in kontinuierlicher Form und nicht in Sprüngen. Ich denke, dass viele von Ihnen nicht genau wissen, wie man diese Dinge mit MQL5 programmiert. Es würde den Rahmen dieses oder eines anderen Artikels in dieser Reihe sprengen, wenn Sie Ihren Ansatz nur zur persönlichen Befriedigung ändern würden. Lassen Sie uns also unsere Arbeit fortsetzen. Fügen wir nun etwas in den Code ein, damit er mit den Grenzen übereinstimmt, die durch die Informationen des in Abbildung 03 hervorgehobenen 1-Minuten-Balkens bestimmt werden.


Durchführung eines bewegungsbeschränkten RANDOM WALK

Ausgehend von dem, was wir im vorherigen Thema gesehen haben, können wir leicht feststellen, was wir aktualisieren müssen. Siehe die Änderungen im Code unten:

inline void Simulation(const MqlRates &rate, MqlTick &tick[])
                        {
#define macroRandomLimits(A, B) (int)(MathMin(A, B) + (((rand() & 32767) / 32767.0) * MathAbs(B - A)))

                                long    il0, max;
                                double  v0, v1;
                                bool    bLowOk, bHighOk;
                                
                                ArrayResize(m_Ticks.Rate, (m_Ticks.nRate > 0 ? m_Ticks.nRate + 3 : def_BarsDiary), def_BarsDiary);
                                m_Ticks.Rate[++m_Ticks.nRate] = rate;
                                max = rate.tick_volume - 1;     
                                v0 = 4.0;
                                v1 = (60000 - v0) / (max + 1.0);
                                for (int c0 = 0; c0 <= max; c0++, v0 += v1)
                                {
                                        tick[c0].last = 0;
                                        tick[c0].flags = 0;
                                        il0 = (long)v0;
                                        tick[c0].time = rate.time + (datetime) (il0 / 1000);
                                        tick[c0].time_msc = il0 % 1000;
                                        tick[c0].volume_real = 1.0;
                                }
                                tick[0].last = rate.open;
                                tick[max].last = rate.close;
                                for (int c0 = (int)(rate.real_volume - rate.tick_volume); c0 > 0; c0--)
                                        tick[macroRandomLimits(0, max)].volume_real += 1.0;
                                bLowOk = bHighOk = false;
                                for (int c0 = 1; c0 < max; c0++)
                                {                               
                                        v0 = tick[c0 - 1].last + (m_PointsPerTick * ((rand() & 1) == 1 ? 1 : -1));
                                        if (v0 <= rate.high)
                                                v0 = tick[c0].last = (v0 >= rate.low ? v0 : tick[c0 - 1].last + m_PointsPerTick);
                                        else
                                                v0 = tick[c0].last = tick[c0 - 1].last - m_PointsPerTick;
                                        bLowOk = (v0 == rate.low ? true : bLowOk);
                                        bHighOk = (v0 == rate.high ? true : bHighOk);
                                }                                       
                                il0 = (long)(max * (0.3));
                                if (!bLowOk) tick[macroRandomLimits(il0, il0 * 2)].last = rate.low;
                                if (!bHighOk) tick[macroRandomLimits(max - il0, max)].last = rate.high;
                                for (int c0 = 0; c0 <= max; c0++)
                                {
                                        ArrayResize(m_Ticks.Info, (m_Ticks.nTicks + 1), def_MaxSizeArray);
                                        m_Ticks.Info[m_Ticks.nTicks++] = tick[c0];
                                }
#undef macroRandomLimits
                        }                       

Es mag den Anschein haben, dass sich nichts ändert, oder Sie fühlen sich durch die vielen Etiketten ein wenig verwirrt. Hier wurden zwei neue Variablen hinzugefügt, die uns helfen werden, die Situation besser zu kontrollieren. Sie werden so initialisiert, dass wir diese Punkte auf jeden Fall im Chart platzieren müssen, wenn auf die Positionen, die sie darstellen, nicht richtig zugegriffen wird. Und diese Punkte werden nach dem Zufallsprinzip ausgewählt. Die erforderlichen Prüfungen werden im Rahmen des Systems zur Auswertung der Grenzwerte durchgeführt. Wir können uns also nur auf eine Sache konzentrieren: den RANDOM WALK innerhalb der Grenzen zu halten, die zuvor durch die 1-Minuten-Balken gesetzt wurden. Als Erstes werden wir prüfen, ob die Obergrenze verletzt wurde und wie sie eingehalten wurde. Sollte dies der Fall sein, werden wir die Bewegung unverzüglich innerhalb der Grenzen zurückgeben. Wenn dies der Fall ist, prüfen wir, ob die untere Grenze verletzt wurde. Ist dies der Fall, werden wir das Werk innerhalb der Grenzen unverzüglich zurücksenden. Andernfalls wird der Wert akzeptiert.

Wir haben nicht allzu viel am Code geändert. Die Ergebnisse haben sich jedoch erheblich verändert. Sehen Sie sich das Ergebnis einer der Ausführungen an.


Abbildung 05 - RANDOM WALK innerhalb bestimmter Grenzen


Tatsächlich war es reines Glück, dass die Bewegung alle losen Punkte abdeckte. Aber wir haben immer noch einen losen Punkt auf dem Chart. Dieser Punkt stellt den letzten Tick des 1-Minuten-Balkens dar. Angesichts der Natur des Random Walk und der Art und Weise, wie wir ihn durchführen, ist es ziemlich schwierig, dies genau zu erreichen. Im Gegensatz zu Abbildung 04, wo die Beschränkungen nicht eingehalten wurden, wurden sie in Abbildung 05 eingehalten, und der gesamte 1-Minuten-Balken wird innerhalb der zuvor festgelegten Grenzen liegen, sodass die Bewegung nahezu perfekt ist. Und ich sage „fast“, weil das Ergebnis von Abbildung 05 reines Glück war. In den meisten Fällen erhalten wir ein ähnliches Ergebnis wie in Abbildung 06 unten dargestellt.


Abbildung 06 - Typisches Bewegungsdiagramm innerhalb der Grenzen


Man beachte, dass auch in Abbildung 06 der Schlusspunkt durch das Zufallsbewegungssystem nicht zum gewünschten Zeitpunkt erreicht wurde. In extrem seltenen Fällen können Sie jedoch ein Ergebnis ähnlich wie in Abbildung 07 erhalten. Hier können wir feststellen, dass der Schlusspunkt durch eine zufällige Bewegung erreicht wurde.


Abbildung 07 - RARE-Bewegung, bei der der Schlusspunkt erreicht wurde


Aber diese Art von Bewegung ist so selten, dass wir nicht mit ihr rechnen können. In den meisten Fällen ist der Tick vor dem Schluss weit vom Schlusspunkt entfernt. Dies führt zu einer starken Bewegung in der vom MetaTrader 5 angezeigten Chart des Handelsinstruments der Replay/Simulation. Wenn Sie sich an diesem Effekt nicht stören, ist das System jetzt brauchbar, aber Sie sollten noch etwas anderes beachten. Zu verschiedenen Zeiten, und das ist gar nicht so selten, sind die Hochs oder Tiefs nicht wirklich betroffen. Das bedeutet, dass wir beim zweiten oder dritten Punkt eine weitere plötzliche Bewegung im System der Vermögenswertdarstellung sehen werden. In gewissem Sinne ist das kein großes Problem, zumindest in den meisten Fällen, denn auf dem realen Markt gibt es tatsächlich an einigen Stellen solche Bewegungen. Auch wenn wir in diesem Fall ein System schaffen wollen, in dem diese Bewegungen nicht so häufig vorkommen, müssen wir andere Maßnahmen ergreifen. Mit anderen Worten: Wir werden weitere Änderungen am Simulationssystem vornehmen müssen, aber diese Änderungen werden nicht ohne Schwierigkeiten vonstatten gehen. Im Gegenteil, diese Umsetzung wird für manche Menschen schwer zu verstehen sein. Wenn wir ein Diagramm wünschen, das dem in Abbildung 07 gezeigten sehr ähnlich ist, müssen wir außerdem diese Änderungen vornehmen.

Ich denke, dass viele Menschen mit den Ergebnissen dieser Version bereits recht zufrieden sind. Aber wir können das alles noch verbessern. Für diejenigen, die meinen, dass dies ausreicht, mag der folgende Artikel überflüssig erscheinen. Aber für die Perfektionisten habe ich noch einen Vorschlag, an dem sie arbeiten sollten. Dadurch wird ein RANDOM WALK ohne lose Punkte erstellt. Auf diese Weise werden alle Punkte besucht. Aber das ist genug für heute. Ich werde Ihnen Zeit geben, die Erkenntnisse aus diesem Artikel zu verdauen. Sie müssen das System mehrere Male mit verschiedenen Arten von Vermögenswerten testen, nur dann werden Sie wirklich wissen, ob die möglichen Bewegungen innerhalb eines 1-Minuten-Balkens angemessen sind und die mögliche Realität des Marktes widerspiegeln, den Sie mit dem Konzept eines begrenzten RANDOM WALK ausnutzen wollen.


Abschließende Überlegungen

Ich denke, dass es mir gelungen ist, Ihnen, liebe Leserinnen und Leser, ohne komplexe mathematische Formeln und in einfacher Sprache ein Konzept zu vermitteln, das sehr interessant und auf dem Markt präsent ist. Dies ist der so genannte RANDOM WALK. Das in diesem Artikel vorgestellte System zeigt, wie weit wir gehen können, ohne komplexe Konzepte zu verstehen, obwohl es natürlich immer gut ist, Wissen zu erwerben. Aber warum etwas verkomplizieren, wenn man es auch auf einfache und angenehme Weise erklären kann, oder?

Die beigefügte Datei enthält das System in seinem derzeitigen Entwicklungsstand. Viele von Ihnen fragen sich wahrscheinlich, wann wir das Auftragssystem tatsächlich in unserem Replay/Simulator einsetzen werden. Keine Sorge, wir werden bald mit dem Auftragssystem beginnen, aber vorher müssen wir noch eine Sache erledigen. Dies ist notwendig, weil das Auftragssystem zu einem interessanten Problem wird, das es zu lösen gilt. Aber zuerst müssen wir die Implementierung des Replay/Simulationsdienstes abschließen, der nun fast fertig zu sein scheint. Wir müssen nur noch ein paar Details hinzufügen. Danach können wir mit der Entwicklung des Auftragssystems beginnen. Auf diese Weise wird es möglich sein, den Replay/Simulator so zu nutzen, als würde man auf einem echten Markt handeln. Allerdings müssen wir vielleicht ein paar Dinge ändern, bevor wir es nutzen können. Aber das werden wir später entscheiden. Wie auch immer, Sie müssen üben und trainieren, um ein erfahrener Programmierer zu werden. Was ich Ihnen zu erklären versuche, wird Ihnen dabei helfen. Wir sehen uns im nächsten Artikel, in dem wir diesen RANDOM WALK beenden werden. Diese Phase ist noch nicht abgeschlossen.


Übersetzt aus dem Portugiesischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/pt/articles/11058

Beigefügte Dateien |
Entwicklung eines Replay Systems — Marktsimulation (Teil 15): Die Geburt des SIMULATORS (V) - RANDOM WALK Entwicklung eines Replay Systems — Marktsimulation (Teil 15): Die Geburt des SIMULATORS (V) - RANDOM WALK
In diesem Artikel werden wir die Entwicklung eines Simulators für unser System abschließen. Das Hauptziel besteht darin, den im vorherigen Artikel beschriebenen Algorithmus zu konfigurieren. Dieser Algorithmus zielt darauf ab, eine zufällige Bewegung, einen „RANDOM WALK“ zu erzeugen. Um das heutige Material zu verstehen, ist es daher notwendig, den Inhalt der früheren Artikel zu kennen. Wenn Sie die Entwicklung des Simulators nicht verfolgt haben, empfehle ich Ihnen, diese Sequenz von Anfang an zu lesen. Andernfalls könnten Sie verwirrt sein über das, was hier erklärt wird.
Elastische Netzregression mit Koordinatenabstieg in MQL5 Elastische Netzregression mit Koordinatenabstieg in MQL5
In diesem Artikel untersuchen wir die praktische Umsetzung der elastischen Netzregression, um die Überanpassung zu minimieren und gleichzeitig automatisch nützliche Prädiktoren von solchen zu trennen, die wenig prognostische Kraft haben.
Kategorientheorie in MQL5 (Teil 19): Induktion natürlicher Quadrate Kategorientheorie in MQL5 (Teil 19): Induktion natürlicher Quadrate
Wir setzen unseren Blick auf natürliche Transformationen fort, indem wir die Induktion natürlicher Quadrate besprechen. Leichte Einschränkungen bei der Implementierung von Mehrfachwährungen für Experten, die mit dem MQL5-Assistenten zusammengestellt wurden, bedeuten, dass wir unsere Fähigkeiten zur Datenklassifizierung mit einem Skript demonstrieren. Die wichtigsten Anwendungen sind die Klassifizierung von Preisänderungen und damit deren Vorhersage.
Entwicklung eines Qualitätsfaktors für Expert Advisors Entwicklung eines Qualitätsfaktors für Expert Advisors
In diesem Artikel sehen wir uns an, wie Sie eine Qualitätsbewertung entwickeln, die Ihr Expert Advisor im Strategietester anzeigen kann. Wir werden uns zwei bekannte Berechnungsmethoden ansehen – Van Tharp und Sunny Harris.