Verwendung von selbstorganisierenden Karten (Kohonenkarten) in MetaTrader 5

MetaQuotes | 7 April, 2016

Einleitung

Eine selbstorganisierende Karte (self-organizing map, SOM) ist eine Art künstliches neuronales Netzwerk, das durch einen nicht überwachten Lernprozess eingelernt wird, um eine zweidimensionale, diskretisierte Darstellung des Eingaberaums der Einlernbeispiele, die als Karte bezeichnet wird, zu erstellen.

Diese Karten sind nützlich für die Klassifizierung und Visualisierung niederdimensionaler Ansichten von hochdimensionalen Daten, ähnlich der multidimensionalen Skalierung. Dieses Modell wurde zuerst durch den finnischen Professor Teuvo Kohonen als künstliches neuronales Netzwerk beschrieben und wird manchmal Kohonenkarte genannt.

Es stehen zahlreiche Algorithmen zur Verfügung. Wir befolgen den unter http://www.ai-junkie.com zu findenden Code. Zur Visualisierung der Daten im MetaTrader 5 Client Terminal nutzen wir die Bibliothek cIntBMP für die Erstellung von BMP-Bildern. In diesem Beitrag werden wir mehrere einfache Anwendungsbeispiele von Kohonenkarten betrachten.



1. Selbstorganisierende Karten

Die selbstorganisierenden Karten wurden erstmals von Teuvo Kohonen im Jahre 1982 beschrieben. Im Gegensatz zu vielen neuronalen Netzwerken benötigen sie keine absolute Entsprechung zwischen Eingabe- und Ziel-Ausgabedaten. Dieses neuronale Netzwerk wird durch einen unüberwachten Lernprozess eingelernt.

Die SOM lässt sich formal als nichtlineare, geordnete, geglättete Abbildung hochdimensionaler Eingabedaten auf die Elemente eines herkömmlichen, niederdimensionalen Arrays beschreiben. Im einfachsten Fall erstellt sie ein Ähnlichkeitsdiagramm von Eingabedaten.

Die SOM konvertiert die nichtlinearen statistischen Beziehungen zwischen hochdimensionalen Daten in eine einfache geometrische Beziehung ihrer Abbildungspunkte auf einem herkömmlichen zweidimensionalen Knotenraster. SOM-Karten können für die Klassifizierung und Visualisierung von hochdimensionalen Daten genutzt werden.

1,1. Netzwerkarchitektur

Eine einfache Kohonenkarte in Form eines Rasters aus 16 Knoten (je 4x4 davon sind mit einem 3-dimensionalen Eingabevektor verbunden) ist in Abb. 1. dargestellt.

Abbildung 1. Einfache Kohonenkarte (16 Knoten)

Abbildung 1. Einfache Kohonenkarte (16 Knoten)

Jeder Knoten hat x- und y-Koordinaten im Raster und einen auf Basis des Eingabevektors definierten Gewichtungsvektor.

1,2. Einlernalgorithmus

Im Gegensatz zu vielen anderen Typen von neuronalen Netzwerken benötigt die SOM keine festgelegte Zielausgabe. Stattdessen wird der Rasterbereich, in dem die Knotengewichtung dem Eingabevektor entspricht, selektiv optimiert, um den Daten der Klasse, zu der der Eingabevektor gehört, näher zu entsprechen.

Ausgehend von einer anfänglichen Verteilung zufälliger Gewichtungen und über viele Durchläufe bildet die SOM schließlich eine Karte aus stabilen Zonen. Jede Zone ist effektiv ein Merkmalsklassifikator, also können Sie sich die grafische Darstellung als eine Art Karte des Eingaberaums vorstellen.

Die Einlernung geschieht in vielen Schritten und über mehrere Durchläufe:

  1. Die Gewichtungen jedes Knotens werden mit zufälligen Werten initialisiert.
  2. Ein Vektor wird zufällig aus dem Satz der Einlerndaten ausgewählt.
  3. Jeder Knoten wird untersucht, um zu berechnen, welche Gewichtungen dem Eingabevektor am ähnlichsten sind. Der ausgewählte Knoten ist allgemein als Best Matching Unit (BMU) bekannt.
  4. Der Radius der Umgebung der BMU wird berechnet. Am Anfang entspricht dieser Wert dem Radius des Rasters, wird aber mit jedem Schritt verkleinert.
  5. Für jeden Knoten innerhalb des Radius der BMU werden die Knotengewichtungen angepasst, damit sie dem Eingabevektor ähnlicher sind. Je näher sich ein Knoten an der BMU befindet, desto wichtiger sind seine Gewichtungen.
  6. Schritt 2 wird N Mal wiederholt.

Die Details finden Sie unter http://www.ai-junkie.com.



2. Fallstudien

2,1. Beispiel 1. "Hello World!" in SOM

Das klassische Beispiel einer Kohonenkarte ist die Clusterung von Farben.

Nehmen wir an, wir haben einen Satz von 8 Farben. Jede von ihnen wird als dreidimensionaler Vektor im RGB-Farbmodell dargestellt.

  1. clrRed Rot: (255,0,0);
  2. clrGreen Grün: (0.128,0);
  3. clrBlue Blau: (0,0,255);
  4. clrDarkGreen Dunkelgrün: (0.100,0);
  5. clrDarkBlue Dunkelblau: (0,0,139);
  6. clrYellow Gelb: (255.255,0);
  7. clrOrange Orange: (255.165,0);
  8. clrPurple Violett: (128,0,128).

Bei der Arbeit mit Kohonenkarten in der MQL5-Sprache befolgen wir das objektorientierte Paradigma.

Wir brauchen zwei Klassen: Die Klasse CSOMNode für einen Knoten des regulären Rasters und CSOM, eine Klasse eines neuronalen Netzwerks.

//+------------------------------------------------------------------+
//| CSOMNode class                                                   |
//+------------------------------------------------------------------+
class CSOMNode
  {
protected:
   int               m_x1;
   int               m_y1;
   int               m_x2;
   int               m_y2;

   double            m_x;
   double            m_y;
   double            m_weights[];
public:
   //--- class constructor
                     CSOMNode();
   //--- class destructor
                    ~CSOMNode();
   //--- node initialization
   void              InitNode(int x1,int y1,int x2,int y2);
   //--- return coordinates of the node's center
   double            X()  const { return(m_x);}
   double            Y()  const { return(m_y);}
   //--- returns the node coordinates
   void              GetCoordinates(int &x1,int &y1,int &x2,int &y2);
   //--- returns the value of weight_index component of weight's vector
   double            GetWeight(int weight_index);
   //--- returns the squared distance between the node weights and specified vector
   double            CalculateDistance(double &vector[]);
   //--- adjust weights of the node
   void              AdjustWeights(double &vector[],double learning_rate,double influence);
  };

Die Umsetzung der Klassenmethoden finden Sie in som_ex1.mq5. Der Code hat zahlreiche Kommentare, wir konzentrieren uns auf die Idee.

Die Beschreibung der CSOM-Klasse sieht so aus:

//+------------------------------------------------------------------+
//| CSOM class                                                       |
//+------------------------------------------------------------------+
class CSOM
  {
protected:
   //--- class for using of bmp images
   cIntBMP           m_bmp;
   //--- grid mode
   int               m_gridmode;
   //--- bmp image size
   int               m_xsize;
   int               m_ysize;
   //--- number of nodes
   int               m_xcells;
   int               m_ycells;
   //--- array with nodes
   CSOMNode          m_som_nodes[];
   //--- total items in training set
   int               m_total_training_sets;
   //--- training set array
   double            m_training_sets_array[];
protected:
   //--- radius of the neighbourhood (used for training)
   double            m_map_radius;
   //--- time constant (used for training)
   double            m_time_constant;
   //--- initial learning rate (used for training)
   double            m_initial_learning_rate;
   //--- iterations (used for training)
   int               m_iterations;

public:
   //--- class constructor
                     CSOM();
   //--- class destructor
                    ~CSOM();
   //--- net initialization
   void              InitParameters(int iterations,int xcells,int ycells,int bmpwidth,int bmpheight);
   //--- finds the best matching node, closest to the specified vector
   int               BestMatchingNode(double &vector[]);
   //--- train method
   void              Train();
   //--- render method
   void              Render();
   //--- shows the bmp image on the chart
   void              ShowBMP(bool back);
   //--- adds a vector to training set
   void              AddVectorToTrainingSet(double &vector[]);
   //--- shows the pattern title
   void              ShowPattern(double c1,double c2,double c3,string name);
   //--- adds a pattern to training set
   void              AddTrainPattern(double c1,double c2,double c3);
   //--- returns the RGB components of the color
   void              ColToRGB(int col,int &r,int &g,int &b);
   //--- returns the color by RGB components
   int               RGB256(int r,int g,int b) const {return(r+256*g+65536*b);      }
   //--- deletes image from the chart
   void              NetDeinit();
  };

Die Verwendung der CSOM-Klasse ist einfach:

CSOM KohonenMap;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
void OnInit()
  {
  MathSrand(200);
//--- initialize net, 10000 iterations will be used for training
//--- the net contains 15x20 nodes, bmp image size 400x400
   KohonenMap.InitParameters(10000,15,20,400,400);
//-- add RGB-components of each color from training set
   KohonenMap.AddTrainPattern(255,  0,  0);   // Red
   KohonenMap.AddTrainPattern(  0,128,  0);   // Green
   KohonenMap.AddTrainPattern(  0,  0,255);   // Blue
   KohonenMap.AddTrainPattern(  0,100,  0);   // Dark green
   KohonenMap.AddTrainPattern(  0,  0,139);   // Dark blue
   KohonenMap.AddTrainPattern(255,255,  0);   // Yellow
   KohonenMap.AddTrainPattern(255,165,  0);   // Orange
   KohonenMap.AddTrainPattern(128,  0,128);   // Purple
//--- train net
   KohonenMap.Train();
//--- render map to bmp
   KohonenMap.Render();
//--- show patterns and titles for each color
   KohonenMap.ShowPattern(255,  0,  0,"Red");
   KohonenMap.ShowPattern(  0,128,  0,"Green");
   KohonenMap.ShowPattern(  0,  0,255,"Blue");
   KohonenMap.ShowPattern(  0,100,  0,"Dark green");
   KohonenMap.ShowPattern(  0,  0,139,"Dark blue");
   KohonenMap.ShowPattern(255,255,  0,"Yellow");
   KohonenMap.ShowPattern(255,165,  0,"Orange");
   KohonenMap.ShowPattern(128,  0,128,"Purple");
//--- show bmp image on the chart
   KohonenMap.ShowBMP(false);
//---
  }

Das Ergebnis wird in Abb. 2 dargestellt.

Abbildung 2. Ausgabe des Expert Advisors SOM_ex1.mq5

Abbildung 2. Ausgabe des Expert Advisors SOM_ex1.mq5

Die Dynamiken der Einlernung der Kohonenkarte werden in Abb. 3 dargestellt (siehe Schritte unter dem Bild):

Abbildung 3. Dynamiken des Einlernens der Kohonenkarte

Abbildung 3. Dynamiken des Einlernens der Kohonenkarte

Aus Abb. 3 ist ersichtlich, dass die Kohonenkarte nach 2400 Schritten entsteht.

Wenn wir ein Raster aus 300 Knoten erstellen und die Bildgröße mit 400x400 festlegen:

//--- lattice of 15x20 nodes, image size 400x400
   KohonenMap.InitParameters(10000,15,20,400,400);

erhalten wir das in Abb. 4 dargestellte Bild:

Abbildung 4. Kohonenkarte mit 300 Knoten, Bildgröße 400x400

Abbildung 4. Kohonenkarte mit 300 Knoten, Bildgröße 400x400

Wenn Sie das Buch Visual Explorations in Finance: with Self-Organizing Maps von Guido Deboeck und Teuvo Kohonen lesen, werden Sie daran erinnert, dass Rasterknoten auch als sechseckige Zellen dargestellt werden können. Durch eine Anpassung des Codes des Expert Advisors können wir eine weitere Visualisierung umsetzen.

Das Ergebnis von SOM-ex1-hex.mq5 wird in Abb. 5 dargestellt:

Abbildung 5. Kohonenkarte mit 300 Knoten, Bildgröße 400x400, Darstellung der Knoten als sechseckige Zellen

Abbildung 5. Kohonenkarte mit 300 Knoten, Bildgröße 400x400, Darstellung der Knoten als sechseckige Zellen

In dieser Version können wir die Anzeige von Zellenrändern durch die Verwendung von Eingabeparametern definieren:

// input parameter, used to show hexagonal cells
input bool HexagonalCell=true;
// input parameter, used to show borders
input bool ShowBorders=true;

In einigen Fällen benötigen wir keine Anzeige der Zellenränder. Wenn Sie ShowBorders=false festlegen, erhalten Sie das folgende Bild (siehe Abb. 6):

Abb. 6. Kohonenkarte mit 300 Knoten, Bildgröße 400x400, Darstellung der Knoten als sechseckige Zellen, Zellenränder deaktiviert

Abb. 6. Kohonenkarte mit 300 Knoten, Bildgröße 400x400, Darstellung der Knoten als sechseckige Zellen, Zellenränder deaktiviert

Im ersten Beispiel haben wir 8 Farben im Einlernsatz mit festgelegten Farbkomponenten verwendet. Wir können den Einlernsatz erweitern und die Festlegung von Farbkomponenten vereinfachen, indem wir die CSOM-Klasse um zwei Methoden erweitern.

Beachten Sie, dass die Kohonenkarten in diesem Fall einfach sind, weil es nur wenige Farben gibt, die im Farbraum getrennt sind. Als Ergebnis erhalten wir die lokalisierten Cluster.

Ein Problem entsteht, wenn wir mehr Farben mit näheren Farbkomponenten betrachten.

2,2. Beispiel 2. Nutzung von Web-Farben als Einlernmuster

In MQL5 sind die Web-Farben vordefinierte Konstanten.

Abbildung 7. Web-Farben

Abbildung 7. Web-Farben

Was wäre, wenn wir den Kohonen-Algorithmus auf einen Vektorsatz mit ähnlichen Komponenten anwenden?

Wir können die von der CSOM-Klasse abgeleitete Klasse CSOMWeb erstellen:

//+------------------------------------------------------------------+
//| CSOMWeb class                                                    |
//+------------------------------------------------------------------+
class CSOMWeb : public CSOM
  {
public:
//--- adds a color to training set (used for colors, instead of AddTrainPattern)
   void              AddTrainColor(int col);
//--- method of showing of title of the pattern (used for colors, instead of ShowPattern)
   void              ShowColor(int col,string name);
  };

Wie Sie sehen können, haben wir zwei neue Methoden hinzugefügt, um die Arbeit mit Farben zu vereinfachen. Die explizite Festlegung von Farbkomponenten ist nicht mehr erforderlich.

Die Umsetzung der Klasse sieht so aus:

//+------------------------------------------------------------------+
//| Adds a color to training set                                     |
//| (used for colors, instead of AddTrainPattern)                    |
//+------------------------------------------------------------------+
void CSOMWeb::AddTrainColor(int col)
  {
   double vector[];
   ArrayResize(vector,3);
   int r=0;
   int g=0;
   int b=0;
   ColToRGB(col,r,g,b);
   vector[0]=r;
   vector[1]=g;
   vector[2]=b;
   AddVectorToTrainingSet(vector);
   ArrayResize(vector,0);
  }
//+------------------------------------------------------------------+
//| Method of showing of title of the pattern                        |
//| (used for colors, instead of ShowPattern)                        |
//+------------------------------------------------------------------+
void CSOMWeb::ShowColor(int col,string name)
  {
   int r=0;
   int g=0;
   int b=0;
   ColToRGB(col,r,g,b);
   ShowPattern(r,g,b,name);
  }

Alle Web-Farben können im Array web_colors[] kombiniert werden:

//--- web colors array
color web_colors[132]=
  {
   clrBlack, clrDarkGreen, clrDarkSlateGray, clrOlive, clrGreen, 
   clrTeal, clrNavy, clrPurple, clrMaroon, clrIndigo, clrMidnightBlue, 
   clrDarkBlue, clrDarkOliveGreen, clrSaddleBrown, clrForestGreen, clrOliveDrab, 
   clrSeaGreen, clrDarkGoldenrod, clrDarkSlateBlue, clrSienna, clrMediumBlue, 
   clrBrown, clrDarkTurquoise, clrDimGray, clrLightSeaGreen, clrDarkViolet, 
   clrFireBrick, clrMediumVioletRed, clrMediumSeaGreen, clrChocolate, clrCrimson, 
   clrSteelBlue, clrGoldenrod, clrMediumSpringGreen, clrLawnGreen, clrCadetBlue, 
   clrDarkOrchid, clrYellowGreen, clrLimeGreen, clrOrangeRed, clrDarkOrange, 
   clrOrange, clrGold, clrYellow, clrChartreuse, clrLime, clrSpringGreen, 
   clrAqua, clrDeepSkyBlue, clrBlue, clrMagenta, clrRed, clrGray, 
   clrSlateGray, clrPeru, clrBlueViolet, clrLightSlateGray, clrDeepPink, 
   clrMediumTurquoise, clrDodgerBlue, clrTurquoise, clrRoyalBlue, clrSlateBlue, 
   clrDarkKhaki, clrIndianRed, clrMediumOrchid, clrGreenYellow, clrMediumAquamarine, 
   clrDarkSeaGreen, clrTomato, clrRosyBrown, clrOrchid, clrMediumPurple, 
   clrPaleVioletRed, clrCoral, clrCornflowerBlue, clrDarkGray, clrSandyBrown, 
   clrMediumSlateBlue, clrTan, clrDarkSalmon, clrBurlyWood, clrHotPink, 
   clrSalmon, clrViolet, clrLightCoral, clrSkyBlue, clrLightSalmon, 
   clrPlum, clrKhaki, clrLightGreen, clrAquamarine, clrSilver, 
   clrLightSkyBlue, clrLightSteelBlue, clrLightBlue, clrPaleGreen, clrThistle, 
   clrPowderBlue, clrPaleGoldenrod, clrPaleTurquoise, clrLightGray, clrWheat, 
   clrNavajoWhite, clrMoccasin, clrLightPink, clrGainsboro, clrPeachPuff, 
   clrPink, clrBisque, clrLightGoldenrod, clrBlanchedAlmond, clrLemonChiffon, 
   clrBeige, clrAntiqueWhite, clrPapayaWhip, clrCornsilk, clrLightYellow, 
   clrLightCyan, clrLinen, clrLavender, clrMistyRose, clrOldLace, 
   clrWhiteSmoke, clrSeashell, clrIvory, clrHoneydew, clrAliceBlue, 
   clrLavenderBlush, clrMintCream, clrSnow, clrWhite
  };

Die OnInit()-Funktion hat die einfache Form:

CSOMWeb KohonenMap;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
void OnInit()
  {
   MathSrand(200);
   int total_web_colors=ArraySize(web_colors);
//--- initialize net, 10000 iterations will be used for training
//--- the net contains 15x20 nodes, bmp image size 400x400
   KohonenMap.InitParameters(10000,50,50,500,500);
//-- add all web colors to training set
   for(int i=0; i<total_web_colors; i++)
     {
      KohonenMap.AddTrainColor(web_colors[i]);
     }
//--- train net
   KohonenMap.Train();
//--- render map to bmp
   KohonenMap.Render();
//--- show patterns and titles for each color
   for(int i=0; i<total_web_colors; i++)
     {
      KohonenMap.ShowColor(web_colors[i],ColorToString(web_colors[i],true));
     }
//--- show bmp image on the chart
   KohonenMap.ShowBMP(false);
  }

Wenn wir som-ex2-hex.mq5 ausführen, erhalten wir das in Abb. 8 dargestellte Bild.

Abbildung 8. Kohonenkarte für Web-Farben

Abbildung 8. Kohonenkarte für Web-Farben

Wie Sie sehen können, gibt es einige Cluster, doch einige Farben (wie xxxBlue) befinden sich in unterschiedlichen Bereichen.

Der Grund dafür ist die Struktur des Einlernsatzes: Es gibt viele Vektoren mit nahen Komponenten.

2,3. Beispiel 3. Clusterung von Produkten

Als Nächstes betrachten wir ein einfaches Beispiel, in dem fünfundzwanzig verschiedene Lebensmittel in Ähnlichkeitsbereichen auf Basis der drei Parameter Eiweiß, Kohlenhydrat und Fett gruppiert werden sollen.

Lebensmittel Eiweiß Kohlehydrat Fett
1 Äpfel 0,4 11,8 0,1
2 Avocado 1,9 1,9 19,5
3 Bananen 1,2 23,2 0,3
4 Rindersteak 20,9 0 7,9
5 Big Mac 13 19 11
6 Paranüsse 15,5 2,9 68,3
7 Brot 10,5 37 3,2
8 Butter 1 0 81
9 Käse 25 0,1 34,4
10 Käsekuchen 6,4 28,2 22,7
11 Kekse 5,7 58,7 29,3
12 Corn Flakes 7 84 0,9
13 Eier 12,5 0 10,8
14 Brathähnchen 17 7 20
15 Pommes 3 36 13
16 Heiße Schokolade 3,8 19,4 10,2
17 Peperoni 20,9 5,1 38,3
18 Pizza 12,5 30 11
19 Schweinefleischpastete 10,1 27,3 24,2
20 Kartoffeln 1,7 16,1 0,3
21 Reis 6,9 74 2,8
22 Backhähnchen 26,1 0,3 5,8
23 Zucker 0 95,1 0
24 Tunfischsteak 25,6 0 0,5
25 Wasser 0 0 0

Tabelle 1. Eiweiß, Kohlenhydrate und Fett von 25 Lebensmitteln.

Dies ist eine interessante Aufgabe, weil die Eingabevektoren unterschiedliche Werte haben und jede Komponente über einen eigenen Wertebereich verfügt. Dies ist für die Visualisierung wichtig, weil wir das RGB-Farbmodell mit Komponenten zwischen 0 und 255 anwenden.

Glücklicherweise sind die Eingabevektoren in diesem Fall ebenfalls 3-dimensional, sodass wir das RGB-Farbmodell für die Visualisierung der Kohonenkarte nutzen können.

//+------------------------------------------------------------------+
//| CSOMFood class                                                   |
//+------------------------------------------------------------------+
class CSOMFood : public CSOM
  {
protected:
   double            m_max_values[];
   double            m_min_values[];
public:
   void              Train();
   void              Render();
   void              ShowPattern(double c1,double c2,double c3,string name);
  };

Wie Sie sehen können, haben wir die Arrays m_max_values[] und m_min_values[] für die Speicherung der Höchst- und Mindestwerte der Einlernsätze hinzugefügt. Für die Visualisierung im RGB-Farbmodell wird die "Skalierung" benötigt, also haben wir die Methoden Train(), Render() und ShowPattern() neu bestimmt.

Die Suche nach den Höchst- und Mindestwerten ist in der Methode Train() enthalten.

//--- find minimal and maximal values of the training set
   ArrayResize(m_max_values,3);
   ArrayResize(m_min_values,3);

   for(int j=0; j<3; j++)
     {
      double maxv=m_training_sets_array[3+j];
      double minv=m_training_sets_array[3+j];
      for(int i=1; i<m_total_training_sets; i++)
        {
         double v=m_training_sets_array[3*i+j];
         if(v>maxv) {maxv=v;}
         if(v<minv) {minv=v;}
        }
      m_max_values[j]=maxv;
      m_min_values[j]=minv;
      Print(j,"m_min_value=",m_min_values[j],"m_max_value=",m_max_values[j]);
     }

Um die Komponenten im RGB-Farbmodell anzuzeigen, müssen wir die Methode Render() anpassen:

// int r = int(m_som_nodes[ind].GetWeight(0));
// int g = int(m_som_nodes[ind].GetWeight(1));
// int b = int(m_som_nodes[ind].GetWeight(2));

int r=int ((255*(m_som_nodes[ind].GetWeight(0)-m_min_values[0])/(m_max_values[0]-m_min_values[0])));
int g=int ((255*(m_som_nodes[ind].GetWeight(1)-m_min_values[1])/(m_max_values[1]-m_min_values[1])));
int b=int ((255*(m_som_nodes[ind].GetWeight(2)-m_min_values[2])/(m_max_values[2]-m_min_values[2])));

Das Ergebnis von som_ex3.mq5 wird in Abb. 9 dargestellt.

Abbildung 9. Lebensmittelkarte, gruppiert in Ähnlichkeitsbereiche auf Basis von Eiweiß, Kohlehydraten und Fett

Abbildung 9. Lebensmittelkarte, gruppiert in Ähnlichkeitsbereiche auf Basis von Eiweiß, Kohlehydraten und Fett

Analyse der Komponenten. In der Karte ist ersichtlich, dass Zucker, Reis und Corn Flakes aufgrund des Kohlenhydrats (2. Komponente) in Grün dargestellt werden. Die Butter ist in der blauen Zone, weil sie viel Fett (3. Komponente) enthält. Rindersteak, Backhähnchen und Tunfischsteak enthalten viel Eiweiß (1. Komponente, rot).

Sie können den Einlernsatz durch das Hinzufügen neuer Lebensmittel aus den Tabellen der Lebensmittelzusammensetzung (alternative Tabelle) erweitern.

Wie Sie sehen können, ist das Problem für die "reinen" R-, G- und B-Richtungen gelöst. Doch wie sieht es bei anderen Lebensmitteln mit mehreren gleichen (oder weitestgehend gleichen) Bestandteilen aus? Im Weiteren betrachten wir die Komponente Ebenen. Diese ist äußerst nützlich, insbesondere in Fällen, in denen die Eingabevektoren mehr als 3 Dimensionen haben.

2,4. Beispiel 4. 4-dimensionaler Fall. Der Fisher'sche Iris-Datensatz. CMYK

Bei der Visualisierung dreidimensionaler Vektoren gibt es keine Probleme. Die Ergebnisse sind dank des für die Visualisierung von Farbkomponenten verwendeten RGB-Farbmodells klar.

Bei der Arbeit mit hochdimensionalen Daten müssen wir einen Weg finden, sie zu visualisieren. Die einfachste Lösung ist die Darstellung als Farbverlaufskarte (beispielsweise Schwarz-Weiß), deren Farben proportional zur Vektorlänge sind. Die andere Variante ist die Nutzung eines anderen Farbraums. In diesem Beispiel betrachten wir das CMYK-Farbmodell für den Fisher'schen Iris-Datensatz. Es gibt noch eine bessere Lösung, die wir später betrachten werden.

Der Iris-Datensatz oder der Fisher'sche Iris-Datensatz ist ein multivariater Datensatz, der von R. Fisher (1936) als Beispiel für die Diskriminanzanalyse eingeführt wurde. Der Datensatz besteht aus 50 Exemplaren von jeder der drei Gattungen der Schwertlilien (Iris setosa, Iris virginica und Iris versicolor).

Vier Merkmale jedes Exemplars, die Länge und Breite des Kelchblatts und des Blütenblatts, wurden in Zentimetern gemessen.

Abbildung 10. Schwertlilie

Abbildung 10. Schwertlilie

Jedes Exemplar weist 4 Merkmale auf:

  1. Länge des Kelchblatts;
  2. Breite des Kelchblatts;
  3. Länge des Blütenblatts;
  4. Breite des Blütenblatts.

Den Iris-Datensatz finden Sie in SOM_ex4.mq5.

In diesem Beispiel nutzen wir den Zwischenfarbraum CMYK für die Darstellung, d. h. wir betrachten die Gewichtungen des Knotens als Vektoren im CMYK-Raum. Für die Visualisierung der Ergebnisse wird die Konvertierung von CMYK in RGB genutzt. Die neue Methode int CSOM::CMYK2Col(uchar c,uchar m,uchar y,uchar k) wird der CSOM-Klasse hinzugefügt, die in der Methode CSOM::Render() verwendet wird. Genauso müssen wir die Klassen anpassen, damit sie 4-dimensionale Vektoren unterstützen.

Das Ergebnis wird in Abb. 11 dargestellt.

Abbildung 11. Kohonenkarte des Iris-Datensatzes, dargestellt im CMYK-Farbmodell

Abbildung 11. Kohonenkarte des Iris-Datensatzes, dargestellt im CMYK-Farbmodell

Was sehen wir? Wir verfügen nicht über die vollständige Clusterung (aufgrund der Merkmale der Aufgabe), doch man sieht eine lineare Trennung der Iris setosa.

Der Grund für diese lineare Trennung der setosa ist der hohe Anteil der Komponente "Magenta" (2. Komponente) im CMYK-Raum.

2,6. Analyse der Komponentenebenen

Anhand der vorhergehenden Beispiele (Clusterung von Lebensmittel- und Iris-Daten) sieht man, dass es ein Problem mit der Datenvisualisierung gibt.

Für die Lebensmittelaufgabe haben wir zum Beispiel die Kohonenkarte mithilfe der Informationen über bestimmte Farben (Rot, Grün, Blau) analysiert. Zusätzlich zu den Grund-Clustern gab es bestimmte Lebensmittel mit mehreren Komponenten. Zusätzlich wird die Analyse erschwert, wenn die Komponenten weitestgehend gleich sind.

Die Ebenen der Komponenten liefern uns die Möglichkeit, die relative Intensität für jedes der Lebensmittel zu sehen.

Wir müssen die Instanzen der Klasse CIntBMP (Array m_bmp[]) in die CSOM-Klasse einfügen und die entsprechenden Abbildungsmethoden anpassen. Ebenso benötigen wir eine Farbverlaufskarte, um die Intensität jeder Komponente zu visualisieren (niedrigere Werte werden in Blau, höhere in Rot angezeigt):

Abbildung 12. Verlaufspalette

Abbildung 12. Verlaufspalette

Wir haben das Array Palette[768] und die Methoden GetPalColor() und Blend() hinzugefügt. Die Darstellung von Knoten befindet sich in der Methode RenderCell().

Iris-Datensatz

Die Ergebnisse von som-ex4-cpr.mq5 werden in Abb. 13 dargestellt.

Abbildung 13. Komponentenebenen-Darstellung des Iris-Datensatzes

Abbildung 13. Komponentenebenen-Darstellung des Iris-Datensatzes

In diesem Fall haben wir ein Raster mit 30x30 Knoten verwendet, die Bildgröße beträgt 300x300.

Die Komponentenebenen spielen eine wichtige Rolle bei der Korrelationssuche: Durch den Vergleich dieser Ebenen können sogar nur teilweise korrelierende Variablen durch eine Sichtprüfung gefunden werden. Dies ist einfacher, wenn die Komponentenebenen neu angeordnet werden, sodass die korrelierenden nahe beieinander sind. Auf diese Weise lassen sich interessante Kombinationen von Komponenten für die weitere Untersuchung einfach auswählen.

Betrachten wir die Komponentenebenen (Abb. 14). 

Die Werte der Maximum- und Minimum-Komponenten werden in der Farbverlaufstabelle gezeigt.

Abbildung 14. Iris-Datensatz. Komponentenebenen

Abbildung 14. Iris-Datensatz. Komponentenebenen

Alle diese im CMYK-Farbmodell dargestellten Komponentenebenen werden in Abb. 15 gezeigt.

Abbildung 15. Iris-Datensatz. Kohonenkarte im CMYK-Farbmodell

Abbildung 15. Iris-Datensatz. Kohonenkarte im CMYK-Farbmodell

Betrachten wir den Iris-Typ setosa. Mithilfe der Analyse der Komponentenebenen (Abb. 14) kann man erkennen, dass er Minimal-Werte in der 1. (Länge des Kelchblatts), 3. (Länge des Blütenblatts) und 4. (Breite des Blütenblatts) Komponentenebene aufweist.

Auffallend ist, dass er Maximal-Werte in der 2. Komponentenebene (Breite des Kelchblatts) aufweist – das gleiche Ergebnis, das wir im CMYK-Farbmodell (Magenta-Komponente, Abb. 15) erhalten haben.

Clusterung von Lebensmitteln

Betrachten wir nun die Aufgabe der Clusterung von Lebensmitteln mithilfe der Analyse von Komponentenebenen (som-ex3-cpr.mq5).

Das Ergebnis wird in Abb. 16 präsentiert (30x30 Knoten, Bildgröße 300x300, sechseckige Zellen ohne Grenzen).

Abbildung 16. Kohonenkarte für Lebensmittel, Darstellung der Komponentenebenen

Abbildung 16. Kohonenkarte für Lebensmittel, Darstellung der Komponentenebenen

Wir haben die Anzeige von Titeln in der Methode ShowPattern() der Klasse CSOM hinzugefügt (Eingabeparameter ShowTitles=true).

Die Komponentenebenen (Eiweiß, Kohlenhydrat, Fett) sehen so aus:

Abbildung 17. Kohonenkarte für Lebensmittel. Komponentenebenen und RGB-Farbmodell

Abbildung 17. Kohonenkarte für Lebensmittel. Komponentenebenen und RGB-Farbmodell

Die in Abb. 17 gezeigte Darstellung der Komponentenebenen ermöglicht eine neue Ansicht der Struktur der Lebensmittelkomponenten. Zudem liefert sie zusätzliche Informationen, die im in Abb. 9 gezeigten RGB-Farbmodell nicht sichtbar sind.

Beispielsweise sehen wir nun, dass Käse sich in der 1. Komponentenebene (Eiweiß) befindet. Im RGB-Farbmodell wird er aufgrund des Fettes (2. Komponente) mit einer Farbe nahe an Magenta dargestellt.

2,5. Umsetzung der Komponentenebenen bei beliebigen Dimensionen

In den Beispielen, die wir betrachtet haben, war die Dimension fix und der Algorithmus der Visualisierung war bei verschiedenen Darstellungsarten (RGB- und CMYK-Farbmodelle) unterschiedlich.

Nun können wir den Algorithmus für beliebige Dimensionen verallgemeinern, doch in diesem Fall visualisieren wir nur die Komponentenebenen. Das Programm muss die beliebigen Daten aus einer CSV-Datei laden können.

Die Datei food.csv sieht beispielsweise so aus:

Protein;Carbohydrate;Fat;Title
0.4;11.8;0.1;Apples
1.9;1.9;19.5;Avocado
1.2;23.2;0.3;Bananas
20.9;0.0;7.9;Beef Steak
13.0;19.0;11.0;Big Mac
15.5;2.9;68.3;Brazil Nuts
10.5;37.0;3.2;Bread
1.0;0.0;81.0;Butter
25.0;0.1;34.4;Cheese
6.4;28.2;22.7;Cheesecake
5.7;58.7;29.3;Cookies
7.0;84.0;0.9;Cornflakes
12.5;0.0;10.8;Eggs
17.0;7.0;20.0;Fried Chicken
3.0;36.0;13.0;Fries
3.8;19.4;10.2;Hot Chocolate
20.9;5.1;38.3;Pepperoni
12.5;30.0;11.0;Pizza
10.1;27.3;24.2;Pork Pie
1.7;16.1;0.3;Potatoes
6.9;74.0;2.8;Rice
26.1;0.3;5.8;Roast Chicken
0.0;95.1;0.0;Sugar
25.6;0.0;0.5;Tuna Steak
0.0;0.0;0.0;Water

Die erste Zeile der Datei enthält die Namen (Titel) des Vektors der Eingabedaten. Die Titel werden für die Unterscheidung der Komponentenebenen benötigt. Wir werden ihre Namen im Farbverlaufs-Panel darstellen.

Der Name des Musters befindet sich in der letzten Spalte, in unserem Fall handelt es sich um den Namen des Lebensmittels.

Der Code von SOM.mq5 (Funktion OnInit) wurde vereinfacht:

CSOM KohonenMap;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   MathSrand(200);
//--- load patterns from file
   if(!KohonenMap.LoadTrainDataFromFile(DataFileName))
     {
      Print("Error in loading data for training.");
      return(1);
     }
//--- train net
   KohonenMap.Train();
//--- render map
   KohonenMap.Render();
//--- show patterns from training set
   KohonenMap.ShowTrainPatterns();
//--- show bmp on the chart
   KohonenMap.ShowBMP(false);
   return(0);
  }

Der Name der Datei, die die Einlernmuster enthält, wird im Eingabeparameter DataFileName angegeben, in unserem Fall "food.csv".

Das Ergebnis wird in Abb. 18 dargestellt.

Abbildung 18. Kohonenkarte für Lebensmittel mit schwarz-weißem Farbverlaufsschema

Abbildung 18. Kohonenkarte für Lebensmittel mit schwarz-weißem Farbverlaufsschema

Wir haben ebenso den Eingabeparameter ColorScheme für die Auswahl des Farbverlaufsschemas hinzugefügt.

Derzeit sind 4 Farbschemata verfügbar (ColorScheme=0,1,2,4=Schwarz-Weiß, Dunkelblau-Blau-Grün-Gelb-Rot, Rot-Schwarz-Grün, Rot-Weiß-Grün).

Sie können Ihr eigenes Schema einfach durch Hinzufügen des Farbverlaufs in der Methode CSOM::InitParameters() hinzufügen.

Das Farbschema kann aus den Eingabeparametern des Expert Advisors ausgewählt werden:

Auf ähnliche Weise können wir den Iris-Datensatz (iris-fisher.csv) vorbereiten:

Sepal length;Sepal width;Petal length;Petal width;Title
5.1;3.5;1.4;0.2;setosa
4.9;3.0;1.4;0.2;setosa
4.7;3.2;1.3;0.2;setosa
4.6;3.1;1.5;0.2;setosa
5.0;3.6;1.4;0.2;setosa
5.4;3.9;1.7;0.4;setosa
4.6;3.4;1.4;0.3;setosa
5.0;3.4;1.5;0.2;setosa
4.4;2.9;1.4;0.2;setosa
4.9;3.1;1.5;0.1;setosa
5.4;3.7;1.5;0.2;setosa
4.8;3.4;1.6;0.2;setosa
4.8;3.0;1.4;0.1;setosa
4.3;3.0;1.1;0.1;setosa
5.8;4.0;1.2;0.2;setosa
5.7;4.4;1.5;0.4;setosa
5.4;3.9;1.3;0.4;setosa
5.1;3.5;1.4;0.3;setosa
5.7;3.8;1.7;0.3;setosa
5.1;3.8;1.5;0.3;setosa
5.4;3.4;1.7;0.2;setosa
5.1;3.7;1.5;0.4;setosa
4.6;3.6;1.0;0.2;setosa
5.1;3.3;1.7;0.5;setosa
4.8;3.4;1.9;0.2;setosa
5.0;3.0;1.6;0.2;setosa
5.0;3.4;1.6;0.4;setosa
5.2;3.5;1.5;0.2;setosa
5.2;3.4;1.4;0.2;setosa
4.7;3.2;1.6;0.2;setosa
4.8;3.1;1.6;0.2;setosa
5.4;3.4;1.5;0.4;setosa
5.2;4.1;1.5;0.1;setosa
5.5;4.2;1.4;0.2;setosa
4.9;3.1;1.5;0.2;setosa
5.0;3.2;1.2;0.2;setosa
5.5;3.5;1.3;0.2;setosa
4.9;3.6;1.4;0.1;setosa
4.4;3.0;1.3;0.2;setosa
5.1;3.4;1.5;0.2;setosa
5.0;3.5;1.3;0.3;setosa
4.5;2.3;1.3;0.3;setosa
4.4;3.2;1.3;0.2;setosa
5.0;3.5;1.6;0.6;setosa
5.1;3.8;1.9;0.4;setosa
4.8;3.0;1.4;0.3;setosa
5.1;3.8;1.6;0.2;setosa
4.6;3.2;1.4;0.2;setosa
5.3;3.7;1.5;0.2;setosa
5.0;3.3;1.4;0.2;setosa
7.0;3.2;4.7;1.4;versicolor
6.4;3.2;4.5;1.5;versicolor
6.9;3.1;4.9;1.5;versicolor
5.5;2.3;4.0;1.3;versicolor
6.5;2.8;4.6;1.5;versicolor
5.7;2.8;4.5;1.3;versicolor
6.3;3.3;4.7;1.6;versicolor
4.9;2.4;3.3;1.0;versicolor
6.6;2.9;4.6;1.3;versicolor
5.2;2.7;3.9;1.4;versicolor
5.0;2.0;3.5;1.0;versicolor
5.9;3.0;4.2;1.5;versicolor
6.0;2.2;4.0;1.0;versicolor
6.1;2.9;4.7;1.4;versicolor
5.6;2.9;3.6;1.3;versicolor
6.7;3.1;4.4;1.4;versicolor
5.6;3.0;4.5;1.5;versicolor
5.8;2.7;4.1;1.0;versicolor
6.2;2.2;4.5;1.5;versicolor
5.6;2.5;3.9;1.1;versicolor
5.9;3.2;4.8;1.8;versicolor
6.1;2.8;4.0;1.3;versicolor
6.3;2.5;4.9;1.5;versicolor
6.1;2.8;4.7;1.2;versicolor
6.4;2.9;4.3;1.3;versicolor
6.6;3.0;4.4;1.4;versicolor
6.8;2.8;4.8;1.4;versicolor
6.7;3.0;5.0;1.7;versicolor
6.0;2.9;4.5;1.5;versicolor
5.7;2.6;3.5;1.0;versicolor
5.5;2.4;3.8;1.1;versicolor
5.5;2.4;3.7;1.0;versicolor
5.8;2.7;3.9;1.2;versicolor
6.0;2.7;5.1;1.6;versicolor
5.4;3.0;4.5;1.5;versicolor
6.0;3.4;4.5;1.6;versicolor
6.7;3.1;4.7;1.5;versicolor
6.3;2.3;4.4;1.3;versicolor
5.6;3.0;4.1;1.3;versicolor
5.5;2.5;4.0;1.3;versicolor
5.5;2.6;4.4;1.2;versicolor
6.1;3.0;4.6;1.4;versicolor
5.8;2.6;4.0;1.2;versicolor
5.0;2.3;3.3;1.0;versicolor
5.6;2.7;4.2;1.3;versicolor
5.7;3.0;4.2;1.2;versicolor
5.7;2.9;4.2;1.3;versicolor
6.2;2.9;4.3;1.3;versicolor
5.1;2.5;3.0;1.1;versicolor
5.7;2.8;4.1;1.3;versicolor
6.3;3.3;6.0;2.5;virginica
5.8;2.7;5.1;1.9;virginica
7.1;3.0;5.9;2.1;virginica
6.3;2.9;5.6;1.8;virginica
6.5;3.0;5.8;2.2;virginica
7.6;3.0;6.6;2.1;virginica
4.9;2.5;4.5;1.7;virginica
7.3;2.9;6.3;1.8;virginica
6.7;2.5;5.8;1.8;virginica
7.2;3.6;6.1;2.5;virginica
6.5;3.2;5.1;2.0;virginica
6.4;2.7;5.3;1.9;virginica
6.8;3.0;5.5;2.1;virginica
5.7;2.5;5.0;2.0;virginica
5.8;2.8;5.1;2.4;virginica
6.4;3.2;5.3;2.3;virginica
6.5;3.0;5.5;1.8;virginica
7.7;3.8;6.7;2.2;virginica
7.7;2.6;6.9;2.3;virginica
6.0;2.2;5.0;1.5;virginica
6.9;3.2;5.7;2.3;virginica
5.6;2.8;4.9;2.0;virginica
7.7;2.8;6.7;2.0;virginica
6.3;2.7;4.9;1.8;virginica
6.7;3.3;5.7;2.1;virginica
7.2;3.2;6.0;1.8;virginica
6.2;2.8;4.8;1.8;virginica
6.1;3.0;4.9;1.8;virginica
6.4;2.8;5.6;2.1;virginica
7.2;3.0;5.8;1.6;virginica
7.4;2.8;6.1;1.9;virginica
7.9;3.8;6.4;2.0;virginica
6.4;2.8;5.6;2.2;virginica
6.3;2.8;5.1;1.5;virginica
6.1;2.6;5.6;1.4;virginica
7.7;3.0;6.1;2.3;virginica
6.3;3.4;5.6;2.4;virginica
6.4;3.1;5.5;1.8;virginica
6.0;3.0;4.8;1.8;virginica
6.9;3.1;5.4;2.1;virginica
6.7;3.1;5.6;2.4;virginica
6.9;3.1;5.1;2.3;virginica
5.8;2.7;5.1;1.9;virginica
6.8;3.2;5.9;2.3;virginica
6.7;3.3;5.7;2.5;virginica
6.7;3.0;5.2;2.3;virginica
6.3;2.5;5.0;1.9;virginica
6.5;3.0;5.2;2.0;virginica
6.2;3.4;5.4;2.3;virginica
5.9;3.0;5.1;1.8;virginica

Das Ergebnis wird in Abb. 19 dargestellt.

Abbildung 19. Iris-Datensatz. Komponentenebenen mit Rot-Schwarz-Grün-Farbschema (ColorScheme=2, iris-fisher.csv)

Abbildung 19. Iris-Datensatz. Komponentenebenen mit Rot-Schwarz-Grün-Farbschema (ColorScheme=2, iris-fisher.csv)

Nun verfügen wir über ein Werkzeug für reale Anwendungen.

2,6. Beispiel 5. Markt-Heatmaps

Selbstorganisierende Karten können für Karten von Marktbewegungen verwendet werden. Manchmal wird ein globales Bild des Marktes benötigt. Dafür ist die Markt-Heatmap ein sehr hilfreiches Werkzeug. Die Aktien werden abhängig von Wirtschaftssektoren kombiniert.

Die aktuelle Farbe der Aktie hängt von der der aktuellen Wachstumsrate (in %) ab:

Abbildung 20. Markt-Heatmap für Aktien aus S&P500

Abbildung 20. Markt-Heatmap für Aktien aus S&P500

Die wöchentliche Markt-Heatmap der Aktien aus S&P (http://finviz.com) wird in Abb. 20 dargestellt. Die Farbe hängt von der Wachstumsrate (in %) ab:

Die Größe des Aktienrechtecks hängt von der Marktkapitalisierung ab. Die gleiche Analyse lässt sich im MetaTrader 5 Client Terminal mithilfe der Kohonenkarten durchführen.

Die Grundidee ist, die Wachstumsraten (in %) für mehrere Timeframes zu benutzen. Wir verfügen über das Werkzeug für die Arbeit mit Kohonenkarten, also wird nur noch ein Script benötigt, das die Daten in einer .csv-Datei speichert.

Die Preisdaten zu CFD-Preisen von amerikanischen Aktien (#AA, #AIG, #AXP, #BA, #BAC, #C, #CAT, #CVX, #DD, #DIS, #EK, #GE, #HD, #HON, #HPQ, #IBM, #INTC, #IP, #JNJ, #JPM, #KFT, #KO, #MCD, #MMM, #MO, #MRK, #MSFT, #PFE, #PG, #T, #TRV, #UTX, #VZ, #WMT и #XOM) können dem MetaQuotes Demo-Server entnommen werden.

Das Script, das die Datei dj.csv erstellt, ist äußerst simpel:

//+------------------------------------------------------------------+
//|                                                           DJ.mq5 |
//|                        Copyright 2011, MetaQuotes Software Corp. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2011, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"

string s_cfd[35]=
  {
   "#AA","#AIG","#AXP","#BA","#BAC","#C","#CAT","#CVX","#DD","#DIS","#EK","#GE",
   "#HD","#HON","#HPQ","#IBM","#INTC","#IP","#JNJ","#JPM","#KFT","#KO","#MCD","#MMM",
   "#MO","#MRK","#MSFT","#PFE","#PG","#T","#TRV","#UTX","#VZ","#WMT","#XOM"
  };
//+------------------------------------------------------------------+
//| Returns price change in percents                                 |
//+------------------------------------------------------------------+
double PercentChange(double Open,double Close)
  {
   return(100.0*(Close-Open)/Close);
  }
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {

   ResetLastError();
   int filehandle=FileOpen("dj.csv",FILE_WRITE|FILE_ANSI);
   if(filehandle==INVALID_HANDLE)
     {
      Alert("Error opening file");
      return;
     }
//---
   MqlRates MyRates[];
   ArraySetAsSeries(MyRates,true);

   string t="M30;M60;M90;M120;M150;M180;M210;M240;Title";
   FileWrite(filehandle,t);
   Print(t);

   int total_symbols=ArraySize(s_cfd);

   for(int i=0; i<total_symbols; i++)
     {
      string cursymbol=s_cfd[i];

      int copied1=CopyRates(cursymbol,PERIOD_M30,0,8,MyRates);
      if(copied1>0)
        {
         string s="";
         s=s+DoubleToString(PercentChange(MyRates[1].open,MyRates[0].close),3)+";";
         s=s+DoubleToString(PercentChange(MyRates[2].open,MyRates[0].close),3)+";";
         s=s+DoubleToString(PercentChange(MyRates[3].open,MyRates[0].close),3)+";";
         s=s+DoubleToString(PercentChange(MyRates[4].open,MyRates[0].close),3)+";";
         s=s+DoubleToString(PercentChange(MyRates[5].open,MyRates[0].close),3)+";";
         s=s+DoubleToString(PercentChange(MyRates[6].open,MyRates[0].close),3)+";";
         s=s+DoubleToString(PercentChange(MyRates[7].open,MyRates[0].close),3)+";";
         s=s+cursymbol;
         Print(s);
         FileWrite(filehandle,s);
         }
         else
           {
            Print("Error in request of historical data on symbol ",cursymbol);
            return;
           }
     }
   Alert("OK");
   FileClose(filehandle);

  }
//+------------------------------------------------------------------+

Die historischen Daten müssen heruntergeladen werden. Dies können Sie mithilfe des Scripts DownloadHistory automatisch ausführen.

Als Ergebnis des Scripts dj.mq5 erhalten wir die Datei dj.csv mit den folgenden Daten:

M30;M60;M90;M120;M150;M180;M210;M240;Title
0.063;-0.564;-0.188;0.376;0.251;0.313;0.627;0.439;#AA
-0.033;0.033;0.067;-0.033;0.067;-0.133;0.266;0.533;#AIG
-0.176;0.039;0.039;0.274;0.196;0.215;0.430;0.646;#AXP
-0.052;-0.328;-0.118;0.315;0.223;0.367;0.288;0.328;#BA
-0.263;-0.351;-0.263;0.000;-0.088;0.088;0.000;-0.088;#BAC
-0.224;-0.274;-0.374;-0.100;-0.274;-0.224;-0.324;-0.598;#C
-0.069;-0.550;-0.079;0.766;0.727;0.638;0.736;0.589;#CAT
-0.049;-0.168;0.099;0.247;0.187;0.049;0.355;0.266;#CVX
0.019;-0.058;0.058;0.446;0.174;0.349;0.136;-0.329;#DD
-0.073;-0.219;-0.146;0.267;0.170;0.292;0.170;0.267;#DIS
-1.099;-1.923;-1.099;0.275;0.275;0.275;-0.549;-1.374;#EK
-0.052;-0.310;-0.103;0.362;0.258;0.362;0.465;0.258;#GE
-0.081;-0.244;-0.326;-0.136;0.081;0.326;0.489;0.489;#HD
-0.137;-0.427;-0.171;0.427;0.445;0.342;0.325;0.359;#HON
-0.335;-0.363;-0.112;0.112;0.168;0.307;0.475;0.251;#HPQ
0.030;-0.095;0.065;0.190;0.071;0.214;0.279;0.327;#IBM
0.000;-0.131;-0.044;-0.088;-0.044;0.000;0.000;0.044;#INTC
-0.100;-0.200;-0.166;0.100;-0.067;0.033;-0.532;-0.798;#IP
-0.076;0.076;0.259;0.473;0.427;0.336;0.336;-0.076;#JNJ
-0.376;-0.353;-0.494;-0.259;-0.423;-0.329;-0.259;-0.541;#JPM
-0.057;-0.086;-0.029;0.086;0.114;0.057;0.257;-0.114;#KFT
0.059;-0.030;0.119;0.282;0.119;0.193;0.208;-0.119;#KO
-0.109;-0.182;0.206;0.352;0.279;0.473;0.521;0.194;#MCD
-0.043;-0.195;-0.151;0.216;0.270;0.227;0.411;0.206;#MMM
-0.036;-0.072;0.072;0.144;-0.072;-0.108;0.108;0.072;#MO
0.081;-0.081;0.027;0.081;-0.054;0.027;-0.027;-0.108;#MRK
0.083;0.083;0.041;0.331;0.083;0.248;0.166;0.041;#MSFT
0.049;0.000;0.243;0.680;0.194;0.243;0.340;0.097;#PFE
-0.045;0.060;0.104;0.015;-0.179;-0.149;-0.224;-0.224;#PG
0.097;-0.032;0.000;0.129;0.129;0.064;0.097;0.064;#T
-0.277;-0.440;-0.326;-0.358;-0.537;-0.619;-0.570;-0.733;#TRV
-0.081;-0.209;0.035;0.325;0.198;0.093;0.128;-0.035;#UTX
0.054;0.000;0.054;0.190;0.136;0.326;0.380;0.353;#VZ
-0.091;-0.091;-0.036;0.036;-0.072;0.000;0.145;-0.127;#WMT
-0.062;-0.211;0.087;0.198;0.186;0.050;0.347;0.508;#XOM

Nach dem Start von som.mq5 (ColorScheme=3, CellsX=30, CellsY=30, ImageXSize=200, ImageXSize=200, DataFileName="dj.csv") erhalten wir 8 Bilder, von denen jedes den Zeitintervallen 30, 60, 90, 120, 150, 180, 210 und 240 Minuten entspricht.

Die Kohonenkarten der Daten der Marktwachstumsrate (amerikanische Aktien) in den letzten 4 Stunden der Handelssitzung am 23. Mai 2011 sind in Abb. 21 dargestellt.

Abbildung 21. Kohonenkarten für amerikanische Aktien (letzte 4 Stunden der Handelssitzung am 23. Mai 2011).

Abbildung 21. Kohonenkarten für amerikanische Aktien (letzte 4 Stunden der Handelssitzung am 23. Mai 2011).

Aus Abb. 21 ist ersichtlich, dass die Dynamiken von #C (Citigroup Inc.), #T (AT&T Inc.), #JPM (JPMorgan Chase & Co) und #BAC (Bank of America) ähnlich sind. Sie wurden in einem langfristigen roten Cluster gruppiert.

In den letzten 1,5 Stunden (M30, M60, M90) wurden ihre Dynamiken grün, im Allgemeinen (M240) befanden sich die Aktien im roten Bereich.

Mithilfe von Kohonenkarten können wir die relativen Dynamiken von Aktien visualisieren und somit Gewinner und Verlierer und deren Umgebung finden. Elemente mit ähnlichen Daten bilden Cluster.

Wie wir in Abb. 21a sehen, war der Preis der Aktien von Citigroup Inc führend beim Fallen. Im Allgemeinen befanden sich alle Aktien von Finanzunternehmen im roten Bereich.

Abb. 21a Markt-Heatmap von 23. Mai 2011 (Quelle: http://finviz.com)

Abb. 21a Markt-Heatmap von 23. Mai 2011 (Quelle: http://finviz.com)

Auf ähnliche Weise können wir die Kohonenkarten des FOREX-Marktes berechnen (Abb. 22):

Abbildung 22. Kohonenkarte des FOREX-Marktes (24. Mai 2011, europäische Sitzung)

Abbildung 22. Kohonenkarte des FOREX-Marktes (24. Mai 2011, europäische Sitzung)

Es wurden die folgenden Paare verwendet: EURUSD, GBPUSD, USDCHF, USDJPY, USDCAD, AUDUSD, NZDUSD, USDSEK, AUDNZD, AUDCAD, AUDCHF, AUDJPY, CHFJPY, EURGBP, EURAUD, EURCHF, EURJPY, EURNZD, EURCAD, GBPCHF, GBPJPY, CADCHF. 

Die Wachstumsraten werden mithilfe des Scripts fx.mq5 in die Datei fx.csv exportiert.

M30;M60;M90;M120;M150;M180;M210;M240;Title
0.058;-0.145;0.045;-0.113;-0.038;-0.063;0.180;0.067;EURUSD
0.046;-0.100;0.078;0.094;0.167;0.048;0.123;0.160;GBPUSD
-0.048;0.109;-0.142;-0.097;-0.219;-0.143;-0.277;-0.236;USDCHF
0.042;0.097;0.043;-0.024;-0.009;-0.067;0.024;0.103;USDJPY
-0.045;0.162;0.155;0.239;0.217;0.246;0.157;0.227;USDCAD
0.095;-0.126;-0.018;-0.141;-0.113;-0.062;0.081;-0.005;AUDUSD
0.131;-0.028;0.167;0.096;-0.013;0.147;0.314;0.279;NZDUSD
-0.047;0.189;-0.016;0.107;0.084;0.076;-0.213;-0.133;USDSEK
-0.034;-0.067;-0.188;-0.227;-0.102;-0.225;-0.234;-0.291;AUDNZD
0.046;0.039;0.117;0.102;0.097;0.170;0.234;0.216;AUDCAD
0.057;-0.016;-0.158;-0.226;-0.328;-0.215;-0.180;-0.237;AUDCHF
0.134;-0.020;0.024;-0.139;-0.124;-0.127;0.107;0.098;AUDJPY
0.083;-0.009;0.184;0.084;0.208;0.082;0.311;0.340;CHFJPY
0.025;-0.036;-0.030;-0.200;-0.185;-0.072;0.058;-0.096;EURGBP
-0.036;-0.028;0.061;0.010;0.074;-0.006;0.088;0.070;EURAUD
0.008;-0.049;-0.098;-0.219;-0.259;-0.217;-0.094;-0.169;EURCHF
0.096;-0.043;0.085;-0.124;-0.049;-0.128;0.206;0.157;EURJPY
-0.073;-0.086;-0.119;-0.211;-0.016;-0.213;-0.128;-0.213;EURNZD
0.002;0.009;0.181;0.119;0.182;0.171;0.327;0.284;EURCAD
-0.008;0.004;-0.077;-0.015;-0.054;-0.127;-0.164;-0.080;GBPCHF
0.079;-0.005;0.115;0.079;0.148;-0.008;0.144;0.253;GBPJPY
0.013;-0.060;-0.294;-0.335;-0.432;-0.376;-0.356;-0.465;CADCHF

Zusätzlich zu den Preisen können Sie die Werte der Indikatoren in unterschiedlichen Timeframes benutzen.

2,6. Beispiel 6. Analyse der Optimierungsergebnisse

Der Strategietester des MetaTrader 5 Client Terminals liefert eine Möglichkeit, die Struktur des Parameterraums zu erforschen und den besten Satz der Strategieparameter zu finden. Sie können auch die Ergebnisse der Optimierung mithilfe der Option "Export to XML (MS Office Excel)" aus dem Kontextmenü der Registerkarte "Optimization Results" exportieren.

Die Testerstatistiken sind ebenfalls in den Ergebnissen der Optimierung enthalten (41 Spalten):

  1. Ergebnis
  2. Profit
  3. Gross Profit
  4. Gross Loss
  5. Withdrawal
  6. Expected Payoff
  7. Profit Factor
  8. Recovery Factor
  9. Sharpe Ratio
  10. Margin Level
  11. Custom
  12. Minimal Balance
  13. Balance DD Maximal
  14. Balance DD Maximal (%)
  15. Balance DD Relative
  16. Balance DD Relative (%)
  17. Minimal Equity
  18. Equity DD Maximal
  19. Equity DD Maximal (%)
  20. Equity DD Relative
  21. Equity DD Relative (%)
  22. Abschluss
  23. Abschlüsse
  24. Short Trades
  25. Profit Short Trades
  26. Long Trades
  27. Profit Long Trades
  28. Profit Trades
  29. Loss Trades
  30. Max profit trade
  31. Max loss trade
  32. Max consecutive wins
  33. Max consecutive wins ($)
  34. Max consecutive profit
  35. Max consecutive profit count    
  36. Max consecutive losses
  37. Max consecutive losses ($)
  38. Max consecutive loss
  39. Max consecutive loss count
  40. Avg consecutive wins
  41. Avg consecutive losses

Durch den Gebrauch der Testerstatistiken wird die Analyse des Parameterraums unterstützt. Wichtig ist, dass viele Parameter der Statistik eng miteinander verknüpft sind und von den Ergebnissen der Handelsperformance abhängen.

Beispielsweise haben die besten Handelsergebnisse die höchsten Werte bei den Parametern Profit, Profit Factor, Recovery Factor und Sharpe Ratio. Dies ermöglicht es uns, sie für die Analyse der Ergebnisse zu nutzen.

Ergebnisse der Optimierung des Expert Advisors MovingAverage.mq5

In diesem Kapitel betrachten wir die Analyse der Ergebnisse der Optimierung des Expert Advisors MovingAverage.mq5, der im Standardpaket des MetaTrader 5 Client Terminals enthalten ist. Dieser Expert Advisor basiert auf der Überkreuzung des Preises und des Indikators des gleitenden Mittelwerts. Er hat zwei Eingabeparameter: MovingPeriod und MovingShift, d. h. wir erhalten als Ergebnis eine XML-Datei mit 43 Spalten.

Wir werden nicht den 43-dimensionalen Parameterraum betrachten. Am interessantesten für uns sind:

  1. Profit;
  2. Profit Factor;
  3. Recovery Factor;
  4. Sharpe Ratio;
  5. Trades;
  6. ProfitTrades(%);
  7. MovingPeriod;
  8. MovingShift;

Beachten Sie, dass wir den Parameter ProfitTrades (%) hinzugefügt haben (fehlt in den Ergebnissen). Er steht für den prozentualen Anteil der gewinnbringenden Abschlüsse und ist das Ergebnis der Teilung von ProfitTrades (28) durch Trades (22), multipliziert mit 100.

Erstellen wir die Datei optim.csv mit 9 Spalten für 400 Sätze von Eingabeparametern des MetaTrader 5 Strategietesters.

Profit;Profit Factor;Recovery Factor;Sharpe Ratio;Trades;ProfitTrades(%);MovingPeriod;MovingShift;Title
-372.3;0.83;-0.51;-0.05;71;28.16901408;43;6;43
-345.79;0.84;-0.37;-0.05;66;27.27272727;50;6;50
...

Beachten Sie, dass wir den Wert von MovingPeriod als Spalte Title verwendet haben. Er wird zum "Markieren" der Muster in den Kohonenkarten genutzt.

Im Strategietester haben wir die Werte von MovingPeriod und MovingShift mit den folgenden Parametern optimiert:

Abbildung 23. Kohonenkarte der Ergebnisse der Optimierung des EA MovingAverage (Darstellung als Komponentenebene)

Abbildung 23. Kohonenkarte der Ergebnisse der Optimierung des EA MovingAverage (Darstellung als Komponentenebene)

Betrachten wir die Komponentenebenen der oberen Reihe (Profit, Profit Factor, Recovery Factor und Sharpe Ratio).

Sie werden in Abb. 24 kombiniert.

Abbildung 24. Komponentenebenen für die Parameter Profit, Profit Factor, Recovery Factor und Sharpe Ratio

Abbildung 24. Komponentenebenen für die Parameter Profit, Profit Factor, Recovery Factor und Sharpe Ratio

Als Erstes müssen wir die Regionen mit den besten Optimierungsergebnissen finden.

Aus Abb. 24 geht hervor, dass sich die Regionen mit den höchsten Werten in der linken oberen Ecke befinden. Die Zahlen entsprechen dem Mittelungszeitraum des Indikators des gleitenden Mittelwerts (Parameter MovingPeriod, den wir als Titel verwendet haben). Die Position der Zahlen ist bei allen Komponentenebenen gleich. Jede Komponentenebene hat ihren eigenen Wertebereich, die Werte werden im Farbverlaufs-Panel wiedergegeben.

Die besten Optimierungsergebnisse haben die höchsten Werte für Profit, Profit Factor, Recovery Factor und Sharpe Ratio. Somit verfügen wir über Informationen über die Regionen auf der Karte (skizziert in Abb. 24).

Die Komponentenebenen für Trades, ProfitTrades(%), MovingPeriod und MovingShift werden in Abb. 25 präsentiert.

Abbildung 25. Komponentenebenen für die Parameter Trades, ProfitTrades(%), MovingPeriod und MovingShift

Abbildung 25. Komponentenebenen für die Parameter Trades, ProfitTrades(%), MovingPeriod und MovingShift

Analyse der Komponentenebenen

Auf den ersten Blick gibt es keine interessanten Informationen. Die ersten 4 Komponentenebenen (Profit, Profit Factor, Recovery Factor und Sharpe Ratio) sehen ähnlich aus, weil sie direkt von der Performance des Handelssystems abhängig sind.

Aus Abb. 24 ist ersichtlich, dass der Bereich links oben sehr interessant ist (beispielsweise lassen sich die besten Ergebnisse erzielen, wenn wir MovingPeriod zwischen 45 und 50 festlegen).

Der Expert Advisor wurde auf einem stündlichen Timeframe von EURUSD getestet, seine Strategie war trendbasiert. Wir können diese Werte als "Trendgedächtnis" des Marktes betrachten. Falls diese Annahme wahr ist, entspricht das Trendgedächtnis des Marktes für die erste Jahreshälfte 2011 2 Tagen.

Betrachten wir die anderen Komponentenebenen.

Abbildung 26. Komponentenebenen von Trades-MovingPeriod

Abbildung 26. Komponentenebenen von Trades-MovingPeriod

Anhand von Abb. 26 können wir erkennen, dass geringere Werte von MovingPeriod (blaue Bereiche) zu höheren Werten von Trades (gelb-rote Bereiche) führen. Wenn der Zeitraum des gleitenden Mittelwerts kurz ist, gibt es viele Überkreuzungen (Abschlüsse).

Dies sehen wir auch in der Komponentenebene von Trades (grüne Bereiche mit Zahlen unter 20).

Abbildung 27. Komponentenebenen von Trades-MovingShift

Abbildung 27. Komponentenebenen von Trades-MovingShift

Die Menge der Abschlüsse sinkt (blaue Bereiche) mit steigendem MovingShift (gelb-rote Bereiche). Anhand des Vergleichs der Komponentenebenen von MovingShift und Abb. 24 sieht man, dass der Parameter MovingShift für die Performance dieser Handelsstrategie nicht sehr wichtig ist.

Der Anteil gewinnbringender Abschlüsse ProfitTrades(%) hängt nicht direkt von MovingPeriod oder MovingShift ab, sondern ist ein integrales Merkmal des Handelssystems. In anderen Worten: Die Analyse seiner Korrelation mit Eingangsparametern hat keine Bedeutung.

Komplexere Handelsstrategien können auf ähnliche Art analysiert werden. Sie müssen den/die wichtigsten Parameter Ihres Handelssystems finden und sie als Titel benutzen.



Fazit

Der wichtigste Vorteil der selbstorganisierenden Karten ist die Möglichkeit, hochdimensionale Daten zweidimensional und diskretisiert darzustellen. Daten mit ähnlichen Merkmalen formen Cluster, was die Analyse von Korrelationen vereinfacht.

Details und weitere Anwendungsmöglichkeiten finden Sie in dem hervorragenden Buch Visual Explorations in Finance: with Self-Organizing Maps von Guide Deboeck und Teuvo Kohonen.


Anhang

Nach der Veröffentlichung der russischen Version schlug Alex Sergeev eine verbesserte Version von Klassen vor (SOM_Alex-Sergeev_en.zip).

Änderungsliste:

1. Die Anzeige von Bildern hat sich geändert: cIntBMP::Show(int aX, int aY, string aBMPFileName, string aObjectName, bool aFromImages=true)
2. Funktion zum Öffnen des Verzeichnisses mit Bildern hinzugefügt:

#import "shell32.dll"
   int ShellExecuteW(int hwnd, string oper, string prog, string param, string dir, int show);
#import

input bool OpenAfterAnaliz=true; // open folder with maps after finish

Änderungen in der Klasse CSOM:

  1. Methode CSOM::HideChart hinzugefügt – blendet Diagramme aus.
  2. Klassenmitglieder m_chart, m_wnd, m_x0, m_y0 hinzugefügt – (Diagramm, Fenster und Koordinaten für die Anzeige von Bildern).
    + Präfix m_sID hinzugefügt – Objektnamen. Das Präfix nutzt den Dateinamen, standardmäßig wird das Präfix "SOM" verwendet.
  3. Alle Karten werden in den Ordner mit dem Namen m_sID gespeichert.
  4. Die Namen von bmp-Dateien werden anhand des Spaltennamen der Muster vergeben.
  5. Methode CSOM::ShowBMP angepasst (Karten werden in \Files anstatt \Images gespeichert, was viel schneller ist).
  6. CSOM::NetDeinit geändert in CSOM::HideBMP.
  7. Methode CSOM::ReadCSVData angepasst, die erste Spalte enthält Titel.
  8. Flag zum Anzeigen von Zwischenkarten in CSOM::Train(bool bShowProgress) hinzugefügt.
  9. Die Anzeige von Zwischenkarten in CSOM::Train wird alle 2 Sekunden ausgeführt (anstatt eines Durchlaufs), der Fortschritt wird mithilfe des Kommentars im Diagramm angezeigt.
  10. Namen einiger Variablen optimiert, Klassenmethoden nach Kategorie sortiert.

Die Zeichnung von bmp ist ein sehr langsamer Prozess. Wenn Sie es nicht wirklich brauchen, zeichnen Sie sie nicht jedes Mal.

Das Beispiel von SOM-Bildern mit Optimierungsergebnissen ist im Archiv beinhaltet.