Showing posts with label Custom Indicator Alerts. Show all posts
Showing posts with label Custom Indicator Alerts. Show all posts

Thursday, August 7, 2025

Introduction

The Average Directional Movement Index Multi-Timeframe (ADX MTF) Indicator for MetaTrader 5 provides directional signals from all 21 standard timeframes, ranging from M1 to MN1.

For each timeframe, it displays a directional arrow object (`OBJ_ARROW`) using Wingdings character 108:

🟢 Green arrow = upward ADX signal
🔴 Red arrow = downward ADX signal

After gathering these signals, the indicator calculates a consensus summary using a unique logic:
If the number of **up** signals is greater than **down + 1**, the indicator plots a larger **Wingdings 217** upward arrow * If the number of **down** signals is greater than **up + 1**, it plots a larger **Wingdings 218** downward arrow

This enables traders to view a high-confidence trend direction based on multi-timeframe ADX analysis directly on the main chart.

🔁 Note: All multi-timeframe indicators developed by Forex Home Expert use this exact signal logic structure.

The Average Directional Movement Index Multi-Timeframe indicator for MT5 (ADX_MTF) utilizes a template and displays a panel on the chart. Its function, operation, and usage are identical to the Strength of Price Movement Multi Timeframe indicator (SPM_MTF) as detailed in the previous article. For a comprehensive guide on creating a multi-timeframe indicator, you can refer to the following resources: Strength of Price Movement Multi Timeframe indicator for MT5

Average Directional Movement Index Multi-Timeframe indicator for MT5

Key Features:

✅ 21-Timeframe Directional ADX Scanning
✅ Wingdings Arrows Overlay (per timeframe)
✅ Summary Arrow with Up/Down Consensus Calculation
✅ Color Customization for Each Signal
✅ Built-in Alerts (pop-up, email, mobile)
✅ Graphical Interface Panel for Timeframe Switching (via `OnChartEvent`)

Inputs and Parameters

| Input | Description | | --------------- | ------------------------------------------ |
| `BarCalc` | Bars used for ADX signal scan |
| `ArrowUp` | Color of up signal arrow |
| `ArrowDn` | Color of down signal arrow |
| `NTArrow` | Color of neutral arrow (default) |
| `f_model` | Font type for arrows (usually "Wingdings") |
| `alerts` | Enable/disable alert popups |
| `UseEmailAlert` | Enable email alerts |
| `UseSendnotify` | Enable push notification alerts |

Why Multi-Timeframe ADX Matters?

The ADX is powerful for identifying **trend strength** but lacks insight into **trend consistency** across timeframes. This custom ADX_MTF indicator solves that:

📈 Confirm short-term trades with long-term trend backing
⚠️ Avoid sideways or weak markets using visual confirmation
🚨 Detect powerful breakouts supported by multiple timeframe trends

Using **all 21 timeframes** (from M1 to MN1) ensures broad trend consistency in your decision-making process.

Technical Overview: How the Indicator Works

Timeframe Management

The indicator prepares and manages handles for all standard MT5 timeframes:


ENUM_TIMEFRAMES TFId[] = {PERIOD_M1, PERIOD_M2, ..., PERIOD_MN1};
int tfxar = ArraySize(TFId);  // total 21 timeframes
/* Handles for all timeframe-specific ADX indicators are stored in `hADXp[]` and initialized inside `OnInit()` using `iADX()` for each timeframe. */

Signal Extraction Logic

Each timeframe is scanned using:


   //---
   int ADXDirectionScan(const ENUM_TIMEFRAMES stf,int shift) // Scan ADX Direction
     {
      //--
      int ret=0;
      int rise=1,
          down=-1;
      //--
      int br=shift+2;
      double res=0.0;
      UpdatePrice(stf);
      //--
      double ADXp[];
      ArrayResize(ADXp,br,br);
      ArraySetAsSeries(ADXp,true);
      //--
      int xx=TFIndexArray(stf);
      CopyBuffer(hADXp[xx],1,0,br,ADXp); // We will use ADX indicator buffer for DI+
      //--
      if(ADXp[shift]>ADXp[shift+1]) ret=rise;
      if(ADXp[shift]<ADXp[shift+1]) ret=down;
      //--
      return(ret);
      //---
     } //-end ADXDirectionScan()
   //---
   
/*
This compares DI+ values (buffer 1) to detect rising or falling strength.
*/

Consensus Calculation Logic.


   //---
   void ADXMovementCalculation(int barCnt) // Scan the direction of iADX on each timeframe
     {
      //--
      ArrayResize(PowerMove,barCnt,barCnt);
      ArraySetAsSeries(PowerMove,true);
      //--
      for(int i=barCnt-1; i>=0; i--)
        {
         up=0;
         dw=0;
         //--
         for(int x=0; x<tfxar; x++)
           {
            Arwcolor[x]=NTArrow;
            PowerMove[i]=0.0;
            int PPM=ADXDirectionScan(TFId[x],0);
            if(PPM>0)
              {
               up++;
               Arwcolor[x]=ArrowUp;
              }
            if(PPM<0)
              {
               dw++;
               Arwcolor[x]=ArrowDn;
              }
            if(x==tfxar-1)
              {
               if(up>dw+1)
                 {
                  PowerMove[i]=1.0;
                  TColor=ArrowUp;
                  curAlert=1;
                 }
               if(dw>up+1)
                 {
                  PowerMove[i]=-1.0;
                  TColor=ArrowDn;
                  curAlert=-1;
                 }
              }
           }
        }
      //--
      return;
      //---
     } //-end ADXMovementCalculation()
   //---

/*
This logic ensures that only dominant directional consensus (not slight differences) triggers a clear summary signal.
*/

Dynamic Timeframe Panel (OnChartEvent)

The indicator creates a clickable panel on the chart containing labels for all 21 timeframes. When a label (e.g., "H4") is clicked, the internal reference timeframe for analysis is updated.

This makes it easy for the user to interact with the indicator dynamically.


void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
//---
//--- handling CHARTEVENT_CLICK event ("Clicking the chart")
   ResetLastError();
//--
   if(id==CHARTEVENT_OBJECT_CLICK)
     {
      //--- if "X" button is click
      if(sparam=="X")
        {
         mi.DeletedADXObject();
         //--- unpress the button
         ObjectSetInteger(mi.CI,"X",OBJPROP_STATE,false);
         ObjectSetInteger(mi.CI,"X",OBJPROP_ZORDER,0);
         //--
         mi.display=false;
         ObjectDelete(mi.CI,"X");
         mi.DisplayPanelButton();
        }
      //--- if "cstar" button is click
      if(sparam==mi.cstar)
        {
         mi.DeletedADXObject();
         mi.DisplayPanelButton();
         //--- unpress the button
         ObjectSetInteger(mi.CI,mi.cstar,OBJPROP_STATE,false);
         ObjectSetInteger(mi.CI,mi.cstar,OBJPROP_ZORDER,0);
         if(!mi.display)
            mi.display=true;
         if(mi.corpos==mi.posbot) ObjectDelete(mi.CI,mi.arbot);
         if(mi.corpos==mi.postop) ObjectDelete(mi.CI,mi.artop);
         mi.DrawADXObject();
         //--
         ChartRedraw(mi.CI);
        }
      //--- if "artop" button is click
      if(sparam==mi.artop)
        {
         mi.DeletedADXObject();
         mi.DisplayPanelButton();
         //--- unpress the button
         ObjectSetInteger(mi.CI,mi.artop,OBJPROP_STATE,false);
         ObjectSetInteger(mi.CI,mi.artop,OBJPROP_ZORDER,0);
         if(!mi.display)
            mi.display=true;
         ObjectDelete(mi.CI,mi.artop);
         mi.PanelPosChange(mi.postop);
         //--
         ObjectDelete(mi.CI,"X");
         mi.DisplayButtonClick("arbot");
         mi.DrawADXObject();
         //--
         ChartRedraw(mi.CI);
        }
      //--- if "arbot" button is click
      if(sparam==mi.arbot)
        {
         mi.DeletedADXObject();
         mi.DisplayPanelButton();
         //--- unpress the button
         ObjectSetInteger(mi.CI,mi.arbot,OBJPROP_STATE,false);
         ObjectSetInteger(mi.CI,mi.arbot,OBJPROP_ZORDER,0);
         if(!mi.display)
            mi.display=true;
         ObjectDelete(mi.CI,mi.arbot);
         mi.PanelPosChange(mi.posbot);
         //--
         ObjectDelete(mi.CI,"X");
         mi.DisplayButtonClick("artop");
         mi.DrawADXObject();
         //--
         ChartRedraw(mi.CI);
        }
      //--- if TF button is click
      //--
      if(sparam==mi.TFSc[0])
        {
         mi.ChangeChartSymbol(mi.TFSc[0],mi.TFId[0]);
        }
      //--
      if(sparam==mi.TFSc[1])
        {
         mi.ChangeChartSymbol(mi.TFSc[1],mi.TFId[1]);
        }
      //--
      if(sparam==mi.TFSc[2])
        {
         mi.ChangeChartSymbol(mi.TFSc[2],mi.TFId[2]);
        }
      //--
      if(sparam==mi.TFSc[3])
        {
         mi.ChangeChartSymbol(mi.TFSc[3],mi.TFId[3]);
        }
      //--
      if(sparam==mi.TFSc[4])
        {
         mi.ChangeChartSymbol(mi.TFSc[4],mi.TFId[4]);
        }
      //--
      if(sparam==mi.TFSc[5])
        {
         mi.ChangeChartSymbol(mi.TFSc[5],mi.TFId[5]);
        }
      //--
      if(sparam==mi.TFSc[6])
        {
         mi.ChangeChartSymbol(mi.TFSc[6],mi.TFId[6]);
        }
      //--
      if(sparam==mi.TFSc[7])
        {
         mi.ChangeChartSymbol(mi.TFSc[7],mi.TFId[7]);
        }
      //--
      if(sparam==mi.TFSc[8])
        {
         mi.ChangeChartSymbol(mi.TFSc[8],mi.TFId[8]);
        }
      //--
      if(sparam==mi.TFSc[9])
        {
         mi.ChangeChartSymbol(mi.TFSc[9],mi.TFId[9]);
        }
      //--
      if(sparam==mi.TFSc[10])
        {
         mi.ChangeChartSymbol(mi.TFSc[10],mi.TFId[10]);
        }
      //--
      if(sparam==mi.TFSc[11])
        {
         mi.ChangeChartSymbol(mi.TFSc[11],mi.TFId[11]);
        }
      //--
      if(sparam==mi.TFSc[12])
        {
         mi.ChangeChartSymbol(mi.TFSc[12],mi.TFId[12]);
        }
      //--
      if(sparam==mi.TFSc[13])
        {
         mi.ChangeChartSymbol(mi.TFSc[13],mi.TFId[13]);
        }
      //--
      if(sparam==mi.TFSc[14])
        {
         mi.ChangeChartSymbol(mi.TFSc[14],mi.TFId[14]);
        }
      //--
      if(sparam==mi.TFSc[15])
        {
         mi.ChangeChartSymbol(mi.TFSc[15],mi.TFId[15]);
        }
      //--
      if(sparam==mi.TFSc[16])
        {
         mi.ChangeChartSymbol(mi.TFSc[16],mi.TFId[16]);
        }
      //--
      if(sparam==mi.TFSc[17])
        {
         mi.ChangeChartSymbol(mi.TFSc[17],mi.TFId[17]);
        }
      //--
      if(sparam==mi.TFSc[18])
        {
         mi.ChangeChartSymbol(mi.TFSc[18],mi.TFId[18]);
        }
      //--
      if(sparam==mi.TFSc[19])
        {
         mi.ChangeChartSymbol(mi.TFSc[19],mi.TFId[19]);
        }
      //--
      if(sparam==mi.TFSc[20])
        {
         mi.ChangeChartSymbol(mi.TFSc[20],mi.TFId[20]);
        }
      //--
     }
//---
  } //-end OnChartEvent()
//---------//

How to Use

1. **Attach to Any Chart** (e.g., EURUSD H1)
2. **Adjust the Inputs**
3. **Observe Directional Arrows** per timeframe on your chart
4. **Watch Summary Signal Arrow** (center chart)
5. **Click Timeframe Labels** to change timeframe view instantly

Frequently Asked Questions (FAQ)

**Q1: What makes this ADX MTF indicator different from the built-in ADX in MetaTrader 5?**
**A1:** The built-in ADX only analyzes the current chart timeframe. This ADX MTF indicator scans and displays directional strength across **21 timeframes**, giving you a full-spectrum view of the market’s trend dynamics. It also features consensus-based summary signals and interactive controls.

**Q2: What do the green and red arrows mean on the chart?**
**A2:**
**Green arrow** (Wingdings 108): Indicates that ADX is rising (positive DI > previous value) on that specific timeframe
**Red arrow** (Wingdings 108): Indicates ADX is falling (trend weakening)
The **large green (217)** or **red (218)** summary arrow shows dominant direction when more than one timeframe agrees

**Q3: How is the final summary signal calculated?**
**A3:** The indicator loops through all timeframes and counts up and down signals.
** If `up > down + 1`, it plots a large **up arrow** (Wingdings 217)
** If `down > up + 1`, it plots a **down arrow** (Wingdings 218)
** If neither, no summary arrow is drawn

**Q4: Can I change the timeframe used for analysis dynamically?**
**A4:** Yes. The indicator includes an interactive panel with all 21 timeframes (M1 to MN1). Just click on any label (like “H4” or “D1”) to switch the analysis source without reattaching the indicator. This is handled via the `OnChartEvent()` function in MQL5.

**Q5: Is this indicator repainting?**
**A5:** No. The indicator uses `CopyBuffer()` with proper indexing and does **not repaint** past signals. All calculations are based on closed candles and historical values.

**Q6: What symbols or assets can I use this on?**
**A6:** This indicator works with all MT5 instruments:
* Forex pairs (e.g., EURUSD, GBPJPY)
* Indices (e.g., DAX, S&P 500)
* Commodities (e.g., gold, oil)
* Crypto (e.g., BTCUSD)

**Q7: Does this indicator send alerts?**
**A7:** Yes. It supports:
* Popup alerts
* Email alerts
* Push notifications
These can be toggled on/off in the input settings.

**Q8: Can this be used inside Expert Advisors (EAs)?**
**A8:** While this is a custom visual indicator, its signal logic can be adapted into EAs. You may extract the consensus signal via `PowerMove[]` or implement a similar formula directly in your EA code.

**Q9: Can I use this for scalping or only for swing trading?**
**A9:** It’s suitable for **both**. Scalpers can confirm short-term moves with higher timeframe trends. Swing traders benefit from trend strength alignment across D1, H4, etc.

**Q10: Do I need to install any external libraries to use it?**
**A10:** No. Just download the `.ex5` file, place it in `MQL5/Indicators`, and run.

Conclusion

The **ADX Multi-Timeframe Indicator for MT5** offers a complete solution for traders who want to understand trend strength across all timeframes simultaneously. Using a unique formula that scans and weighs up/down movement across 21 timeframes, it delivers a summary arrow signal that simplifies complex data into an actionable visual.

With features like dynamic chart interaction, visual arrows, alerts, and a lightweight design, this tool is ideal for discretionary and algorithmic traders alike.

We hope that this article and the ADX_MTF or Average Directional Movement Index Multi-Timeframe Indicator for MT5 program will be useful for traders in learning and generating new ideas for trading, who can ultimately make money from home by trading forex.

Please download the ADX_MTF indicator: Average Directional Movement Index Multi-Timeframe Indicator

Vital Records

If you would like to receive a source program for this article, please send a request via Contact Us form page, and I will send it to your email, source code: Average Directional Movement Index Multi-Timeframe Indicator for MT5

If you think the Average Directional Movement Index Multi-Timeframe Indicator for MT5 is worthy of being used for automated trading as an Expert Advisor, please leave a comment below this article.

If at least 25 people agree that this indicator is worthy of being used as an Expert Advisor, I will create an Expert Advisor based on its signals and share it on this blog.

Thanks for reading this article.

Sunday, November 24, 2024

In this article I will discuss how to add alerts to indicator programs or Expert Advisors using MQL5.

The alerts that will be discussed include sound and pop-up alerts on MT5 or MT4, notification alerts and email alerts.

But before discussing the creation of the program, we need to know what the benefits of alerts in indicator or expert advisor programs actually are?

the benefits of alerts in indicator or expert advisor programs

What are the benefits of alerts in indicator or expert advisor programs in MT4 or MT5?

Alerts in MT4 and MT5 indicators and expert advisors (EAs) are invaluable tools for traders. They provide timely notifications about specific market conditions, allowing traders to react quickly and make informed decisions.

Here are the key benefits of using alerts:

1.Timely Notifications:

  • Real-time alerts: Receive immediate notifications when a specific condition is met, such as a price crossing a moving average or a support/resistance level being breached.
  • No Constant Monitoring: You don't have to constantly stare at charts to catch these opportunities. Alerts can notify you even when you're away from your computer.

2. Improved Decision-Making:

  • Quick Reaction: Alerts allow you to react promptly to market changes, potentially leading to better entry and exit points.
  • Reduced Emotional Trading: By automating notifications, you can avoid impulsive decisions based on fear or greed.

3. Enhanced Risk Management:

  • Stop-Loss and Take-Profit Alerts: Set up alerts to trigger when your positions reach predefined profit or loss levels.
  • Risk Management Strategies: Automate risk management strategies, such as trailing stop-loss orders, to protect your profits.

4. Increased Efficiency:

  • Automation: Automate repetitive tasks like monitoring indicators and placing orders.
  • Focus on Other Tasks: Spend more time on other aspects of your trading strategy, such as fundamental analysis or portfolio management.

5. Scalping and Day Trading:

  • Quick Entry and Exit: Alerts can help you capitalize on short-term price movements and scalping opportunities.

Remember:

While alerts can be a powerful tool, it's important to use them wisely. Overreliance on alerts can lead to impulsive decisions and potential losses. Always combine alerts with sound risk management practices and thorough analysis.

In this article I will demonstrate the implementation of alerts using the modified MACD indicator by adding alerts.

First of all, I will create a template that is usually used to add alerts to indicators or expert advisors in MQL5.

Template program alerts:


//+------------------------------------------------------------------+
//|                                                  MACD_Alerts.mq5 |
//|                             Copyright 2000-2024, MetaQuotes Ltd. |
//|                                             https://www.mql5.com ||
//|                              https://www.mql5.com/en/users/3rjfx |
//+------------------------------------------------------------------+
#property copyright   "Copyright 2000-2024, MetaQuotes Ltd."
#property link        "https://www.mql5.com"
#property link        "https://www.mql5.com/en/users/3rjfx"
#property description "Moving Average Convergence/Divergence"
#property version     "1.00"
#property description "Modify by: Roberto Jacobs (3rjfx) ~ Date: 2024-11-24"

#property indicator_separate_window
//---


//-- Enumeration
enum YN
 {
   No,  
   Yes
 };
//---
//--- Input parameters for alerts
input YN                   alerts = Yes;             // Display Alerts Pop-up on Chart (Yes) or (No)
input YN            UseEmailAlert = No;              // Email Alert (Yes) or (No)
input YN            UseSendnotify = No;              // Send Notification (Yes) or (No)

//---Variables used in alerts
double MACDAlert[];
string AlertTxt;
string _name;
int curAlert;
int prvAlert;
//--
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   
   
   //--
   _name="Your Indicator Name";
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
  {
//---
   
   
   
   //--
   double priceB=0.0;
   double priceS=0.0;
   datetime dtB=0;
   datetime dtS=0;
   //--
   if(alerts==Yes||UseEmailAlert==Yes||UseSendnotify==Yes)
     {
       if(curAlert==1 && curAlert!=prvAlert)
         {
           AlertTxt="Your Alerts Text here";
           Do_Alerts(AlertTxt,dtB);
           prvAlert=curAlert;
         }
       if(curAlert==-1 && curAlert!=prvAlert)
         {
           AlertTxt="Your Alerts Text here";
           Do_Alerts(AlertTxt,dtS);
           prvAlert=curAlert;
         }
     }
   //--
   
   
//--- return value of prev_calculated for next call
   return(rates_total);
  }
//+------------------------------------------------------------------+

string TF2Str(int period)
  {
   switch(period)
     {
       //--
       case PERIOD_M1:   return("M1");
       case PERIOD_M2:   return("M2");
       case PERIOD_M3:   return("M3");
       case PERIOD_M4:   return("M4");
       case PERIOD_M5:   return("M5");
       case PERIOD_M6:   return("M6");
       case PERIOD_M10:  return("M10");
       case PERIOD_M12:  return("M12");
       case PERIOD_M15:  return("M15");
       case PERIOD_M20:  return("M20");
       case PERIOD_M30:  return("M30");
       case PERIOD_H1:   return("H1");
       case PERIOD_H2:   return("H2");
       case PERIOD_H3:   return("H3");
       case PERIOD_H4:   return("H4");
       case PERIOD_H6:   return("H6");
       case PERIOD_H8:   return("H8");
       case PERIOD_H12:  return("H12");
       case PERIOD_D1:   return("D1");
       case PERIOD_W1:   return("W1");
       case PERIOD_MN1:  return("MN");
       //--
     }
   return(string(period));
  }  
//---------//

void Do_Alerts(string msgText,datetime Altime)
  {
//---
    //--
    Print("--- "+Symbol()+": "+msgText+
          "\n --- at: ",TimeToString(Altime,TIME_DATE|TIME_MINUTES));
    //--
    if(alerts==Yes)
      {
        Alert("--- "+Symbol()+": "+msgText+
              " --- at: ",TimeToString(Altime,TIME_DATE|TIME_MINUTES));
      }
    //--
    if(UseEmailAlert==Yes) 
      SendMail(_name," --- "+Symbol()+" "+TF2Str(Period())+": "+msgText+
                       "\n--- at: "+TimeToString(Altime,TIME_DATE|TIME_MINUTES));
    //--
    if(UseSendnotify==Yes) 
      SendNotification(_name+"--- "+Symbol()+" "+TF2Str(Period())+": "+msgText+
                      "\n --- at: "+TimeToString(Altime,TIME_DATE|TIME_MINUTES));
    //--
    return;
    //--
//---
  } //-end Do_Alerts()
//---------//

Enumeration.

An enum (short for "enumeration") is a distinct type that consists of a set of named values called elements or members. Enums are used to represent a collection of related constants in a more readable and maintainable way.

Enums are particularly useful for representing a series of constants or actions that are related in a fixed manner, and this will make our code more readable and less error-prone.

The YN enum we've defined contains two possible values: No and Yes.

Breakdown:

  • enum YN: This defines a new enumeration type named YN.
  • { No, Yes }: These are the members of the enum, representing two possible states or values: No and Yes.

Then we use that enumeration in the indicator input properties.


//--- Input parameters for alerts
input YN                   alerts = Yes;             // Display Alerts Pop-up on Chart (Yes) or (No)
input YN            UseEmailAlert = No;              // Email Alert (Yes) or (No)
input YN            UseSendnotify = No;              // Send Notification (Yes) or (No)

In order not to disturb the MACD buffer calculation, we add a buffer variable named MACDAlert. In this MACDAlert buffer we will copy all values from the MACD buffer.

Then below are some variables that will be used in the alerts that we must place on the global scope of the indicator or expert advisor.

  • string AlertTxt: For the alert text to be created.
  • string _name: Name of the indicator or program that will provide the alert.
  • int curAlert: Current alert value, with a value of 1 for an Up or Buy Alert and minus 1 for a Down or Sell Alert.
  • int prvAlert: This variable is to hold the current alert value, to prevent the alert from repeating without interruption.

Explanation

Variables Initialization:


datetime dtB=0;
datetime dtS=0;
double priceB=0.0;
double priceS=0.0;

These variables store the date and price when a Moving Average Convergence Divergence (MACD) signal occurs. dtB and dtS store the date for the Buy and Sell signals, respectively. priceB and priceS store the prices at those times.

Array Manipulation:


ArraySetAsSeries(time, true);
ArraySetAsSeries(close, true);
ArrayCopy(MACDAlert, ExtMacdBuffer, 0, 0, WHOLE_ARRAY);
ArraySetAsSeries(MACDAlert, true);

These lines set up the arrays for time, closing prices, and MACD values to be used as series (reverse the array indexing). ArrayCopy copies the ExtMacdBuffer into MACDAlert.

Loop to Detect MACD Crossings:


for (int x = calculated - 2; x >= 0; x--)
{
    if (MACDAlert[x+1] <= 0.0 && MACDAlert[x] > 0.0)
    {
        curAlert = 1;
        dtB = time[x];
        priceB = close[x];
    }
    if (MACDAlert[x+1] >= 0.0 && MACDAlert[x] < 0.0)
    {
        curAlert = -1;
        dtS = time[x];
        priceS = close[x];
    }
}

This loop iterates over the MACDAlert array to detect crossings of the MACD line over the zero line.

  • If the MACD value crosses from negative to positive (MACDAlert[x+1] <= 0.0 && MACDAlert[x] > 0.0), a buy signal is generated, and the current time and price are recorded.
  • If the MACD value crosses from positive to negative (MACDAlert[x+1] >= 0.0 && MACDAlert[x] < 0.0), a sell signal is generated, and the current time and price are recorded.

Alerts:


if (alerts == Yes || UseEmailAlert == Yes || UseSendnotify == Yes)
{
    if (curAlert == 1 && curAlert != prvAlert)
    {
        AlertTxt = "MACD cross from below to above zero : " + DoubleToString(priceB, Digits()) + " @ bar shift: " + (string)iBarShift(Symbol(), 0, dtB, false);
        Do_Alerts(AlertTxt, dtB);
        prvAlert = curAlert;
    }
    if (curAlert == -1 && curAlert != prvAlert)
    {
        AlertTxt = "MACD cross from above to below zero : " + DoubleToString(priceS, Digits()) + " @ bar shift: " + (string)iBarShift(Symbol(), 0, dtS, false);
        Do_Alerts(AlertTxt, dtS);
        prvAlert = curAlert;
    }
}

If any alerts are enabled (regular alerts, email alerts, or notifications), the code sends an alert whenever a new MACD crossing signal is detected.

  • If a buy signal is detected (curAlert == 1) and it differs from the previous signal (curAlert != prvAlert), an alert message is constructed and sent.
  • If a sell signal is detected (curAlert == -1) and it differs from the previous signal, a similar alert message is constructed and sent.

Summary:

The code primarily focuses on detecting MACD zero-line crossings and issuing alerts when these crossings occur. This is useful in trading algorithms where MACD crossings can indicate buy or sell signals.


string TF2Str(int period)
  {
   switch(period)
     {
       //--
       case PERIOD_M1:   return("M1");
       case PERIOD_M2:   return("M2");
       case PERIOD_M3:   return("M3");
       case PERIOD_M4:   return("M4");
       case PERIOD_M5:   return("M5");
       case PERIOD_M6:   return("M6");
       case PERIOD_M10:  return("M10");
       case PERIOD_M12:  return("M12");
       case PERIOD_M15:  return("M15");
       case PERIOD_M20:  return("M20");
       case PERIOD_M30:  return("M30");
       case PERIOD_H1:   return("H1");
       case PERIOD_H2:   return("H2");
       case PERIOD_H3:   return("H3");
       case PERIOD_H4:   return("H4");
       case PERIOD_H6:   return("H6");
       case PERIOD_H8:   return("H8");
       case PERIOD_H12:  return("H12");
       case PERIOD_D1:   return("D1");
       case PERIOD_W1:   return("W1");
       case PERIOD_MN1:  return("MN");
       //--
     }
   return(string(period));
  }  
//---------//

This code defines a function TF2Str that converts a time period constant into a string representation. It uses a switch statement to match different period constants and returns the corresponding string.

Explanation:

  • 1. Function Signature: string TF2Str(int period): The function returns a string and takes an int parameter named period.
  • 2. Switch Statement: The switch statement evaluates the period and returns a corresponding string for each case.
  • 3. Case Statements: case PERIOD_M1: return("M1");: If period equals PERIOD_M1, the function returns the string "M1". This pattern is repeated for each predefined period constant, such as PERIOD_M2, PERIOD_M3, etc.
  • Default Case: If the period does not match any of the predefined cases, the function converts the period integer to a string and returns it. This ensures that the function always returns a valid string.

Use Case: This function is useful in scenarios where you need to convert time period constants (used in trading software or financial applications) to their string representations for display or logging purposes.

Function Alerts:

Function Definition:


void Do_Alerts(string msgText,datetime Altime)
  {
//---
    //--
    Print("--- "+Symbol()+": "+msgText+
          "\n --- at: ",TimeToString(Altime,TIME_DATE|TIME_MINUTES));
    //--
    if(alerts==Yes)
      {
        Alert(_name," --- "+Symbol()+": "+msgText+
              " --- at: ",TimeToString(Altime,TIME_DATE|TIME_MINUTES));
      }
    //--
    if(UseEmailAlert==Yes) 
      SendMail(_name," --- "+Symbol()+" "+TF2Str(Period())+": "+msgText+
                       "\n--- at: "+TimeToString(Altime,TIME_DATE|TIME_MINUTES));
    //--
    if(UseSendnotify==Yes) 
      SendNotification(_name+"--- "+Symbol()+" "+TF2Str(Period())+": "+msgText+
                      "\n --- at: "+TimeToString(Altime,TIME_DATE|TIME_MINUTES));
    //--
    return;
    //--
//---
  } //-end Do_Alerts()
//---------//

This function, Do_Alerts, sends different types of alerts (print messages, alerts, emails, notifications) based on MACD signal crosses detected. Here's a detailed breakdown:

  • 1. Print Message: This line prints the alert message along with the time of the alert. The Symbol() function returns the current symbol (currency pair or instrument), and TimeToString converts the datetime to a human-readable string format.
  • 2. Conditional Alerts:
    • Regular Alerts: If alerts are enabled (Yes), it sends an alert message.
    • Email Alerts: If UseEmailAlert is enabled, it sends an email with the alert message. The TF2Str(Period()) function converts the period to a string representation.
    • Push Notifications: If UseSendnotify is enabled, it sends a push notification with the alert message.
  • 3. Return Statement: The function ends here. The return statement ensures the function exits after executing the necessary alert commands.

Summary:

This function is designed to handle various types of alerts based on market conditions or trading signals. It ensures that you are notified through different channels (console print, alert, email, and push notification) whenever an important event occurs in your trading strategy.

The programs and functions in the template that I show above are just examples, they can be applied to both custom indicators and expert advisors with MQL5 and MQL4.

If the function template is applied to MQL4, then you must delete the timeframe periods that do not exist in MQL4, because MQL5 uses 21 timeframes while MQL4 only uses 9 timeframes.

You can adjust and modify the handling according to your needs.

MACD_Alerts indicator test results:

MACD_Alerts indicator test results

That's all for the article How to add Alerts to MT4 and MT5 programs, hopefully it's useful.

Thank you for reading.

Please download the MACD Indicator Alert: MACD Alert

If you are subscribed to my YouTube Channel, and would like to receive the source program of this article, please send a request via the Contact Us form page, and I will send it to your email, source code: MACD_Alerts Indicator.

Don't forget to stop by and subscribe to Forex Home Experts YouTube Channel:

YouTube Channel: @ForexHomeExperts

YouTube Playlist: @ForexHomeExperts YouTube Playlist

Featured Post

How to create a simple Multi-Currency Expert Advisor using MQL5 with Zigzag and RSI Indicators Signal

Introduction The Expert Advisor discussed in this article is a multi-currency trading robot that uses the Zigzag and RSI indicators. It fol...