English Русский 中文 Español Português
preview
Von der Grundstufe bis zur Mittelstufe: Struktur (III)

Von der Grundstufe bis zur Mittelstufe: Struktur (III)

MetaTrader 5Beispiele |
34 0
CODE X
CODE X

Einführung

Im vorherigen Artikel „Von der Grundstufe zur Mittelstufe: Indikator (IV)" haben wir gezeigt, wie man auf einfache und klare Weise etwas tut, was für viele Anfänger sehr schwierig ist. Damit kennt nun jeder einen einfachen Weg, Ideen in die Praxis umzusetzen. Das Ziel war es, einen Indikator zu erstellen, der anhand von Farben ein bestimmtes Handelssystem anzeigt. Natürlich haben wir dort gezeigt, wie man das Muster der Inside Bar umsetzt. Dieses Wissen kann jedoch auf jedes Muster angewandt werden, bei dem das Farbmuster der Kerzen auf eine Handelsmöglichkeit hinweist (oder nicht hinweist).

Nun, das war sehr interessant. Ich denke jedoch, dass wir ein anderes Thema ansprechen können, das meiner Meinung nach auch recht unterhaltsam und interessant ist. Wir haben am Ende des letzten Artikels begonnen, uns mit diesem Thema zu beschäftigen. Doch bevor wir uns dem Thema zuwenden, mit dem wir uns in diesem Artikel beschäftigen werden, müssen wir einen kurzen Rückblick halten.

In den Artikeln über Strukturen, insbesondere in „Von der Grundstufe bis zur Mittelstufe: Struct (II)", haben wir erklärt, wie man mit Strukturen arbeitet, um Blöcke von Datensätzen zu erstellen. In diesen beiden Artikeln haben wir erwähnt, dass Strukturen eine besondere Art von Daten sind, in denen Sie verschiedene Informationen unterbringen können, allerdings auf logische und vereinfachte Weise. Da wir jedoch zuvor nichts anderes gezeigt hatten, wäre es schwierig und sogar unnötig gewesen, sich mit den Details der Strukturen zu befassen. Der vorangegangene Artikel hat jedoch eine ausreichende Grundlage geschaffen, um sich mit einigen anderen Themen zu befassen. Im Wesentlichen wollen wir nun zeigen, dass Strukturen nicht nur für die Organisation von Datensätzen verwendet werden können.

Nach dieser kurzen Einführung können wir nun endlich zur Sache kommen und beginnen, die Gründe für die Entstehung von Klassen zu verstehen. Beginnen wir mit dem ersten Schwerpunkt zu diesem Thema.


Strukturierter Code

Was mich wahrscheinlich am meisten frustriert, ist, wenn ich Code sehe, in dem alles durcheinandergeraten ist. In den Tagen des guten alten BASIC gab es eine gewisse Logik, wenn der Code keine vordefinierte Struktur hatte. Das hängt mit der Natur dieser Sprache zusammen. In Sprachen wie BATCH und anderen skriptbasierten Verarbeitungssprachen (wie zum Beispiel SQL) ist die Struktur mitunter weniger klar ausgeprägt. Denn in den meisten Fällen sind die auszuführenden Aufgaben relativ einfach, ebenso wie die Codes, die in der Regel recht kurz sind.

Allerdings wird alles komplizierter, wenn wir zu Sprachen mit anspruchsvolleren Zielen übergehen, wie im Fall von MQL5. In diesem Fall haben wir oft ein Ziel, das mit nur ein paar Zeilen Code schwer zu erreichen ist, selbst wenn wir eine Header-Datei verwenden, um einen Großteil der Komplexität zu verbergen. Aber es gibt einige Aspekte, die das Programmieren mühsam und lästig machen. Einer davon ist die Neigung von Programmieranfängern, Codefragmente zu wiederholen, die besser hätten strukturiert werden können.

Und wenn ich von strukturiertem Code spreche, meine ich nicht die Verwendung von Funktionen oder Prozeduren, um eine bestimmte Strukturierung des Codes aufrechtzuerhalten. In diesem Fall meine ich die Einbettung von Code in Strukturen, um seine Wartung und Verwaltung zu erleichtern. Viele Programmiermentoren sagen, dass die Verwendung von Funktionen und Prozeduren im Code diesen bereits strukturiert macht. Das bedeutet aber nicht unbedingt, dass der Code strukturiert ist. Es ist einfach besser organisiert, und mehr nicht.

Um wirklich strukturierten Code zu erhalten, müssen wir Methoden und Konzepte verwenden, die viele für verrückt oder zumindest für zu komplex halten. Ein solches Instrument sind Klassen. Aber es ist noch nicht an der Zeit, über Klassen zu sprechen, denn Klassen sind nicht entstanden, weil eines schönen Tages Programmierer aufgewacht sind und gesagt haben: "Wir werden etwas schaffen, das allen Berufsanfängern das Leben schwer macht. Auf diese Weise werden wir die coolsten Programmierer sein". Nein, Klassen sind entstanden, um das Problem der Erstellung von wirklich strukturiertem Code zu lösen.

Um diese Einschränkung zu verstehen, müssen wir uns mit komplexeren Fragen befassen. Machen Sie sich also bereit, denn von nun an wird es sehr interessant und sogar lustig.

Vielleicht sehen Sie mich mit einer gewissen Skepsis an, weil Sie nicht verstehen, was ich zeigen will. Aber keine Sorge, wir werden Schritt für Schritt vorgehen, denn es ist äußerst wichtig, dass Sie unsere Absichten verstehen. Andernfalls wird Sie verwirren, wenn wir nun Modelle zur objektorientierten Programmierung aufbauen.

Im vorigen Artikel haben wir den folgenden Code gesehen:

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. input bool user01 = true;       //Show time scale
05. input bool user02 = true;       //Show price scale
06. //+----------------+
07. struct st_Mem
08. {
09.     long    View_DateScale,
10.             View_PriceScale;
11. }gl_StyleGraphic;
12. //+------------------------------------------------------------------+
13. int OnInit()
14. {
15.     gl_StyleGraphic.View_DateScale = ChartGetInteger(0, CHART_SHOW_DATE_SCALE);
16.     gl_StyleGraphic.View_PriceScale = ChartGetInteger(0, CHART_SHOW_PRICE_SCALE);
17. 
18.     ChartSetInteger(0, CHART_SHOW_DATE_SCALE, user01);
19.     ChartSetInteger(0, CHART_SHOW_PRICE_SCALE, user02);
20. 
21.     return INIT_SUCCEEDED;
22. };
23. //+------------------------------------------------------------------+
24. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[])
25. {
26.     return rates_total;
27. };
28. //+------------------------------------------------------------------+
29. void OnDeinit(const int reason)
30. {
31.     ChartSetInteger(0, CHART_SHOW_DATE_SCALE, gl_StyleGraphic.View_DateScale);
32.     ChartSetInteger(0, CHART_SHOW_PRICE_SCALE, gl_StyleGraphic.View_PriceScale);
33.     ChartRedraw();
34. };
35. //+------------------------------------------------------------------+

Code 01

Dieser Code ist recht einfach. Wenn Sie jedoch wirklich neugierig sind, können Sie die Chart-Eigenschaften untersuchen und versuchen, sein Erscheinungsbild direkt per Code zu steuern und zu verändern. Wenn Sie das geschafft haben, dann gratuliere ich Ihnen, denn das ist eine der notwendigen Voraussetzungen für diejenigen, die in Zukunft gute Fachleute werden wollen.

Trotz der scheinbaren Einfachheit dieses Codes wird er von vielen als strukturierter Code angesehen. Meiner Meinung nach ist das, was wir in Code 01 sehen, nicht gerade strukturierter Code, sondern eher gut organisierter Code. Trotz seiner Einfachheit ist es nicht ganz der Code, der meiner Meinung nach ideal ist, um strukturierten Code zu erklären. Zu diesem Zweck werden wir uns etwas noch Einfacherem zuwenden: Skripten. Das liegt daran, dass Skripte nur auf das Ereignis „Start" reagieren. Sobald dieses Ereignis abgeschlossen ist, endet auch die Ausführung des Codes. Einfacher geht's nicht.

Beginnen wir mit dem unten stehenden Code.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. void OnStart(void)
05. {
06.     struct st_Mem
07.     {
08.         long    View_DateScale,
09.                 View_PriceScale;
10.     }StyleGraphic;
11. 
12.     StyleGraphic.View_DateScale = ChartGetInteger(0, CHART_SHOW_DATE_SCALE);
13.     StyleGraphic.View_PriceScale = ChartGetInteger(0, CHART_SHOW_PRICE_SCALE);
14. 
15.     ChartSetInteger(0, CHART_SHOW_DATE_SCALE, false);
16.     ChartSetInteger(0, CHART_SHOW_PRICE_SCALE, false);
17.     ChartRedraw();
18. 
19.     Sleep(2000);
20. 
21.     ChartSetInteger(0, CHART_SHOW_DATE_SCALE, StyleGraphic.View_DateScale);
22.     ChartSetInteger(0, CHART_SHOW_PRICE_SCALE, StyleGraphic.View_PriceScale);
23.     ChartRedraw();
24. }
25. //+------------------------------------------------------------------+

Code 02

Dieser Code ist viel einfacher als der in Code 01 und verfolgt das gleiche Ziel: die Preis- und Zeitskala auszublenden und dann wieder einzublenden. Wenn Sie dieses Skript auf einem Chart ausführen, sehen Sie etwas Ähnliches wie die folgende Animation:

Animation 01

Wie Sie sehen, ist alles sehr einfach: Zeile 19 sorgt dafür, dass die Skalen für einige Augenblicke ausgeblendet werden. Darin geben wir an, dass wir eine Pause von etwa zwei Sekunden einlegen wollen, bevor die Ausführung des Codes fortgesetzt wird. Ich möchte Sie jedoch auf zwei Punkte aufmerksam machen: Zeile 17 und 23. Im vorherigen Artikel habe ich erklärt, warum dieser Befehl im Code verwendet werden sollte. Aber hier arbeiten wir mit einem Skript, und die Wartezeit ist kurz, daher ist dieser Befehl, der in beiden genannten Zeilen enthalten ist, sehr wichtig. Ohne diesen Befehl würden wir wahrscheinlich nicht sehen, wie die Preis- und Zeitskalen aus- und wieder eingeblendet werden.

Na gut. So weit, so gut. Aber Code 02 ist meiner Meinung nach kein strukturierter Code, auch wenn wir in Zeile 06 eine Struktur deklarieren. Fangen wir also an, das zu schreiben, was viele als strukturierten Code bezeichnen. Zu diesem Zweck ändern wir den Code 02 in die unten dargestellte Version:

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. struct st_Mem
05. {
06.     long    View_DateScale,
07.             View_PriceScale;
08. };
09. //+------------------------------------------------------------------+
10. void OnStart(void)
11. {
12.     st_Mem StyleGraphic;
13. 
14.     StyleGraphic = SAVE();
15. 
16.     ChartSetInteger(0, CHART_SHOW_DATE_SCALE, false);
17.     ChartSetInteger(0, CHART_SHOW_PRICE_SCALE, false);
18.     ChartRedraw();
19. 
20.     Sleep(2000);
21.     
22.     RESTORE(StyleGraphic);
23. }
24. //+------------------------------------------------------------------+
25. st_Mem SAVE(void)
26. {
27.     st_Mem local;
28. 
29.     local.View_DateScale = ChartGetInteger(0, CHART_SHOW_DATE_SCALE);
30.     local.View_PriceScale = ChartGetInteger(0, CHART_SHOW_PRICE_SCALE);
31. 
32.     return local;
33. }
34. //+------------------------------------------------------------------+
35. void RESTORE(const st_Mem &arg)
36. {
37.     ChartSetInteger(0, CHART_SHOW_DATE_SCALE, arg.View_DateScale);
38.     ChartSetInteger(0, CHART_SHOW_PRICE_SCALE, arg.View_PriceScale);
39. 
40.     ChartRedraw();
41. }
42. //+------------------------------------------------------------------+

Code 03

Code 03 führt zu demselben Ergebnis wie Animation 01, allerdings mit einer kleinen Nuance. Im Gegensatz zu Code 02 haben wir hier eine bessere Organisation, da wir die Funktion in Zeile 25 zu verschiedenen Zeitpunkten und die Prozedur in Zeile 35 zu jedem Zeitpunkt verwenden können. Der Hauptvorteil dieser Art von Modellierung und Implementierung, die wir in Code 03 sehen können, ist, dass wir alle Werte der Chart-Eigenschaften speichern und wiederherstellen können, ohne uns Gedanken darüber zu machen, welche Werte geändert werden. So vermeidet man viele zusätzliche Codezeilen mit immer demselben Muster.

Es gibt jedoch ein kleines Problem mit diesem Ansatz, das in Code 03 sichtbar wird. Das Problem ist folgendes: Wir arbeiten mit einer Struktur, die Daten enthält. So weit, so gut. Aber was nützt es, eine Funktion in Zeile 25 und eine Prozedur in Zeile 35 zu implementieren, wenn das Ziel darin besteht, direkt mit den in der Struktur vorhandenen Daten zu arbeiten?

Anfängern oder erfahrenen Programmierern macht das zunächst nichts aus, vor allem wenn sie mit einfachem Code arbeiten, aber es wird zu einem echten Problem, wenn wir mit komplexerem Code arbeiten. Dies geschieht, weil wir anfangen, Dinge einzubeziehen, die außerhalb des Kontexts der von uns verwendeten Daten nicht viel Sinn machen.

Code 03 ist sehr gut geeignet, um dies zu erklären und Ihnen, liebe Leserin, lieber Leser, das Konzept dessen zu verdeutlichen, was wir bald tun werden. Bitte beachten Sie Folgendes: Wir haben eine Struktur, die an verschiedenen Stellen im Code verwendet werden kann. Der Zweck dieser Struktur besteht darin, den Zustand, in dem sich das Chart zu einem bestimmten Zeitpunkt befindet, zu speichern und wiederherzustellen. Daher können wir den Code wie oben gezeigt implementieren.

Wenn wir jedoch neue Elemente erstellen, verlieren die SAVE-Funktion und die RESTORE-Prozedur ihren Kontext. Möglicherweise müssen wir auch eine andere Funktion und Prozedur mit genau demselben Namen erstellen, aber mit einem anderen Zweck als dem Speichern und Wiederherstellen von Chart-Eigenschaften. An diesem Punkt könnten wir Überladungen verwenden, aber das würde den Code völlig unnötig verkomplizieren. Und genau in diesem Moment stellt sich die Frage, ob der Code strukturiert ist oder nicht.

In strukturiertem Code werden die Funktionen SAVE und RESTORE nicht mehr wie in Code 03 deklariert, wo sie nicht richtig mit dem Kontext der in Zeile 04 definierten Struktur verknüpft sind, sondern sie werden im Kontext dieser Struktur deklariert bzw. implementiert. Da dies nicht in Fragmenten gezeigt werden kann, gehen wir direkt zu der in anderen Codes diskutierten Lösung über, nur jetzt in einem vollständig strukturierten Modell. Dies ist im folgenden Code zu sehen:

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. struct st_PropertyGraphics
05. {
06.     long    View_DateScale,
07.             View_PriceScale;
08. //+----------------+
09.     void SAVE(void)
10.     {
11.         View_DateScale = ChartGetInteger(0, CHART_SHOW_DATE_SCALE);
12.         View_PriceScale = ChartGetInteger(0, CHART_SHOW_PRICE_SCALE);
13.     }
14. //+----------------+
15.     void RESTORE(void)
16.     {
17.         ChartSetInteger(0, CHART_SHOW_DATE_SCALE, View_DateScale);
18.         ChartSetInteger(0, CHART_SHOW_PRICE_SCALE, View_PriceScale);
19. 
20.         ChartRedraw();
21.     }
22. //+----------------+
23. };
24. //+------------------------------------------------------------------+
25. void OnStart(void)
26. {
27.     st_PropertyGraphics StyleGraphic;
28. 
29.     StyleGraphic.SAVE();
30. 
31.     ChartSetInteger(0, CHART_SHOW_DATE_SCALE, false);
32.     ChartSetInteger(0, CHART_SHOW_PRICE_SCALE, false);
33.     ChartRedraw();
34. 
35.     Sleep(2000);
36.     
37.     StyleGraphic.RESTORE();
38. }
39. //+------------------------------------------------------------------+

Code 04

„Wow! Was für ein Chaos. Jetzt hat mein Gehirn verrückt gespielt, denn soweit ich weiß, ist eine Struktur eine besondere Art von Variable, die so organisiert werden kann, dass kleine Datenbanken mit Datensätzen entstehen. Aber was ich in Code 04 sehe, ergibt für mich überhaupt keinen Sinn".

Nun, wir haben gerade die Messlatte höher gelegt. Wer das hier Gezeigte nicht geübt und verstanden hat, wird ab diesem Punkt kaum noch weiterkommen. Es gibt jedoch keinen Grund, Code 04 zu fürchten. Ich versuche, alles so lehrreich wie möglich zu gestalten, um den Bedarf an Erklärungen zu vermeiden und mich auf etwas Interessanteres zu konzentrieren.

Schauen wir uns also an, was in Code 04 passiert. Zunächst einmal funktioniert der Code 04 genauso wie die anderen Codes, die wir oben beschrieben haben. Hier haben wir jedoch einen Vorteil: Die Prozeduren und Funktionen zum Speichern der grafischen Eigenschaften befinden sich nun direkt im Kontext der Struktur, die diese Daten enthält – und bleiben dort auch. Das ist es, was wir strukturierte Programmierung nennen.

Vorerst ignorieren wir die in Zeile 04 definierte Struktur und konzentrieren uns auf den OnStart-Ereignishandler. In Zeile 27 deklarieren wir wieder eine Variable dieses Strukturtyps. Achten Sie aber auf die Zeilen 29 und 37. Was denken Sie, wenn Sie diese Zeilen sehen? Sie denken jetzt wahrscheinlich: „Nun, in Zeile 29 bitte ich darum, etwas zu speichern, und in Zeile 37 darum, etwas wiederherzustellen". Wenn Sie das gedacht haben, dann sind wir auf dem richtigen Weg.

Schauen Sie sich diese Zeilen noch einmal an: Was wollen wir speichern und wiederherstellen? Es handelt sich tatsächlich um die Variable, die wir in Zeile 27 deklariert haben. Interessant. Schauen wir uns das mal an. In Zeile 27 deklarieren wir eine Variable. Bei der Ausführung von Zeile 29 wird die gleiche Variable gespeichert. Gut, da diese Variable vom Typ eines Datensatzes für grafische Chart-Eigenschaften ist,

In Zeile 29 fordern wir also die Speicherung der Grafikeigenschaften an. Auf diese Weise können wir in den Zeilen 31 und 32 die Eigenschaften ändern, ohne uns Gedanken über mögliche Änderungen zu machen. „Großartig, es scheint klarer zu werden. Wenn wir Zeile 37 ausführen, bitten wir darum, dieselben gespeicherten Eigenschaften wiederherzustellen, wodurch alle zwischen den Zeilen 29 und 37 vorgenommenen Änderungen verworfen werden. Ist das alles, und habe ich richtig verstanden, was hier im OnStart-Ereignishandler gemacht wird?" Ja, meine lieben Leserinnen und Leser, Ihre Vermutungen waren in der Tat sehr treffend.

"Super! Aber jetzt habe ich Zweifel. Beim Vergleich von Code 03 mit Code 04 ist mir aufgefallen, dass die Art und Weise der Deklaration der Prozeduren SAVE und RESTORE hier anders ist. Warum gibt es einen solchen Unterschied zwischen diesen beiden Codes? Denn im Grunde verfolgen beide denselben Zweck und verhalten sich gleich. Ich verstehe das immer noch nicht".

Ich bin froh, dass Sie das bemerkt haben, denn jetzt ist es dank Ihres Verständnisses des Codes in OnStart an der Zeit, den in Zeile 04 deklarierten Strukturcode zu erklären. Dieses Mal möchte ich, dass Sie alles andere in Code 04 ignorieren und sich nur auf den Strukturblock konzentrieren.

Bitte beachten Sie, dass ich den Namen der Struktur geändert habe, um den Prozess zu vereinfachen. Sie können jedoch jeden beliebigen Namen verwenden. Wichtig ist, dass es sich um eine Struktur auf globaler Ebene handelt. Sie könnte sogar in einer Header-Datei enthalten sein. Aber darüber machen wir uns erst einmal keine Gedanken. Achten Sie einfach darauf, was Ihnen erklärt wird.

Bitte beachten Sie, dass wir die gleichen Variablen wie in den vorherigen Codes verwenden. Diese Variablen bleiben zugänglich und funktionieren perfekt, genau wie in Code 03. Sie können sogar mit ihnen arbeiten, aber darüber reden wir ein anderes Mal. Wichtig ist, was innerhalb der Unterroutine geschieht. In diesem Fall haben wir die SAVE-Prozedur in Zeile 09 und die RESTORE-Prozedur in Zeile 15. Beachten Sie, dass sie denjenigen in Code 03 sehr ähnlich sind.

Aber jetzt wird es interessant: Die Variablen View_DateScale und View_PriceScale müssen nicht mehr deklariert werden, wie in Code 03 gezeigt. Der Grund dafür ist, dass diese Variablen für den Compiler und für den Programmierer Teil des Kontexts sind. In diesem Fall ist der Kontext genau die Struktur st_PropertyGraphics.

Das heißt, da wir in einem Kontext arbeiten, der in der Struktur Sinn macht, müssen die Variablen NICHT MEHR extra deklariert werden, wie es in Code 03 (in den Zeilen 29, 30, 37 und 38) geschehen ist, wo wir die Datentypen angeben mussten, mit denen die Variablen verbunden sein würden, da in Code 03 sowohl die SAVE- als auch die RESTORE-Unterprogramme nicht zum Kontext der Struktur gehörten. Dies ist im Code 04 nicht mehr sinnvoll, da beide Unterprogramme zur Struktur gehören.

Dies können wir als strukturierten Code bezeichnen, da wir nun mit Elementen in ihrem vollständigen Kontext arbeiten können, ohne sie darstellen oder den gesamten Code lesen zu müssen, um zu verstehen, was geschieht.

Sie können gerne Änderungen vornehmen und mit diesem Code experimentieren, um zu verstehen, was wirklich vor sich geht. Aber bevor ich diesen Artikel beende, möchte ich noch etwas anderes zeigen, diesmal mit einem anderen Code. Da dies aber mit anderen Themen zusammenhängt, werden wir sie in einem neuen Thema behandeln.


Einfache Manipulationen mit Strukturen

Im vorangegangenen Thema haben wir erörtert, wie Code durch die Erstellung von strukturiertem Code Kontext erhält. Bei aller Schönheit gibt es aber auch einige Punkte, die man beachten sollte. Natürlich war es gerade dieses Erfordernis besonderer Sorgfalt, das die Schaffung von Klassen notwendig gemacht hat. Aber darüber reden wir ein andermal. Sehen wir uns zunächst einige dieser „Bedenken" an.

Zunächst einmal folgen alle Daten in einer Struktur einem sehr einfachen Kriterium: Sie können entweder öffentlich oder privat sein. Wenn wir eine einfache Struktur deklarieren, haben wir in der Regel immer öffentliche Daten. Aber wenn wir mit strukturierter Programmierung arbeiten, wollen wir KEINE öffentlichen Daten. In solchen Fällen wollen wir sicherstellen, dass die Daten während ihrer gesamten Lebensdauer intakt und sicher bleiben.

Um diese Integrität zu gewährleisten, können wir die Art des Zugriffs auf die Daten ändern. Und jetzt passen Sie auf. Was wir hier sehen werden, sollte NICHT in einfachen Konstruktionen, wie den oben gezeigten, verwendet werden. Verwenden Sie diese Option nur in Fällen, in denen Sie strukturierten Code implementieren und mehr Kontrolle über seine Funktionsweise haben möchten. Wenn Sie nicht über die erforderlichen Kenntnisse verfügen, wird die Anwendung der hier gezeigten Methoden das, was im Prinzip recht einfach ist, verkomplizieren.

Um dies richtig zu erklären, betrachten wir ein einfaches Codebeispiel, das aber für das, was wir im Moment erklären wollen, geeignet ist. Es ist unten zu sehen:

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. struct st_PropertyGraphics
05. {
06.     long    View_DateScale,
07.             View_PriceScale,
08.             Chart_Mode;
09. //+----------------+
10.     void SAVE(void)
11.     {
12.         View_DateScale = ChartGetInteger(0, CHART_SHOW_DATE_SCALE);
13.         View_PriceScale = ChartGetInteger(0, CHART_SHOW_PRICE_SCALE);
14.         Chart_Mode = ChartGetInteger(0, CHART_MODE);
15.     }
16. //+----------------+
17.     void RESTORE(void)
18.     {
19.         ChartSetInteger(0, CHART_SHOW_DATE_SCALE, View_DateScale);
20.         ChartSetInteger(0, CHART_SHOW_PRICE_SCALE, View_PriceScale);
21.         ChartSetInteger(0, CHART_MODE, Chart_Mode);
22. 
23.         ChartRedraw();
24.     }
25. //+----------------+
26. };
27. //+------------------------------------------------------------------+
28. void OnStart(void)
29. {
30.     st_PropertyGraphics StyleGraphic;
31. 
32.     StyleGraphic.SAVE();
33. 
34.     StyleGraphic.Chart_Mode = CHART_LINE;
35. 
36.     ChartSetInteger(0, CHART_SHOW_DATE_SCALE, false);
37.     ChartSetInteger(0, CHART_SHOW_PRICE_SCALE, false);
38.     ChartSetInteger(0, CHART_MODE, CHART_BARS);
39.     ChartRedraw();
40. 
41.     Sleep(2000);
42.     
43.     StyleGraphic.RESTORE();
44. }
45. //+------------------------------------------------------------------+

Code 05

Bitte beachten Sie, dass Code 05 dem Code 04 sehr ähnlich ist. Um jedoch zu zeigen, was wir zeigen wollen, haben wir der Struktur eine neue grafische Eigenschaft hinzugefügt. Diese Eigenschaft wird in Zeile 08 von Code 05 angegeben. Beachten Sie, dass den Prozeduren SAVE und RESTORE neue Zeilen hinzugefügt wurden. Diese Änderungen sind nicht signifikant genug, um eine detaillierte Erklärung zu rechtfertigen. Geringfügige Änderungen wurden auch an der Funktion OnStart vorgenommen, die einfach sind und keiner ausführlichen Erklärung bedürfen. Wenn wir dieses Skript jedoch auf einem Chart ausführen, erhalten wir in etwa folgendes Ergebnis:

Animation 02

„Wow! Lassen Sie uns das Band anhalten und zurückspulen, denn wir haben gerade ein unerwartetes Ergebnis erhalten, und ich möchte verstehen, warum das Chart nicht in seinen ursprünglichen Zustand zurückversetzt wurde, da wir dasselbe Prinzip und dieselbe Idee wie in Code 04 beibehalten. Ich denke jedoch, dass der Fehler in der neuen Eigenschaft liegen könnte, die wir gerade hinzugefügt haben". Im Grunde stimmt das – aber genau das ist nicht das eigentliche Problem. Dieses Problem wird als Datenleck oder als Verletzung der Kapselung bezeichnet, d. h. es wird etwas getan, was vorher nicht getan werden konnte. Dies ist genau das, was zu dem in Animation 02 gezeigten Ergebnis führt.

Bitte beachten Sie, dass wir in Zeile 32 die Grafikeigenschaften speichern und in Zeile 43 wiederherstellen, genau wie in Code 04. Aber hier ist das Problem: Zeile 34. "Ich sehe darin kein Problem. Vielleicht wird alles wieder normal, wenn wir diese Zeile entfernen?" Ja, wenn wir die Zeile 34 streichen, wird sich alles fügen. Aber das ist nicht der Punkt.

Die Frage ist, wie die Daten in der Variablen StyleGraphics gespeichert werden. Diese Variable ist direkt mit einem kleinen Datensatz verbunden, der sich zwischen den Zeilen 06 und 08 befindet. Alle Änderungen, die wir an diesen Datensätzen vornehmen, wirken sich auf den Inhalt der Variablen StyleGraphics aus.

Wenn wir also in Zeile 43 die Wiederherstellung der Daten anfordern, werden alle in diesem Datensatz gespeicherten Daten verwendet. Aufgrund der in Zeile 34 vorgenommenen Änderung ging der ursprüngliche Datensatz jedoch verloren. Daher haben wir jetzt einen anderen Wert als den, der gespeichert wurde, und dieser wird auf das Chart angewendet, wodurch es mit falschen Informationen zurückgesetzt wird.

Dieses Problem ist sehr ernst und gleichzeitig sehr häufig. Um dieses Problem zu lösen, müssen wir die Zugriffsbedingungen der Strukturmitglieder ändern. Denken Sie daran, dass standardmäßig alle Werte öffentlich sind. Wenn wir jedoch den Code 05 in den unten gezeigten ändern, sieht alles anders aus:

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. struct st_PropertyGraphics
05. {
06.     private:
07. //+----------------+
08.         long    View_DateScale,
09.                 View_PriceScale,
10.                 Chart_Mode;
11. //+----------------+
12.     public:
13. //+----------------+
14.         void SAVE(void)
15.         {
16.             View_DateScale = ChartGetInteger(0, CHART_SHOW_DATE_SCALE);
17.             View_PriceScale = ChartGetInteger(0, CHART_SHOW_PRICE_SCALE);
18.             Chart_Mode = ChartGetInteger(0, CHART_MODE);
19.         }
20. //+----------------+
21.         void RESTORE(void)
22.         {
23.             ChartSetInteger(0, CHART_SHOW_DATE_SCALE, View_DateScale);
24.             ChartSetInteger(0, CHART_SHOW_PRICE_SCALE, View_PriceScale);
25.             ChartSetInteger(0, CHART_MODE, Chart_Mode);
26. 
27.             ChartRedraw();
28.         }
29. //+----------------+
30. };
31. //+------------------------------------------------------------------+
32. void OnStart(void)
33. {
34.     st_PropertyGraphics StyleGraphic;
35. 
36.     StyleGraphic.SAVE();
37. 
38.     StyleGraphic.Chart_Mode = CHART_LINE;
39. 
40.     ChartSetInteger(0, CHART_SHOW_DATE_SCALE, false);
41.     ChartSetInteger(0, CHART_SHOW_PRICE_SCALE, false);
42.     ChartSetInteger(0, CHART_MODE, CHART_BARS);
43.     ChartRedraw();
44. 
45.     Sleep(2000);
46.     
47.     StyleGraphic.RESTORE();
48. }
49. //+------------------------------------------------------------------+

Code 06

In diesem Fall wird beim Kompilieren des Codes ein Fehler angezeigt, der dem folgenden sehr ähnlich ist:

Abbildung 01

Beachten Sie den Fehler, denn in Zeile 38 versuchen wir, auf einen Wert zuzugreifen, der nicht mehr öffentlich ist; dies geschieht, weil wir in Zeile 06 den Zugriffsmodifikator private hinzugefügt haben. Wenn wir jedoch Zeile 38 aus Code 06 entfernen, können wir den Code kompilieren, da die Unterprogramme SAVE und RESTORE öffentlich sind, weil wir den Zugriffsmodifikator public in Zeile 12 hinzugefügt haben. Ich weiß, dass alles in diesem Moment verwirrend erscheinen mag, aber glauben Sie mir, es ist viel einfacher, als Sie denken, vor allem, weil wir von nun an eine Form der strukturierten Programmierung verwenden, indem wir öffentliche und private Teile in unseren Code aufnehmen.


Abschließende Gedanken

Nun, wir sind am Ende des heutigen Artikels angelangt. Dieser Artikel ist etwas Besonderes. Denn an diesem Punkt steigen wir in das ein, was man als strukturierte Programmierung bezeichnet: Wir erstellen kleine Datenstrukturen und bauen einen Kontext für sie auf, indem wir Prozeduren und Funktionen verwenden, die sich ausschließlich auf die Verarbeitung, Wartung und Analyse der in der Codestruktur vorhandenen Daten konzentrieren.

Ich weiß, dass all dies zunächst sehr komplex und verwirrend erscheinen mag, insbesondere für viele, die vielleicht zum ersten Mal mit dieser Form der Code-Implementierung in Berührung kommen. In der Anwendung finden Sie die wichtigsten heute besprochenen Codebeispiele, sodass Sie in Ruhe üben und jedes Detail dieses Artikels genauer studieren können.

Es ist sehr wichtig, dass Sie den Inhalt dieses Materials richtig verstehen. Wenn Sie das richtig verstanden haben, werden die nächsten Schritte viel einfacher sein. Außerdem wird das Verständnis der Lektionen, die wir später erklären werden, viel einfacher und unkomplizierter sein. In jedem Fall ist dies nur eine kurze Einführung in das Thema.

Im nächsten Artikel werden wir ausführlicher auf das eingehen, was wir heute gesehen haben. Vernachlässigen Sie jedoch nicht, diese Grundlagen zu studieren, denn sie werden Ihnen das Verständnis für den Inhalt der folgenden Artikel erheblich erleichtern.

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

Beigefügte Dateien |
Anexo.zip (2.89 KB)
Neuronale Netze im Trading: Adaptive Erkennung von Marktanomalien (DADA) Neuronale Netze im Trading: Adaptive Erkennung von Marktanomalien (DADA)
Wir laden Sie ein, sich mit dem DADA-Framework vertraut zu machen, das eine innovative Methode zur Erkennung von Anomalien in Zeitreihen darstellt. Es hilft, zufällige Schwankungen von verdächtigen Abweichungen zu unterscheiden. Im Gegensatz zu herkömmlichen Methoden ist DADA flexibel und passt sich an unterschiedliche Daten an. Anstelle einer festen Komprimierungsstufe werden mehrere Optionen verwendet und die jeweils am besten geeignete ausgewählt.
Battle Royale Optimizer (BRO) Battle Royale Optimizer (BRO)
Der Artikel untersucht den Algorithmus Battle Royale Optimizer – eine Metaheuristik, bei der Lösungen mit ihren nächsten Nachbarn konkurrieren, „Schaden“ anhäufen, ersetzt werden, wenn ein Schwellenwert überschritten wird, und den Suchraum um die aktuell beste Lösung herum regelmäßig verkleinern. Es werden sowohl Pseudocode als auch eine MQL5-Implementierung der Klasse C_AO_BRO vorgestellt, einschließlich Nachbarschaftssuche, Bewegung in Richtung der besten Lösung und eines adaptiven Delta-Intervalls. Die Testergebnisse für die Funktionen „Hilly“, „Forest“ und „Megacity“ zeigen die Stärken und Grenzen des Ansatzes auf. Der Leser erhält eine gebrauchsfertige Grundlage für Experimente und die Einstellung wichtiger Parameter wie popSize und maxDamage.
Eine alternative Log-datei mit der Verwendung der HTML und CSS Eine alternative Log-datei mit der Verwendung der HTML und CSS
In diesem Artikel werden wir eine sehr einfache, aber leistungsfähige Bibliothek zur Erstellung der HTML-Dateien schreiben, dabei lernen wir auch, wie man eine ihre Darstellung einstellen kann (nach seinem Geschmack) und sehen wir, wie man es leicht in seinem Expert Advisor oder Skript hinzufügen oder verwenden kann.
Pair-Trading: Algorithmischer Handel mit automatischer Optimierung auf Basis von Z-Score-Differenzen Pair-Trading: Algorithmischer Handel mit automatischer Optimierung auf Basis von Z-Score-Differenzen
In diesem Artikel werden wir untersuchen, was Pair-Trading ist und wie der Korrelationshandel funktioniert. Wir werden auch einen EA für die Automatisierung des Pair-Tradings erstellen und die Fähigkeit hinzufügen, diesen Handelsalgorithmus automatisch auf der Grundlage historischer Daten zu optimieren. Darüber hinaus werden wir im Rahmen des Projekts lernen, wie man mithilfe des Z-Scores die Abweichung zwischen zwei Paaren berechnet.