In diesem Beitrag möchte ich euch einen grafischen Indikator vorstellen, der auf dem Slope-Direction-Trend Indikator basiert und in mehreren Varianten veröffentlicht wurde. Doch keine dieser Versionen zeigt alle Zeitrahmen in einem einzigen grafischen Panel auf eurem Bildschirm an.
Wenn ihr mehr Informationen zu diesem Indikator sucht, könnt ihr hier nachsehen: MQL5 Suche.
Ich habe diesen Indikator modifiziert, um ein grafisches Panel zu erstellen, das alle Zeitrahmen anzeigt, und ich habe einige kleine Anpassungen am Originalcode vorgenommen. Eine der Änderungen ermöglicht es dem Nutzer, die zweite Methode des gleitenden Durchschnitts zur Glättung auszuwählen. Während der Originalcode den Linear Weighted Ansatz für die zweite Berechnung verwendet hat, gebe ich dem Nutzer die Wahl, die Methode zur Glättung zu wählen. Wenn wir bei beiden Berechnungen Linear Weighted verwenden, reagiert der Indikator zu empfindlich und könnte somit falsche Signale zur aktuellen Trendrichtung liefern. Durch die Verwendung des einfachen gleitenden Durchschnitts als zweite Methode erhalten wir einen Trend, der besser anzeigt, wohin sich der Preis bewegt.
Eine weitere Änderung, die ich vorgenommen habe, ist die Möglichkeit, nicht nur die Richtung des Trends (steigend, fallend oder seitwärts) zu bestimmen, sondern auch dessen Wert. Darüber werde ich in einem zukünftigen Artikel schreiben, in dem ich erkläre, wie man einen doppelten SlopeDirection Indikator verwendet und ein Expert Advisor damit erstellt.
Schauen wir uns jetzt kurz den Code an. Zuerst definiere ich alle Objekt-Namen, die ich verwenden werde. Es ist gute Praxis, diese einmal zu definieren, da der Code so nur einmal Speicherplatz für die Benennung reserviert.
// Trendrichtungen definieren #define UPTREND 1 #define DOWNTREND -1 #define FLATTREND 0 // Objekte definieren #define TrendPanel "TrendPanel" #define InfoLine1 "InfoLine1" #define InfoLine2 "InfoLine2" #define TrendLabel "Trend: M1 M5 M15 M30 H1 H4 D1 W1 MN" #define TrendUp "\233" #define TrendDown "\234" #define TrendFlat "\232" #define TrendUnknown "\251" #define StatObjectError "%s(%d) Fehler beim Erstellen von '%s'. Fehler = %d"
Als Nächstes definiere ich zwei Arrays. Eines mit den Pixelpositionen für jeden der 9 Zeitrahmen und das andere mit den Zeitrahmen. Diese werden als globale Variablen definiert.
// Globale Variablen definieren int TrendPosition[] = { 44, 64, 88, 114, 136, 156, 174, 194, 216 }; int TrendPeriods[] = { PERIOD_M1, PERIOD_M5, PERIOD_M15, PERIOD_M30, PERIOD_H1, PERIOD_H4, PERIOD_D1, PERIOD_W1, PERIOD_MN1 };
Die OnInit() Funktion unseres Indikators ruft eine Funktion auf, um das Panel und die Objekte innerhalb des Panels zu erstellen. Sie führt auch eine schnelle Überprüfung der Balken durch, die zur Berechnung des Trends verwendet werden – weniger als 3 macht nicht viel Sinn.
//+------------------------------------------------------------------+ //| Initialisierungsfunktion des benutzerdefinierten Indikators | //+------------------------------------------------------------------+ int OnInit() { // Objekte für das Indikatorpanel erstellen if(Create_Panel() && BarCount >= 3) return(INIT_SUCCEEDED); else return(INIT_FAILED); }
Ich werde nicht ins Detail gehen, wie die Funktion GetTrend() genau funktioniert, dafür gibt es bereits gute Dokumentationen auf dieser Seite. Wir schauen uns einfach die grafische DisplayTrend() Funktion an.
//+------------------------------------------------------------------+ //| Zeige den aktuellen Trend für alle Zeitrahmen an //+------------------------------------------------------------------+ void DisplayTrend(void) { int i, cntr, Trend, LastTrend; string str; for(i=1; i<10; i++) { str = "Trend" + DoubleToStr(i, 0); Trend = (int)GetTrend(TrendPeriods[i-1], BarCount, Method); if(Trend == FLATTREND) { // Ich bin flach, finde die letzte Trendrichtung cntr = 1; do { LastTrend = (int)GetTrend(TrendPeriods[i-1], BarCount, Method, false, cntr++); } while(LastTrend == Trend); ObjectSetText(str, TrendFlat, 8, "WingDings", (LastTrend == UPTREND ? Green : Red)); ObjectSetInteger(0, str, OBJPROP_YDISTANCE, 6); } else { ObjectSetText(str, (Trend == UPTREND ? TrendUp : TrendDown), 8, "WingDings", (Trend == UPTREND ? Green : Red)); ObjectSetInteger(0, str, OBJPROP_YDISTANCE, 5 + (Trend == UPTREND ? 1 : -1)); } } }
Im Grunde genommen durchlaufen wir einfach das TrendPeriods[] Array (um alle Zeitrahmen zu erhalten) und setzen den Trendpfeil entsprechend der Trendrichtung dieses Zeitrahmens. Wenn der Trend flach ist, finden wir die erste Richtung, die nicht flach ist, um zu wissen, woher der Trend kam, damit wir den Seitenpfeil in der Farbe dieser Richtung anzeigen können.
Die Create_Panel() Funktion in unserem OnInit() erstellt die Objekte, die an der unteren linken Seite des Bildschirms verankert sind, und verwendet das TrendPosition[], um die Pfeile an die richtige Stelle zu setzen.
//+------------------------------------------------------------------+ //| Erstelle das Trendpanel in der unteren linken Ecke des Bildschirms //+------------------------------------------------------------------+ bool Create_Panel(void) { int i; string str; // Erstelle das Trendindikatorfenster if(ObjectCreate(TrendPanel, OBJ_RECTANGLE_LABEL, 0, 0, 0)) { ObjectSetInteger(0, TrendPanel, OBJPROP_XDISTANCE, 1); ObjectSetInteger(0, TrendPanel, OBJPROP_YDISTANCE, 29); ObjectSetInteger(0, TrendPanel, OBJPROP_XSIZE, 240); ObjectSetInteger(0, TrendPanel, OBJPROP_YSIZE, 26); ObjectSetInteger(0, TrendPanel, OBJPROP_BGCOLOR, White); ObjectSetInteger(0, TrendPanel, OBJPROP_BORDER_TYPE, 0); ObjectSetInteger(0, TrendPanel, OBJPROP_CORNER, CORNER_LEFT_LOWER); ObjectSetInteger(0, TrendPanel, OBJPROP_COLOR, Red); ObjectSetInteger(0, TrendPanel, OBJPROP_STYLE, STYLE_SOLID); ObjectSetInteger(0, TrendPanel, OBJPROP_WIDTH, 2); ObjectSetInteger(0, TrendPanel, OBJPROP_BACK, false); ObjectSetInteger(0, TrendPanel, OBJPROP_SELECTABLE, false); ObjectSetInteger(0, TrendPanel, OBJPROP_SELECTED, false); ObjectSetInteger(0, TrendPanel, OBJPROP_HIDDEN, true); ObjectSetString(0, TrendPanel, OBJPROP_TOOLTIP, "\n"); } else { PrintFormat(StatObjectError, __FUNCTION__, __LINE__, TrendPanel, GetLastError()); return(false); } if(ObjectCreate(InfoLine1, OBJ_LABEL, 0, 0, 0)) { ObjectSet(InfoLine1, OBJPROP_CORNER, CORNER_LEFT_LOWER); ObjectSet(InfoLine1, OBJPROP_XDISTANCE, 6); ObjectSet(InfoLine1, OBJPROP_YDISTANCE, 15); ObjectSetInteger(0, InfoLine1, OBJPROP_SELECTABLE, false); ObjectSetInteger(0, InfoLine1, OBJPROP_HIDDEN, true); ObjectSetString(0, InfoLine1, OBJPROP_TOOLTIP, "\n"); ObjectSetText(InfoLine1, TrendLabel, 8, "Arial", Black); } else { PrintFormat(StatObjectError, __FUNCTION__, __LINE__, InfoLine1, GetLastError()); return(false); } if(ObjectCreate(InfoLine2, OBJ_LABEL, 0, 0, 0)) { ObjectSet(InfoLine2, OBJPROP_CORNER, CORNER_LEFT_LOWER); ObjectSet(InfoLine2, OBJPROP_XDISTANCE, 6); ObjectSet(InfoLine2, OBJPROP_YDISTANCE, 5); ObjectSetInteger(0, InfoLine2, OBJPROP_SELECTABLE, false); ObjectSetInteger(0, InfoLine2, OBJPROP_HIDDEN, true); ObjectSetString(0, InfoLine2, OBJPROP_TOOLTIP, "\n"); ObjectSetText(InfoLine2, " " + DoubleToStr(BarCount, 0) + " / " + DoubleToStr(Method, 0), 8, "Arial", Black); } else { PrintFormat(StatObjectError, __FUNCTION__, __LINE__, InfoLine2, GetLastError()); return(false); } // Erstelle das Trendobjekt und zeige den aktuellen Trend an for(i=1; i<10; i++) { str = "Trend" + DoubleToStr(i, 0); if(ObjectCreate(str, OBJ_LABEL, 0, 0, 0)) { ObjectSet(str, OBJPROP_CORNER, CORNER_LEFT_LOWER); ObjectSet(str, OBJPROP_XDISTANCE, TrendPosition[i-1]); ObjectSet(str, OBJPROP_YDISTANCE, 5); ObjectSetInteger(0, str, OBJPROP_SELECTABLE, false); ObjectSetInteger(0, str, OBJPROP_HIDDEN, true); ObjectSetString(0, str, OBJPROP_TOOLTIP, "\n"); } else { PrintFormat(StatObjectError, __FUNCTION__, __LINE__, str, GetLastError()); return(false); } } // Zeige den aktuellen Trend an DisplayTrend(); // Alles gut return(true); }
Diese Funktion gibt TRUE zurück, wenn alle Objekte erfolgreich erstellt wurden, oder FALSE, wenn ein Fehler beim Erstellen eines Objekts aufgetreten ist. Der Vorteil ist, dass der Indikator im EXPERT-Tab eurer Konsole den Fehlercode und die Zeilennummer des Codes, in dem der Fehler aufgetreten ist, anzeigt.
Wir müssen auch den Trendindikator für jeden neuen Tick, den wir empfangen, aktualisieren. Dies geschieht, indem wir DisplayTrend() in unserer start() Funktion aufrufen.
//+------------------------------------------------------------------+ //| Iterationsfunktion des benutzerdefinierten Indikators | //+------------------------------------------------------------------+ int start() { // Zeige den aktuellen Trend für alle Zeitrahmen an DisplayTrend(); return(0); }
Zu guter Letzt löschen wir alle Objekte, die vom Indikator erstellt wurden, wenn wir den Indikator schließen.
//+------------------------------------------------------------------+ //| Deinitialisierungsfunktion | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { // Lösche die Objekte des Indikators if(ObjectFind(TrendPanel) >= 0) ObjectDelete(TrendPanel); if(ObjectFind(InfoLine1) >= 0) ObjectDelete(InfoLine1); if(ObjectFind(InfoLine2) >= 0) ObjectDelete(InfoLine2); for(int i=1; i<10; i++) if(ObjectFind("Trend"+DoubleToStr(i, 0)) >= 0) ObjectDelete("Trend"+DoubleToStr(i, 0)); }
Das ist alles! Ihr habt nun ein nützliches Indikatorpanel, das den aktuellen Trend für alle Zeitrahmen in der unteren linken Ecke eures Bildschirms anzeigt.
Viel Spaß beim Traden!