MultiCharts indicators and signals can only generate alerts when we’ve turned on the ‘Enable Alerts’ option. How can we programmatically verify whether we’ve enabled that manual option?

In this article:

Using and enabling programmatic alerts in MultiCharts

We use the Alert() keyword in MultiCharts to generate alerts programmatically (MultiCharts Wiki, 2012a), and with that we can create notifications for situations like when an oscillator enters or leaves an overbought area. Alerts in MultiCharts can generate as an audio alert, notification window, and/or email alert (MultiCharts Wiki, 2013).

But before our indicator or strategy can generate alerts, we need to enable its alert settings by hand – we currently cannot use code to turn on a script’s alerts. This is slightly counter-intuitive: unless we’ve enabled the script’s alert settings, our Alert() statements will simply not execute.

That option that needs to be enabled in the script’s alert settings before an alert can generate is called ‘Enable Alerts’:

Example of the 'Enable Alerts' checkbox option in MultiCharts

This checkbox is the most important manual alert setting: without enabling it, our script cannot generate alerts programmatically. Luckily, there are two keywords with which we can check whether that option is enabled (MultiCharts Wiki, 2012b, 2012c):

  • The AlertEnabled keyword returns true when the script’s ‘Enable Alerts’ option is enabled and false when that checkbox is disabled.
  • The CheckAlert keyword returns true when the script’s ‘Enable Alerts’ setting is enabled and the bar that’s currently processed by the script is the last bar of the data series. CheckAlert returns false when that setting is disabled or when the current bar isn’t the last.
Note: While AlertEnabled also checks on historical bars whether the script’s alerts are enabled, the Alert() keyword only generates alerts on the last bar (MultiCharts Wiki, 2012a). AlertEnabled is helpful, however, for instance when we want to minimise the script’s calculations when alerts are disabled.

Thanks to AlertEnabled and CheckAlert, we can treat several parts of our script differently based on the state of the ‘Enable Alerts’ option. This means we can use these keywords to make scripts run more efficient (by preventing unnecessary calculations when alerts are turned off), generate an error when alerts are disabled, or create a notifying text box when alerts are off.

For a better idea of how AlertEnabled and CheckAlert work, let’s look at a programming example.

Example: using code to verify if MultiCharts alerts are enabled

In the example indicator below we programmatically generate an alert whenever the 14-bar RSI (Relative Strength Index) indicator crosses over its 10-bar EMA (Exponential Moving Average), and generate another alert when that RSI crosses below its moving average.

Should one of those two situations occur, we use AlertEnabled to conditionally draw an arrow on the chart that highlights the cross. With CheckAlert we’ll only create the text of the alert message when alerts are actually enabled. Both things also mean that when the ‘Enable Alerts’ option is turned off, neither arrows nor alert texts are generated.

The image below gives an example of the alerts generated by the script. After discussing the code, we’ll take a closer look at the indicator’s appearance and behaviour.

Examples of the MultiCharts alerts generated by the script

Inputs:
    RSI_Length(14),
    EMA_Length(10);
    
Variables:
    rsiValue(0),
    emaValue(0),
    alertMessage("");
    
rsiValue = RSI(Close, RSI_Length);
emaValue = XAverage(rsiValue, EMA_Length);

Plot1(rsiValue, "RSI");
Plot2(emaValue, "EMA");

if (rsiValue crosses over emaValue) then begin

    // Draw arrow
    if (AlertEnabled and BarStatus = 2) then
        Arw_New_Self_s(Date, Time_s, emaValue, false);    

    // Trigger alert message
    if (CheckAlert) then begin
    
        alertMessage = Text("RSI crossed above EMA. Highest RSI: ",
            Highest(rsiValue, 10), ", and lowest RSI: ", 
            Lowest(rsiValue, 10), ".");
            
        Alert(alertMessage);

    end;
    
end;

if (rsiValue crosses below emaValue) then begin
    
    // Draw arrow on bar close, if alerts are enabled
    if (AlertEnabled and BarStatus = 2) then
        Arw_New_Self_s(Date, Time_s, rsiValue, true);
    
    // Trigger alert message
    if (CheckAlert) then begin

        alertMessage = Text("RSI dropped below EMA. ",
            "10-bar extremes of EMA are ",
            Highest(emaValue, 10), " and ", Lowest(emaValue, 10), ".");
            
        Alert(alertMessage);
        
    end; 

end;

We begin with creating two inputs and three variables:


Inputs:
    RSI_Length(14),
    EMA_Length(10);
    
Variables:
    rsiValue(0),
    emaValue(0),
    alertMessage("");

We use the RSI_Length and EMA_Length input options later on when computing the RSI and EMA. By setting these lengths with an input option, we can easily configure them without having to edit and compile the script’s code.

The first two variables are numerical variables. We use rsiValue later on to hold the RSI value, and store the moving average’s value in emaValue. The alertMessage string variable is going to hold our dynamically-generated alert message.

Then we calculate the oscillator and moving average, and plot these on the chart:


rsiValue = RSI(Close, RSI_Length);
emaValue = XAverage(rsiValue, EMA_Length);

Plot1(rsiValue, "RSI");
Plot2(emaValue, "EMA");

We use RSI() to compute the RSI, and that function requires two parameters: a series of values to process and the number of bars to calculate the oscillator on. Here we set those parameters to the bar’s closing prices (Close) and the RSI_Length input, that we gave a default value of 14. We assign the value returned by the function in the rsiValue variable.

Then we use the XAverage() function to calculate the moving average. This function also requires two parameters: a series of values to process and an integer that sets the number of bars to compute on. We set those parameters to the rsiValue variable (to calculate it on the 14-bar RSI) and the EMA_Length input option which has a default value of 10. We store that EMA of the RSI in the emaValue variable.

We plot both variables with Plot1() and Plot2(). These keywords can be configured with a range of parameters, of which we only use two here: the value to plot and the plot’s name (MultiCharts Wiki, 2012d). With Plot1() we display the rsiValue on the chart and name that plot ‘RSI’. The second plot, made with Plot2(), is named ‘EMA’ and plots the emaValue variable.

Next is the first if statement in the code, in which we draw an arrow and trigger an alert programmatically:


if (rsiValue crosses over emaValue) then begin

    // Draw arrow
    if (AlertEnabled and BarStatus = 2) then
        Arw_New_Self_s(Date, Time_s, emaValue, false);    

    // Trigger alert message
    if (CheckAlert) then begin
    
        alertMessage = Text("RSI crossed above EMA. Highest RSI: ",
            Highest(rsiValue, 10), ", and lowest RSI: ", 
            Lowest(rsiValue, 10), ".");
            
        Alert(alertMessage);

    end;
    
end;

With this if statement’s condition we check whether the oscillator crossed above its moving average. We translate that in code with the rsiValue and emaValue variables and the crosses over keyword combination. 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, the left value was less than or equal to the right value (MultiCharts Wiki, 2012f). And so whenever the RSI drops below its EMA, rsiValue crosses over emaValue returns true; and without such a crossover, that keyword combination returns false.

Now when a crossover did happen, the code inside our if statement executes. That code begins with another if statement, that checks whether the script’s alerts are enabled (AlertEnabled) and if the current script calculation happens on the close of the price bar. We verify that latter with the BarStatus keyword, which returns a value equal to (=) 2 when the price update that’s currently processed by the script is the bar’s closing tick (MultiCharts Wiki, 2014). There are two reasons why we require a closed bar here. First, it prevents repeatedly drawing an arrow on the same bar (given that each bar only closes once). Second, MultiCharts automatically removes intra-bar drawings and drawing our arrow when the bar closed makes it persistent.

When both conditions of that nested if statement evaluate to true, we draw an arrow with Arw_New_Self_s(). That keyword creates an arrow on the indicator’s subchart and requires four parameters: the date and time of the bar, the price of where to place the arrow, and if the arrow should point down (true) or up (false) (MultiCharts Wiki, 2012e). We place our arrow at the current bar’s date (Date) and time (Time_s), with its price coordinate being the EMA of RSI values (emaValue) while pointing up (false). Given that AlertEnabled is a requirement for creating this drawing, no arrows will be made on historical nor real-time bars when the ‘Enable Alerts’ setting is turned off.

There’s also a second nested if statement that’s evaluated when the RSI crosses above its EMA. That if statement generates the text of the alert message as well as the alert itself. Its condition evaluates whether the CheckAlert variable returns true, which it does when the script’s alerts are enabled and the current bar is the last of the data series (MultiCharts Wiki, 2012b). When that happens, we update the alertMessage variable inside the if statement with the text that we want to include in the alert. That text contains literal text (like "RSI crossed above EMA. Highest RSI: ") as well as dynamic values, which we combine with the Text() keyword.

Those dynamic values are the 10-bar highest and lowest RSI value. We compute those with Highest() and Lowest(), and both functions require two parameters: a series of values to process and the number of bars to calculate on. We set the arguments of these functions to rsiValue (the 14-bar RSI) and 10 to get the 10-bar highest and lowest RSI value. Since this code only executes when CheckAlert returns true, MultiCharts won’t perform these Highest() and Lowest() calculations when alerts are disabled. That makes the code a bit more efficient.

After generating the alert message and storing it in the alertMessage variable, we generate an alert programmatically with the Alert() keyword (MultiCharts Wiki, 2012a). By passing the alertMessage variable inside the parentheses of that keyword, the text stored in that variable is used as the alert message when the alert fires.

We end the example indicator with another if statement:


if (rsiValue crosses below emaValue) then begin
    
    // Draw arrow on bar close, if alerts are enabled
    if (AlertEnabled and BarStatus = 2) then
        Arw_New_Self_s(Date, Time_s, rsiValue, true);
    
    // Trigger alert message
    if (CheckAlert) then begin

        alertMessage = Text("RSI dropped below EMA. ",
            "10-bar extremes of EMA are ",
            Highest(emaValue, 10), " and ", Lowest(emaValue, 10), ".");
            
        Alert(alertMessage);
        
    end; 

end;

This second if statement is much like the previous. Here we evaluate if the RSI (rsiValue) crossed below (crosses below) the EMA of RSI values (emaValue). That crosses below keyword combination 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, its left value was greater than or equal to its right value (MultiCharts Wiki, 2012f). When such a cross happened, the code inside the if statement executes.

That code consists out of two nested if statements, both practically the same as we saw earlier. The first if statement checks whether the script’s alerts are enabled (AlertEnabled) and if the script calculates on bar close (BarStatus = 2). When both expressions evaluate to true, we draw a downward pointing arrow at the RSI value with Arw_New_Self_s().

The other nested if statement executes when CheckAlert returns true. When it does, we generate an alert message that contains the RSI EMA’s extreme prices. Since we use CheckAlert as a filter, the Highest() and Lowest() functions won’t calculate when the script’s alerts are enabled.

Example: generate an oscillator’s moving average alerts

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

Example of the input options of the MultiCharts script

The indicator itself looks like the following when added to a Crude CFD chart:

Chart of the MultiCharts example indicator

Since the indicator was added here to the chart with alerts disabled by default, the arrows that highlight the historical crosses aren’t drawn. To enable the indicator’s alert settings, we right-click on the indicator’s name in the Status Line and select ‘Format [indicator name]’:

Formatting the settings of a MultiCharts indicator on the chart

This opens a window with the indicator settings. There we go to the ‘Alerts’ tab and enable the manual alert settings:

Enabling the alerts of a MultiCharts indicator by hand

When the script’s alerts are enabled, the AlertEnabled keyword returns true on historical and real-time bars (MultiCharts Wiki, 2012c). Since we used that keyword as requirement for drawing an arrow, with ‘Enable Alerts’ turned on the arrows appear:

Example chart of the MultiCharts indicator

The CheckAlert keyword also returns true now on the last bar of the data series when alerts are enabled (MultiCharts Wiki, 2012b). Since that keyword was our requirement for generating the text message and alert itself, the alerts appear now as follows when the RSI crosses its EMA:

Examples of the alerts generated by the MultiCharts indicator

Summary

The Alert() keyword generates MultiCharts alerts programmatically. But before those alerts fire, we need to turn on the ‘Enable Alerts’ option. There are two keywords we can use to verify whether that option is enabled or disabled. The CheckAlert keyword returns true when the alert settings of the indicator or strategy are enabled and the bar currently processed by the script is the last bar of the data series. When one or both of these situations aren’t the case, CheckAlert returns false. The AlertEnabled keyword, on the other hand, simply returns true when the script’s alerts are enabled and false when the ‘Enable Alerts’ option is turned off. Those features of CheckAlert and AlertEnabled allow us to execute code conditionally based on the state of the ‘Enable Alerts’ checkbox, and have our script run a bit more efficient by not calculating values that alerts use when those alerts cannot fire.

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 19). Plot. Retrieved on March 14, 2016, from https://www.multicharts.com/trading-software/index.php/Plot

MultiCharts Wiki (2012e, February 19). Arw_new_self_s. Retrieved on March 14, 2016, from https://www.multicharts.com/trading-software/index.php/Arw_New_self_s

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

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

Visit programming tutorials for more helpful coding articles.