When we manually turn on a script’s alerts, there’s a manual option to configure whether the alert should fire once per bar or possibly with every price update. But what if we want to limit the number of alerts per bar, for instance by only generating an alert every certain number of times that the alert condition happens?

In this article:

Limiting MultiCharts alerts by not firing with each alert condition

In MultiCharts PowerLanguage, we generate alerts programmatically with Alert() (MultiCharts Wiki, 2012a). Before that keyword can actually fire alerts, however, we need to enable the script’s alert setting. Then, depending on our manual alert settings, our alert can appear as an audio alert, notification window, and/or email alert (MultiCharts Wiki, 2013).

We enable the script’s alerts with the ‘Enable Alerts’ option, and use the ‘Alert Condition Check’ radio buttons to configure how often the alert can fire:

Example of enabling the alerts of MultiCharts indicators and strategies

With these options the script can either generate an alert once per bar (‘On Bar Close’ or ‘Once Per Bar’) or potentially with every price update (‘Every Tick’). So we prevent a flood of alert message by having the script fire once per bar. But that’s also a loss of flexibility. Because what if we want to limit the alerts, but also generate an occasional reminder alert in case we were away from the computer or too busy managing other trades?

Luckily, with PowerLanguage code we can generate an alert every number of times that the alert condition is true. This is particularly a big help in cases where our alert condition, once triggered, remains active for the whole price bar. Like when we generate alerts based on the bar’s high or low breaking out, then on all other price updates in the same bar that condition remains active. However, it would be too much to generate an alert on all those price updates, but an occasional alert to confirm our bullish or bearish outlook is helpful.

Using code to generate an alert every number of times

Programmatically firing an alert every number of times the alert condition happens requires a couple of things. First, we’ll have to count how often the alert condition happens during a bar. With that information we can determine whether the alert should fire with this alert condition, or if we should wait till a later alert condition.

To track how often the alert condition occurred, we’ll need to create a numerical counter variable and mark that variable as IntrabarPersist. That keyword makes the variable remember the values stored in it during an intra-bar script calculation (MultiCharts Wiki, 2012b). With IntrabarPersist we override the default behaviour of PowerLanguage variables, which is to only remember the values that we assign to them when the price bar closes, surprisingly enough.

Next we increase that counter variable with 1 each time the alert condition happens. That way we track how often the alert condition (like a price breakout) happens during the current bar. That knowledge makes it possible to figure out if the alert condition has been triggered for the nth time during the current bar.

Say we want to generate a reminder alert every 5th time the alert condition happens. We do that by determining whether our counter variable is an even multiple of 5 (so 5, 10, 15, 20, etcetera) and then generate an alert each time that’s the case. Programmatically checking for an even multiple is done with mod(). That keyword requires two parameters (the dividend and divisor), and returns the remainder of dividing the first parameter by the second (MultiCharts Wiki, 2012c). That returned value is called the arithmetic remainder or modulus (Sharp, 2013).

mod() is helpful because, when the remainder equals 0, then the keyword’s second parameter divides evenly into the first. For instance, mod(10, 5) returns 0 (since 5 divides evenly into 10). And so when the counter variable (that tracks how often the alert condition happens) divides evenly into 5, then the current script calculation is the 5th time that the alert condition happened during the current bar. And when that happens, we generate an alert programmatically. In practice, this means our alerts only fire when the alert condition triggers for the first time, and then on the 5th, 10th, 15th, and so on times.

The last step to make this approach work is to reset the counter variable on the close of each price bar. That way, on the next price bar, we start counting again how often the alert condition happens. To check if the price bar closed we use the BarStatus keyword, which returns 2 when the most recent tick of the data series that the script calculates on is the bar’s closing tick (MultiCharts Wiki, 2014).

Now let’s see how this above discussion of generating an alert every certain number of times that the alert condition happens works in a full example indicator.

Example: triggering an alert every nth time

The example indicator below plots the daily high and low on the chart. Whenever the bar’s high or low crosses those daily values, we increase our alert condition counter with 1. That way we track how often the alert condition happens during the current bar. Now when that counter is an even multiple of the Occurrence input option, then we generate the actual alert. Since that input has a default value of 5, once every fifth time that the price crosses above the daily high or below the daily low, we generate an alert.

The image below shows how those alerts look like. After discussing the code, we’ll take a closer look at the indicator’s appearance and alerts.

Example of the alerts generated by the MultiCharts indicator

Inputs:
    Occurrence(5);
    
Variables:
    IntrabarPersist triggeredAlerts(0),
    dayHigh(0), dayLow(0);

// On the first bar of the day, we reset the daily variables
if (Date > Date[1]) then begin

    dayHigh = 0;
    dayLow  = 99999;
    
end;

// Trigger alerts
if (CheckAlert and (High > dayHigh)) then begin

    if (mod(triggeredAlerts, Occurrence) = 0) then
        Alert("New daily high!");
        
    triggeredAlerts = triggeredAlerts + 1;

end;

if (CheckAlert and (Low < dayLow)) then begin

    if (mod(triggeredAlerts, Occurrence) = 0) then
        Alert("New daily low!");
        
    triggeredAlerts += 1;

end;

// Update and plot values
dayHigh = MaxList(High, dayHigh);
dayLow  = MinList(Low, dayLow);

Plot1(dayHigh, "Day High", Green);
Plot2(dayLow,  "Day Low", Red);

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

We start with creating an input option and several variables:


Inputs:
    Occurrence(5);
    
Variables:
    IntrabarPersist triggeredAlerts(0),
    dayHigh(0), dayLow(0);

With manual input options we can easily set values that are used in the code, without having to edit and recompile the code. Here we create a numerical input option, Occurrence, and give it a default value of 5. We’ll use this input later on to see if how often the alert condition happened is cause for generating an alert. (This also means that, the higher this input’s value, the less often an actual alert generates when the alert condition happens.)

To track how often those alert conditions happen during a bar, we create the triggeredAlerts numerical variable. We mark this variable as IntrabarPersist. That way it retains the value we assign to it during an intra-bar calculation (MultiCharts Wiki, 2012b). And that overrides the default PowerLanguage behaviour whereby variables only remember the values stored in them during a calculation when the bar closes.

The other two numerical variables that we make, dayHigh and dayLow, will be used to track the daily high and low. These variables aren’t set to IntrabarPersist since we don’t use their intra-bar values. Instead, we use them more as temporary variables during the current script calculation.

Since those variables track daily prices, we’ll need to reset them once per day. That’s done with the following if statement:


if (Date > Date[1]) then begin

    dayHigh = 0;
    dayLow  = 99999;
    
end;

The if statement’s condition evaluates whether the date of the current bar (Date) is greater than (>) the date of the previous bar (Date[1]). This evaluates to true whenever the current bar is the first bar of the calendar day. When that happens, we assign the dayHigh variable a value of 0 and set dayLow to 99999.

Given how we calculate the values for these variables later on, resetting them at the start of each day ensures they track the day high and low (and not the highest high and lowest low since the beginning of the chart). dayLow is given a seemingly odd value of 99999 here because we’ll update this variable later to either its current value or the bar’s low, whichever of these is less. That means if we would reset dayLow to 0, then the variable never tracks the day low since its default value of 0 will always be less than the bar’s low.

Next is the first if statement that counts alert conditions and can trigger an alert too:


if (CheckAlert and (High > dayHigh)) then begin

    if (mod(triggeredAlerts, Occurrence) = 0) then
        Alert("New daily high!");
        
    triggeredAlerts = triggeredAlerts + 1;

end;

The condition of this if statement evaluates to expressions, joined together with and. That logical keyword returns true when the value on its left and the value on its right are both true too; otherwise, when one or both values are false, then and returns false too (MultiCharts Wiki, 2012e).

The first expression is CheckAlert. That keyword returns true when the current bar is the last of the data series and the script’s alert setting is enabled (MultiCharts Wiki, 2012d). This way we programmatically check if alerts are enabled, meaning the code inside the if statement only executes when the script can actually generate an alert.

The second expression checks whether the high of the current bar (High) is greater than (>) the dayHigh variable, which tracks the daily high (we’ll code the dayHigh value later on). Now when alerts are enabled and the bar reached a new daily high, the code inside the if statement executes. That code begins with another, nested if statement.

That nested if statement uses the mod() keyword to see whether the value of the triggeredAlerts variable divided by the Occurrence input option equals (=) 0. To get a better idea of what happens here, let’s take a step back first. That triggeredAlerts variable counts how often an alert condition happens during the current bar. And we gave the Occurrence input option a default of 5 earlier. Combined, this means mod(triggeredAlerts, Occurrence) returns 0 when triggeredAlerts divides evenly into 5 (so values of 0, 5, 10, 15, 20, and so on).

And in those situations, the if statement’s code executes. That indented statement contains the Alert() keyword for generating an alert programmatically. Inside that keyword’s parentheses we specify the message that a new daily high happened. And since we require that triggeredAlerts is an even multiple of 5, that alert only fires every fifth time that the alert condition happens.

Next is a statement that increases the value of triggeredAlerts with 1. This way we count how often the alert condition (that is, High > dayHigh) happens during the bar. Note that this line of code is not below the if statement that uses mod(), but rather at the level of the if statement that checks whether alerts are enabled and the bar’s high surpasses the dayHigh variable. This makes the triggeredAlerts variable track how often the alert condition happens, but not the actual number of generated alerts.

Then we have another if statement. This one checks if the bar’s low is below the daily low:


if (CheckAlert and (Low < dayLow)) then begin

    if (mod(triggeredAlerts, Occurrence) = 0) then
        Alert("New daily low!");
        
    triggeredAlerts += 1;

end;

This if statement is much like the previous one. We evaluate two expressions here before executing the code inside the if statement: CheckAlert has to return true and the current bar’s low (Low) needs to be less than (<) the dayLow variable. With both expressions true, the code inside the if statement executes.

That code begins with a nested if statement that uses mod() to see if the value of the triggeredAlerts variable is an even multiple of the Occurrence input option. When that’s the case, we use Alert() to generate an alert message that says the current bar’s low is a new daily low.

There’s also a second line of code inside the if statement that checks whether alerts are enabled and the low is below dayLow. That statement increases the triggeredAlerts variable with 1. We do that with the += operator, which combines adding 1 with assignment. So instead of writing triggeredAlerts = triggeredAlerts + 1, we can code triggeredAlerts += 1. Other than less typing, using += has no benefit over the regular approach; it’s just included here to show the different ways to increase a variable with 1.

After those if statements that check for possible alerts, we update the variables and plot them on the chart:


dayHigh = MaxList(High, dayHigh);
dayLow  = MinList(Low, dayLow);

Plot1(dayHigh, "Day High", Green);
Plot2(dayLow,  "Day Low", Red);

This part of the indicator is where we compute the values of dayHigh and dayLow. Because we reset both variables at the start of each calendar day, we know at this point that they track the daily extreme prices (as opposed to the weekly or all-time highs and lows). To update the dayHigh variable, we set it to the value returned by MaxList(). That keyword accepts a list of values and returns whichever value is the greatest (MultiCharts Wiki, 2012f).

Because we use MaxList() with the bar’s high (High) and dayHigh, the keyword either returns the current value of the dayHigh variable (when there’s no new daily high) or the high of the current bar (when there is a new daily high). The value that’s returned from these two is what we store in the dayHigh variable. That makes this variable track the highest high as it develops throughout the day.

Similarly, we update the dayLow variable with MinList(). That keyword returns the lowest of the values between its parentheses (MultiCharts Wiki, 2012g). Here, those values are the bar’s low (Low) and the current value of dayLow. With that, the ‘new’ value of dayLow is either its current value (when there isn’t a new daily low) or the bar’s low (when there is a new low for the day).

Then we plot both variables on the chart with Plot1() and Plot2(). Those keywords can use a range of parameters, of which we use three: the plot’s value, name, and colour (MultiCharts Wiki, 2012h). While the plot name isn’t directly useful in our example, we do need to set that parameter before we can define the plot’s colour.

We plot the dayHigh variable in the Green standard MultiCharts colour on the chart, and name this plot “Day High”. The second plot, “Day Low”, plots the dayLow values in the Red colour.

We end the example by resetting the triggeredAlerts variable:


if (BarStatus = 2) then
    triggeredAlerts = 0;

This if statement evaluates whether BarStatus returns a value equal to (=) 2. That keyword does that when the most recent price of the data series that the script calculates on is the bar’s closing tick (MultiCharts Wiki, 2014). So when the bar closes, we set triggeredAlerts back to 0. That makes the script start counting anew on the next bar, meaning it can accurately track how often an alert condition happens on that bar.

Example: fire MultiCharts alerts every number of alert conditions

Let’s see how the above code behaves. When we add the indicator to a chart, we use the following manual alert settings:

Configuring the alert settings of the MultiCharts example indicator

Even though we set the ‘Alert Conditions Check’ option to ‘Every Tick’, our indicator won’t generate an alert each time the alert condition happens. That’s because our code generates an alert every fifth time the alert condition happens.

We configure how often those alert conditions should translate into an actual alert with the ‘Occurrence’ input option:

Input options of the MultiCharts indicator

On the chart, the indicator looks like this:

Plotting the highest high and lowest low on the MultiCharts chart

And the alerts generated by the indicator appear as:

Examples of alerts triggered by the example indicator

These example alerts were triggered in real time, every fifth time a new daily high was reached. For more approaches to prevent a flood of alert messages, see limiting the number of alerts generated in MultiCharts.

Summary

We generate MultiCharts alerts programmatically with Alert(), although we do need to manually enable the script’s alert setting for that. Then each time our script executes the Alert() keyword, an alert can generate. One approach that limits how many alerts fire is to only generate them every nth time our alert condition happens. That way we get the initial alert as well as occasional reminder alerts when the alert condition occurs again. To implement this, we create a counter variable that tracks how often the alert condition happens. To make that variable remember its value from one intra-bar script calculation to the next, we mark it as IntrabarPersist. Otherwise, the variable only remembers the value stored in it when the bar closed. With the mod() keyword we can, by using that variable, generate an alert every number of alert conditions. That’s because mod() returns the arithmetic remainder of integer division, meaning it gives a value of 0 when its first parameter is an even multiple of the second parameter. By checking whether that keyword returns 0 we can trigger an alert every fifth time an alert condition happens.

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 13). Mod. Retrieved on May 10, 2016, from https://www.multicharts.com/trading-software/index.php/Mod

MultiCharts Wiki (2012d, February 7). CheckAlert. Retrieved on May 11, 2016, from https://www.multicharts.com/trading-software/index.php/CheckAlert

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

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

MultiCharts Wiki (2012g, February 9). MinList. Retrieved on May 11, 2016, from https://www.multicharts.com/trading-software/index.php/MinList

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

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 11, 2016, from https://www.multicharts.com/trading-software/index.php/BarStatus

Sharp, J. (2013). Microsoft Visual C# 2013 Step by Step. Microsoft Press.