English Русский 中文 Español 日本語 Português
Verbesserung der Codequalität mit Hilfe eines Komponententests

Verbesserung der Codequalität mit Hilfe eines Komponententests

MetaTrader 4Beispiele | 4 Mai 2016, 14:51
1 109 0
Андрей
Андрей

Einleitung

Hinsichtlich Programmieren in MQL4 habe ich eine umfangreiche Erfahrung mit einigen fertigen MQL4 Programmen bzw. habe ich auch Dutzende selbst kreiert. Als Ergebnis kam ich zum Schluss, dass MQL4 ein sehr günstiges Umfeld für die Erstellung minderwertiger Programme ist. Die Gründe dafür sind nachfolgend aufgeführt:

  1. MetaTrader 4 hat keinen integrierten Debugger. Die Suche nach Fehlern kann manchmal ein ziemlich lästiger Prozess sein.
  2. MQL4 hat keine Einrichtung zum Handhaben von Ausnahmen, wie es sie bei C++ oder Java gibt.
  3. MQL4 Programme werden oft in Eile kreiert, wobei die Idee im Vordergrund steht und die Codequalität weniger zählt.

All dies führt zu der niedrigen Codequalität und diese Tatsache führt wiederum zu den folgenen Problemen:

  1. Fehler beim Arbeiten mit Expert Advisors, Fehler beim Arbeiten mit Algorithmen (besonders kritisch bei Echtgeld-Konten).
  2. Langsame Ausführung. Sehr langsame Optimierung.
  3. Schlechte Verarbeitung von Fehlerfällen. Ein Expert Advisor kann sich als nicht einsetzbar erweisen.

Ich möchte erwähnen, dass alles, das zuvor gesagt wurde, langjährig erfahrenen MQL4 Programmierern keine Sorgen bereitet. Geschickte Programmierer finden Wege, um einen qualitativ hochwertigen Code zu erstellen.

Da mein Hauptberuf mit dem Testen von Software-Qualität verbunden ist, war ich an allem interessiert, das mit dem Testen und Debuggen von MQL4 Programmen zu tun hat. Jedoch war die Anzahl der Artikel, die sich mit diesem Problem auseinandersetzen, sehr gering. Daher möchte ich hier eine der Möglichkeiten beschreiben, um die Qualität der Programme zu verbessern. Falls sich dieses Thema als interessant erweist, können weitere Probleme in den nächsten Artikeln berücksichtigt werden.



Etwas Theorie bezüglich Qualität

Wenn wir ein wenig googeln, können wir herausfinden, dass:

Qualität ist ein Komplex von Produktionseigenschaften und Merkmalen, die dieser Produktion die Möglichkeit geben, bedingte und vorausgesetzte Bedürfnisse zu erfüllen.

Was die Software betrifft, so können wir die Qualität des Programms als gut ansehen, wenn es den Bedürfnissen eines Kunden gerecht wird und die auferlegten Funktionen korrekt erfüllt.

Zwei Arten von Aktivitäten sind in der Regel erforderlich, um ein Programm von guter Qualität zu erschaffen:

  • Qualitätssicherung - Maßnahmen, die getroffen werden, um die Bildung von Defekten zu verhindern.
  • Qualitätskontrolle - Qualitätskontrolle eines fertigen Programms, die sich auf die Erkennung von Defekten konzentriert, für den Fall, dass die Qualitätssicherung nicht hilft. Es ist wichtig zu verstehen, dass ein Codefehler kaum beseitigt werden kann, wenn er nicht erkannt wird. Und natürlich ist es besonders schlimm, wenn ein Defekt vom Kunden entdeckt wird...

Qualitätssicherung ist eine komplizierte Angelegenheit. Es geht dabei um viele Aufgaben, angefangen beim Schaffen eines komfortablen Arbeitsplatzes für den Programmierer, bis hin zur Implementierung von komplizierten Geschäftsprozessen. Wir werden uns noch nicht mit diesem Problem auseinandersetzen. Lassen Sie uns über die Qualitätskontrolle sprechen.

Je mehr Aufmerksamkeit wir auf die Qualitätskontrolle legen, desto größer ist die Chance, dass unser Programm wie am Schnürchen laufen wird. Theoretisch muss die Qualitätskontrolle (oder in anderen Worten das Testen) bei jeder Entwicklungsstufe durchgeführt werden:

  1. Testen der technischen Spezifikation - es ist unmöglich, ein normal arbeitendes Programm basierend auf einer falschen technischen Spezifikation zu entwickeln.
  2. Bewerten des Quellcodes. Die Suche nach Fehlern, ineffektiven Codes, Regelwidrigkeiten beim Code, offensichtlichen Fehlern.
  3. Testen der verschiedenen Funktionen des Programms im Automatikmodus (Komponententest).
  4. Testen des gesamten fertigen Programms im manuellen Modus. Ein Mensch (Tester) prüft, ob das Programm korrekt arbeitet.
  5. Testen des Programms im Automatikmodus (Automatisiertes Testen). Das ist, wenn die Roboter selbst die Qualität des Programms testen. Es klingt wie eine Utopie, aber manchmal funktioniert es.
  6. Testen des Programms durch einen Kunden.

usw. Es gibt eine ganze Reihe von Testarten...

Und der Komponententest ist einer der interessantesten.

Etwas Theorie bezüglich dem Komponententest

Google gibt uns die folgende Definition für das Wort "Komponententest". Komponententest - ist eine Methode, bei der ein Programmierer verschiedene Komponenten (Blöcke) des Qellcodes auf ihre Verwendbarkeit im Rest des Programms überprüft. Eine Komponente ist der kleinste Teil eines Programms, der für das Testen geeignet ist. Bei Progammiersprachen (einschließlich MQL4) kann eine bestimmte Funktion als eine Komponente betrachtet werden.

In den meisten Fällen wird der Komponententest automatisch durchgeführt. Mit anderen Worten wird ein Programm geschaffen, das eine geprüfte Funktion mit verschiedenen Parametern aufruft, und dieses Programm erstellt dann einen Bericht, der angibt, ob die Funktion den Wert TRUE zurückmeldet oder nicht.

Komponententests können aus folgenden Gründen sehr nützlich sein:

  1. Falls ein Fehler entdeckt wird, können Sie dessen Wurzeln leicht finden, da nur eine Funktion getestet wird. Falls ein Fehler in der gesamten Anwendung entdeckt wird, müssen Sie etwas mehr Zeit investieren, um die Funktion zu finden, die dieses Problem verursacht.
  2. Es ist recht einfach zu überprüfen, ob ein Defekt behoben wurde oder nicht. Führen Sie den automatischen Komponententest einfach noch einmal aus. Es besteht keine Notwendigeit, die gesamte Anwendung neu zu starten. Zum Beispiel können in einigen seltenen Fällen einige Fehler aufscheinen, die kaum rekonstruiert werden können. Komponententests beseitigen dieses Problem.
  3. Sie können den Funktionscode optimieren, ohne sich Sorgen machen zu müssen, dass etwas schief geht. Der Komponententest kann jederzeit anzeigen, ob eine Funktion weiterhin normal arbeitet oder nicht.
  4. Sie können aber auch Probleme erkennen, die sich nicht sofort manifestieren, sondern erst beim Kunden erscheinen und viele Stunden für das Suchen und Debuggen erfordern.
  5. Der moderne testgesteuerte Ansatz kann verwendet werden, wenn zuerst der Komponententest erstellt und danach die Funktion entwickelt wird. Die Funktion wird so lange entwickelt, bis der Komponententest bestanden wird. Ich habe diesen Ansatz zum ersten Mal bei einer der C++ Anwendungen versucht und es hat sich als gut herausgestellt. Ich fühlte mich gut, denn ich war am Ende der Programmierung, hinsichtlich der Nutzbarkeit der Funktionen, voller Zuversicht, und auch deren Nutzung im Programm verlief einwandfrei.

Sehen wir uns an, wie es aussieht. Nehmen wir an, dass wir die Funktion zur Radizierung erstellt haben:
y=sqrt(x)

Daher werden wir eine andere Funktion für unseren Test kreieren, die nach folgendem Algorithmus arbeitet:

  • überprüfe, dass sqrt(-1) == error
  • überprüfe, dass sqrt(0) == 0
  • überprüfe, dass sqrt(0.01) == 0.1
  • überprüfe, dass sqrt(1) == 1
  • überprüfe, dass sqrt(4) == 2
  • überprüfe, dass sqrt(7) == 2.6....


Wir können eine Testfunktion kreieren, bevor wir die Hauptfunktion erstellen. Wir sollten daher die Anforderungen bestimmen, die die kreierte Funktion erfüllen muss. Das ist unsere Nutzung des testgesteuerten Ansatzes. Wir sollten nur dann in der Lage sein, die Funktion in unserem Hauptprogramm nutzen zu können, wenn unser Komponententest ein einwandfreies Arbeiten anzeigt.

Aber eine Frage bleibt noch immer offen: wie sollten wir eine Reihe von Prüfparametern für eine getestete Funktion auswählen? Natürlich ist es notwendig, alle möglichen Werte zu verwenden, aber in fast allen Fällen ist es unmöglich oder zu arbeitsintensiv. Ein brandneuer Artikel kann im Abschnitt über die Testwerte gefunden werden. Hier werde ich versuchen, einige allgemeine Tipps zu geben:

  1. Es ist notwendig, nicht nur korrekte Daten zu verwenden, sondern auch die Daten, die zu Fehlern führen, da wir nicht nur überprüfen müssen, ob die Funktion die auferlegten Pflichten erfüllt, sondern auch, wie gut sie bei der Verarbeitung von Fehlern ist.
  2. Wir müssen Grenzwerte verwenden. Wenn zum Beispiel der Wertebereich von 0 bis 100 ist, dann sollten sowohl die Werte 0 als auch 100 verwendet werden. Wenn die Eingabedaten aus Zeilen bestehen, dann sollte eine Leerzeile, als auch eine Zeile mit der maximalen Länge versucht werden.
  3. Die Werte, die über die zulässigen Markierungen gehen, sollten verwendet werden. Wenn wir uns das Beispiel aus dem vorherigen Punkt anschauen, sehen wir, dass die Werte 101 und -1 verwendet werden sollten. Für die Zeile sollte der Wert max+1 verwendet werden.
  4. Wir sollten versuchen, die Menge aller möglichen Werte, für Teilmengen von äquivalenten Werten (Äquivalenzklassen) aufzuteilen, bei denen die Art und Weise, wie sich die Funktion verhält, ähnlich ist. Für jede Klasse sollte ein Wert ausgewählt werden. Es macht zum Beispiel keinen Sinn, sowohl sqrt(4) und sqrt(9) zu überprüfen. Es ist viel interessanter, sqrt(4) und sqrt(5) zu überprüfen, da im letzteren Fall, die Funktion einen irrationalen Wert zurückbringen wird, während es im ersten Fall ein integraler sein wird.
  5. Für den Fall, dass die Funktion Verzweigungen hat (if, switch), sollten wir dafür sorgen, dass jede von ihnen vom Komponententest verarbeitet wird.

Ich werde versuchen, dies im nächsten Kapitel mit Hilfe eines bestimmten Beispiels zu zeigen.



Einige Praktiken in Bezug auf die Erstellung des Komponententests

Lassen Sie uns ein Trainingsziel festlegen! Nehmen wir an, unsere Aufgabe ist es, die Bibliothek zu entwickeln, welche die Aufgabe hat, zwei Reihen mit gleichen Eingaben zu akzeptieren. Die Funktion löscht aus der ersten Reihe jene Elemente, die in der zweiten Reihe fehlen. Als Ergebnis ist die erste Reihe eine Teilmenge der zweiten.

Lassen Sie uns den Prototyp für unsere Funktion bestimmen:

void CreateSubset(int & a1[], int a2[]);

Wir verden versuchen, den testgesteuerten Ansatz für die Funktionsentwicklung zu nutzen. Lassen Sie uns einen Satz von Testdaten bestimmen. Wir sollten mehrere Eingabedaten und Äquivalenzklassen verwenden, um dies zu erreichen:

  1. Beide Reihen sind leer.
  2. A1 ist leer, A2 enthält die Elemente.
  3. A1 enthält die Inhalte, A2 ist leer.
  4. Beide enthalten einen ähnlichen Satz von Elementen und haben eine ähnliche Größe.
  5. A1 enthält die Elemente, die nicht in A2 enthalten sind.
  6. Ein Teil der Elemente in A1 ist nicht in A2 enthalten, ein Teil von A2 ist in A1 enthalten (beide Mengen haben einen Schnittmenge).
  7. Alle A1 Elemente sind in A2 vorhanden, aber die Größe von A2 ist größer.
  8. Ein kleiner Teil der A1 Elemente ist in A2 vorhanden. Außerdem sind die Elemente über eine Reihe verteilt.
  9. Ein kleiner Teil der A1 Elemente ist in A2 vorhanden. Außerdem sind die Elemente am Anfang der Reihe konzentriert.
  10. Ein kleiner Teil der A1 Elemente ist in A2 vorhanden. Außerdem sind die Elemente am Ende der Reihe konzentriert.

Sollte unsere Funktion in allen 10 Fällen funktionieren, können wir absolut sicher sein, dass die Experts, die diese Funktion nutzen werden, nicht durch ihrer Unvollkommenheit leiden werden. Wir sollten jedoch verstehen, dass es unmöglich ist, etwas zu 100% zu testen und dass einige versteckte Mängel immer übrigbleiben können.

Zur Vereinfachung habe ich eine kleine MQL4 Komponenten-Bibliothek erstellt. Ich habe jene Funktionen angeführt, die für Komponententests erforderlich sind:

//-------------------------------------------------------------------+

//Current test conditions are kept by the global variables
//-------------------------------------------------------------------+
int tests_passed;    //Number of successful tests
int tests_failed;    //Number of unsuccessful tests
int tests_total;     //Total number of tests

string test_name;    //Test name

//-------------------------------------------------------------------+
//The function initializes test environment for one test
//-------------------------------------------------------------------+
void UnitTestStart(string TestName)
{

   test_name = TestName;
   tests_passed = 0;
   tests_failed = 0;
   tests_total = 0;
   Print("*--------------------------------------------------*");

   Print("Starting unit test execution ", test_name);
}

//-------------------------------------------------------------------+
//the function is called at the end of the test. Brings back true if all the tests
//are successful. Otherwise - False.
//-------------------------------------------------------------------+
bool UnitTestEnd()
{
   if (tests_failed == 0)

   {
      Print("HURRAY!!! ", test_name, " PASSED. ", tests_passed, " tests are successful.");
   }
   else
   {

      Print(":((( ", test_name, " FAILED. ", tests_passed,"/",tests_total, " tests are successful.");   
   }
   Print("*--------------------------------------------------*");
}


//-------------------------------------------------------------------+
//The function executes the test for two arrays of int type
//Brings back true, if the arrays are equal
//-------------------------------------------------------------------+
bool TestIntArray(int actual[], int expected[]){

   tests_total++;
   //Comparing arrays' sizes
   if (ArraySize(actual) != ArraySize(expected))
   {
      Print("Test #", tests_total," ERROR. Array size ", ArraySize(actual), " instead of ", ArraySize(expected));

      tests_failed++;
      return(false);      
   }
   //Then comparing element by element
   for (int i=0; i<ArraySize(actual);i++)

   {
      if (actual[i]!=expected[i]){
         Print("Test #", tests_total," ERROR. Element value #",i,"=", actual, " instead of ", expected);
         tests_failed++;

         return(false);
      }
   }
   //If all the elements are equal, the test is passed
   Print("Test #", tests_total," OK: Passed!");  

   tests_passed++;
   return(true);
}
Lassen Sie uns das "mytests" Testskript mit einem leeren Körper unserer Funktion erstellen. Erstellen Sie die Testfunktion darin und beschreiben Sie alle Komponententests darin.
bool Test()
{
   UnitTestStart("CreateSubset function testing");
   Print("1. Both arrays are empty.");

   int a1_1[], a1_2[];
   int result_1[]; //Waiting for an empty array as a result of the function execution
   CreateSubset(a1_1, a1_2);
   TestIntArray(a1_1, result_1);
   
   Print("2. A1 is empty, A2 contains the elements");

   int a2_1[], a2_2[] = {1,2,3};
   int result_2[]; //Waiting for an empty array as a result of the function execution
   CreateSubset(a2_1, a2_2);

   TestIntArray(a2_1, result_2);

   Print("3. A1 contains the elements, A2 is empty");
   int a3_1[] = {1,2,3}, a3_2[];

   int result_3[]; //Waiting for an empty array as a result of the function execution
   CreateSubset(a3_1, a3_2);
   TestIntArray(a3_1, result_3);

   Print("4. Both contain similar set of the elements and have similar size");
   int a4_1[] = {1,2,3}, a4_2[] = {1,2,3};

   int result_4[] = {1,2,3}; //Waiting for an unchanged array as a result of the function execution
   CreateSubset(a4_1, a4_2);
   TestIntArray(a4_1, result_4);

   Print("5. A1 contains the elements that are not present in A2");

   int a5_1[] = {4,5,6}, a5_2[] = {1,2,3};
   int result_5[]; //Waiting for an empty array as a result of the function execution

   CreateSubset(a5_1, a5_2);
   TestIntArray(a5_1, result_5);
   
   Print("6. Part of the elements in A1 are present in A2, A2 part is contained in A1 (both multitudes have an intersection)");
   int a6_1[] = {1,2,3,4,5,6,7,8,9,10}, a6_2[] = {3,5,7,9,11,13,15};

   int result_6[] = {3,5,7,9}; //Waiting for arrays intersection as a result of the function execution
   CreateSubset(a6_1, a6_2);
   TestIntArray(a6_1, result_6);

   
   Print("7. All A1 elements are present in A2, but A2 size is bigger");
   int a7_1[] = {3,4,5}, a7_2[] = {1,2,3,4,5,6,7,8,9,10};

   int result_7[] = {3,4,5}; //Waiting for arrays intersection as a result of the function execution
   CreateSubset(a7_1, a7_2);
   TestIntArray(a7_1, result_7);
   

   Print("8. A small part of A1 elements is present in A2. Besides, the elements are scattered all over an array.");
   int a8_1[] = {1,2,3,4,5,6,7,8,9,10}, a8_2[] = {2,5,9};

   int result_8[] = {2,5,9}; //Waiting for arrays intersection as a result of the function execution
   CreateSubset(a8_1, a8_2);
   TestIntArray(a8_1, result_8);
   

   Print("9. A small part of A1 elements is present in A2. Besides, the elements are concentrated at an array leader.");
   int a9_1[] = {1,2,3,4,5,6,7,8,9,10}, a9_2[] = {1,2,3};

   int result_9[] = {1,2,3}; //Waiting for arrays intersection as a result of the function execution
   CreateSubset(a9_1, a9_2);
   TestIntArray(a9_1, result_9);

   Print("10. A small part of A1 elements is present in A2. Besides, the elements are concentrated at an array's end.");

   int a10_1[] = {1,2,3,4,5,6,7,8,9,10}, a10_2[] = {8,9,10};

   int result_10[] = {8,9,10}; //Waiting for arrays intersection as a result of the function execution
   CreateSubset(a10_1, a10_2);
   TestIntArray(a10_1, result_10);
   

   return (UnitTestEnd());
}

Um den Komponententest auszuführen, müssen wir die Testfunktion bei der Hauptfunktion aufrufen und das Skript ausführen.

Führen wir nun unseren Test aus.

Wie wir sehen können, sind die Ergebnisse enttäuschend. Das ist nicht überraschend, da die Funktion überhaupt nicht bereit ist. Aber trotzdem! 4 von 10 Tests wurden erfolgreich bestanden. Das bedeutet, dass wir theoretisch sogar die Tatsache übersehen hätten können, dass die Funktion leer ist, da sie in einigen Fällen normal agiert hätte.

Mit anderen Worten, kann es eine solche Teilmenge von Eingabedaten geben, für die eine inkorrekte Funktion korrekt arbeitet. Wenn ein Programmierer nur solche Testdaten verwendet hätte, die zu einem Erfolg führen, hätte die leere Funktion leicht zu einem Kunden gelangen können.

Lassen Sie uns nun die Funktion CreateSubset erstellen. Wir werden dabei jetzt nicht über die Effizienz und Schönheit dieser Funktion sprechen.

void CreateSubset(int & a1[], int a2[]){
   int i=0;

   while(i<ArraySize(a1)){
      bool b_exist = false;
      for (int j=0; j<ArraySize(a2);j++){

         if (a1[i] == a2[j]) b_exist = true;
      }
      if (!b_exist){
         for (j=i; j<ArraySize(a1)-1;j++){
            a1[j] = a1[j+1];   

         }
         ArrayResize(a1, ArraySize(a1)-1);
      }else{
         i++;
      }
   }
}
Lassen Sie uns den Test erneut durchführen:

Die Funktion kann von überall ausgeführt werden. Sie kann innerhalb eines Experts festgestellt und während der Initialisierung ausgeführt werden. Falls ein separates Modul verarbeitet wird, können eine oder mehrere Testfunktionen darin bestimmt und von einem Skript aufgerufen werden. Hier könnten wir ein wenig fantasieren.

Natürlich wäre die ideale Variante die Möglichkeit zu haben, einen Komponententest direkt nach der Kompilierung der Bibliothek laufen zu lassen, aber ich verstehe noch immer nicht, ob dies in MQL4 getan werden kann. Höchstwahrscheinlich nicht. Wenn Sie wissen, wie dies getan werden kann, dann schreiben Sie mir bitte.

Jedes Mal, nachdem wir den Test ausgeführt haben, können wir erleichtert aufatmen und sicher sein, dss alles so funktioniert, wie es soll.

Ein paar Kommentare

  1. Es scheint, als ob das Schreiben von Tests nur Zeit verbraucht. Aber ich versichere Ihnen, dass sich die Zeit für die Entwicklung von Komponententests mehr als nur bezahlt macht.
  2. Natürlich zahlt es sich nicht aus, für alle Funktionen Komponententests zu entwickeln. Es sollte ein Gleichgewicht zwischen der Wichtigkeit, der Ausfallwahrscheinlichkeit und der Menge eines Codes innerhalb der Funktion geben. Zum Beispiel gibt es keine Notwendigkeit, einen Test für die einfachste Funktion zu schreiben, die nur aus ein paar Zeilen besteht.
  3. Innerhalb von Komponententests können Sie alles machen, was Sie wollen: Orders öffnen/schließen, Indikatoren, Charts, Objekte verwenden, usw. Ihren Aktionen sind hier keine Grenzen gesetzt.

Und schlussendlich die letzte Sache

Ich hoffe, dass dieses Material nützlich für Sie sein wird. Ich werde gerne alle Ihre Fragen beantworten. Ich bin auch offen für alle Vorschläge, die diesen Artikel verbessern und/oder beim Schreiben neuer Artikel helfen können.

Ich wünsche Ihnen allen viel Glück und einwandfreie Codes!

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

Beigefügte Dateien |
mql4unit.mq4 (5.31 KB)
testscript.mq4 (4.34 KB)
Die Verwendung von WinInet in MQL5   Teil 2:  POST-Anfragen und -Dateien Die Verwendung von WinInet in MQL5 Teil 2: POST-Anfragen und -Dateien
In diesem Artikel werden wir uns weiterhin mit den Grundlagen von internetbasierten HTTP-Anfragen und dem Informationsaustausch mit Servern befassen. Es werden neue Funktionen der CMqINet-Klasse, Methoden der Informationsübertragung mit Formularen, das Senden von Dateien mit POST-Anfragen sowie Autorisierungen auf Webseiten mit Ihrem Login unter Verwendung von Cookies behandelt.
Wettbewerb an Expert Advisors innerhalb eines Expert Advisor Wettbewerb an Expert Advisors innerhalb eines Expert Advisor
Mit dem virtuellen Handel können Sie einen anpassungsfähigen Expert Advisor kreieren, der das Einsetzen von virtuellen Trades im realen Markt automatisch ein- und ausschalten wird. Kombinieren Sie mehrere Strategien in einem einzigen Expert Advisor! Ihr Multi-System Expert Advisor wird automatisch eine Handelsstrategie wählen, mit der Sie, basierend auf der Rentabilität der virtuellen Trades, am besten im realen Markt handeln können. Diese Herangehensweise ermöglicht eine Reduzierung der Inanspruchnahme und eine Erhöhung der Rentabilität Ihrer Arbeit auf dem Markt. Experimentieren Sie und teilen Sie Ihre Ergebnisse mit anderen! Ich denke, viele Leute werden sich dafür interessieren, Ihr Portfolio von Strategien kennenzulernen.
Überweisungen und Zahlungsmethoden Überweisungen und Zahlungsmethoden
Die MQL5.community Services bieten sowohl Händlern als auch den Entwicklern von Anwendungen für das MetaTrader-Terminal großartige Möglichkeiten. In diesem Artikel erklären wir, wie Zahlungen für MQL5-Dienstleistungen durchgeführt werden, wie verdientes Geld abgehoben werden kann und wie die Betriebssicherheit gewährleistet wird.
Die Magie der Filtration Die Magie der Filtration
Die meisten Entwickler automatischer Handelssysteme verwenden irgendeine Form von Filtration für Handelssignale. In diesem Artikel erkunden wir die Erstellung und Implementierung von Bandpass- und diskreten Filtern für Expert Advisors, um die Eigenschaften des automatisierten Handelssystems zu verbessern.