English Русский 中文 Español 日本語 Português
preview
Experimente mit neuronalen Netzen (Teil 2): Intelligente Optimierung neuronaler Netze

Experimente mit neuronalen Netzen (Teil 2): Intelligente Optimierung neuronaler Netze

MetaTrader 5Tester | 10 Oktober 2022, 16:37
255 0
Roman Poshtar
Roman Poshtar

Einführung

Im vorherigen Artikel Experimente mit neuronalen Netzen (Teil 1): Die Geometrie neu betrachten habe ich meine Beobachtungen und Experimente mit neuronalen Netzen vorgestellt. Ich habe mich mit der Frage befasst, welche Art von Daten an ein neuronales Netz weitergegeben werden sollten, und ein einfaches Beispiel mit einem Perceptron demonstriert, um ein profitables Handelssystem zu erhalten. Ich war in einigen Punkten erfolgreich, stieß aber auch auf einige Schwierigkeiten, auf die hier eingegangen werden soll. Außerdem möchte ich auch zu komplexeren neuronalen Netzen übergehen. Um dies zu erreichen, werde ich die Bibliothek aus dem Artikel Programmierung eines tiefen neuronalen Netzes von Grund auf mit der Sprache MQL verwenden. Der Autor hat die Funktionsweise sehr detailliert beschrieben, sodass ich mich nur auf die wichtigsten Aspekte konzentrieren werde. Das Hauptziel dieses Artikels ist die Entwicklung eines vollwertigen Handelsroboters, der auf einem neuronalen Netzwerk basiert und MetaTrader 5 ohne Software von Drittanbietern nutzt.


Grundlagen und Beispiele

Der Autor der obigen Bibliothek verwendet ein tiefes neuronales Netz, aber ich schlage vor, klein anzufangen und ein Netz mit der 4-4-3-Struktur aufzubauen. Insgesamt benötigen wir (4 * 4) + 4 + (4 * 3) + 3 = 35 Gewichte und Biaswerte.

Sie können die geänderte Bibliothek unten herunterladen. Ich habe absichtlich alle Änderungen im Code kommentiert, damit Sie sehen können, wie man nutzerdefinierte neuronale Netze erstellt. 

Gewicht und Biaswerte:

input double w0=1.0;
input double w1=1.0;
input double w2=1.0;
input double w3=1.0;
input double w4=1.0;
input double w5=1.0;
input double w6=1.0;
input double w7=1.0;
input double w8=1.0;
input double w9=1.0;
input double w10=1.0;
input double w11=1.0;
input double w12=1.0;
input double w13=1.0;
input double w14=1.0;
input double w15=1.0;

input double b0=1.0;
input double b1=1.0;
input double b2=1.0;
input double b3=1.0;

input double x0=1.0;
input double x1=1.0;
input double x2=1.0;
input double x3=1.0;
input double x4=1.0;
input double x5=1.0;
input double x6=1.0;
input double x7=1.0;
input double x8=1.0;
input double x9=1.0;
input double x10=1.0;
input double x11=1.0;
input double x12=1.0;
input double x13=1.0;
input double x14=1.0;
input double x15=1.0;

input double s0=1.0;
input double s1=1.0;
input double s2=1.0;

W und X sind Gewichte, B und S sind Biasparameter.

Binden wir die Bibliothek für neuronale Netze ein:

#include <DeepNeuralNetwork2.mqh> 

int numInput=4;
int numHiddenA = 4;
int numOutput=3;

DeepNeuralNetwork dnn(numInput,numHiddenA,numOutput);

Als Nächstes werden wir zwei Beispiele aus meinem vorherigen Artikel betrachten, nämlich eine Form und ein Muster mit Steigungswinkel. Schauen wir uns auch die Ergebnisse der Strategie des Bibliotheksautors an. Prüfen wir schließlich all dies mit verschiedenen neuronalen Netzen - 4-4-3 und 4-4-4-3.  Mit anderen Worten: Wir entwickeln sechs EAs auf einmal.

Übergeben wir den Schmetterling (Umschlag). Abbildung des EAs: 

r1


int error=CandlePatterns(ind_In1[1], ind_In1[10], ind_In2[1], ind_In2[10], _xValues);// Call the function

int CandlePatterns(double v1,double v2,double v3,double v4,double &xInputs[])// Function
  {

   xInputs[0] = (v1-v2)/Point();
   xInputs[1] = (v3-v4)/Point();
   xInputs[2] = (v1-v4)/Point();
   xInputs[3] = (v3-v2)/Point();
   
   return(1);

  }

Übergabe des Musters mit den Steigungswinkel (vier MA 1 und MA 24 Indikatorneigungswinkel). Angle EA:

r2


int error=CandlePatterns(ind_In1[1], ind_In1[5], ind_In1[10], ind_In2[1], ind_In2[5], ind_In2[10], _xValues);// Call the function

int CandlePatterns(double v1,double v2,double v3,double v4,double v5,double v6,double &xInputs[])// Function
  {

   xInputs[0] = (((v1-v2)/Point())/5);
   xInputs[1] = (((v1-v3)/Point())/10);
   xInputs[2] = (((v4-v5)/Point())/5);
   xInputs[3] = (((v4-v6)/Point())/50);
   
   return(1);

  }

Nachdem wir den Strategietester verwendet haben, stellen wir die Optimierungswerte für die Gewichte und Bias von -1 bis 1 mit einem Schritt von 0,1 ein. Wir erhalten 3,68597592780611e+51 Durchläufe. Fahren wir mit dem nächsten Abschnitt fort.

r3


Lösung der Optimierungsprobleme

Wenn wir den EA wie oben beschrieben verwenden, führt der Strategietester etwas mehr als 10.000 Durchläufe im Modus (langsamer vollständiger Algorithmus) durch, was in unserem Fall zu wenig ist, um das neuronale Netz zu optimieren. Ich denke, der Modus (Schneller genetischer Algorithmus) ist hier nicht von Nutzen.

Der Grundgedanke ist, nur eine Variable für die Durchgänge zu verwenden, z. B. eine Art Zähler. Die übrigen Parameter der Gewichte und Bias sind innerhalb des EA einzustellen. Für diese Zwecke habe ich beschlossen, einen Zufallszahlengenerator zu verwenden. Außerdem ist es notwendig, sich zu merken, welche Optionen wir bei der Optimierung bereits verwendet haben.

Die Funktion des Zufallszahlengenerators:

double RNDfromCI(double minp, double maxp) 
{ 
  if(minp == maxp) 
    return (minp); 
  double Minp, Maxp; 
  if(minp > maxp) 
  {
    Minp = maxp; 
    Maxp = minp;
  }
  else 
  {
    Minp = minp; 
    Maxp = maxp;
  }
  return (NormalizeDouble(double(Minp + ((Maxp - Minp) * (double)MathRand() / 32767.0)),1));
}

Um sich die Parameter des Durchlaufs zu merken, wurden mehrere Möglichkeiten in Betracht gezogen. Insbesondere das Array innerhalb des EA ist nicht geeignet, da es bei jeder Initialisierung des EA auf Null zurückgesetzt wird. Auch die globalen Variablen des Terminals sind aufgrund der großen Datenmenge nicht geeignet. Es ist notwendig, die Ergebnisse der abgeschlossenen Durchgänge über den Optimierungsprozess hinaus mit der Möglichkeit, die Daten zu lesen, zu entnehmen. Ich habe mich für die Verwendung von CSV-Dateien entschieden.

Lassen Sie uns eine Variable zur Optimierung einführen:

input int Passages = 10000;

Optimieren wir den Parameter Passagen von 1 bis zum Maximum in Schritten von 1. Ermitteln wir versuchsweise die maximale Anzahl von Durchläufen im Modus mit einer Variablen. Sie beläuft sich auf 100.000.000.  Ich denke, das ist ausreichend.

r4

Ursprünglich gab es die Idee, den EA in zwei Teile aufzuteilen - einen für die Optimierung, den zweiten für den Handel. Aber ich denke, ein einzelner EA ist praktischer. Fügen wir einen Schalter für den Modus hinzu:

input bool Optimization = true;

Der wichtigste Optimierungscode befindet sich in der EA-Initialisierungsfunktion OnInit():

if (Optimization==true){
int r=0;
int q=0;

 while(q!=1 && !IsStopped())
 {

string str;
 while(r!=1 && !IsStopped())
 {
   sw0=DoubleToString(RNDfromCI(Min, Max),1);
   sw1=DoubleToString(RNDfromCI(Min, Max),1);
   sw2=DoubleToString(RNDfromCI(Min, Max),1);
   sw3=DoubleToString(RNDfromCI(Min, Max),1);
   sw4=DoubleToString(RNDfromCI(Min, Max),1);
   sw5=DoubleToString(RNDfromCI(Min, Max),1);
   sw6=DoubleToString(RNDfromCI(Min, Max),1);
   sw7=DoubleToString(RNDfromCI(Min, Max),1);
   sw8=DoubleToString(RNDfromCI(Min, Max),1);
   sw9=DoubleToString(RNDfromCI(Min, Max),1);
   sw10=DoubleToString(RNDfromCI(Min, Max),1);
   sw11=DoubleToString(RNDfromCI(Min, Max),1);
   sw12=DoubleToString(RNDfromCI(Min, Max),1);
   sw13=DoubleToString(RNDfromCI(Min, Max),1);
   sw14=DoubleToString(RNDfromCI(Min, Max),1);
   sw15=DoubleToString(RNDfromCI(Min, Max),1);
   
   sb0=DoubleToString(RNDfromCI(Min, Max),1);
   sb1=DoubleToString(RNDfromCI(Min, Max),1);
   sb2=DoubleToString(RNDfromCI(Min, Max),1);
   sb3=DoubleToString(RNDfromCI(Min, Max),1);
   
   sx0=DoubleToString(RNDfromCI(Min, Max),1);
   sx1=DoubleToString(RNDfromCI(Min, Max),1);
   sx2=DoubleToString(RNDfromCI(Min, Max),1);
   sx3=DoubleToString(RNDfromCI(Min, Max),1);
   sx4=DoubleToString(RNDfromCI(Min, Max),1);
   sx5=DoubleToString(RNDfromCI(Min, Max),1);
   sx6=DoubleToString(RNDfromCI(Min, Max),1);
   sx7=DoubleToString(RNDfromCI(Min, Max),1);
   sx8=DoubleToString(RNDfromCI(Min, Max),1);
   sx9=DoubleToString(RNDfromCI(Min, Max),1);
   sx10=DoubleToString(RNDfromCI(Min, Max),1);
   sx11=DoubleToString(RNDfromCI(Min, Max),1);
   
   ss0=DoubleToString(RNDfromCI(Min, Max),1);
   ss1=DoubleToString(RNDfromCI(Min, Max),1);
   ss2=DoubleToString(RNDfromCI(Min, Max),1);
   
   if(StringFind(sw0,".", 0) == -1 ){sw0=sw0+".0";}
   if(StringFind(sw1,".", 0) == -1 ){sw1=sw1+".0";}
   if(StringFind(sw2,".", 0) == -1 ){sw2=sw2+".0";}
   if(StringFind(sw3,".", 0) == -1 ){sw3=sw3+".0";}
   if(StringFind(sw4,".", 0) == -1 ){sw4=sw4+".0";}
   if(StringFind(sw5,".", 0) == -1 ){sw5=sw5+".0";}
   if(StringFind(sw6,".", 0) == -1 ){sw6=sw6+".0";}
   if(StringFind(sw7,".", 0) == -1 ){sw7=sw7+".0";}
   if(StringFind(sw8,".", 0) == -1 ){sw8=sw8+".0";}
   if(StringFind(sw9,".", 0) == -1 ){sw9=sw9+".0";}
   if(StringFind(sw10,".", 0) == -1 ){sw10=sw10+".0";}
   if(StringFind(sw11,".", 0) == -1 ){sw11=sw11+".0";}
   if(StringFind(sw12,".", 0) == -1 ){sw12=sw12+".0";}
   if(StringFind(sw13,".", 0) == -1 ){sw13=sw13+".0";}
   if(StringFind(sw14,".", 0) == -1 ){sw14=sw14+".0";}
   if(StringFind(sw15,".", 0) == -1 ){sw15=sw15+".0";}

   if(StringFind(sb0,".", 0) == -1 ){sb0=sb0+".0";}
   if(StringFind(sb1,".", 0) == -1 ){sb1=sb1+".0";}
   if(StringFind(sb2,".", 0) == -1 ){sb2=sb2+".0";}
   if(StringFind(sb3,".", 0) == -1 ){sb3=sb3+".0";}
   
   if(StringFind(sx0,".", 0) == -1 ){sx0=sx0+".0";}
   if(StringFind(sx1,".", 0) == -1 ){sx1=sx1+".0";}
   if(StringFind(sx2,".", 0) == -1 ){sx2=sx2+".0";}
   if(StringFind(sx3,".", 0) == -1 ){sx3=sx3+".0";}
   if(StringFind(sx4,".", 0) == -1 ){sx4=sx4+".0";}
   if(StringFind(sx5,".", 0) == -1 ){sx5=sx5+".0";}
   if(StringFind(sx6,".", 0) == -1 ){sx6=sx6+".0";}
   if(StringFind(sx7,".", 0) == -1 ){sx7=sx7+".0";}
   if(StringFind(sx8,".", 0) == -1 ){sx8=sx8+".0";}
   if(StringFind(sx9,".", 0) == -1 ){sx9=sx9+".0";}
   if(StringFind(sx10,".", 0) == -1 ){sx10=sx10+".0";}
   if(StringFind(sx11,".", 0) == -1 ){sx11=sx11+".0";}
   
   if(StringFind(ss0,".", 0) == -1 ){ss0=ss0+".0";}
   if(StringFind(ss1,".", 0) == -1 ){ss1=ss1+".0";}
   if(StringFind(ss2,".", 0) == -1 ){ss2=ss2+".0";}
   
   str=sw0+","+sw1+","+sw2+","+sw3+","+sw4+","+sw5+","+sw6+","+sw7+","+sw8+","+sw9+","+sw10+","+sw11+","+sw12+","+sw13+","+sw14+","+sw15
   +","+sb0+","+sb1+","+sb2+","+sb3
   +","+sx0+","+sx1+","+sx2+","+sx3+","+sx4+","+sx5+","+sx6+","+sx7+","+sx8+","+sx9+","+sx10+","+sx11
   +","+ss0+","+ss1+","+ss2;
   if (VerifyPassagesInFile(str)==true)
   {
      ResetLastError();
      filehandle = FileOpen(OptimizationFileName,FILE_WRITE|FILE_READ|FILE_CSV|FILE_COMMON|FILE_ANSI, ";");
      if(filehandle!=INVALID_HANDLE)
       {
        Print("FileOpen OK");
        FileSeek(filehandle, 0, SEEK_END);
        FileWrite(filehandle,Passages,sw0,sw1,sw2,sw3,sw4,sw5,sw6,sw7,sw8,sw9,sw10,sw11,sw12,sw13,sw14,sw15,
        sb0,sb1,sb2,sb3,
        sx0,sx1,sx2,sx3,sx4,sx5,sx6,sx7,sx8,sx9,sx10,sx11,
        ss0,ss1,ss2);
        FileClose(filehandle); 
        
   weight[0]=StringToDouble(sw0);
   weight[1]=StringToDouble(sw1);
   weight[2]=StringToDouble(sw2);
   weight[3]=StringToDouble(sw3);
   weight[4]=StringToDouble(sw4);
   weight[5]=StringToDouble(sw5);
   weight[6]=StringToDouble(sw6);
   weight[7]=StringToDouble(sw7);
   weight[8]=StringToDouble(sw8);
   weight[9]=StringToDouble(sw9);
   weight[10]=StringToDouble(sw10);
   weight[11]=StringToDouble(sw11);
   weight[12]=StringToDouble(sw12);
   weight[13]=StringToDouble(sw13);
   weight[14]=StringToDouble(sw14);
   weight[15]=StringToDouble(sw15);
   
   weight[16]=StringToDouble(sb0);
   weight[17]=StringToDouble(sb1);
   weight[18]=StringToDouble(sb2);
   weight[19]=StringToDouble(sb3);
   
   weight[20]=StringToDouble(sx0);
   weight[21]=StringToDouble(sx1);
   weight[22]=StringToDouble(sx2);
   weight[23]=StringToDouble(sx3);
   weight[24]=StringToDouble(sx4);
   weight[25]=StringToDouble(sx5);
   weight[26]=StringToDouble(sx6);
   weight[27]=StringToDouble(sx7);
   weight[28]=StringToDouble(sx8);
   weight[29]=StringToDouble(sx9);
   weight[30]=StringToDouble(sx10);
   weight[31]=StringToDouble(sx11);
   
   weight[32]=StringToDouble(ss0);
   weight[33]=StringToDouble(ss1);
   weight[34]=StringToDouble(ss2);
        
        r=1;
        q=1;
       }
      else 
       {
       Print("FileOpen ERROR, error ",GetLastError());
       q=0;
       }
   }
 }
 
 }
}

Lassen Sie mich den Code erklären. Dem EA beizubringen, dass er warten muss, bis er an der Reihe ist, um eine Datei zu öffnen, erwies sich als eine spannende Aufgabe. Ich bin auf das Problem gestoßen, eine Datei gleichzeitig im Optimierungsmodus zu öffnen und dabei mehrere CPU-Kerne gleichzeitig zu verwenden. Dieses Problem wurde in der ersten ‚while‘-Schleife gelöst. Der EA beendet die Funktion OnInit() erst, wenn die Datei zum Schreiben geöffnet wird. Es stellte sich heraus, dass die EAs während der Optimierung nacheinander gestartet werden.

Während der Test auf dem ersten Kern läuft, kann der EA eine Datei zum Schreiben auf dem zweiten Kern öffnen. Weiterhin weisen wir allen Gewichten und Bias einen Zufallsparameter im Bereich von Min und Max zu. Wenn sich herausstellt, dass die Zahl rund ist, fügen Sie .0 hinzu. Alle Werte werden zu einer einzigen Zeichenkette ‚str‘ zusammengefasst. Überprüfen wir die Zeichenkette mit der Funktion VerifyPassagesInFile(str), um festzustellen, ob die gleiche Zeichenkette in der Datei vorhanden ist. Ist dies nicht der Fall, schreiben wir sie an das Ende der Datei und weisen dem Array weight[] die erhaltenen Zufallswerten der Gewichte und Bias zu

Der Code der Funktion zur Überprüfung der Parameter auf ihre Ähnlichkeit mit den vorhergehenden Parametern:

bool VerifyPassagesInFile(string st){
string str="";
string str1="";
string str2="";
string str3="";
string str4="";
string str5="";
string str6="";
string str7="";
string str8="";
string str9="";
string str10="";
string str11="";
string str12="";
string str13="";
string str14="";
string str15="";
string str16="";
string str17="";
string str18="";
string str19="";
string str20="";
string str21="";
string str22="";
string str23="";
string str24="";
string str25="";
string str26="";
string str27="";
string str28="";
string str29="";
string str30="";
string str31="";
string str32="";
string str33="";
string str34="";
string str35="";
string str36="";

if (FileIsExist(OptimizationFileName)==
true ){
   ResetLastError();
   filehandle = FileOpen(OptimizationFileName,FILE_WRITE|FILE_READ|FILE_CSV|FILE_COMMON|FILE_ANSI, ";");
   if(filehandle!=INVALID_HANDLE)
     {
      Print("FileCreate OK");
     }
   else Print("FileCreate ERROR, error ",GetLastError());
   FileClose(filehandle); 
}

   ResetLastError();
   filehandle = FileOpen(OptimizationFileName,FILE_WRITE|FILE_READ|FILE_CSV|FILE_COMMON|FILE_ANSI, ";");
   if(filehandle!=INVALID_HANDLE)
     {
      Print("FileOpen OK");
     }
   else Print("FileOpen ERROR, error ",GetLastError());
   
//--- read the data from the file
 while(!FileIsEnding(filehandle) && !IsStopped())
 {
  str1=FileReadString(filehandle);
  str2=FileReadString(filehandle);
  str3=FileReadString(filehandle);
  str4=FileReadString(filehandle);
  str5=FileReadString(filehandle);
  str6=FileReadString(filehandle);
  str7=FileReadString(filehandle);
  str8=FileReadString(filehandle);
  str9=FileReadString(filehandle);
  str10=FileReadString(filehandle);
  str11=FileReadString(filehandle);
  str12=FileReadString(filehandle);
  str13=FileReadString(filehandle);
  str14=FileReadString(filehandle);
  str15=FileReadString(filehandle);
  str16=FileReadString(filehandle);
  str17=FileReadString(filehandle);
  str18=FileReadString(filehandle);
  str19=FileReadString(filehandle);
  str20=FileReadString(filehandle);
  str21=FileReadString(filehandle);
  str22=FileReadString(filehandle);
  str23=FileReadString(filehandle);
  str24=FileReadString(filehandle);
  str25=FileReadString(filehandle);
  str26=FileReadString(filehandle);
  str27=FileReadString(filehandle);
  str28=FileReadString(filehandle);
  str29=FileReadString(filehandle);
  str30=FileReadString(filehandle);
  str31=FileReadString(filehandle);
  str32=FileReadString(filehandle);
  str33=FileReadString(filehandle);
  str34=FileReadString(filehandle);
  str35=FileReadString(filehandle);
  str36=FileReadString(filehandle);
    
    str=str2+","+str3+","+str4+","+str5+","+str6+","+str7+","+str8+","+str9+","+str10+","+str11
    +","+str12+","+str13+","+str14+","+str15+","+str16+","+str17+","+str18+","+str19+","+str20+","+str21
    +","+str22+","+str23+","+str24+","+str25+","+str26+","+str27+","+str28+","+str29+","+str30+","+str31+","+str32+","+str33+","+str34+","+str35+","+str36;
  if (str==st){FileClose(filehandle); return(false);}
 }

FileClose(filehandle); 
 
return(true); 
}

Hier prüfen wir zunächst, ob unsere Datei existiert: FileIsExist(OptimizationFileName). Wenn nicht, wird sie erstellt. Als Nächstes wird die Zeichenkette in der Schleife while(!FileIsEnding(filehandle) && !IsStopped()) in die Variablen str1- strN eingelesen. Fügen wir alles in der Variablen ‚str‘ zusammen. Wir vergleichen jede Zeichenkette „str“ mit der eingehenden Zeichenkette „st“ am Eingang der Funktion. Am Ende geben wir das Ergebnis zurück, ob es eine Übereinstimmung gibt oder nicht.

Daraus resultierende EA-Parameter:

"------------Open settings----------------";

Optimization - Moduswechsel, optimieren oder handeln;

Min - Mindestwert der Parameter Gewichte und Bias; 

Max - Höchstwert der Parameter Gewichte und Bias; 

OptimizationFileName - Dateiname für das Schreiben von Parametern während der Optimierung und das Lesen im Handelsmodus;

Passages - Wert des Durchlaufes. Der Optimierungsparameter von 1 bis maximal 100.000.000 in Schritten von 1;

LL - Die Softmax-Funktion liefert 3 Ergebnisse auf der Grundlage einer 100%igen Summe. 0,6 entspricht einem Wert von über 60 %;

"------------Lots settings----------------";

SetFixLotOrPercent - Auswahl der Losgröße oder des Kapitalprozentsatzes;

LotsOrPercent - Losgröße oder Prozentsatz je nach SetFixLotOrPercent;

"------------Other settings---------------";

MaxSpread - maximaler Spread für die Eröffnung eines Auftrags;

Slippage - Schlupf.

Magic - Magic-Number;

EAComment - Kommentare zu den Aufträgen;

Wie Sie vielleicht wissen, erstellt MetaTrader 5 standardmäßig Dateien in seiner Sandbox. 

Der Pfad zu den Dateien:

C:\Users\Ihr Name\AppDaten\Roaming\MetaQuotes\Terminal\Common\Files


Optimierung

Führen wir die Optimierung durch. Zeitraum: von 2018.07.12 bis 2021.07.12. EURUSD. H1, Nur Öffnungspreise. Anzahl an Testläufen 10,000.

Modus: (Komplexes Kriterium max). Angle EA 4-4-3

a1

Modus: (Komplexes Kriterium max). Angle EA 4-4-4-3

a2

Modus: (Komplexes Kriterium max). Figure EA 4-4-3

f1

Modus: (Komplexes Kriterium max). Figure EA 4-4-4-3

f2

Modus: (Komplexes Kriterium max). Original EA 4-4-3. Die Strategie des Autors der Bibliothek.

o1

Modus: (Komplexes Kriterium max). Original EA 4-4-4-3. Die Strategie des Autors der Bibliothek.

o2

Nach der Optimierung (z.B. 10.000 Durchläufe) können wir unsere Datei mit neuen Parametern füllen, indem wir eine neue Optimierung starten. Vergessen wir nicht, den Optimierungsbericht des Strategietesters mit den erforderlichen Passagen-Parametern vorher zu speichern. Wir müssen auch die Terminal-Historie löschen, sonst zeigt der Tester die Ergebnisse der bereits abgeschlossenen Optimierung an. Ich mache das mit einem Skript vom Typ .bat.

del C:\Users\Ihr Name\AppData\Roaming\MetaQuotes\Terminal\36A64B8C79A6163D85E6173B54096685\Tester\cache\*.* /q /f /s

for /d %%i in (C:\Users\Ihr Name\AppData\Roaming\MetaQuotes\Terminal\36A64B8C79A6163D85E6173B54096685\Tester\cache\*) do rd /s /q "%%i"


del C:\Users\Your Username\AppData\Roaming\MetaQuotes\Terminal\36A64B8C79A6163D85E6173B54096685\Tester\logs\*.* /q /f /s

for /d %%i in (C:\Benutzer\IhrIhr Name\AppData\Roaming\MetaQuotes\Terminal\36A64B8C79A6163D85E6173B54096685\Tester\logs\*) do rd /s /q "%%i"

Ersetzen Sie „Ihr Name“ und „36A64B8C79A6163D85E6173B54096685“ durch Ihre eigenen Angaben. Sie können sie mit einem normalen Texteditor öffnen. Das Bereinigungsskript ist unten beigefügt.


Verwendung der Optimierungsergebnisse

Um die Optimierungsergebnisse zu überprüfen, setzen wir den Schalter Optimierung auf ‚false‘ und stellen den gewünschten Durchlaufindex im Parameter Passagen ein. Dazu genügt ein Doppelklick auf das gewünschte Ergebnis.

Der Code zum Hochladen der Parameter für Gewichte und Bias für die Prüfung:

if (FileIsExist(OptimizationFileName)==false){
int id = 0;
int i = 0;
string f1,f2,f3,f4,f5,f6,f7,f8,f9,f10,f11,f12,f13,f14,f15,f16,f17,f18,f19,f20,f21,f22,f23,f24,f25,f26,f27,f28,f29,f30,f31,f32,f33,f34,f35,f36;
 int handle = FileOpen(OptimizationFileName,FILE_WRITE|FILE_READ|FILE_CSV|FILE_COMMON|FILE_ANSI, ";");
  if(handle!=INVALID_HANDLE)
   {Print("Loading optimization file.");
   
  while(!FileIsEnding(handle) && !IsStopped())
   {
   f1=FileReadString(handle);
   f2=FileReadString(handle);
   f3=FileReadString(handle);
   f4=FileReadString(handle);
   f5=FileReadString(handle);
   f6=FileReadString(handle);
   f7=FileReadString(handle);
   f8=FileReadString(handle);
   f9=FileReadString(handle);
   f10=FileReadString(handle);
   f11=FileReadString(handle);
   f12=FileReadString(handle);
   f13=FileReadString(handle);
   f14=FileReadString(handle);
   f15=FileReadString(handle);
   f16=FileReadString(handle);
   f17=FileReadString(handle);
   f18=FileReadString(handle);
   f19=FileReadString(handle);
   f20=FileReadString(handle);
   f21=FileReadString(handle);
   f22=FileReadString(handle);
   f23=FileReadString(handle);
   f24=FileReadString(handle);
   f25=FileReadString(handle);
   f26=FileReadString(handle);
   f27=FileReadString(handle);
   f28=FileReadString(handle);
   f29=FileReadString(handle);
   f30=FileReadString(handle);
   f31=FileReadString(handle);
   f32=FileReadString(handle);
   f33=FileReadString(handle);
   f34=FileReadString(handle);
   f35=FileReadString(handle);
   f36=FileReadString(handle);
 
   if (StringToInteger(f1)==Passages){
   weight[0]=StringToDouble(f2);
   Print(weight[0]);
   weight[1]=StringToDouble(f3);
   Print(weight[1]);
   weight[2]=StringToDouble(f4);
   Print(weight[2]);
   weight[3]=StringToDouble(f5);
   weight[4]=StringToDouble(f6);
   weight[5]=StringToDouble(f7);
   weight[6]=StringToDouble(f8);
   weight[7]=StringToDouble(f9);
   weight[8]=StringToDouble(f10);
   weight[9]=StringToDouble(f11);
   weight[10]=StringToDouble(f12);
   weight[11]=StringToDouble(f13);
   weight[12]=StringToDouble(f14);
   weight[13]=StringToDouble(f15);
   weight[14]=StringToDouble(f16);
   weight[15]=StringToDouble(f17);
   
   weight[16]=StringToDouble(f18);
   weight[17]=StringToDouble(f19);
   weight[18]=StringToDouble(f20);
   weight[19]=StringToDouble(f21);
   
   weight[20]=StringToDouble(f22);
   weight[21]=StringToDouble(f23);
   weight[22]=StringToDouble(f24);
   weight[23]=StringToDouble(f25);
   weight[24]=StringToDouble(f26);
   weight[25]=StringToDouble(f27);
   weight[26]=StringToDouble(f28);
   weight[27]=StringToDouble(f29);
   weight[28]=StringToDouble(f30);
   weight[29]=StringToDouble(f31);
   weight[30]=StringToDouble(f32);
   weight[31]=StringToDouble(f33);
   
   weight[32]=StringToDouble(f34);
   weight[33]=StringToDouble(f35);
   weight[34]=StringToDouble(f36);
   
   FileClose(handle);  
   break; 
   }
  
   }  
 FileClose(handle);
   }
   else{
   PrintFormat("Could not open file %s, error code = %d",OptimizationFileName,GetLastError());
   return(INIT_FAILED);
   }
}else{
   PrintFormat("Could not open file %s, error code = %d",OptimizationFileName,GetLastError());
   return(INIT_FAILED);
   }

Die Datei wird gelesen, wenn der Schalter „Optimization“ deaktiviert ist. Vergleichen wir den Wert der ersten Spalte mit dem Wert des Parameters Passagen. Wenn es eine Übereinstimmung gibt, weisen wir die Werte der Gewichte und Bias unseren Array weight[] zu. So können wir die besten Ergebnisse testen.

Führen wir Vorwärtstests der erhaltenen Ergebnisse durch, um die drei besten zu finden. In meinem Fall sind die Auswahlkriterien der maximale Gewinnfaktor und die Anzahl der Transaktionen von mehr als 100:

  • Testzeitraum: von 2021.07.12 bis 2022.07.12;
  • Modus: (Jeder Tick anhand realer Ticks);
  • Ersteinlage: 10,000;
  • Zeitrahmen: H1;
  • Festes Losgröße 0,01;
  • Angle EA 4-4-3.

Test 1:

t1

Test 2:

t2

Test 3:

t3

  • Testzeitraum: von 2021.07.12 bis 2022.07.12;
  • Modus: (Jeder Tick anhand realer Ticks);
  • Ersteinlage: 10,000;
  • Zeitrahmen: H1;
  • Festes Losgröße 0,01;
  • Angle EA 4-4-4-3.

Test 1:

t4

Test 2:

t5

Test 3:

t6

  • Testzeitraum: von 2021.07.12 bis 2022.07.12;
  • Modus: (Jeder Tick anhand realer Ticks);
  • Ersteinlage: 10,000;
  • Zeitrahmen: H1;
  • Festes Losgröße 0,01;
  • Figure EA 4-4-3.

Test 1:

t7

Test 2:

t8

Test 3:

t9

  • Testzeitraum: von 2021.07.12 bis 2022.07.12;
  • Modus: (Jeder Tick anhand realer Ticks);
  • Ersteinlage: 10,000;
  • Zeitrahmen: H1;
  • Festes Losgröße 0,01;
  • Figure EA 4-4-4-3.

Test 1:

t10

Test 2:

t11

Test 3:

t12

Anschließend testen wir die ursprüngliche Strategie des Bibliotheksautors in den neuronalen Netzen 4-4-3 und 4-4-4-3.

  • Testzeitraum: von 2021.07.12 bis 2022.07.12;
  • Modus: (Jeder Tick anhand realer Ticks);
  • Ersteinlage: 10,000;
  • Zeitrahmen: H1;
  • Festes Losgröße 0,01;
  • Original EA 4-4-3.

Test 1:

t13

Test 2:

t14

Test 3:

t15

  • Testzeitraum: von 2021.07.12 bis 2022.07.12;
  • Modus: (Jeder Tick anhand realer Ticks);
  • Ersteinlage: 10,000;
  • Zeitrahmen: H1;
  • Festes Losgröße 0,01;
  • Original EA 4-4-4-3.

Test 1:

t16

Test 2:

t17

Test 3:

t18

Infolgedessen haben die Strategien Angle EA 4-4-3 und Angle EA 4-4-4-3 besser funktioniert als Figure EA 4-4-3 und Figure EA 4-4-4-3. Ich denke, der Grund liegt in der Verwendung von nicht standardisierten Ansätzen zur Marktanalyse. Die Optimierung auf 2 Kernen dauert etwa 20 Minuten über einen Zeitraum von 3 Jahren. Auch nach den Experimenten ergeben sich eine Reihe von Fragen, die beantwortet werden müssen:

  1. Durchführung der Optimierung über einen großen Zeitraum.
  2. Erhöhung der Anzahl der Durchläufe.
  3. Entscheidung über die beste Strategie für das weitere Vorgehen.
  4. Entwicklung eines Algorithmus für die gleichzeitige Arbeit mit einer bestimmten Datenbank von Handelsoptimierungsergebnissen. Ich habe bereits damit begonnen, darüber nachzudenken. 
  5. Entwicklung eines Algorithmus für gleichzeitige Optimierung und Handel.
  6. Nutzung verschiedener Zeitrahmen, um das beste Ergebnis zu erzielen.
  7. Kombination von zwei oder mehr neuronalen Netzen mit unterschiedlichen Datensätzen in einem EA.

    Natürlich erfordert der vollständige Test eine tiefere Ausbildung. Aber die erzielten Ergebnisse sprechen für sich. Darüber hinaus erfordern solche Experimente große Rechenressourcen.


    Schlussfolgerung

    Im vorliegenden Artikel gehen wir zu komplexeren neuronalen Netzen über. Es wurde viel Arbeit geleistet, um die erforderlichen Daten zu ermitteln, die an ein neuronales Netz weitergegeben werden müssen. Doch damit sind die Möglichkeiten noch nicht erschöpft. Wir müssen versuchen, Daten von einer größeren Anzahl von Indikatoren zu übermitteln und komplexe Verbindungen zu verwenden. Ich hoffe, dies wird uns zu neuen Erfolgen bei der Entwicklung eines profitablen Handelsroboters führen. Wie sich herausstellt, kommt der MetaTrader 5 ohne Software von Drittanbietern aus. Darüber hinaus habe ich einen sehr interessanten Optimierungsalgorithmus entwickelt, der unsere Möglichkeiten erweitern wird. 

    Wie üblich überlasse ich es Ihnen, eine tiefere Optimierung und Vorwärtsprüfung vorzunehmen.

    Anhänge:

    Angle EA 4-4-3 - МA1 and МA24 indicator angle slopes strategy, neural network 4-4-3.
    
    Angle EA 4-4-4-3 - МA1 and МA24 indicator angle slopes strategy, neural network 4-4-4-3.
    
    Figure EA 4-4-3 - МA1 and МA24 indicator butterfly (envelope) strategy, neural network 4-4-3.
    
    Figure EA 4-4-4-3 - МA1 and МA24 indicator butterfly (envelope) strategy, neural network 4-4-4-3.
    
    Original EA 4-4-3 - candle size percentage strategy, neural network 4-4-3.
    
    Original EA 4-4-4-3 - candle size percentage strategy, neural network 4-4-4-3.
    
    Clear.bat - script for cleaning terminal files (Log and Cache).
    
    DeepNeuralNetwork – 4-4-4-3 neural network library.
    
    DeepNeuralNetwork2 – 4-4-3 neural network library.
    


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

    Beigefügte Dateien |
    EA.zip (610.58 KB)
    DoEasy. Steuerung (Teil 11): WinForms Objekte — Gruppen, das WinForms-Objekt CheckedListBox DoEasy. Steuerung (Teil 11): WinForms Objekte — Gruppen, das WinForms-Objekt CheckedListBox
    Der Artikel behandelt die Gruppierung von WinForms-Objekten und die Erstellung des Listenobjekts CheckBox-Objekte.
    Einen handelnden Expert Advisor von Grund auf neu entwickeln (Teil 23): Neues Auftragssystems (VI) Einen handelnden Expert Advisor von Grund auf neu entwickeln (Teil 23): Neues Auftragssystems (VI)
    Wir werden das Auftragssystem flexibler gestalten. Hier werden wir Änderungen am Code in Erwägung ziehen, die ihn flexibler machen, sodass wir die Positionsstopp-Levels viel schneller ändern können.
    Neuronale Netze leicht gemacht (Teil 21): Variierter Autoencoder (VAE) Neuronale Netze leicht gemacht (Teil 21): Variierter Autoencoder (VAE)
    Im letzten Artikel haben wir uns mit dem Algorithmus des Autoencoders vertraut gemacht. Wie jeder andere Algorithmus hat auch dieser seine Vor- und Nachteile. In seiner ursprünglichen Implementierung wird der Autoencoder verwendet, um die Objekte so weit wie möglich von der Trainingsstichprobe zu trennen. Dieses Mal werden wir darüber sprechen, wie man mit einigen ihrer Nachteile umgehen kann.
    Einen handelnden Expert Advisor von Grund auf neu entwickeln (Teil 22): Neues Auftragssystems (V) Einen handelnden Expert Advisor von Grund auf neu entwickeln (Teil 22): Neues Auftragssystems (V)
    Heute werden wir die Entwicklung des neuen Auftragssystems fortsetzen. Es ist nicht einfach, ein neues System einzuführen, da wir häufig auf Probleme stoßen, die den Prozess erheblich erschweren. Wenn diese Probleme auftreten, müssen wir innehalten und die Richtung, in die wir uns bewegen, neu analysieren.