//--- Enumerationen enum ENUM_INTERSECT_DIRECTION { INTERSECT_DIRECTION_NONE= 0, // kein Kreuzen INTERSECT_DIRECTION_UP = 1, // aufwärts kreuzen INTERSECT_DIRECTION_DOWN=-1, // abwärts kreuzen }; //--- Eingabeparameter input uint InpPeriod = 10; // MA Periodenlänge input int InpShift = 0; // MA Versatz input ENUM_MA_METHOD InpMethod = MODE_SMA; // MA Methode input ENUM_APPLIED_PRICE InpPrice = PRICE_CLOSE; // MA verwendeter Preis //--- globale Variable int ExtMaHandle; int ExtMaPeriod; double ExtData[2]; MqlRates ExtRates[2]; //+------------------------------------------------------------------+ //| Expert Initialisierungsfunktion | //+------------------------------------------------------------------+ int OnInit() { //--- die Periodenlänge für die Berechnung des gleitenden Durchschnitts ist gleich dem Standardwert (10), wenn im Eingabeparameter Null angegeben ist ExtMaPeriod=int(InpPeriod<1 ? 10 : InpPeriod); //--- Erstellen eines Handles für den Indikator Gleitender Durchschnitt mit den angegebenen Parametern ExtMaHandle=iMA(Symbol(),PERIOD_CURRENT,ExtMaPeriod,InpShift,InpMethod,InpPrice); ResetLastError(); if(ExtMaHandle==INVALID_HANDLE) { PrintFormat("Failed to create iMA() handle. Error code: %d",GetLastError()); return(INIT_FAILED); } //--- Abrufen des Zeitpunkts der letzten Preisaktualisierung datetime tick_time=TickTime(); //--- Abrufen der Daten des gleitenden Durchschnitts und der Preisdaten der letzten beiden Balken if(GetData(ExtMaHandle,ExtData,ExtRates) && tick_time!=0) { //--- wenn der Preis über dem MA ist if(ExtRates[1].close>ExtData[1]) { //--- Textnachricht erstellen und eine Warnung (Alert) anzeigen string message=StringFormat("Bar time: %s. The price is above the moving average",TimeToString(ExtRates[1].time)); Alert(message+" at "+TimeToString(tick_time,TIME_DATE|TIME_MINUTES|TIME_SECONDS)); /* Ergebnis: Alert: Bar time: 2024.02.16 18:00. The price is above the moving average at 2024.02.16 18:47:43 */ } else { //--- wenn der Preis unter dem MA ist if(ExtRates[1].close<ExtData[1]) { //--- Textnachricht erstellen und eine Warnung (Alert) anzeigen string message=StringFormat("Bar time: %s. The price is below the moving average.",TimeToString(ExtRates[1].time)); Alert(message+" at "+TimeToString(tick_time,TIME_DATE|TIME_MINUTES|TIME_SECONDS)); /* Ergebnis: Alert: Bar time: 2024.02.16 19:00. The price is below the moving average at 2024.02.16 19:33:14 */ } else { //--- Textnachricht erstellen und eine Warnung (Alert) anzeigen string message=StringFormat("Bar time: %s. The price and moving average are equal.",TimeToString(ExtRates[1].time)); Alert(message+" at "+TimeToString(tick_time,TIME_DATE|TIME_MINUTES|TIME_SECONDS)); /* Ergebnis: Alert: Bar time: 2024.02.16 20:00. The price and moving average are equal at 2024.02.16 20:12:22 */ } } } //--- Erfolg return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Tick-Funktion des Experten | //+------------------------------------------------------------------+ void OnTick() { ResetLastError(); //--- Abrufen der Daten des gleitenden Durchschnitts und der Preisdaten der letzten beiden Balken if(!GetData(ExtMaHandle,ExtData,ExtRates)) return; //--- Ermitteln der Richtung, in der der Preis den gleitenden Durchschnitt auf dem aktuellen Balken kreuzt ENUM_INTERSECT_DIRECTION intersect=GetIntersectDirection(ExtData,ExtRates); //--- Variable zum Speichern der vorherigen Nachricht static string message_prev=""; //--- wenn der Kurs den gleitenden Durchschnitt auf dem aktuellen Balken nach oben gekreuzt hat if(intersect==INTERSECT_DIRECTION_UP) { //--- Ermitteln der Zeit des Ticks, zu der das Kreuzen stattgefunden hat datetime tick_time=TickTime(); if(tick_time==0) return; //--- Erstellen einer Textnachricht string message=StringFormat("Bar time: %s. The price crossed the MA from bottom to top",TimeToString(ExtRates[1].time)); //--- wenn die vorherige Nachricht nicht mit der aktuellen übereinstimmt, wird eine Warnung mit der Nachricht und der Zeit des Ticks angezeigt if(message!=message_prev) { Alert(message+" at "+TimeToString(tick_time,TIME_DATE|TIME_MINUTES|TIME_SECONDS)); message_prev=message; /* Result:\ Alert: Bar time: 2024.02.16 09:00. The price crossed the MA from bottom to top at 2024.02.16 09:20:35 */ } } //--- wenn der Kurs den gleitenden Durchschnitt auf dem aktuellen Balken nach unten gekreuzt hat if(intersect==INTERSECT_DIRECTION_DOWN) { //--- Ermitteln der Zeit des Ticks, zu der das Kreuzen stattgefunden hat datetime tick_time=TickTime(); if(tick_time==0) return; //--- Erstellen einer Textnachricht string message=StringFormat("Bar time: %s. The price crossed the MA from top to bottom",TimeToString(ExtRates[1].time)); //--- wenn die vorherige Nachricht nicht mit der aktuellen übereinstimmt, wird eine Warnung mit der Nachricht und der Zeit des Ticks angezeigt if(message!=message_prev) { Alert(message+" at "+TimeToString(tick_time,TIME_DATE|TIME_MINUTES|TIME_SECONDS)); message_prev=message; /* Result:\ Alert: Bar time: 2024.02.16 10:00. The price crossed the MA from top to bottom at 2024.02.16 10:42:15 */ } } } //+------------------------------------------------------------------+ //| Kurs- und gleitende Durchschnittsdaten in Arrays kopieren | //+------------------------------------------------------------------+ bool GetData(int handle,double &ma_data[],MqlRates &price_data[]) { ResetLastError(); //--- Abrufen der Daten des gleitenden Durchschnitts der letzten beiden Balken if(CopyBuffer(handle,0,0,2,ma_data)!=2) { PrintFormat("CopyBuffer() failed. Error code: %d",GetLastError()); return(false); } //--- Abrufen der Preisdaten der letzten beiden Balken if(CopyRates(Symbol(),PERIOD_CURRENT,0,2,price_data)!=2) { PrintFormat("CopyRates() failed. Error code: %d",GetLastError()); return(false); } return(true); } //+------------------------------------------------------------------+ //| Rückgabe der Kreuzungsrichtung von Preisen und gl. Durchschnitt | //+------------------------------------------------------------------+ ENUM_INTERSECT_DIRECTION GetIntersectDirection(double &ma_data[],MqlRates &price_data[]) { double ma0=ma_data[1]; double ma1=ma_data[0]; double close0=price_data[1].close; double close1=price_data[0].close; if(close1<=ma1 && close0>ma0) return(INTERSECT_DIRECTION_UP); else { if(close1>=ma1 && close0<ma0) return(INTERSECT_DIRECTION_DOWN); else return(INTERSECT_DIRECTION_NONE); } } //+------------------------------------------------------------------+ //| Rückgabe der Tick-Zeit in Sekunden | //+------------------------------------------------------------------+ datetime TickTime() { MqlTick tick={}; ResetLastError(); if(!SymbolInfoTick(Symbol(),tick)) { PrintFormat("SymbolInfoTick() failed. Error code: %d",GetLastError()); return(0); } return(tick.time); } |