Today I am going to teach you how to implement alerts in your custom indicators. To do so, we’ll further ellaborate on top of our previously coded Custom Indicator 102. The resulting code will serve as a template for a filtered signals indicator with alerts.
If you haven’t read my previous post entitled Custom Indicators 102, start there instead. Else, you’ll be lost in translation reading this post.
How alerts work in MQL4
The MQL4 language has a native function called Alert() which we can use to raise a visual alert in Metatrader, informing the user about a signal or situation that requires attention. The prototype is quite simple.
void Alert( argument, // first value ... // other values );
The issue when it comes to indicators is to raise alerts properly. A proper alert requires auxiliary code to avoid raising alerts when the indicator loads and iterates past bars, as well as alerting just once per bar and not every single tick.
Create a new file
Before proceeding, open the Indicator102.mq4 indicator in MetaEditor, and click on File -> Save As. Next, save the file as Indicator103.mq4 to make this a new project and avoid overriding the original indicator.
Add inputs and variables
First things first: we need to make alerts an optional feature and let the user enable and disable alerts at will. This might seem unnecessary but if we intend to use this indicator to later code other indicators or expert advisors, we need to be able to disable alerts to avoid alerts permeating into other programs later.
To do so, we need to add another input parameter to the indicator like so, above the OnInit() function in the input parameters block. I usually declare alerts disabled by default and let the user enable them at will.
extern bool DisplayAlerts = false;
Secondly, we also need two global variables to control when the alerts are raised. We want to raise alerts after the indicator has loaded and a new bar has closed storing a trading signal. We don’t want the indicator to raise alerts on past bars or every single tick.
Declare the following variables above the OnInit() function.
static datetime TimeStamp; static int AlertCount = 1;
The first variable will hold the open time of the unclosed bar and will help us to avoid raising repeated signals every single tick. The second variable will avoid the indicator from raising an alert just after loading. We’ll arrange the code to update these values to meet our needs below.
Implement the alert logic
All that remains to be done is implementing the alert code logic. The alert code logic must be implemented outside the loop that iterates past bars from past to present, to avoid the indicator from raising alerts on past bars which are no longer actionable. Paste the following code outside the bar loop, inside the OnCalculate(…) function.
// Alerts if(DisplayAlerts) { // On new bar closing if(TimeStamp != Time[0]) { // Check buy signal if(ExtMapBuffer1[Shift] != 0 && ExtMapBuffer1[Shift] != EMPTY_VALUE && AlertCount == 0) { Alert(ShortName +" ["+ Symbol() +"] Buy"); // Check sell signal } else if(ExtMapBuffer2[Shift] != 0 && ExtMapBuffer2[Shift] != EMPTY_VALUE && AlertCount == 0) { Alert(ShortName +" ["+ Symbol() +"] Sell"); } TimeStamp = Time[0]; AlertCount = 0; } }
The above code evaluates theĀ buffers of the indicator and raises alerts when needed with the text “Buy” or “Sell”, only for the recently closed bar. It ignores past bars and does not execute when the indicator has just loaded. Additionaly, the code block is not executed if the user has disabled alerts in inputs.
The complete code
The final source code of Indicator103.mq4 is the following. It implements all the features of Indicator 102, plus the alerts we recently added in this post. Two other constants have been added with the indicator name and shift to read signals from, and default values for the signal values have been set to empty value on the main bar iteration.
//---- File Properties #property copyright "Arthur Lopez" #property link "http://www.pointzero-trading.com" #property description "101: Sample indicator that plots breakout arrows." #property description "102: Implements mtf native filters." #property description "103: Implements alerts." #property version "1.0" #property strict //---- Indicator drawing and buffers #property indicator_chart_window #property indicator_buffers 2 //---- Colors and sizes for buffers #property indicator_color1 clrDodgerBlue #property indicator_color2 clrTomato #property indicator_width1 2 #property indicator_width2 2 //---- Constants #define ShortName "Indicator 103" #define Shift 1 //---- Input Parameters extern ENUM_TIMEFRAMES FTF = PERIOD_CURRENT; // Filter Timeframe extern int RSIPeriod = 14; // RSI Period extern int RSIOverbought = 70; // RSI Overbought extern int RSIOversold = 30; // RSI Oversold extern int MACDFastEMA = 12; // MACD Fast EMA extern int MACDSlowEMA = 26; // MACD Slow EMA extern int MACDSignal = 9; // MACD Signal extern bool DisplayAlerts = false; // Alerts //---- Buffer Arrays double ExtMapBuffer1[]; double ExtMapBuffer2[]; //---- Alert control static datetime TimeStamp; static int AlertCount = 1; //+------------------------------------------------------------------+ //| Custom indicator initialization function //+------------------------------------------------------------------+ int init() { // First buffer SetIndexBuffer(0, ExtMapBuffer1); // Assign buffer array SetIndexStyle(0, DRAW_ARROW); // Style to arrow SetIndexArrow(0, 233); // Arrow code //Second buffer SetIndexBuffer(1, ExtMapBuffer2); // Assign buffer array SetIndexStyle(1, DRAW_ARROW); // Style to arrow SetIndexArrow(1, 234); // Arrow code // Exit return(0); } //+------------------------------------------------------------------+ //| 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[]) { // Start and limit int start = 1; int limit; // Bars counted so far int counted_bars = IndicatorCounted(); // No more bars? if(counted_bars < 0) return(-1); // Do not check repeated bars limit = Bars - 1 - counted_bars; // Iterate bars from past to present for(int i = limit; i >= start; i--) { // Set signals to empty ExtMapBuffer1[i] = EMPTY_VALUE; ExtMapBuffer2[2] = EMPTY_VALUE; // If not enough data... if(i > Bars-3) continue; // Set values to empty ExtMapBuffer1[i] = EMPTY_VALUE; ExtMapBuffer2[2] = EMPTY_VALUE; // RSI double rsi_value = iRSI( Symbol(), FTF, RSIPeriod, PRICE_CLOSE, i); // MACD Main double macd_main = iMACD( Symbol(), FTF, MACDFastEMA, MACDSlowEMA, MACDSignal, PRICE_CLOSE, MODE_MAIN, i); // MACD Signal double macd_signal = iMACD( Symbol(), FTF, MACDFastEMA, MACDSlowEMA, MACDSignal, PRICE_CLOSE, MODE_SIGNAL, i); // Check buy signal if(Close[i] > High[i+1] && !(Close[i+1] > High[i+2]) && rsi_value < RSIOverbought && macd_main > macd_signal) { ExtMapBuffer1[i] = Low[i]; } // Sell check signal if(Close[i] < Low[i+1] && !(Close[i+1] < Low[i+2]) && rsi_value > RSIOversold && macd_main < macd_signal) { ExtMapBuffer2[i] = High[i]; } } // Alerts if(DisplayAlerts) { // On new bar closing if(TimeStamp != Time[0]) { // Check buy signal if(ExtMapBuffer1[Shift] != 0 && ExtMapBuffer1[Shift] != EMPTY_VALUE && AlertCount == 0) { Alert(ShortName +" ["+ Symbol() +"] Buy"); // Check sell signal } else if(ExtMapBuffer2[Shift] != 0 && ExtMapBuffer2[Shift] != EMPTY_VALUE && AlertCount == 0) { Alert(ShortName +" ["+ Symbol() +"] Sell"); } TimeStamp = Time[0]; AlertCount = 0; } } // Exit return(rates_total); }
Test the result
To make sure everything works fine, all we need to do is run the indicator in the tester. The Journal tab will store and display all the alerts raised. During live trading, these alerts will be raised as dialogs.
I hope this serves as an useful template for your own custom signal indicators with alerts. This guide can also be used to implement alerts on existing custom indicators.
Feel free to post your comments or questions below. Thank you.
Dear Arthur,
Thanks for your informative videos, it has benefited me a lot. I have a small doubt. I am combining two indicators into one, to make it a single indicator. Both the source has for loops, how can I merge them into one ?
You can’t mix two indicators into one, not without many problems. It is better to call one from the other using iCustom() and blending the trading logic only.