When we configure the manual alert options of a MultiCharts indicator or signal (trading strategy), we can have our script generate an alert once per bar or with every price update. But how to limit our alerts to a maximum amount per bar?

In this article:

Limiting the number of intra-bar alerts programmatically

We trigger MultiCharts alerts programmatically with Alert() (MultiCharts Wiki, 2012a). Before this keyword can generate alerts, however, we do need to enable the script’s alert settings. Those alerts can appear as a notification window, audio alert, and/or email alert (MultiCharts Wiki, 2013). How our indicator or signal generates alerts depends on the script’s manual alert settings.

We turn on the alerts of a script with the ‘Enable Alerts’ checkbox, and there are three ‘Alert Conditions Check’ settings for when the alert should fire:

Enabling MultiCharts alerts in indicators and trading strategies

What these three options also show, is that we can’t limit the number of alerts to a certain amount: we either have the script generate at most one alert per bar (‘On Bar Close’ or ‘Once Per Bar’) or allow it to possibly generate an alert with every price update (‘Every Tick’).

While a limit of at most 1 alert per bar does prevent a flood of alert messages, it also prevents us from getting an occasional reminder alert when we missed the first alert. Luckily, we can programmatically limit the number of alerts per price bar by using PowerLanguage code.

One approach for that is creating a counter variable, and then use that variable to track how often we’ve executed the Alert() keyword during the current bar. Since that variable will be updated during intra-bar script calculations, we need to declare it with IntrabarPersist. That keyword makes it possible for the variable to keep the value that we assign to it during an intra-bar script calculation (MultiCharts Wiki, 2012b). It does make sense that variables remember their values, but the default behaviour of PowerLanguage is that variables only keep the value stored in them during an calculation on bar close.

Now if we increment such a counter variable each time we fire an alert, we can also check its value before generating an alert. That way we can see if we’ve already reached the maximum number of allowed alerts per bar or not. The last step of this approach is to reset the counter variable when the price bar closes. By doing so the variable starts counting anew at the start of the next price bar.

Let’s see how we can combine those different steps into one coherent example script.

Example: generating at most 3 MultiCharts alerts per price bar

In the example indicator below we trigger intra-bar alerts based on two Exponential Moving Averages (EMAs) crossing each other. With input options we set the length of these averages, but also have an input that specifies how many alerts the script may generate per bar. We also have the alert messages display how many alerts are generated during the current bar. That way we track the indicator’s alert behaviour.

The image below gives an example of those alerts. After discussing the code, we’ll take a closer look at the indicator’s behaviour and the alerts it generates.

Example alerts generated by the MultiCharts indicator

Inputs:
    Max_Alerts_Per_Bar(3),
    Quick_EMA_Length(10),
    Slow_EMA_Length(24);
    
Variables:
    IntrabarPersist alertsGenerated(0),
    quickMA(0), slowMA(0);
    
// Compute and plot moving averages
quickMA = XAverage(Close, Quick_EMA_Length);
slowMA  = XAverage(Close, Slow_EMA_Length);

Plot1(quickMA, "Fast EMA", Magenta);
Plot2(slowMA,  "Slow EMA", Blue); 

// Generate an intra-bar alert when the fast EMA crossed above the slow one
if (alertsGenerated < Max_Alerts_Per_Bar) and 
      (quickMA crosses over slowMA) then begin

    alertsGenerated = alertsGenerated + 1;
    
    Alert("#" + NumToStr(alertsGenerated, 0) + 
        ". Fast moving average crossed above the slow one.");

end

// Trigger another alert when the fast average drops below the slow one
else if (alertsGenerated < Max_Alerts_Per_Bar) and 
      (quickMA crosses under slowMA) then begin

    alertsGenerated += 1;
    
    Alert("#" + NumToStr(alertsGenerated, 0) + 
        ". Quick EMA dropped below the slower average.");

end;

// Reset counter on bar close
if (BarStatus = 2) then
    alertsGenerated = 0;

We begin by creating a couple of inputs and variables:


Inputs:
    Max_Alerts_Per_Bar(3),
    Quick_EMA_Length(10),
    Slow_EMA_Length(24);
    
Variables:
    IntrabarPersist alertsGenerated(0),
    quickMA(0), slowMA(0);

With these numerical input options we can easily configure the script without having to edit and recompile the code. The first is named Max_Alerts_Per_Bar and given a default value of 3. This input’s value is used later when we determine whether the number of alerts generated during the current bar are still within the allowable range.

The other two inputs (Quick_EMA_Length and Slow_EMA_Length) have default values of 10 and 24, and we’ll use these when computing the moving averages.

Then we create three numerical variables. The first is alertsGenerated, and we mark this variable with the IntrabarPersist keyword. That makes the variable hold any value that’s stored in it during an intra-bar script calculation (MultiCharts Wiki, 2012b). With this we override the default MultiCharts behaviour, which is to have variables only remember values that are assigned to them during an on-bar-close calculation. The purpose of the alertsGenerated variable is to track how many alerts are generated during the same bar.

We use the quickMA and slowMA variables to hold the values of the 10-bar and 24-bar EMAs, which we calculate next:


quickMA = XAverage(Close, Quick_EMA_Length);
slowMA  = XAverage(Close, Slow_EMA_Length);

Both variables are set to the value returned by XAverage(). That function calculates an EMA and requires two parameters: a series of values to process and the length of the moving average in number of bars. For the quickMA variable, XAverage() uses the bar’s closing prices (Close) with a length of Quick_EMA_Length bars, the input option that we gave a default value of 10. The slowMA variable is set to the 24-bar (the default value of Slow_EMA_Length) EMA of closing prices.

After calculating the EMAs we plot them on the chart:


Plot1(quickMA, "Fast EMA", Magenta);
Plot2(slowMA,  "Slow EMA", Blue); 

The Plot1() and Plot2() keywords can accept a lot of parameters, but we only use three here: the plot’s value, name, and colour (MultiCharts Wiki, 2012c).

The Plot1() statement displays the quickMA variable on the chart, and we name that plot “Fast EMA”. Though we have no use for the plot’s name in the current example, we still need to set this parameter in order to set the plot’s colour. That third parameter is set to the Magenta basic MultiCharts colour.

With the Plot2() keyword we display the slowMA variable on the chart. We name that plot “Slow EMA” and have it appear in the Blue standard colour.

The rest of the indicator’s code generates alerts with an if/else statement, whose if portion looks as follows:


if (alertsGenerated < Max_Alerts_Per_Bar) and 
      (quickMA crosses over slowMA) then begin

    alertsGenerated = alertsGenerated + 1;
    
    Alert("#" + NumToStr(alertsGenerated, 0) + 
        ". Fast moving average crossed above the slow one.");

end

This if statement’s condition has two expressions that are combined with and. That PowerLanguage keyword only returns true when the value on its left and the value on its right are true too. Should one or both values be false, then and returns false too (MultiCharts Wiki, 2012d). And so this if statement’s code only executes when both expressions evaluate to true.

The first expression checks if the alertsGenerated variable is less than (<) the Max_Alerts_Per_Bar input option, that we gave a value of 3. Because the alertsGenerated variable counts how many alerts generate during the current bar, this expression is only true when there are 0, 1, or 2 alerts fired during this bar.

The second expression evaluates whether the 10-bar moving average (quickMA) crosses over the 24-bar EMA (slowMA). To translate that into PowerLanguage code, we use crosses over. That keyword combination returns true when, on the current bar, the value on its left is greater than the value on its right while, on the previous bar, its left value was less than or equal to the right value (MultiCharts Wiki, 2012e). When such a crossover didn’t happen, crosses over returns false.

Note: That crossover can happen multiple times on a real-time price bar. That’s because crosses over compares the previous bar value with the current bar’s price – and that latter changes with each incoming tick. Because we track how many alerts are generated during the current bar and use that as a filter, we prevent the indicator from generating too many alerts.

With less than 3 alerts generated on the current bar and the fast moving average crossing above the slower one, the code inside the if statement executes. That code first increases the alertsGenerated variable with 1 so we accurately track how many alerts we generate.

Then we generate an alert programmatically with the Alert() keyword (MultiCharts Wiki, 2012a). We set the alert’s message to be a fixed textual string coupled with a dynamic numerical value (the alertGenerated variable), and we format that latter with NumToStr(). That keyword converts a number to a string, with its first parameter the number to convert and the second specifying how many decimals that number should get (MultiCharts Wiki, 2012f). By formatting the alertsGenerated variable to a zero-decimal string, the alert messages look nicer (see image above).

Note: The code inside this if statement only executes as long as the script hasn’t reached the maximum number of alerts per bar. This can also make a script more efficient, since calculations inside this if statement only happen when the maximum number of alerts hasn’t been reached yet.

The else portion of the if/else statement is much the same, but this time we trigger an alert whenever the 10-bar EMA drops below the 24-bar EMA:


else if (alertsGenerated < Max_Alerts_Per_Bar) and 
      (quickMA crosses under slowMA) then begin

    alertsGenerated += 1;
    
    Alert("#" + NumToStr(alertsGenerated, 0) + 
        ". Quick EMA dropped below the slower average.");

end;

The first expression in this if statement’s condition checks whether the script hasn’t generated the maximum number of alerts per bar (alertsGenerated < Max_Alerts_Per_Bar). The other expression evaluates if the value of the quickMA variable dropped below that of the slowMA variable. We implement that with crosses under.

That keyword combination that returns true when, on the current bar, the value on its left is less than the value on its right while, on the previous bar, the left value was greater than or equal to the right value (MultiCharts Wiki, 2012e). Without such a crossunder, crosses under returns false. With the quickMA and slowMA variables, that means this expression evaluates to true when the 10-bar moving average falls below the 24-bar average.

When that happens, we add 1 to the value of the alertsGenerated variable. This time, instead of updating that variable’s value to alertsGenerated + 1, we use the += operator. This operator combines adding 1 with assigning the updated value, and that makes it a shorthand way to increase the value of any variable with 1. But other than less code to type, += has no benefit and is only used here to show the different approaches you can use.

After updating alertsGenerated we generate an alert programmatically with Alert(). We again include that variable’s value in the alert message, which this time says the quick EMA dropped below the slower one.

We end the example by resetting the counter variable as soon as the bar closes:


if (BarStatus = 2) then
    alertsGenerated = 0;

The condition of this if statement checks whether the BarStatus keyword returns a value equal to (=) 2. With that keyword we can determine whether the most recent tick is the bar’s opening tick, closing tick, or a price update that’s in between (MultiCharts Wiki, 2014). Now when BarStatus returns a value of 2, then the latest price update of the instrument that the script calculates on is the bar’s closing tick (MultiCharts Wiki, 2014).

We use that situation here to reset our alertsGenerated variable back to 0. This way our variable starts again from zero on the next price bar, which allows the indicator to again generate up to 3 alerts on that next price bar. If we don’t reset alertsGenerated at the close of each price bar, then the script can generate only 3 alerts in total, and not 3 per price bar.

Example: limiting moving average crossover alerts in MultiCharts

Now let’s see how the alerts generated by the indicator look like. Before firing alerts, we add the script to the chart with the following manual alert settings:

Configuring the alert settings of the MultiCharts indicator

Since the code already limits the number of alerts per bar, we can choose the ‘Every Tick’ option without the risk of being flooded in alert messages. Note that, if we choose ‘On Bar Close’ or ‘Once Per Bar’, then the MultiCharts program limits the number of alerts the indicator can generates and we will not get the three alerts per bar.

We configure that maximum number of alerts, by the way, with the ‘Max_Alerts_Per_Bar’ input option:

Input options of the MultiCharts example indicator

The indicator with its default settings looks like this on the chart:

The moving averages of the example MultiCharts indicator plotted on the chart

And the different alerts generated by script appear as follows:

Examples of the MultiCharts alerts generated by the indicator

Here we see with the number that’s printed in each alert message that there are at most three consecutive alerts. For other approaches that place a maximum on the amount of alerts fired, see limiting how many alerts a script generates.

Summary

MultiCharts alerts are generated with Alert(), although this does require that we enable the script’s manual alert setting. With other manual options we can configure whether the alert fires once per bar or possibly with every price update. Luckily, we can use code to specify exactly how many times the alert may fire per bar. That’s possible by increasing a counter variable with 1 each time we use Alert() to generate an alert. That approach requires a couple of things. First, we’ll need to mark our counter variable as IntrabarPersist. That keyword makes the variable remember the value we store in it during an intra-bar calculation, while the default behaviour (that is, without that keyword) only keeps the values that we assigned to a variable on bar close. Second, each time prior to generating an alert, we’ll need to check the value of our counter variable to see if we haven’t reached the maximum number of alerts for the current bar. The third and last step is resetting the variable at bar close. That way, on the next price bar, the script can generate up to its maximum number of alerts again. We use BarStatus to determine whether the price bar of the data series that the script calculates on has closed, in which case that keyword returns a value of 2.

Learn more:


References

MultiCharts Wiki (2012a, February 7). Alert. Retrieved on March 7, 2016, from http://www.multicharts.com/trading-software/index.php/Alert

MultiCharts Wiki (2012b, August 11). IntraBarPersist. Retrieved on May 8, 2016, from https://www.multicharts.com/trading-software/index.php/IntraBarPersist

MultiCharts Wiki (2012c, February 19). Plot. Retrieved on May 10, 2016, from https://www.multicharts.com/trading-software/index.php/Plot

MultiCharts Wiki (2012d, February 19). And. Retrieved on May 10, 2016, from http://www.multicharts.com/trading-software/index.php/And

MultiCharts Wiki (2012e, February 19). Cross. Retrieved on May 10, 2016, from https://www.multicharts.com/trading-software/index.php/Cross

MultiCharts Wiki (2012f, February 13). NumToStr. Retrieved on May 10, 2016, from https://www.multicharts.com/trading-software/index.php/NumToStr

MultiCharts Wiki (2013, May 10). Using Alerts. Retrieved on March 7, 2016, from https://www.multicharts.com/trading-software/index.php/Using_Alerts

MultiCharts Wiki (2014, August 12). BarStatus. Retrieved on May 10, 2016, from https://www.multicharts.com/trading-software/index.php/BarStatus

Visit programming tutorials for more helpful coding articles.