After generating a MultiCharts alert programmatically, in rare circumstances we might want to cancel the alert before it has a chance to fire. How do we program that?

In this article:

Generating and cancelling MultiCharts alerts programmatically

We generate PowerLanguage alerts programmatically with the Alert() keyword (MultiCharts Wiki, 2012a). Before such an alert fires, we need to enable the script’s alert setting and likely also want to configure MultiCharts’ alert settings. Depending on those settings, the kind of alerts a script can fire are audio alerts, notification windows, and/or email alerts (MultiCharts Wiki, 2013).

When Alert() generates an alert, that alert fires immediately after the indicator or signal has executed all of its code on the current price update. We can, however, prevent that an already generated alert fires with the Cancel Alert keyword combination (MultiCharts Wiki, 2012d). This does require that we execute Cancel Alert in the same script calculation during which Alert() generated the alert; otherwise, the alert has already fired before Cancel Alert could cancel it. That means we’ll need to place Cancel Alert somewhere between Alert() and the very last line of the script’s code.

Tip: Don’t execute the Cancel Alert keyword unconditionally in your script, because then it will cancel each alert the script generates. Instead, execute Cancel Alert conditionally, like in an if statement.

In theory, the Cancel Alert keyword can be useful. For instance, when you have several Alert() statements in a script and want to cancel all of them whenever something specific happens. But Cancel Alert also makes the code harder to understand. And using an if statement to filter when Alert() should generate an alert is nearly always clearer.

Tip: It’s also possible to have the SetAlertState() keyword ’re-activate’ an alert that was cancelled with Cancel Alert. There might be a situation in which that’s actually needed, but most of the time your script becomes much harder to understand. For more, see programming tip: don’t combine Cancel Alert with SetAlertState().

One thing not possible with Cancel Alert is specifying which alert should be cancelled when there are multiple alerts generated with Alert(). Instead, Cancel Alert simply cancels any alert generated during the current script calculation.

Example: generate and then cancel MultiCharts alerts programmatically

Now let’s see how we can use Cancel Alert in a script. In the example indicator below, we generate an alert when the faster EMA (Exponential Moving Average) crosses a slower one. The script processes mouse clicks so that a click on the chart with Control allows us to execute the Cancel Alert keyword to prevent any alert from generating. When we cancel alerts like that, we do print a message to the Output tab of the PowerLanguage Editor to keep track of the script.

The image below shows an example of the script’s alert messages. After discussing the code, we’ll take a closer look at the indicator’s behaviour, the alerts, and text output.

Example alerts generated by the MultiCharts script

[ProcessMouseEvents = true];

Inputs:
    Fast_EMA_Length(10),
    Slow_EMA_Length(25);

Variables:
    IntrabarPersist alertOn(true),
    fastEMA(0),
    slowEMA(0);

if (BarStatus = 2) then begin

    // Calculate the moving averages
    fastEMA = XAverage(Close, Fast_EMA_Length);
    slowEMA = XAverage(Close, Slow_EMA_Length);
    
    // Trigger an alert on EMA cross
    if (fastEMA crosses over slowEMA) then begin
        Alert("Fast EMA crossed above the slow one");
        
        // .. but output an info message when the
        // alert will be cancelled later
        if (alertOn = false) then
            Print("Fast EMA crossed above slow EMA, ",
                "but not generating an alert here.");
    end 
    
    else if (fastEMA crosses under slowEMA) then begin
        Alert("Fast EMA dropped below the slow moving average");
        
        if (alertOn = false) then
            Print("Fast EMA dropped below slow EMA, ",
                "but not generating an alert here.");

    end;

    // Cancel any generated alert
    if (alertOn = false) then
        Cancel Alert;
        
end;

// Enable or disable alerts with a mouse click on the chart
if (MouseClickCtrlPressed) then begin
    
    alertOn = not alertOn;
    
    Print("Click + Ctrl. Alerts enabled now? ", alertOn);
    
end;

We first set the ProcessMouseEvents attribute to true, which programmatically processing mouse clicks. Then we add two input options to the indicator:


Inputs:
    Fast_EMA_Length(10),
    Slow_EMA_Length(25);

The Fast_EMA_Length and Slow_EMA_Length inputs have default values of 10 and 25, and we use them later when computing the moving averages. By configuring them with input options, we can easily change the length of the EMAs without having to edit and recompile the script.

Next we create three variables:


Variables:
    IntrabarPersist alertOn(true),
    fastEMA(0),
    slowEMA(0);

The first variable is named alertOn, and this true/false variable starts with a default value of true. We use alertOn in the script to determine whether we should cancel the script’s alerts or not. This variable is marked with the IntrabarPersist keyword.

That keyword ensures that the variable holds its value, even when we update it during an intra-bar calculation (see MultiCharts Wiki, 2012e). While it makes sense for variables to keep (and not ‘forget’) their value, MultiCharts variables by default only keep the value assigned to them when the bar closes. With IntrabarPersist, we override that default behaviour and have the variable keep its value regardless of when we update it.

The two other variables that we make are numerical variables: fastEMA will hold the quick EMA value later on, while the value of the slower moving average is tracked with slowEMA.

Then a large part of the script’s code is placed inside the following if statement:


if (BarStatus = 2) then begin

    // ...

end;

Here we evaluate whether the BarStatus keyword returns a value that’s equal to (=) 2. That keyword returns such a value when the script current calculation happens on the closing tick of its data series (MultiCharts Wiki, 2014). That means that the code inside the if statement only executes during the closing tick of the current price bar.

By executing all that code when the bar has closed, the script runs more efficient. For instance, now the moving averages don’t have to be calculated with every tick but only once per bar. And we also prevent multiple alerts generating on the same bar by only firing an alert when the bar has closed.

In the if statement that checks whether the bar is currently closed, we first compute the EMAs:


fastEMA = XAverage(Close, Fast_EMA_Length);
slowEMA = XAverage(Close, Slow_EMA_Length);

We use the XAverage() function to get the moving average values. That function calculates an Exponential Moving Average with two parameters: the values to process and the length of the moving average. In the first statement, we calculate the moving average based on closing prices (Close) with a length set by the Fast_EMA_Length input option, that we gave a default value of 10 earlier. We store the moving average’s value in the fastEMA variable to use later.

Then we calculate the other EMA with the second XAverage() function, which also uses closing prices but has a length of Slow_EMA_Length, the input with a standard value of 25. We store this second EMA value in the slowEMA variable.

Next we trigger an alert based on those EMA variables:


if (fastEMA crosses over slowEMA) then begin
    Alert("Fast EMA crossed above the slow one");

    if (alertOn = false) then
        Print("Fast EMA crossed above slow EMA, ",
            "but not generating an alert here.");
end 

This if statement’s condition evaluates whether the 10-bar EMA (stored in the fastEMA variable) crossed above (crosses over) the 25-bar EMA (slowEMA). The crosses over keyword combination returns true when, on the current bar, the value left of this keyword is above the value on its right while, on the previous bar, the left value was less than or equal to the right value (MultiCharts Wiki, 2012f).

When that crossover happens, we programmatically generate an alert with Alert(). Inside the parentheses of that keyword we specify a static alert message saying “Fast EMA crossed above slow EMA”.

A nested if statement then checks whether the alertOn true/false variable equals (=) false. Later in the script, we’ll update the value of alertOn and cancel alerts with Cancel Alert when that variable is false. But to keep track of when we cancel alerts, we use the Print() keyword to output information to the PowerLanguage Editor (MultiCharts Wiki, 2012g). That way we can verify in the Output tab of the PowerLanguage Editor that a crossover indeed happened, but that the alert was cancelled later on in the script due to the alertOn variable.

Then we come across an else if statement that triggers alerts for downward crossovers:


else if (fastEMA crosses under slowEMA) then begin
    Alert("Fast EMA dropped below the slow moving average");
    
    if (alertOn = false) then
        Print("Fast EMA dropped below slow EMA, ",
            "but not generating an alert here.");

end;

This code is much like previous if statement, except that here we check whether the 10-bar EMA (fastEMA) dropped below (crosses under) the 25-bar EMA (slowEMA). That crosses under keyword combination returns true when, on the current bar, the value on the left is less than the value on the right of this keyword combination while, on the previous bar, the left value was greater than or equal to the right value (MultiCharts Wiki, 2012f).

With such a crossover, we generate an alert message programmatically with Alert(). A nested if statement then checks if alertOn is false, and when it is, we display another message in the Output tab of the PowerLanguage Editor to keep track of the indicator.

Cancelling alerts is what we do next in the script:


if (alertOn = false) then
    Cancel Alert;

Here we evaluate whether the alertOn variable equals (=) false. When it does, we use the Cancel Alert keyword to cancel any alert that’s generated by the indicator during the current script calculation (MultiCharts Wiki, 2012d).

Then in the last part of the indicator we update that alertOn true/false variable:


if (MouseClickCtrlPressed) then begin
    
    alertOn = not alertOn;
    
    Print("Click + Ctrl. Alerts enabled now? ", alertOn);
    
end;

The first to note here is that this code is not placed inside the if statement that checks if the bar has closed (the BarStatus = 2 if statement). This means we can update the alertOn variable each time we click on the chart, and don’t have to time those clicks to happen at the same time the bar closes.

This last if statement evaluates MouseClickCtrlPressed, a keyword that returns true when the Control key is held during a mouse click on the chart (MultiCharts Wiki, 2012h). When such a click happens, the code inside the if statement first switches the value of alertOn to false (when it’s currently true) or to true when this variable is currently false. We do this by setting this variable’s new value to not alertOn. That not logical keyword performs logical negation: it returns the logical opposite of the value it’s placed for (MultiCharts Wiki, 2012i).

So when alertOn is true, then not alertOn returns false. And when alertOn is false, then not alertOn returns true. This way we ‘flip’ the variable’s value. Since this happens in the if statement that only executes with a mouse click plus Control, each of those clicks toggles the value of the variable.

After flipping the value of alertOn we use Print() to output an informative message to the Output tab of the PowerLanguage Editor. That allows us to track whether the script currently cancels any alert it generates or not.

Example: cancel alerts with PowerLanguage code

Now let’s see how our example script behaves. First, our indicator has the following input options:

Input options of the MultiCharts script

Since our indicator generates alerts but doesn’t plot the EMAs, we need to add the ‘Mov Avg Exp 2 Lines’ standard indicator to the chart for visual confirmation:

Example chart with the indicator's moving averages

Before the example script can generate its alerts, we need to enable the script’s alert settings. For that we right-click on the indicator’s name in the chart’s Status Line window and select ‘Format [script name]’:

Formatting the settings of a MultiCharts indicator

This opens a window with different indicator settings. There we move to the ‘Alerts’ tab to enable and manually configure the alert settings like so:

Configuring the alert settings of the MultiCharts example indicator

After confirming those settings, the script generates alert messages like the following whenever the fast moving average crosses the slower one:

Example of the alert messages generated by the script

Now to cancel alerts, we need to click somewhere in the price chart and hold down the Control key. When we do, the following message appears in the Output tab of the PowerLanguage Editor:

Click + Ctrl. Alerts enabled now? FALSE

Now the indicator cancels any generated alert with Cancel Alert. But it does print the following output each time the moving averages cross:

Fast EMA dropped below slow EMA, but not generating an alert here.
Fast EMA crossed above slow EMA, but not generating an alert here.

This shows how MultiCharts mouse clicks allows us to quickly turn on or off a script’s alert generation. For another example that combines alerts with mouse clicks, see generating semi-automatic alerts with mouse clicks.

Summary

We generate alerts programmatically with the Alert() keyword. That does require that we enable the script’s manual alert settings. We prevent an alert generated by Alert() from firing with Cancel Alert. That keyword combination cancels any alert generated during the current script calculation. As such we need to execute Cancel Alert conditionally, like in an if statement; otherwise, all alerts generated by the script are cancelled before they had a chance to fire. There is probably a situation in which Cancel Alert is useful. But this keyword does make the code harder to understand and increases the bug potential. Using an if statement to filter when Alert() generates the alert in the first place gives much clearer code.

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, February 7). CheckAlert. Retrieved on March 11, 2016, from http://www.multicharts.com/trading-software/index.php/CheckAlert

MultiCharts Wiki (2012c, February 26). AlertEnabled. Retrieved on March 11, 2016, from http://www.multicharts.com/trading-software/index.php/AlertEnabled

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

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

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

MultiCharts Wiki (2012g, February 13). Print. Retrieved on March 18, 2016, from https://www.multicharts.com/trading-software/index.php/Print

MultiCharts Wiki (2012h, February 24). MouseClickCtrlPressed. Retrieved on March 18, 2016, from http://www.multicharts.com/trading-software/index.php/MouseClickCtrlPressed

MultiCharts Wiki (2012i, February 19). Not. Retrieved on March 18, 2016, from https://www.multicharts.com/trading-software/index.php/Not

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

Visit Kodify.net for more helpful coding articles.