Hilfen zur Auswahl und Navigation in MQL5 und MQL4: Hinzufügen von Daten zum Chart

30 Mai 2019, 08:48
Roman Klymenko
0
297

Einführung

Wir haben bereits viel in den vorherigen Artikeln getan (Auswahl- und Navigationsprogramm in MQL5 und MQL4: Hinzufügen einer automatischen Suche nach Mustern und das Darstellen der gefundenen Symbole, Hilfen zur Auswahl und Navigation in MQL5 und MQL4: Tabs für "Hausaufgaben" und das Sichern grafischer Objekte, Entwicklung eines Symbolauswahl- und Navigationsprogramms in MQL5 und MQL4). Aber das ist immer noch nicht genug für einen qualitativ hochwertigen Intraday-Handel. In diesem Artikel werden wir neue Funktionen hinzufügen, die es uns ermöglichen, geeignete Markteintritts-/Exitpunkte zu finden.

Jedes Funktionselement wird in einem separaten Abschnitt beschrieben. Zunächst werden wir uns mit dem Ziel befassen. Dann analysieren wir eine Funktion oder einen Code, falls Sie die gleiche Funktionalität in Ihren Projekten implementieren wollen.


Ausblenden der Symbole, deren heutiger Trend sich vom gestrigen unterscheidet.

Eingabe: Verbergen, wenn der aktuelle Trend != gestrigem
Bereich: Sortiereinstellungen

Viele Gurus des Intraday-Handels empfehlen den Handel mit Aktien, deren heutiger Trend der gleiche ist wie der von gestern. Einfach ausgedrückt, wenn der Aktienkurs gestern gestiegen ist, dann sollte er heute auch steigen, was bedeutet, dass Sie an diesem Tag nur kaufen sollten und umgekehrt.

Mit der folgenden Funktion können Sie die Symbole danach klassifizieren:

/*
Rückgabe von 'true', wenn der heutige Trend nicht mit dem gestrigen übereinstimmt.
symname - verwendeter Symbolname
*/
bool check_no_trend(string symname){
   MqlRates rates2[];
   ArraySetAsSeries(rates2, true);
   if(CopyRates(symname, PERIOD_D1, 0, 2, rates2)==2){
      if( rates2[0].close>rates2[0].open && rates2[1].close>rates2[1].open ){
         return false;
      }
      if( rates2[0].close<rates2[0].open && rates2[1].close<rates2[1].open ){
         return false;
      }
   }
   return true;
}


Anzeigen des Sitzungsbeginns

Eingabe: Anzeige des Tagesbeginns (auf Zeitrahmen <D1)
Bereich: Chart-Einstellungen

Der Beginn einer Handelssitzung ist ein Zeitpunkt, zu dem die Aktienmärkte geöffnet werden (wenn wir über Aktien sprechen), z.B. 16:30 Uhr für den amerikanischen Aktienmarkt und 10:00 Uhr für den europäischen und russischen. Im Falle von Forex betrachten wir Mitternacht als Beginn einer Handelssitzung.

In niedrigeren Zeitrahmen, wie z.B. M5, kann es schwierig sein, den Beginn der aktuellen Sitzung zu definieren, um z.B. auf einen Blick zu sehen, ob eine Aktie heute steigt oder fällt. Wir werden also eine Einstellung hinzufügen, die es uns ermöglicht, einen Balken zu sehen, von dem aus der aktuelle Handelstag auf einem Symbol begonnen hat.

Die Funktion für die Anzeige des Sitzungsstarts:

/*
Anzeigen des Tagesbeginns auf dem Chart.
currChart - Chart-ID
day - Nummer des Tages (0 - heute)
*/
void showNdays(long currChart, int day){
   MqlRates rates[];
   ArraySetAsSeries(rates, true);
   if(CopyRates(ChartSymbol(currChart), PERIOD_D1, day, 1, rates)>0){
      ObjectCreate(currChart, exprefix+"_Nday", OBJ_VLINE, 0, rates[0].time, 0);
      ObjectSetInteger(currChart,exprefix+"_Nday",OBJPROP_STYLE,STYLE_DOT);
      ObjectSetInteger(currChart,exprefix+"_Nday",OBJPROP_RAY,true); 
      ObjectSetInteger(currChart,exprefix+"_Nday",OBJPROP_SELECTABLE,false); 
      ObjectSetInteger(currChart,exprefix+"_Nday",OBJPROP_BACK,true); 
   }
}

Auf dem Chart wird damit eine rote Linie gezeichnet:

Anzeigen des Sitzungsbeginns

Etwas Ähnliches existiert bereits für den MetaTrader. Sie sehen aber nicht nur den Beginn der letzten Sitzung, sondern den Beginn von jeder Sitzung. Aktivieren Sie dazu das Kontrollkästchen "Periodentrennung anzeigen" in den Chart-Eigenschaften. In der Praxis und für bestimmte Zeitrahmen ist diese Funktion redundant und überlädt das Chart und erschwert die Analyse. Zum Beispiel:

Darstellung der Session-Trennung


Darstellung der gestrigen und der vorgestrigen Tiefst- und Höchstwerte

Eingabe: Darstellung des Tiefst- und des Höchstwerts von gestern und Darstellung des Tiefst- und des Höchstwerts von vorgestern
Bereich: Chart-Einstellungen

Beim Intraday-Handel werden die Höchst- und Tiefstkurse von gestern und vorgestern oft als Unterstützungs- und Widerstandswerte verwendet. Der Preis fällt oft, trifft das gestrige oder das vorgestrige Hoch und erholt sich wieder. Nach meiner Erfahrung durchbricht der Preis in 70% der Fälle solche Höchst-/Tiefststände nicht.

Daher sollten diese Werte nicht vernachlässigt werden.

Die folgende Funktion dient zur Darstellung von Hoch und Tief eines ausgewählten Tages:

/*
Darstellung der Tiefst- und Höchstwerte des angegebenen Tages in der Grafik
currChart - Chart-ID
day - angezeigter Tagesindex
*/
void showHOBeforeDay(long currChart, int day=1){
   MqlRates rates[];
   ArraySetAsSeries(rates, true);
   
   color curColor=clrAquamarine;
   switch(day){
      case 2:
         curColor=clrOlive;
         break;
   }
   
   if(CopyRates(ChartSymbol(currChart), PERIOD_D1, day, 1, rates)>0){
      ObjectCreate(currChart, exprefix+"_beforeday_high_line"+(string) day, OBJ_HLINE, 0, 0, rates[0].high);
      ObjectSetInteger(currChart,exprefix+"_beforeday_high_line"+(string) day,OBJPROP_COLOR,curColor); 
      ObjectSetInteger(currChart,exprefix+"_beforeday_high_line"+(string) day,OBJPROP_SELECTABLE,false); 
      ObjectSetInteger(currChart,exprefix+"_beforeday_high_line"+(string) day,OBJPROP_BACK,true); 
      
      ObjectCreate(currChart, exprefix+"_beforeday_low_line"+(string) day, OBJ_HLINE, 0, 0, rates[0].low);
      ObjectSetInteger(currChart,exprefix+"_beforeday_low_line"+(string) day,OBJPROP_COLOR,curColor); 
      ObjectSetInteger(currChart,exprefix+"_beforeday_low_line"+(string) day,OBJPROP_SELECTABLE,false); 
      ObjectSetInteger(currChart,exprefix+"_beforeday_low_line"+(string) day,OBJPROP_BACK,true); 
   }
}

Die Werte von gestern werden als helle horizontale Linien angezeigt, während die von vorgestern als moosgrüne Linien angezeigt werden:

Darstellung der gestrigen/vorvorigen Tiefststände und Höchststände


Anzeigen der nächstgelegenen runden Preise

Eingabe: Darstellung der nächstgelegenen runden Preise (Zeitraum < 1 Tag)
Bereich: Chart-Einstellungen

Gerundete Preise sind ein weiteres natürliches Unterstützungs-/Widerstandsniveau. Dies sind die Preise, die mit .00 oder .50 enden. Viele Händler suchen Handelsmöglichkeiten nur in der Nähe der Rundungsniveaus.

Die .25- und .75- Niveaus können auch als rund angesehen werden, aber sie sind weniger zuverlässig, deshalb werden wir sie nicht verfolgen, um das Chart nicht zu überladen.

Die folgende Funktion dient der Darstellung der runden Preise:

/*
Zeigt drei nächstgelegene Rundungsniveaus des aktuellen Preises an.
currChart - Chart-ID
*/
void showRoundPrice(long currChart){
   string name=ChartSymbol(currChart);
   int tmpPrice;
   
   MqlRates rates[];
   ArraySetAsSeries(rates, true);
   if(CopyRates(name, PERIOD_D1, 0, 1, rates)==1){
      switch((int) SymbolInfoInteger(name, SYMBOL_DIGITS)){
         case 0:
            break;
         case 2:
         case 3:
         case 5:
            tmpPrice=(int) rates[0].close;

            ObjectCreate(currChart, exprefix+"_round_line_00_0", OBJ_HLINE, 0, 0, (double) tmpPrice-1 );
            ObjectSetInteger(currChart,exprefix+"_round_line_00_0",OBJPROP_COLOR,clrCadetBlue); 
            ObjectSetInteger(currChart,exprefix+"_round_line_00_0",OBJPROP_STYLE, STYLE_DASH); 
            ObjectSetInteger(currChart,exprefix+"_round_line_00_0",OBJPROP_SELECTABLE,false); 
            ObjectSetInteger(currChart,exprefix+"_round_line_00_0",OBJPROP_BACK,true); 

            ObjectCreate(currChart, exprefix+"_round_line_05_0", OBJ_HLINE, 0, 0, (double) tmpPrice-0.5 );
            ObjectSetInteger(currChart,exprefix+"_round_line_05_0",OBJPROP_COLOR,clrCadetBlue); 
            ObjectSetInteger(currChart,exprefix+"_round_line_05_0",OBJPROP_STYLE, STYLE_DASH); 
            ObjectSetInteger(currChart,exprefix+"_round_line_05_0",OBJPROP_SELECTABLE,false); 
            ObjectSetInteger(currChart,exprefix+"_round_line_05_0",OBJPROP_BACK,true); 
            
            ObjectCreate(currChart, exprefix+"_round_line_00_1", OBJ_HLINE, 0, 0, (double) tmpPrice );
            ObjectSetInteger(currChart,exprefix+"_round_line_00_1",OBJPROP_COLOR,clrCadetBlue); 
            ObjectSetInteger(currChart,exprefix+"_round_line_00_1",OBJPROP_STYLE, STYLE_DASH); 
            ObjectSetInteger(currChart,exprefix+"_round_line_00_1",OBJPROP_SELECTABLE,false); 
            ObjectSetInteger(currChart,exprefix+"_round_line_00_1",OBJPROP_BACK,true); 

            ObjectCreate(currChart, exprefix+"_round_line_05_1", OBJ_HLINE, 0, 0, (double) tmpPrice+0.5 );
            ObjectSetInteger(currChart,exprefix+"_round_line_05_1",OBJPROP_COLOR,clrCadetBlue); 
            ObjectSetInteger(currChart,exprefix+"_round_line_05_1",OBJPROP_STYLE, STYLE_DASH); 
            ObjectSetInteger(currChart,exprefix+"_round_line_05_1",OBJPROP_SELECTABLE,false); 
            ObjectSetInteger(currChart,exprefix+"_round_line_05_1",OBJPROP_BACK,true); 

            ObjectCreate(currChart, exprefix+"_round_line_00_2", OBJ_HLINE, 0, 0, (double) tmpPrice+1 );
            ObjectSetInteger(currChart,exprefix+"_round_line_00_2",OBJPROP_COLOR,clrCadetBlue); 
            ObjectSetInteger(currChart,exprefix+"_round_line_00_2",OBJPROP_STYLE, STYLE_DASH); 
            ObjectSetInteger(currChart,exprefix+"_round_line_00_2",OBJPROP_SELECTABLE,false); 
            ObjectSetInteger(currChart,exprefix+"_round_line_00_2",OBJPROP_BACK,true); 

            ObjectCreate(currChart, exprefix+"_round_line_05_2", OBJ_HLINE, 0, 0, (double) tmpPrice+1.5 );
            ObjectSetInteger(currChart,exprefix+"_round_line_05_2",OBJPROP_COLOR,clrCadetBlue); 
            ObjectSetInteger(currChart,exprefix+"_round_line_05_2",OBJPROP_STYLE, STYLE_DASH); 
            ObjectSetInteger(currChart,exprefix+"_round_line_05_2",OBJPROP_SELECTABLE,false); 
            ObjectSetInteger(currChart,exprefix+"_round_line_05_2",OBJPROP_BACK,true); 
            
            break;
      }
   }
}

Auf dem Chart werden die gerundeten Niveaus als horizontale, gestrichelte Linien dargestellt:

Anzeigen der nächstgelegenen runden Preise


Darstellung der Stunden zum Schließen

Eingabeparameter: Darstellung der Stunden zum Schließen (Zeitrahmen < 1 Stunde)
Bereich: Chart-Einstellungen

Um das Thema der natürlichen Unterstützungs-/Widerstandsniveaus fortzusetzen, können wir auch die Kurse zum Ende der vollen Stunde nennen. Es wird angenommen, dass der Stundenschlusskurs auch ein Unterstützungs-/Widerstandsniveau für kleinere Zeitrahmen sein kann, obwohl ich das im realen Handel nie bemerkt habe. Lassen Sie uns dennoch die Möglichkeit implementieren, diesen Parameter mindestens für die letzten vier Stunden anzuzeigen.

Die Funktion zur Hervorhebung des Stundenendes auf dem Chart:

/*
Darstellung der letzten vier Stunden auf dem Chart
currChart - Chart-ID
*/
void showCloseHour(long currChart){
   MqlDateTime tmpTime;
   int tmpOffset=0;
   MqlRates rates[];
   ArraySetAsSeries(rates, true);
   if(CopyRates(ChartSymbol(currChart), PERIOD_M30, 0, 9, rates)>0){
      tmpOffset=0;
      TimeToStruct(rates[tmpOffset].time, tmpTime);
      if(tmpTime.min!=0){
         tmpOffset++;
      }
      ObjectCreate(currChart, exprefix+"_hour_0", OBJ_VLINE, 0, rates[tmpOffset].time, 0);
      ObjectSetInteger(currChart,exprefix+"_hour_0",OBJPROP_SELECTABLE,false); 
      ObjectSetInteger(currChart,exprefix+"_hour_0",OBJPROP_STYLE,STYLE_DOT);
      ObjectSetInteger(currChart,exprefix+"_hour_0",OBJPROP_RAY,true); 
      ObjectSetInteger(currChart,exprefix+"_hour_0",OBJPROP_COLOR,clrYellow); 
      ObjectSetInteger(currChart,exprefix+"_hour_0",OBJPROP_BACK,true); 

      tmpOffset++;
      TimeToStruct(rates[tmpOffset].time, tmpTime);
      if(tmpTime.min!=0){
         tmpOffset++;
      }
      ObjectCreate(currChart, exprefix+"_hour_1", OBJ_VLINE, 0, rates[tmpOffset].time, 0);
      ObjectSetInteger(currChart,exprefix+"_hour_1",OBJPROP_SELECTABLE,false); 
      ObjectSetInteger(currChart,exprefix+"_hour_1",OBJPROP_STYLE,STYLE_DOT);
      ObjectSetInteger(currChart,exprefix+"_hour_1",OBJPROP_RAY,true); 
      ObjectSetInteger(currChart,exprefix+"_hour_1",OBJPROP_COLOR,clrYellow); 
      ObjectSetInteger(currChart,exprefix+"_hour_1",OBJPROP_BACK,true); 

      tmpOffset++;
      TimeToStruct(rates[tmpOffset].time, tmpTime);
      if(tmpTime.min!=0){
         tmpOffset++;
      }
      ObjectCreate(currChart, exprefix+"_hour_2", OBJ_VLINE, 0, rates[tmpOffset].time, 0);
      ObjectSetInteger(currChart,exprefix+"_hour_2",OBJPROP_SELECTABLE,false); 
      ObjectSetInteger(currChart,exprefix+"_hour_2",OBJPROP_STYLE,STYLE_DOT);
      ObjectSetInteger(currChart,exprefix+"_hour_2",OBJPROP_RAY,true); 
      ObjectSetInteger(currChart,exprefix+"_hour_2",OBJPROP_COLOR,clrYellow); 
      ObjectSetInteger(currChart,exprefix+"_hour_2",OBJPROP_BACK,true); 

      tmpOffset++;
      TimeToStruct(rates[tmpOffset].time, tmpTime);
      if(tmpTime.min!=0){
         tmpOffset++;
      }
      ObjectCreate(currChart, exprefix+"_hour_3", OBJ_VLINE, 0, rates[tmpOffset].time, 0);
      ObjectSetInteger(currChart,exprefix+"_hour_3",OBJPROP_SELECTABLE,false); 
      ObjectSetInteger(currChart,exprefix+"_hour_3",OBJPROP_STYLE,STYLE_DOT);
      ObjectSetInteger(currChart,exprefix+"_hour_3",OBJPROP_RAY,true); 
      ObjectSetInteger(currChart,exprefix+"_hour_3",OBJPROP_COLOR,clrYellow); 
      ObjectSetInteger(currChart,exprefix+"_hour_3",OBJPROP_BACK,true); 
      
   }
}

Auf dem Chart wird das Ende der jeweils letzten vier Stunden als vertikale gelbe Linien dargestellt:

Darstellung der Stunden zum Schließen


Anzeige des Höchst- und Mindestpreises für ein Jahr

Eingabe: Max/Min-Preis für ein Jahr anzeigen
Bereich: Chart-Einstellungen

Höchst- und Tiefstpreise für ein Jahr sind auch bei Händlern sehr beliebt. Zeigen wir sie auch auf dem Chart an.

Die folgende Funktion ermöglicht es Ihnen, Extrempreise innerhalb eines Jahres anzuzeigen:

/*
Anzeige des Höchst- und Tiefstpreises für das letzte Jahr auf dem Chart.
currChart - Chart-ID
*/
void showMaxPrice(long currChart){
   MqlRates rates[];
   ArraySetAsSeries(rates, true);
   if(CopyRates(ChartSymbol(currChart), PERIOD_MN1, 0, 12, rates)==12){
      double maxPrice=0;
      double minPrice=0;
      
      
      for(int j=0; j<12; j++){
         if( maxPrice==0 || maxPrice<rates[j].high ){
            maxPrice=rates[j].high;
         }
         if( minPrice==0 || minPrice>rates[j].low ){
            minPrice=rates[j].low;
         }
      }
      
      ObjectCreate(currChart, exprefix+"_maxprice_line", OBJ_HLINE, 0, 0, maxPrice);
      ObjectSetInteger(currChart,exprefix+"_maxprice_line",OBJPROP_COLOR,clrMagenta); 
      ObjectSetInteger(currChart,exprefix+"_maxprice_line",OBJPROP_SELECTABLE,false); 
      ObjectSetInteger(currChart,exprefix+"_maxprice_line",OBJPROP_BACK,true); 

      ObjectCreate(currChart, exprefix+"_minprice_line", OBJ_HLINE, 0, 0, minPrice);
      ObjectSetInteger(currChart,exprefix+"_minprice_line",OBJPROP_COLOR,clrMagenta); 
      ObjectSetInteger(currChart,exprefix+"_minprice_line",OBJPROP_SELECTABLE,false); 
      ObjectSetInteger(currChart,exprefix+"_minprice_line",OBJPROP_BACK,true); 
      
      
   }
}

Die Höchst- und Tiefstpreise der letzten 12 Monate werden als violette horizontale Linien angezeigt:

Darstellung des Maximal-/Minimalpreises eines Jahres


Anzeige des Spreads beim Öffnen des Charts

Eingabe: Anzeige des Spreads beim Öffnen des Charts
Bereich: Chart-Einstellungen

Wenn Sie enge Stop-Loss' verwenden, ist der aktuelle Spread des Symbols einer der entscheidenden Faktoren für das Eröffnen einer Position. Daher ist es wichtig, ihn zum Zeitpunkt des Öffnens eines Charts zu kennen. Also, lassen Sie uns weitere Daten zu unseren Chart hinzufügen.

Beachten Sie, dass wir den Spread nur in dem Moment anzeigen, in dem ein Chart geöffnet wurde. Er kann sich im Laufe der Zeit ändern. Der Spread wird nicht in Echtzeit angezeigt. Sie dient nur zur Auswertung des aktuellen Spread-Spanne eines Symbols.

Die folgende kleine Funktion gibt den Spread zurück:

/*
Liefert die Zeichenkette mit dem aktuellen Spread eines bestimmten Symbols.
symname - Symbolname
*/
string getmespread_symbol(string symname){
   double curSpread=SymbolInfoDouble(symname, SYMBOL_ASK)-SymbolInfoDouble(symname, SYMBOL_BID);
   return "Spread: "+(string) DoubleToString(curSpread, (int) SymbolInfoInteger(symname, SYMBOL_DIGITS))+" "+SymbolInfoString(symname, SYMBOL_CURRENCY_PROFIT)+" ("+DoubleToString(curSpread/SymbolInfoDouble(symname, SYMBOL_POINT), 0)+" p)";
}

Der Spread wird in dem Kommentar eines Charts mit weiteren Daten angezeigt:

Anzeige des Spread

Eine Vorlage mit einem Namen für ein Chart verwenden

Eingabe: Verwendung einer Vorlage mit einem Namen für ein Chart
Bereich: Chart-Einstellungen

In MetaTrader werden Vorlagen verwendet, um bevorzugte Einstellungen, EAs und, was noch wichtiger ist, Indikatoren mit bevorzugten Parametern schnell auf ein Chart zu bringen.

"Schnell" ist jedoch ein ungenaues Konzept. Um eine Vorlage auf ein Chart anzuwenden, wählen Sie Vorlagen/"Vorlagenname" im Kontextmenü des Charts. Aber was ist, wenn ein Indikator, z.B. Moving Average, für Sie bei der Entscheidungsfindung wichtig ist, und Sie möchten ihn auf jedem Chart sehen, den Sie öffnen, für Hunderte von Instrumenten pro Tag mit den Sie arbeiten. Müssten Sie wirklich auf jedes von ihnen klicken?

Es wäre viel einfacher, automatisch eine bestimmte Vorlage mit einem Satz von Indikatoren auf jedes geöffnete Chart anzuwenden. Also implementieren wir auch dieses Feature.

Um eine Vorlage auf das Chart anzuwenden, verwenden wir den Befehl ChartApplyTemplate, der sowohl in MQL5 als auch in MQL4 funktioniert:

      ChartApplyTemplate(curChartID[ArraySize(curChartID)-1], allApplyTemplate+".tpl");


Darstellung von Gerchiks ATR

Input: Darstellung Gerchiks ATR
Bereich: Chart-Einstellungen

ATR, das ist die durchschnittliche tägliche Symbolbewegung innerhalb eines bestimmten Zeitraums, er ist ein wichtiger Parameter bei der Bestimmung des Aktionsbereichs des Symbols. Er wird aus verschiedenen Gründen verwendet.

Beispielsweise hilft er zu entscheiden, ob es sich lohnt, einen Handel im Intraday-Handel einzugehen. Wenn Sie es auf Bewegungen von 100 Punkten abgesehen haben, die durchschnittliche Kursspanne des Symbols innerhalb eines Tages aber nur 50 Punkte beträgt, sind Ihre Chancen gering und es wäre besser, keine Position zu eröffnen.

Es wird auch berücksichtigt, dass es keinen Sinn macht, in die gleiche Richtung zu handeln, wenn ein Symbol bereits mehr als 80% seines täglichen ATR in eine Richtung passiert hat, und man eigentlich nur in die entgegengesetzte Richtung arbeiten kann.

Gerchiks ATR unterscheidet sich vom herkömmlichen ATR dadurch, dass nur ungewöhnliche Bars berücksichtigt werden. Ungewöhnliche Bars sind diejenigen, die doppelt so groß oder 0,3 kleiner als die durchschnittlichen sind.

Der ATR wird in der Regel für 5 oder 3 Tage berechnet.

Die folgende Funktion zeigt Gerchiks ATR an:

/*
Gibt Gerchiks ATR für ein bestimmtes Symbol als Zeichenkette zurück:
symname - Symbolname
*/
string getmeatr_symbol(string symname){
   string msg="";
   MqlRates rates[];
   ArraySetAsSeries(rates, true);
   double atr=0;
   double pre_atr=0;
   int curDigits=(int) SymbolInfoInteger(symname, SYMBOL_DIGITS);
   string currencyS=SymbolInfoString(symname, SYMBOL_CURRENCY_PROFIT);
   int count=0;
   int copied=CopyRates(symname, PERIOD_D1, 0, 8, rates);
   if(copied>1){
      for(int j=1; j<copied; j++){
         pre_atr+=rates[j].high-rates[j].low;
      }
      pre_atr/=(copied-1);
   }
   if(pre_atr>0){
      for(int j=1; j<copied; j++){
         if( rates[j].high-rates[j].low > pre_atr*2 ) continue;
         if( rates[j].high-rates[j].low < pre_atr*0.3 ) continue;
               
         if( ++count > 5 ){
            break;
         }
               
         atr+=rates[j].high-rates[j].low;
      }
      if( count > 5 ){
         count=5;
      }
      atr= NormalizeDouble(atr/count, curDigits );
   }
   if(atr>0){
      StringAdd(msg, "ATR: "+(string) DoubleToString(atr, curDigits)+" "+currencyS+", today: "+DoubleToString(rates[0].high-rates[0].low, curDigits)+" "+currencyS+" ("+(string) (int) (((rates[0].high-rates[0].low)/atr)*100) +"%)");
   }
   
   return msg;
}

Das Dienstprogramm zeigt den ATR im Kommentar des Charts an, wie die im vorherigen Abschnitt beschrieben. Der ATR ist im vorherigen Screenshot zu sehen.


Darstellung der Richtung der Leitsymbole

Eingang: Anzeige der Richtung auf #N
Bereich: Darstellung zusätzlicher Daten

Ausgehend von dem, was ich bereits in diesem Artikel erwähnt habe, ist der Intraday-Handel ein sehr kompliziertes Unterfangen, da es viele Dinge zu verfolgen und zu beachten gibt. Und wie sich herausstellt, ist das nicht alles.

Viele Händler empfehlen, die aktuelle Richtung sogenannter Leitsymbole zu beachten, bevor Sie eine Position eröffnen.

Zum Beispiel, wenn Sie an der US-Börse handeln, dann sollten Sie kontrollieren:

  • die wichtigsten US-Indizes, mindestens Dow Jones oder SP500;
  • einen Index der übrigen Länder: China, Europa, Japan;
  • Großunternehmen verschiedener Marktsegmente: JPMorgan im Bankensektor, Apple in der Technologie, ExxonMobil im Energiebereich, IBM und einige andere.

Sie können auch Öl-, Gold- und USD-Kurse berücksichtigen.

Am besten ist es, wenn alle Leitsymbole in eine Richtung gehen. Wie Sie wahrscheinlich erraten haben, ist es besser, nur in die Richtung zu handeln, in die die Leitsymbole sich bewegen.

Da verschiedene Broker unterschiedliche Namen für dasselbe Instrument haben können, ist es unmöglich, die zu überwachenden Instrumente programmgesteuert anzugeben. Aber wir können die eingehenden Parameter vom Typ string hinzufügen, so dass Benutzer die Ticker der Symbole so einstellen können, wie sie von ihren Brokern benannt werden. Das Dienstprogramm verfügt dafür über sieben Parameter.

Die folgende Funktion gibt die Richtung zu einem bestimmten Symbol zurück:

/*
Liefert die Richtung der Preisbewegung eines bestimmten Symbols als Zeichenkette zurück:
symname - Symbolname
show - wenn in die Zeichenfolge eine Bezeichnung mit dem Namen des Symbols eingefügt werden soll
*/
string getmeinfo_symbol(string symname, bool show=true){
   MqlRates rates2[];
   ArraySetAsSeries(rates2, true);
   string msg="";

   if(CopyRates(symname, PERIOD_D1, 0, 1, rates2)>0){
      if(show){
         StringAdd(msg, (string) symname+": ");
      }
      StringAdd(msg, "D1 ");
      if( rates2[0].close > rates2[0].open ){
         StringAdd(msg, "+"+DoubleToString(((rates2[0].close-rates2[0].open)/rates2[0].close)*100, 2) +"% (+"+DoubleToString(rates2[0].close-rates2[0].open, (int) SymbolInfoInteger(symname, SYMBOL_DIGITS))+" "+SymbolInfoString(symname, SYMBOL_CURRENCY_PROFIT)+")");
      }else{
         if( rates2[0].close < rates2[0].open ){
            StringAdd(msg, "-"+DoubleToString(((rates2[0].open-rates2[0].close)/rates2[0].close)*100, 2) +"% (-"+DoubleToString(rates2[0].open-rates2[0].close, (int) SymbolInfoInteger(symname, SYMBOL_DIGITS))+" "+SymbolInfoString(symname, SYMBOL_CURRENCY_PROFIT)+")");
         }else{
            StringAdd(msg, "0%");
         }
      }
   }
   if(CopyRates(symname, PERIOD_H1, 0, 1, rates2)>0){
      StringAdd(msg, ", H1 ");
      if( rates2[0].close > rates2[0].open ){
         StringAdd(msg, "+"+DoubleToString(((rates2[0].close-rates2[0].open)/rates2[0].close)*100, 2)+"% (+"+DoubleToString(rates2[0].close-rates2[0].open, (int) SymbolInfoInteger(symname, SYMBOL_DIGITS))+" "+SymbolInfoString(symname, SYMBOL_CURRENCY_PROFIT)+")");
      }else{
         if( rates2[0].close < rates2[0].open ){
            StringAdd(msg, "-"+DoubleToString(((rates2[0].open-rates2[0].close)/rates2[0].close)*100, 2)+"% (-"+DoubleToString(rates2[0].open-rates2[0].close, (int) SymbolInfoInteger(symname, SYMBOL_DIGITS))+" "+SymbolInfoString(symname, SYMBOL_CURRENCY_PROFIT)+")");
         }else{
            StringAdd(msg, "0%");
         }
      }
   }
   
   return msg;
}

Die Richtungen werden im Kommentar des Charts, auf dem das Dienstprogramm startete, dargestellt. Dies sieht wie folgt aus.

Darstellung der Richtung der Leitsymbole

Bitte beachten Sie, dass die Bewegungsrichtung der Leitsymbole nicht automatisch aktualisiert wird. Um die Daten zu aktualisieren, wechseln Sie zu einer anderen Registerkarte oder drücken Sie R. Dies kann aber auch durch eine neue Eingabe vereinfacht werden.


Automatische Aktualisierung der Utility-Tabs

Eingabe: Aktualisieren eines geöffneten Tabs alle n Sekunden
Bereich: Darstellung zusätzlicher Daten

Wenn Sie möchten, dass der Inhalt einer aktuell geöffneten Registerkarte automatisch aktualisiert wird (und nicht nur durch das Drücken von R), stellen Sie einfach die Anzahl der Sekunden ein, nach denen die Aktualisierung erfolgen soll. Ein Wert größer 0 fordert das Dienstprogramm auf, die Registerkarte nach Ablauf der angegebenen Anzahl von Sekunden zu aktualisieren. Dies bedeutet nicht, dass die Registerkarte strikt alle N Sekunden aktualisiert wird. Stattdessen bedeutet dies, dass die Registerkarte etwa in N plus zwei weitere Sekunden aktualisiert wird.

Der Code, der das Verhalten implementiert, befindet sich innerhalb der Funktion OnTimer und ist sehr einfach:

   // Aktualisierung des Inhalts der Registerkarte nach einer bestimmten Anzahl von Sekunden
   if( autoUpdateAfter>0 && TimeCurrent()-lastUpd >= autoUpdateAfter ){
      start_symbols();
      lastUpd=TimeCurrent();
   }

Zu Beginn des Programmablaufs haben wir den Variablenwert lastUpd mit der aktuellen Zeit in der Funktion OnInit initialisiert.

Darstellung von Finanzdaten der Aktien

Eingabe: Anzeige der Firmeninfo
Bereich: Externe Daten

Wenn Sie die grundlegenden Parameter eines Unternehmens vor dem Kauf oder Verkauf seiner Aktien verfolgen, sollten diese Parameter wahrscheinlich direkt im MetaTrader-Fenster angezeigt werden, damit Sie nicht durch verschiedene Websites blättern müssen.

Lassen Sie uns versuchen, dies zu implementieren. Um es einfach zu machen, werden wir die Parameter auf der Registerkarte Experten des Terminals anzeigen, sobald ein Chart mit dem Dienstprogramm geöffnet wird.

Die finanziellen Parameter selbst können natürlich nicht aus dem Nichts geladen werden. Zuerst wollte ich sie direkt in den EA "hardcodieren", aber der Fehler über zu wenig Speicher störte meinen Plan. Daher werden alle finanziellen Parameter separat im Ordner finder gespeichert, der dem Artikel beigefügt ist. Damit diese Darstellung funktioniert, laden Sie das Archiv herunter, entpacken Sie es und kopieren Sie den Ordner finder in das Verzeichnis Files Ihres Terminals.

Um das Verzeichnis Files zu finden, öffnen Sie das Menü Datei im MetaTrader und klicken Sie auf Datenordner öffnen. Wechseln Sie im neu geöffneten Explorer-Fenster zum Ordner MQL4 oder MQL5.

Diese Finanzparameter sind ab dem Tag der Erstellung dieses Artikels und, möglicherweise, in den nächsten Monaten relevant. Schreiben Sie mir eine persönliche Nachricht, wenn Sie später weitere relevante Daten benötigen.

Aber zurück zur Datenausgabefunktion. Die Funktion entfernt redundante Elemente aus dem Ticker des Unternehmens, nämlich das Präfix # sowie die von einigen Brokern hinzugefügten Suffixe .us und .eu. Wenn Ihr Broker dem Ticker etwas anderes hinzufügt, fügen Sie dem Code dieses Dienstprogramms Ihre eigenen Filter hinzu, um die überflüssigen Zeichen zu entfernen.

Werden im Ordner finder die benötigten Tickerdaten nicht gefunden, erfolgt die Suche über den Firmennamen.

void printTicker(string ticker, string name){
   bool isYes=false;
   int filehandle;
   
   // Entfernen von redundanten Suffixen und Präfixen aus dem Ticker
   // und konvertieren in Kleinbuchstaben.
   StringToLower(ticker);
   StringReplace(ticker, "#", "");
   StringReplace(ticker, ".us", "");
   StringReplace(ticker, ".eu", "");
   
   // Konvertieren des Firmennamens in Kleinbuchstaben
   StringToLower(name);
   
   ResetLastError(); 
   // Wenn das Verzeichnis 'finder' Daten über die Firma hat, anzeigen
   if( FileIsExist("finder\\"+ticker+".dat") ){
      isYes=true;
      filehandle=FileOpen("finder\\"+ticker+".dat",FILE_READ|FILE_TXT); 
      if(filehandle!=INVALID_HANDLE){ 
         int str_size; 
         string str; 
         Print("----------------");
         while(!FileIsEnding(filehandle)){ 
            str_size=FileReadInteger(filehandle,INT_VALUE); 
            str=FileReadString(filehandle,str_size); 
            Print(str);
         }
         FileClose(filehandle); 
      }
   }else if( FileIsExist("finder\\"+name+".dat") ){
      isYes=true;
      filehandle=FileOpen("finder\\"+name+".dat",FILE_READ|FILE_TXT); 
      if(filehandle!=INVALID_HANDLE){ 
         int str_size; 
         string str; 
         Print("----------------");
         while(!FileIsEnding(filehandle)){ 
            str_size=FileReadInteger(filehandle,INT_VALUE); 
            str=FileReadString(filehandle,str_size); 
            Print(str);
        }
         FileClose(filehandle); 
      }
   }
   
   // andernfalls informieren, dass keine Daten gefunden wurden
   if(!isYes){
      Print("No symbol data");
   }
}

Daher wird beim Öffnen eines Charts mit dem Dienstprogramm die Firmeninformation auf der Registerkarte Experten angezeigt. Dies sieht ungefähr wie folgt aus:

Finanzinformationen des Unternehmens


Darstellung des heutigen Gewinns

Input: Display today's profit
Bereich: Darstellung zusätzlicher Daten

Abschließend fügen wir den Parameter hinzu, der es uns ermöglicht, unsere Day-Trading-Aktivitäten rechtzeitig zu stoppen, d.h. die Höhe des an einem Tag erzielten Gewinns oder Verlusts sowie die Gesamtzahl der Geschäfte pro Tag mit der Anzahl der gewinn- und verlustbringenden Geschäfte (dargestellt in der Grafik in der genannten Reihenfolge).

Den aktuellen Gewinn für MQL4 erhalten Sie mit der unten gezeigten Nutzerfunktion getmetoday_profit(). Im Falle von MQL5 ist diese Funktion unzureichend.

In MQL5 prüfen wir zunächst, ob die Daten zu geschlossenen Positionen aktualisiert werden müssten. Verwenden Sie dazu die global deklarierte Variable needHistory. In der Standardfunktion OnInit() wird dieser Variablen der Wert 'true' zugewiesen. Daher werden während des ersten Starts der Funktion getmetoday_profit() die Daten der historischen Geschäfte geladen. Danach wird der Wert der Variablen needHistory auf 'false' gesetzt.

Als Nächstes verwenden wir die MQL5-StandardfunktionOnTrade(), um die Transaktionshistorie bei jedem Schließen einer unserer offenen Positionen erneut zu laden.

Daraus ergibt sich folgender Code:

#ifdef __MQL5__ 
   void OnTrade(){
      if(orders_total==PositionsTotal()){
         return;
      }
      if(orders_total>PositionsTotal()){
         needHistory=true;
      }
      orders_total=(ushort) PositionsTotal();
   }
#endif 
/*
Liefert den heutigen Gewinn/Verlust als Zeichenkette.
*/
string getmetoday_profit(){
   string msg="";
   double curProfit=0;
   int tradeAll=0;
   int tradeMinus=0;
   int tradePlus=0;
   
   MqlDateTime curD;
   TimeCurrent(curD);
   curD.hour=0;
   curD.min=0;
   curD.sec=0;
   
   #ifdef __MQL5__ 
      if( needHistory ){
         HistorySelect(StructToTime(curD),TimeCurrent()); 
      }
      uint totalHistory=HistoryDealsTotal();
      double currHistory=0;
      ulong ticket_history;
      for(uint j=0;j<totalHistory;j++){
         if((ticket_history=HistoryDealGetTicket(j))>0 ){
            double profitHistory=HistoryDealGetDouble(ticket_history,DEAL_PROFIT);
            profitHistory+=HistoryDealGetDouble(ticket_history,DEAL_COMMISSION);
            profitHistory+=HistoryDealGetDouble(ticket_history,DEAL_SWAP);
            if(profitHistory!=0){
               currHistory+=profitHistory;
            }
         }
      }
         
   #else 
      int cntMyPos=OrdersHistoryTotal();
      if(cntMyPos>0){
         for(int ti=cntMyPos-1; ti>=0; ti--){
            if(OrderSelect(ti,SELECT_BY_POS,MODE_HISTORY)==false) continue;
            
            if( OrderCloseTime()<StructToTime(curD) ){ continue; }
            
            double tmpProfit=OrderProfit();
            tmpProfit+=OrderSwap();
            tmpProfit+=OrderCommission();
            
            tradeAll++;
            if(tmpProfit>0){
               tradePlus++;
            }else if(tmpProfit<0){
               tradeMinus++;
            }
            curProfit+=tmpProfit;
         }
      }
   #endif 
   
   if(tradeAll>0){
      StringAdd(msg, "Today: "+DoubleToString(curProfit, 2)+" "+AccountInfoString(ACCOUNT_CURRENCY)+" ("+(string) tradeAll+";+"+(string) tradePlus+";-"+(string) tradeMinus+")");
   }
   
   return msg;
}

Der Gewinn wird auch auf dem Chart angezeigt, auf dem das Dienstprogramm gestartet wird. Das sieht wie folgt aus:

Darstellung des heutigen Gewinns

Beachten Sie, dass auch der Tagesgewinn nicht automatisch neu berechnet wird. Um die aktuellen Gewinndaten zu aktualisieren, öffnen Sie eine andere Registerkarte oder drücken Sie R.


Schlussfolgerung

Dies ist höchstwahrscheinlich der letzte Artikel der Serie. Ich hoffe, dass das resultierende Dienstprogramm Ihnen nützt.

Aber wenn Sie die eine oder andere Funktion vermissen, schreiben Sie mir. Ich werde das Dienstprogramm weiter verbessern, falls es genug fehlende Funktionen gibt, um einen neuen Artikel zu schreiben.

Abschließend lassen Sie uns das Verhalten, das wir in dieser Artikelreihe implementiert haben, zusammenfassen und kurz überprüfen.

Nach dem Start des Dienstprogramms erhalten wir Zugang zu einer Liste von Tools, die unseren Bedingungen entsprechen. Über der Liste sehen wir die Schaltflächen von All, LONG (Steigt), SHORT (Fällt) und Range (Seitwärts) sowie Registerkarten für eine automatische Sortierung. Die Registerkarte All wird standardmäßig geöffnet:

Chart mit dem gestarteten Dienstprogramm

Im Kommentar des Charts sehen Sie die Zeile, die mit update beginnt. Diese Zeile enthält die Uhrzeit der letzten Aktualisierung des Inhalts der Registerkarte. Drücken Sie R, um die aktuelle Registerkarte manuell zu aktualisieren. Außerdem können Sie in den Einstellungen des Dienstprogramms die Häufigkeit der Aktualisierung des Inhalts der aktuell geöffneten Registerkarte (in Sekunden) festlegen.

Apropos Einstellungen des Dienstprogramms... Es wird viel einfacher sein, die Funktionen unseres Dienstprogramms zu verstehen, wenn wir diese Einstellungen berücksichtigen.

Die Liste der Symbole, die auf der Registerkarte All angezeigt werden, hängt von der Gruppe Filtereinstellungen ab:

Einstellungsgruppe der Filter

Wenn wir auf eine vom Dienstprogramm angezeigte Symbolschaltfläche klicken, wird die entsprechende Symboltabelle mit zusätzlichen Daten geöffnet:

Symbolchart, das mit dem Dienstprogramm geöffnet wurde.

Das Erste, was wir auf der Karte sehen, sind die Navigationstasten. Sie ermöglichen es uns, von einem Symbol, das vom Dienstprogramm sortiert ist, zu einem anderen zu wechseln. Außerdem können wir mit den Schaltflächen Symbole zu den "Hausaufgaben-Registerkarten" hinzufügen (LONG (Steigt), SHORT (Fällt) und Range (Seitwärts)) oder von dort entfernen.

Außerdem enthält der Chart-Kommentar eine Vielzahl von Symboldaten. Weiters gibt es verschiedene horizontale Linien.

Die violette Linie zeigt das Hoch/Tief des Jahres an.

Die Rote steht für den benutzerdefinierten Level. Das Dienstprogramm kann alle benutzerdefinierten Linien, die für ein Symbol gezeichnet wurden, speichern und wiederherstellen.

Wie bereits erwähnt, steht die moosgrüne Linie für den vorgestrigen Eröffnungs-/Schlusskurs. Die letzte Linie auf dem Screenshot zeigt den gestrigen Eröffnungs-/Schlusskurs.

Die Gruppe der Chart-Einstellungen definiert, welche Linien und Daten auf dem Chart eines Symbols angezeigt werden sollen:

Die Gruppe der Einstellungen eines Charts

Der Zeitrahmen und die Skalierung des Charts sind ebenfalls anpassbar. Dies geschieht separat für die Registerkarten All, den"Hausaufgaben-Registerkarten" und einige Registerkarten für eine automatische Sortierung.

Ein Zeitrahmen für die Registerkarte All wird in der Gruppe Additional data (Weitere Daten) festgelegt:

Einstellungsgruppe der zusätzlichen Daten

D1 wird standardmäßig für alle Symboltasten auf der Registerkarte All verwendet. Ändern wir es mal auf M15:

Symboltabelle mit dem Zeitrahmen von M15

Dies ermöglicht es uns, ein paar weitere Linien auf dem Chart zu sehen, das das Dienstprogramm anzeigen kann, da diese Linien nur bei Zeitrahmen, die kleiner als einem Tag sind, angezeigt werden.

Die rote vertikale Linie zeigt den Balken, mit dem die aktuelle Handelssitzung beginnt, und das macht es einfach, visuell zu erkennen, ob ein Symbol heute steigt oder fällt.

Die gestrichelte horizontale Linie zeigt runde Preisniveaus an, d.h. die Preise enden mit .00 oder .50 für Kurse mit 2 Nachkommastellen oder mit 0,x1000/0,xx500 für Preise mit 4 und 5 Nachkommastellen (wie hier).

Aber zurück zu den Einstellungen. Die Registerkarten für die automatische Sortierung haben auch ihre eigenen Einstellungen. Die globalen befinden sich in den Gruppen der zusätzlichen Registerkarten. Es gibt auch separate Gruppen mit Einstellungen für einige Registerkarten:

Einstellungen für die automatische Sortierung von Registerkarten

Die letzten Gruppen von Einstellungen sind Opening a chart in a new window (Chart im neuen Fenster öffnen) und External data (externe Daten).

Öffnen eines Charts in einem neuen Fenster und Einstellungsgruppen für externe Daten

Die Einstellungen unter Opening a chart in a new window wirken sich auf den Zeitrahmen und die Skalierung der beim Klicken auf Neue Fenster geöffneten Charts aus.

Weitere Details zu den Funktionen des Dienstprogramms finden Sie in den vorherigen Artikeln der Serie.


Übersetzt aus dem Russischen von MetaQuotes Software Corp.
Originalartikel: https://www.mql5.com/ru/articles/5614

Beigefügte Dateien |
finder.zip (8456.89 KB)
_finder.ex5 (354.46 KB)
_finder.mq5 (258.68 KB)
_finder.ex4 (230.82 KB)
_finder.mq4 (258.68 KB)
Bibliothek für ein leichtes und schnelles Entwickeln vom Programmen für den MetaTrader (Teil IV). Bibliothek für ein leichtes und schnelles Entwickeln vom Programmen für den MetaTrader (Teil IV).

In den vorherigen Artikeln haben wir begonnen, eine große plattformübergreifende Bibliothek zu erstellen, die die Entwicklung von Programmen für MetaTrader 5 und MetaTrader 4 Plattformen vereinfacht. Wir verfügen bereits über Sammlungen historischer Orders und Deals, Market Orders und Positionen sowie über die Klasse zur komfortablen Auswahl und Sortierung der Aufträge. In diesem Teil werden wir die Entwicklung des Basisobjekts fortsetzen und die Engine Library lehren, Handelsereignisse auf dem Konto zu verfolgen.

Wie man den Handelsverlauf mehrerer Währungen basierend auf HTML- und CSV-Berichten visualisiert. Wie man den Handelsverlauf mehrerer Währungen basierend auf HTML- und CSV-Berichten visualisiert.

Seit seiner Einführung bietet MetaTrader 5 die Möglichkeit, mehrere Währungen zu testen. Diese Möglichkeit wird von Händlern oft genutzt. Die Funktion ist jedoch nicht universell einsetzbar. Der Artikel stellt mehrere Programme zum Zeichnen von grafischen Objekten in Diagrammen vor, die auf den Berichten der Handelshistorie im HTML- und CSV-Format basieren. Der Mehrwährungshandel kann parallel, in mehreren Unterfenstern sowie in einem Fenster mit dem dynamischen Schaltbefehl analysiert werden.

Eine neue Schiene: Benutzerdefinierte Indikatoren in MQL5 Eine neue Schiene: Benutzerdefinierte Indikatoren in MQL5

Ich werde nicht alle neuen Möglichkeiten und Funktionen des neuen Terminals und der Sprache aufzählen. Sie sind zahlreich und einige der Neuheiten sind eine Diskussion in einem eigenen Beitrag wert. Auch gibt es hier keinen Code, der mit objektorientierter Programmierung geschrieben wurde. Das Thema ist zu wichtig, um es nur im Kontext zusätzlicher Vorteile für Entwickler zu erwähnen. In diesem Beitrag gehen wir auf Indikatoren, ihre Struktur, Zeichnung, Typen und Programmierdetails im Vergleich zu MQL4 ein. Ich hoffe, dass dieser Beitrag für Einsteiger und erfahrene Entwickler hilfreich sein wird. Vielleicht entdeckt auch jemand etwas Neues.

Hier sind der neue MetaTrader 5 und MQL5 Hier sind der neue MetaTrader 5 und MQL5

Dies ist nur ein kurzer Überblick über MetaTrader 5. Ich kann nicht alle neuen Funktionen des Systems in so kurzer Zeit beschreiben. Die Tests begannen am 09.09.2009. Das ist ein symbolisches Datum und ich bin sicher, dass es eine Glückszahl werden wird. Es sind ein paar Tage vergangen, seit ich die Beta-Version des MetaTrader-5-Terminals und MQL5 bekommen habe. Ich konnte noch nicht alle Funktionen ausprobieren, doch ich bin jetzt schon beeindruckt.