English Русский 中文 Español 日本語 Português
Automatische Auswahl vielversprechender Signale

Automatische Auswahl vielversprechender Signale

MetaTrader 5Integration | 27 Februar 2018, 09:17
1 121 0
Alexander Fedosov
Alexander Fedosov

Einleitung

Automatisierter Handel an den Finanzmärkten ist das oberste Ziel der Entwicklung neuer Handelsroboter, denn der Markt ist schnelllebig. Dennoch können automatisierte Expert Advisors nicht alle Situationen auf dem Markt vorhersehen. Besonders effektiv ist und bleibt eine Symbiose zwischen einem Roboter und einem Menschen, der die Arbeit seiner automatisierter Systeme kontrolliert und korrigiert. Eine solche Kombination kann man im Signale-Service beobachten. Da werden Handelssysteme und Handelsmethoden mit unterschiedlichen Risikoparametern oder Handelsdynamik angeboten. Es gibt viele Werkzeuge im Service, die es erlauben, das gewünschte Signal zu finden. Aber wie kann man den Set von Parametern bestimmen, die genau Ihrem Trading-Stil passen? Es wäre ganz praktisch, einen Set von Parametern eines Handelssignals und deren Werte festzulegen, die einen riskanten, mäßigen und konservativen Handel kennzeichnen würden.

Modell zur Bewertung von Handelssignalen

Für eine umfassende Bewertung von Handelssignalen wurden fünf Kriterien ausgewählt. Jedes Kriterium wird nach einem 20-Punkte-System bewertet, wobei 0 — einen riskanten Handel, 20 — einen konservativen Handel charakterisieren. Jedes Handelssignal wird nach einem 100-Punkte-System bewertet. Als Kriterien werden folgende Charakteristiken verwendet.

1) Hebel des Handelskontos.

Wie bekannt, je höher der Hebel, desto höher das Risiko, einen wesentlichen Teil der Einlage bei Kursschwankungen zu verlieren. Aus diesem Grund werden folgende Werte eines 20-Punkte-Systems für die Bewertung des Hebels verwendet: 

  • 20 Punkte gibt es für den Hebel 1:1.
  • 0 Punkte gibt es für den Hebel 1:500 und höher.

Um ein Signal basierend auf dem angegeben Hebel zu bewerten, nutzen wir die folgende Gleichung einer Geraden:

wobei Xa = 1, Ya = 20, Xb = 500 und Yb = 0. Auf diese Weise bekommen wir die Gleichung einer Geraden durch zwei Punkte. In unserem Fall beschreibt sie die Abhängigkeit der Punktzahl nach einem 20-Punkte-System von dem aktuellen Hebelwert. 

Ich möchte noch einmal betonen, dass diese Abhängigkeit nur im vorgegebenen Bereich von 0 bis 20 gültig ist. D.h. auch wenn der Hebel höher als 1:500 sein wird (z.B. 1:1000), wird er sowieso 0 Punkte haben.

2) Wachstum in Prozent.

Um diese Kennzahl nach demselben 20-Punkte-System zu bewerten, muss man zwei Faktoren berücksichtigen. Erstens kann das Wachstum negativ sein. Zweitens ist es nicht ganz korrekt, seinen absoluten Wert zu bewerten. Deswegen führen wir folgende Regeln und Prämissen für diese Kennzahl ein.

  • Ein negatives Wachstum bedeutet, dass das zu bewertende Signal momentan Risiko aufweist, deswegen wird es mit 0 Punkten bewertet.
  • Wir bewerten nicht das absolute Wachstum, sondern seine Dynamik im Laufe der Zeit. Dafür teilen wir das Wachstum durch die Lebensdauer des Signals in Wochen.
  • Jeder hat eigene Begriffe für Risiko. Für einen sind 10% Wachstum pro Woche wenig, für den anderen — viel. Man sollte aber einen bestimmte Bereich festlegen. Sagen wir 1% Wachstum pro Woche ist der Referenzwert für ein konservatives Signal, 15% pro Woche werden als Grenzwert für einen riskanten Handel festgelegt.

Wir bedienen uns wieder der Formel der Gleichung einer Geraden über zwei Punkte, wobei Xa = 1, Ya = 20, und Xb = 15 und Yb = 0. Wir erhalten die folgende Abhängigkeit:

3) Maximaler Rückgang in Prozent.

Diese Kennzahl charakterisiert direkt das Handelsrisiko. Um die Grenzwerte zu bestimmen, führen wir folgende Regeln ein.

  • Ein Rückgang bis zu 20% einschließlich gilt als konservativer Handelsstil und wird mit 20 Punkten bewertet.
  • Ein Rückgang größer als 40% gilt als riskant und wird mit 0 Punkten bewertet.
  • Der maximale Rückgang im Bereich 20-40% wird basierend auf der Gleichung der Geraden bewertet, die durch zwei vorherigen Punkte vorgegeben wurde.  

In dieser Gleichung ist Xa = 20, Ya = 20, und jeweils Xb = 40 und Yb = 0. Wir erhalten die folgende Abhängigkeit:

4) ROI (Return on Investment) in Prozent.

Eine Rentabilität von Investitionen von über 100% bedeutet, dass das Geld effektiv genutzt wird. Wenn der Wert unter 100% liegt, heißt das, dass die Mittel ineffektiv verwendet werden. Bewerten wir diesen Indikator des Erfolgs nach dem 20-Punkte-System.

  • ROI kleiner als 100% wird mit 0 Punkten bewertet.
  • ROI größer als 200% wird mit 20 Punkten bewertet.
  • Der Bereich von 100 bis 200 wird basierend auf der Gleichung der Geraden bewertet, die durch zwei vorherigen Punkten vorgegeben wurde.

In dieser Gleichung sind Xa = 100, Ya = 0, und Xb = 200 und Yb = 20. Wir erhalten die folgende Abhängigkeit:

5) Lebensdauer des Handelssignals.

Die Lebensdauer eines Handelssignals ist eine sehr wichtige Kennzahl, die zeigt, ob das Signal im Allgemeinen richtig handelt. Um diese Kennzahl nach dem 20-Punkte-System zu bewerten, müssen wir zuerst die Zeitdauer definieren, die wir für verlässlich und vertrauenswürdig halten. Als Zeiteinheit nehmen wir Wochen, denn sie wurden bereits bei der Bewertung des Wachstums verwendet. Ich möchte betonen: diese Kennzahl ist sehr subjektiv, und jeder kann die Zeit-Kriterien für sich selbst auswählen. Wählen wir folgende Grenzwerte für unser konkretes System aus:

  • Eine Lebensdauer von unter 4 Wochen (Anzahl der vollen Wochen in einem Monat) bewerten wir mit 0 Punkten.
  • Eine Lebensdauer von über 25 Wochen (Anzahl der vollen in einem halben Jahr) bewerten wir mit 20 Punkten.
  • Das Intervall zwischen 4 und 25 Wochen wird basierend auf der Gleichung einer Geraden durch zwei vorherigen Punkte bewertet.  


Implementierung des Bewertungwerkzeuges

Es wurde die Entscheidung getroffen, die Bibliothek grafischer Interfaces EasyandFastGUI zu nutzen. Die Struktur der Anwendung sieht wie auf den Abbildungen 1 a und 1 b (s. unten) aus und beinhaltet folgende Elemente:

  • Eine Tabelle aller verfügbaren Signale für das aktuelle Handelskonto im Terminal.
  • Eine ausführliche Bewertung des ausgewählten Handelssignals nach Kategorien.
  • Die Anzahl verfügbarer Handelssignale für das aktuelle Handelskonto.
  • Eine visuelle Gesamtbewertung des in der Tabelle ausgewählten Handelssignals.


Abb.1a Struktur der Anwendung (der linke Teil)

Die Gesamtbewertung, die als eine Skala mit einem Farbverlauf dargestellt wird, bedeutet nicht, dass der linke Teil (der rote) ungünstige Signale und der grüne — vielversprechende Signale zeigt. Sie visualisiert nur den Trading-Stil eines konkreten Signals. Obwohl ein riskanter Handel mit höheren Risiken verbunden ist, impliziert er auch höhere Gewinne.


Abb.1b Die Struktur der Anwendung (rechter Teil)

Bei der Implementierung des Programms gehen wir auf die Schlüsselmethoden ein, die das Wesen der Anwendung darstellen. Die erste Methode ist CreateGUI(), die eine Zusammensetzung aller anderen Methoden darstellt und für die Ausgabe der ganzen visuellen Informationen verantwortlich ist.

  • Die Methode CreateWindow() erstellt das Fenster der Anwendung mit dem Kopfteil. Es gibt die Option, es zu schließen und seine Größe zu minimieren.
  • Die Methode CreateTable() erstellt eine Tabelle mit allen verfügbaren Signalen für das aktuelle Handelskonto.
  • Die Methode CreateStatusBar() erstellt eine Statusleiste, die die Anzahl verfügbarer Handelssignale anzeigt.
  • Die Methoden CreatePicture1() und CreatePicture2() erstellen jeweils eine Skala und einen Pointer auf diese Skala.
  • Die Methode CreateTextLabel() setzt die Anzeige ausführlicher Informationen über die Bewertung des ausgewählten Signals.
  • Die Methode CreateButton() erstellt einen Button für das Abonnieren des in der Tabelle ausgewählten Signals.
//+------------------------------------------------------------------+
//| Erstellt das grafische Interface des Programms                   |
//+------------------------------------------------------------------+
bool CProgram::CreateGUI(void)
  { 
//--- Erstellen eines Panels
   if(!CreateWindow("Auto Search Signal"))
      return(false);
//--- Erstellen einer Tabelle
   if(!CreateTable(7,100))
      return(false);
//--- Statusleiste
   if(!CreateStatusBar(1,26))
      return(false);
//--- Bilder
   if(!CreatePicture1(618,40))
      return(false);
   if(!CreatePicture2(610,80))
      return(false);
//--- Text-Label
   if(!CreateTextLabel1(20,20,"Punktzahl für Hebel: -"))
      return(false);
   if(!CreateTextLabel2(20,40,"Punktzahl für Wachstum: -"))
      return(false);
   if(!CreateTextLabel3(20,60,"Punktzahl für Rückgang: -"))
      return(false);
   if(!CreateTextLabel4(200,20,"Punktzahl für ROI: -"))
      return(false);
   if(!CreateTextLabel5(200,40,"Punktzahl für Lebensdauer: -"))
      return(false);
//--- Icon Buttons
   if(!CreateButton(440,40,"Abonnieren"))
      return(false);
//--- Die Erstellung des GUI beenden
   CWndEvents::CompletedGUI();
   return(true);
  }
//+-----------------------------------------------------------------


Die weitere Methode ist für die Interaktion verantwortlich: sie ermöglicht es, ein Handelssignal in der Liste der Tabelle auszuwählen und Informationen über dieses Handelssignal anzuzeigen. Darüber hinaus protokolliert sie das Ereignis eines Klicks auf den erstellten Button und des Abonnierens des in der Tabelle ausgewählten Signals.

//+------------------------------------------------------------------+
//| Event-Handler                                               |
//+------------------------------------------------------------------+
void CProgram::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
  { 
//--- Das Ereignis eines Klicks auf der Zeile einer Liste oder einer Tabelle
   if(id==CHARTEVENT_CUSTOM+ON_CLICK_LIST_ITEM)
     { 
      int x=610+3*int(m_table.GetValue(9,m_table.SelectedItem()));
      +//---+
      CreateTextLabel1(20,20,"Punktzahl für Hebel: "+IntegerToString(GetLeverageRating(int(m_table.GetValue(2,m_table.SelectedItem())))));
      CreateTextLabel2(20,40,"Punktzahl für Wachstum: "+IntegerToString(GetGainRating(int(m_table.GetValue(3,m_table.SelectedItem())),int(m_table.GetValue(8,m_table.SelectedItem())))));
      CreateTextLabel3(20,60,"Punktzahl für Rückgang: "+IntegerToString(GetDrawDownRating(int(m_table.GetValue(5,m_table.SelectedItem())))));
      CreateTextLabel4(200,20,"Punktzahl für ROI: "+IntegerToString(GetROIRating(int(m_table.GetValue(4,m_table.SelectedItem())))));
      CreateTextLabel5(200,40,"Punktzahl für Lebensdauer: "+IntegerToString(GetWeeksRating(int(m_table.GetValue(8,m_table.SelectedItem())))));
      CreatePicture2(x,80);
      +//---+
      m_button.IsLocked(false);
      Update(true);
     }
+//---+
   if(id==CHARTEVENT_CUSTOM+ON_CLICK_BUTTON)
     { 
      //--- Wenn man auf den Button geklickt hat
      if(lparam==m_button.Id())
        { 
         SignalSubscribe(long(m_table.GetValue(6,m_table.SelectedItem())));
        }
     }
  }

Als nächstes betrachten wir Methoden, die die Bewertung von Handelssignalen umsetzen. Zuerst muss man die Liste aller verfügbaren Handelssignale für das aktuelle Konto sowie alle benötigten Informationen erhalten, um diese anschließend in die Tabelle auszugeben und für die Gesamtbewertung zu verwenden.

Die Methode GetTradingSignals() ruft die ganzen Informationen über verfügbare Signale ab und fügt diese zu Datenarrays hinzu:

//+------------------------------------------------------------------+
//| Erhalten der Informationen über verfügbare Handelssignale              |
//+------------------------------------------------------------------+
bool CProgram::GetTradingSignals(void)
  { 
//--- Abfragen der Gesamtzahl der Signale in der Datenbank 
   m_signals_total=SignalBaseTotal();
+//---+
   ArrayResize(m_name,m_signals_total);
   ArrayResize(m_curr,m_signals_total);
   ArrayResize(m_leverage,m_signals_total);
   ArrayResize(m_gain,m_signals_total);
   ArrayResize(m_roi,m_signals_total);
   ArrayResize(m_max_drawdown,m_signals_total);
   ArrayResize(m_pips,m_signals_total);
   ArrayResize(m_subscr,m_signals_total);
   ArrayResize(m_weeks,m_signals_total);
   ArrayResize(m_rating,m_signals_total);
//--- Schleife durch alle Signale 
   for(int i=0;i<m_signals_total;i++)
     { 
      //--- Auswählen eines Signals für die weitere Arbeit 
      if(SignalBaseSelect(i))
        { 
         //--- Eigenschaften des Signals 
         m_name[i]=SignalBaseGetString(SIGNAL_BASE_NAME);                                                // Symbolname
         m_curr[i]=SignalBaseGetString(SIGNAL_BASE_CURRENCY);                                            // Währung des Signals
         m_leverage[i]=SignalBaseGetInteger(SIGNAL_BASE_LEVERAGE);                                       // Hebel
         m_gain[i]=SignalBaseGetDouble(SIGNAL_BASE_GAIN);                                                // Wachstum in %
         m_roi[i]=SignalBaseGetDouble(SIGNAL_BASE_ROI);                                                  // ROI
         m_max_drawdown[i]=SignalBaseGetDouble(SIGNAL_BASE_MAX_DRAWDOWN);                                // Maximaler Rückgang
         m_id[i]=SignalBaseGetInteger(SIGNAL_BASE_ID);                                                   // Signal-ID
         m_subscr[i]=SignalBaseGetInteger(SIGNAL_BASE_SUBSCRIBERS);                                      // Anzahl der Abonnenten 
         m_weeks[i]=int((TimeCurrent()-SignalBaseGetInteger(SIGNAL_BASE_DATE_PUBLISHED))/3600/24/7);     // Lebensdauer des Signals
         //--- Gesamtbewertung erhalten
         m_rating[i]=GetLeverageRating(m_leverage[i])+GetGainRating(m_gain[i],m_weeks[i])+GetDrawDownRating(m_max_drawdown[i])+GetROIRating(m_roi[i])+GetWeeksRating(m_weeks[i]);
        }
      else
        { 
         PrintFormat("Fehler bei der Auswahl des Signals. Fehlercode=%d",GetLastError());
         return(false);
        }
     }
   return (true);
  }
//+------------------------------------------------------------------+

Wie man im Listing oben sieht, werden die Daten der Gesamtbewertung für jedes Handelssignal dem Array m_rating[] hinzugefügt. Betrachten wir die Methoden, die bei der Berechnung verwendet werden. Sie stellen eine Implementierung des Modells aus dem ersten Abschnitt des Artikels dar.

//+------------------------------------------------------------------+
//| Bewertung des Hebels                                           |
//+------------------------------------------------------------------+
int CProgram::GetLeverageRating(long leverage)
  { 
   int lev_rating=int(-20.0/499.0*double(leverage)+10000.0/499.0);
   lev_rating=(lev_rating>20)?20:lev_rating;
   return lev_rating;
  }
//+------------------------------------------------------------------+
//| Bewertung des Wachstums                                                  |
//+------------------------------------------------------------------+
int CProgram::GetGainRating(double gain,int weeks)
  { 
   weeks=(weeks==0)?1:weeks;
   int gain_rating=int(-10*(gain/double(weeks)/7.0)+150.0/7.0);
   gain_rating=(gain_rating>20)?20:gain_rating;
   gain_rating=(gain_rating<0)?0:gain_rating;
   gain_rating=(gain<0)?0:gain_rating;
   return gain_rating;
  }
//+------------------------------------------------------------------+
//| Bewertung des maximalen Rückgangs                                     |
//+------------------------------------------------------------------+
int CProgram::GetDrawDownRating(double max_drawdown)
  { 
   int drawdn_rating=int(-max_drawdown+40);
   drawdn_rating=(drawdn_rating>20)?20:drawdn_rating;
   drawdn_rating=(drawdn_rating<0)?0:drawdn_rating;
   return drawdn_rating;
  }
//+------------------------------------------------------------------+
//| Bewertung von ROI                                                       |
//+------------------------------------------------------------------+
int CProgram::GetROIRating(double roi)
  { 
   int roi_rating=int(0.2*roi-20);
   roi_rating=(roi_rating>20)?20:roi_rating;
   roi_rating=(roi_rating<0)?0:roi_rating;
   return roi_rating;
  }
//+------------------------------------------------------------------+
//| Bewertung der Lebensdauer                                 |
//+------------------------------------------------------------------+
int CProgram::GetWeeksRating(int weeks)
  { 
   int age_rating=int(20.0*double(weeks)/21.0-80.0/21.0);
   age_rating=(age_rating>20)?20:age_rating;
   age_rating=(age_rating<0)?0:age_rating;
   return age_rating;
  }

Danach werden alle erhaltenen Daten mithilfe der Methode InitializingTable() in eine Tabelle eingefügt und mithilfe der Methode CreateTable() visualisiert.

//+------------------------------------------------------------------+
//| Initialisierung der Tabelle                                           |
//+------------------------------------------------------------------+
void CProgram::InitializingTable(void)
  { 
+//---+
   string columns[10]=
     { 
      "Signalname",
      "Kontowährung",
      "Hebel auf dem Konto",
      "Wachstum, %",
      "ROI",
      "Max. Rückgang",
      "Signal-ID",
      "Anzahl der Abonnenten",
      "Lebensdauer, Wochen",
      "Bewertung"
     };
+//---+
   for(int c=0; c<COLUMNS1_TOTAL; c++)
     { 
      //--- Text der Headers setzen
      m_table.SetHeaderText(c,columns[c]);
      +//---+
      for(int r=0; r<m_signals_total; r++)
        { 
         if(c==0)
            m_table.SetValue(c,r,m_name[r]);
         else if(c==1)
            m_table.SetValue(c,r,m_curr[r]);
         else if(c==2)
            m_table.SetValue(c,r,IntegerToString(m_leverage[r]));
         else if(c==3)
            m_table.SetValue(c,r,DoubleToString(m_gain[r],2));
         else if(c==4)
            m_table.SetValue(c,r,DoubleToString(m_roi[r],2));
         else if(c==5)
            m_table.SetValue(c,r,DoubleToString(m_max_drawdown[r],2));
         else if(c==6)
            m_table.SetValue(c,r,IntegerToString(m_id[r]));
         else if(c==7)
            m_table.SetValue(c,r,IntegerToString(m_subscr[r]));
         else if(c==8)
            m_table.SetValue(c,r,IntegerToString(m_weeks[r]));
         else if(c==9)
            m_table.SetValue(c,r,IntegerToString(m_rating[r]));
        }
     }
  }
//+------------------------------------------------------------------+
//| Erstellt eine Tabelle                                   |
//+------------------------------------------------------------------+
#resource "\\Images\\EasyAndFastGUI\\Icons\\bmp16\\arrow_up.bmp"
#resource "\\Images\\EasyAndFastGUI\\Icons\\bmp16\\arrow_down.bmp"
#resource "\\Images\\EasyAndFastGUI\\Icons\\bmp16\\circle_gray.bmp"
#resource "\\Images\\EasyAndFastGUI\\Icons\\bmp16\\calendar.bmp"
+//---+
bool CProgram::CreateTable(const int x_gap,const int y_gap)
  { 
#define COLUMNS1_TOTAL 10
//--- Speichern des Pointers auf das Hauptelement
   m_table.MainPointer(m_window);
//--- Array für die Breite von Spalten
   int width[COLUMNS1_TOTAL];
   ::ArrayInitialize(width,110);
   width[1]=80;
   width[2]=100;
   width[4]=90;
   width[8]=85;
   width[9]=90;
//--- Array für den Einzug des Textes in Spalten auf der X-Achse
   int text_x_offset[COLUMNS1_TOTAL];
   ::ArrayInitialize(text_x_offset,7);
//--- Array für die Ausrichtung des Textes in Spalten
   ENUM_ALIGN_MODE align[COLUMNS1_TOTAL];
   ::ArrayInitialize(align,ALIGN_CENTER);
+//---+
   GetTradingSignals();
//--- Eigenschaften
   m_table.XSize(1000);
   m_table.YSize(470);
   m_table.CellYSize(20);
   m_table.TableSize(COLUMNS1_TOTAL,m_signals_total);
   m_table.TextAlign(align);
   m_table.ColumnsWidth(width);
   m_table.TextXOffset(text_x_offset);
   m_table.LabelXGap(5);
   m_table.LabelYGap(4);
   m_table.IconXGap(7);
   m_table.IconYGap(4);
   m_table.MinColumnWidth(0);
   m_table.ShowHeaders(true);
   m_table.IsSortMode(true);
   m_table.LightsHover(true);
   m_table.SelectableRow(true);
   m_table.IsWithoutDeselect(true);
   m_table.ColumnResizeMode(true);
   m_table.IsZebraFormatRows(clrWhiteSmoke);
   m_table.AutoXResizeMode(true);
   m_table.AutoXResizeRightOffset(7);
   m_table.AutoYResizeBottomOffset(28);
   m_table.HeadersColor(clrSkyBlue);
   m_table.DataType(2,TYPE_INT);
   m_table.DataType(3,TYPE_FLOAT);
   m_table.DataType(4,TYPE_FLOAT);
   m_table.DataType(5,TYPE_FLOAT);
   m_table.DataType(6,TYPE_INT);
   m_table.DataType(7,TYPE_INT);
   m_table.DataType(8,TYPE_INT);
   m_table.DataType(9,TYPE_INT);

//--- Füllen der Tabelle mit den Daten
   InitializingTable();
//--- Erstellen eines Steuerelements
   if(!m_table.CreateTable(x_gap,y_gap))
      return(false);
//--- Hinzufügen des Objekts dem gemeinsamen Array für Objektgruppen
   CWndContainer::AddToElementsArray(0,m_table);
   m_table.SortData(9);
   m_table.SortData(9);
   return(true);
  }

Für eine bequeme Nutzung der Daten aus der Tabelle von Handelssignalen sollte man den angezeigten Zellen Datentypen zuweisen. Dies wird benötigt, damit die Daten in den Spalten richtig sortiert werden. Für eine bessere visuelle Darstellung wird die anfängliche Sortierung absteigend nach der letzten Spalte durchgeführt, d.h. nach der Gesamtbewertung eines Signals. Es wird zweimal sortiert: zuerst absteigend, und dann in die entgegengesetzte Richtung.

Das letzte Element, auf das wir eingehen, ist die visuelle Darstellung der Gesamtbewertung als eine Skala mit Farbverlauf. Dafür sind zwei Methoden verantwortlich, deren Listing unten angeführt sind. Die Änderung der Position des Pointers auf der Skala wurde bereits in der Methode OnEvent() oben beschrieben.

//+------------------------------------------------------------------+
//| Erstellt eine Skala mit Farbverlauf                                |
//+------------------------------------------------------------------+
#resource "\\Images\\EasyAndFastGUI\\Icons\\bmp64\\000.bmp"
#resource "\\Images\\EasyAndFastGUI\\Controls\\ArrowUp_blue.bmp"
+//---+
bool CProgram::CreatePicture1(const int x_gap,const int y_gap)
  { 
//--- Speichern des Pointers auf das Hauptelement
   m_picture1.MainPointer(m_window);
//--- Eigenschaften
   m_picture1.XSize(300);
   m_picture1.YSize(40);
   m_picture1.IconFile("Images\\EasyAndFastGUI\\Icons\\bmp64\\000.bmp");
//--- Erstellen eines Buttons
   if(!m_picture1.CreatePicture(x_gap,y_gap))
      return(false);
//--- Hinzufügen eines Pointers auf das Element zur Datenbank
   CWndContainer::AddToElementsArray(0,m_picture1);
   return(true);
  }
//+------------------------------------------------------------------+
//| Erstellt einen Pointer für die Skala                                      |
//+------------------------------------------------------------------+
bool CProgram::CreatePicture2(const int x_gap,const int y_gap)
  { 
//--- Speichern des Pointers auf das Hauptelement
   m_picture2.MainPointer(m_window);
//--- Eigenschaften
   m_picture2.XSize(16);
   m_picture2.YSize(16);
   m_picture2.IconFile("Images\\EasyAndFastGUI\\Controls\\ArrowUp_blue.bmp");
//--- Erstellen eines Buttons
   if(!m_picture2.CreatePicture(x_gap,y_gap))
      return(false);
//--- Hinzufügen eines Pointers auf das Element zur Datenbank
   CWndContainer::AddToElementsArray(0,m_picture2);
   return(true);
  }


Auswahl vielversprechender Signale

Wenn wir ein Signal auswählen und seine Perspektiven einschätzen, erwarten wir, dass ein gutes Signal bestimmte Ergebnisse in der Zukunft erzielen wird. Die Praxis zeigt, dass Signale, die eine hohe Wachstumsrate innerhalb einer kurzen Zeit zeigen, eine kurze Lebensdauer haben. Das ist damit verbunden, dass hoch riskante Handelsstrategien für das Erzielen hoher Profite am häufigsten verwendet werden. Nichtsdestotrotz ist es nicht gerecht, Handelssignale mit einem riskanten Trading-Stil von der Liste der vielversprechenden zu streichen, denn jeder Händler hat eigene Ziele. Der eine hat vor, lange im Markt zu sein und langsam Geld zu verdienen, der andere braucht Profite schnell und ist bereit, ein bestimmtes Risiko einzugehen. 

Teilen wir das von uns entwickelte Bewertungssystem für Signale visuell in drei Kategorien auf (Abb.2).

  • Erste Kategorie. Roter Bereich. Handelssignale in diesem Bereich können eine hohe Rentabilität aufweisen, gehen aber mit hohen Risiken einher.
  • Zweite Kategorie. Gelber Bereich. Signale in diesem Bereich sind erfolgversprechend dank einer guten Rentabilität bei mittlerem Risiko.
  • Dritte Kategorie. Grüner Bereich. Diese Signale gelten als vielversprechend, denn sie sind verlässlich, ihre Rentabilität ist aber nicht sehr hoch.

Abb.2 Kategorien der Bewertungsskala für Handelssignale

Um diese Kategorisierung zu programmieren, fügen wir der Methode InitializingTable() folgende Zeilen hinzu:

//+------------------------------------------------------------------+
//| Initialisierung der Tabelle                                           |
//+------------------------------------------------------------------+
void CProgram::InitializingTable(void)
  { 
+//---+
   string columns[10]=
     { 
      "Signalname",
      "Kontowährung",
      "Hebel auf dem Konto",
      "Wachstum, %",
      "ROI",
      "Max. Rückgang",
      "Signal-ID",
      "Anzahl der Abonnenten",
      "Lebensdauer, Wochen",
      "Bewertung"
     };
+//---+
   for(int c=0; c<COLUMNS1_TOTAL; c++)
     { 
      //--- Text der Headers setzen
      m_table.SetHeaderText(c,columns[c]);

      +//---+
      for(int r=0; r<m_signals_total; r++)
        { 
         if(c==0)
           { 
            m_table.SetValue(c,r,m_name[r]);
            if(m_rating[r]<=30)
               m_table.TextColor(c,r,clrCrimson);
            else if(m_rating[r]>30 && m_rating[r]<=66)
               m_table.TextColor(c,r,clrOrange);
            else if(m_rating[r]>66)
               m_table.TextColor(c,r,clrForestGreen);
           }
         else if(c==1)
            m_table.SetValue(c,r,m_curr[r]);
         else if(c==2)
            m_table.SetValue(c,r,IntegerToString(m_leverage[r]));
         else if(c==3)
            m_table.SetValue(c,r,DoubleToString(m_gain[r],2));
         else if(c==4)
            m_table.SetValue(c,r,DoubleToString(m_roi[r],2));
         else if(c==5)
            m_table.SetValue(c,r,DoubleToString(m_max_drawdown[r],2));
         else if(c==6)
            m_table.SetValue(c,r,IntegerToString(m_id[r]));
         else if(c==7)
            m_table.SetValue(c,r,IntegerToString(m_subscr[r]));
         else if(c==8)
            m_table.SetValue(c,r,IntegerToString(m_weeks[r]));
         else if(c==9)
            m_table.SetValue(c,r,IntegerToString(m_rating[r]));
        }
     }
  }

Mithilfe der Methode TextColor() ändern wir die Farbe des Namens des Signals (die erste Spalte) basierend auf den erhaltenen Bewertungsergebnissen. So kann man sehen, zu welcher Kategorie das Signal gehört, auch ohne es zu analysieren oder sich die letzte Spalte der Tabelle anzuschauen, die die Punktzahlen beinhaltet.

Abb.3 Farbanzeige von Handelssignalen

Signale können in Kategorien eingeteilt werden, indem man die Tabelle nach der letzten Spalte sortiert. Standardmäßig ist diese Sortierung aktiviert. Die letzte logische Aktion ist die Option zu implementieren, ein Signal zu abonnieren. Dafür ist die Methode CreateButton() verantwortlich:

//+------------------------------------------------------------------+
//| Erstellt einen Button mit einem Bild                                       |
//+------------------------------------------------------------------+
#resource "\\Images\\EasyAndFastGUI\\Icons\\bmp16\\start.bmp"
+//---+
bool CProgram::CreateButton(const int x_gap,const int y_gap,const string text)
  { 
//--- Speichern des Pointers auf das Hauptelement
   m_button.MainPointer(m_window);
//--- Eigenschaften
   m_button.XSize(120);
   m_button.YSize(22);
   m_button.IconXGap(3);
   m_button.IconYGap(3);
   m_button.FontSize(10);
   m_button.IsCenterText(true);
   m_button.IconFile("Images\\EasyAndFastGUI\\Icons\\bmp16\\start.bmp");
   m_button.IsLocked(true);
//--- Erstellen eines Steuerelements
   if(!m_button.CreateButton(text,x_gap,y_gap))
      return(false);
//--- Hinzufügen eines Pointers auf das Element zur Datenbank
   CWndContainer::AddToElementsArray(0,m_button);
   return(true);
  }
//+------------------------------------------------------------------+

Damit Sie eventuelle Fehler bei der Nutzung der oben entwickelten Funktionalität vermeiden, weisen wir Sie auf die benötigten Voreinstellungen des Terminals hin.

1. Um mit Handelssignalen im MetaTrader 5 Terminal zu arbeiten, müssen Sie sich in Ihren mql5-Account einloggen:

Abb.4 Autorisierung im Terminal

2. Beim Starten der Anwendung muss die Option Änderung der Signaleinstellungen erlauben aktiviert werden. Sonst wird das Abonnement für ein Signal den Fehler 4014 ("Funktion darf nicht aufgerufen werden") zurückgeben.

Abb.5 Einstellungen beim Start der Anwendung

3. Und das letzte, was den Betrieb der Anwendung beeinträchtigen kann, ist die Datei signals.dat. Wenn die Daten in der Tabelle inkorrekt angezeigt werden oder gar fehlen, sollte man diese Datei unter C:\Users\Computer name\AppData\Roaming\MetaQuotes\Terminal\..\bases\signals finden und löschen. Danach starten Sie das Terminal neu und eröffnen Sie den Signale-Reiter, wie auf der Abb. 6. Eine neue Datei wird automatisch generiert, danach kann man die Anwendung starten und nutzen.

Abb.6 Der Signale-Reiter im MetaTrader 5 Terminal

Im Unterschied zum Bereich "Signale" auf der Webseite werden im Terminal nicht alle Signale angezeigt, sondern nur die, die für das aktuelle Handelskonto geeignet sind. 


Fazit

Im Artikel wurde ein einfaches Bewertungssystem basierend auf Punktzahlen für verschiedene Charakteristiken der Handelssignale entwickelt. Das System bietet ein 100-Punkte-System für die Bewertung des Trading-Stils. Basierend auf dieser Bewertung wurden alle verfügbaren Signale, die sich durch Aussichten, Risiken, Lebensdauer und Wachstum in Prozent voneinander unterscheiden, in drei Kategorien aufgeteilt.

Die beigefügte Datei enthält alle aufgelisteten Dateien, die sich bereits in den entsprechenden Ordnern befinden. Für ein reibungsloses Funktionieren müssen Sie nur den MQL5-Ordner im Wurzelverzeichnis des Terminals speichern. Hier wird die Bibliothek des grafischen Interfaces EasyAndFastGUI aus dem einschlägigen Artikel verwendet. Die Bibliothek wurde leicht geändert, deswegen finden Sie sie auch im Anhang.

Die Programme dieses Artikels:

#
 Name
Typ
Beschreibung
1
AutoSearch.mq5 Expert Advisor
 Anwendung für eine automatische Auswahl vielversprechender Signale
2
Program.mqh Bibliothek  Klasse für die Erstellung der Anwendung
3
MainWindow.mqh Bibliothek  Ein Set von Methoden, die für die Erstellung der Anwendung verwendet werden


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

Beigefügte Dateien |
MQL5.zip (1631.66 KB)
Automatisches Erstellen von Unterstützung- und Widerstandslinien Automatisches Erstellen von Unterstützung- und Widerstandslinien
Der Artikel beschäftigt sich mit der automatischen Konstruktion von Unterstützungs-/Widerstandslinien unter Verwendung aktueller Hochs und Tiefs. Zur Definition dieser Extremwerte wird der bekannte ZigZag-Indikator verwendet.
Testen von Mustern, die beim Handel mit Währungskörben entstehen. Teil III Testen von Mustern, die beim Handel mit Währungskörben entstehen. Teil III
In diesem Artikel beenden wir die Tests der Muster, die beim Handel mit Währungskörben erkannt werden können. Hier präsentieren wir Ihnen die Ergebnisse der Tests der Muster, die die Bewegungen der Währungen des Paares relativ zueinander verfolgen.
Individuell Strategien testen basierend auf schnellen mathematischen Berechnungen Individuell Strategien testen basierend auf schnellen mathematischen Berechnungen
Der Artikel beschreibt die Art und Weise, wie man Strategien individuell testen und einen benutzerdefinierten Analysator für die Optimierungsdurchläufe erstellt. Nach dem Lesen werden Sie verstehen, wie die "Mathematische Berechnung" und der Mechanismus der sogenannten Frames funktionieren, wie Sie benutzerdefinierte Daten für Berechnungen vorbereiten und laden und effektive Algorithmen für ihre Komprimierung verwenden. Dieser Artikel wird auch für diejenigen interessant sein, die an Möglichkeiten interessiert sind, benutzerdefinierte Informationen innerhalb eines Experten zu speichern.
Muster von Ausbrüchen aus einem Kanal Muster von Ausbrüchen aus einem Kanal
Kursverläufe bilden Preiskanäle, die auf dem Chart des Finanzsymbols beobachtet werden können. Der Ausbruch aus einem aktuellen Kanal ist ein starkes Signal einer Trendwende. In diesem Artikel schlage ich eine Möglichkeit vor, den Prozess der Suche nach solchen Signalen zu automatisieren und zu sehen, ob die Muster eines Kanalausbruchs für die Erstellung einer Handelsstrategie verwendet werden kann.