While MultiCharts alerts can be fired based on practically anything accessible in PowerLanguage, a common approach is to generate an alert when a faster moving average crosses above or below a slower one. Let’s see how we can do that in MultiCharts.

In this article:

Triggering MultiCharts alerts with moving averages

We programmatically generate MultiCharts alerts with the Alert() keyword (PowerLanguage Keyword Reference, 2016). That does require that we enable the script’s alert setting. Then when the indicator or signal script executes Alert(), that alert can appear as a notification window, audio alert, and/or email alert (MultiCharts Wiki, 2013) depending on how we’ve configured the alert settings.

We can generate an alert based on practically anything, including prices, indicator values, or even how long ago the data feed updated last. Another way is to generate MultiCharts alerts when two moving averages cross. To see how we can use two moving averages (MAs) to signal possible trend changes, let’s look at combining a simple and exponential moving average.

To calculate a Simple Moving Average (SMA) in MultiCharts, we use the AverageFC() function. That function requires two parameters: a series of values to calculate on and a number with the moving average’s length in number of bars. For example, AverageFC(Close, 10) calculates a 10-bar SMA based on the closing prices of the instrument that our script calculates on. Similarly, we use the XAverage() function to calculate an Exponential Moving Average (EMA). This function also has two parameters: the values to compute on and the moving average’s length. And so with XAverage(Close, 25) we get the 25-bar EMA of closing prices.

Let’s see how we can use those two functions to generate alerts based on a SMA crossing an EMA.

Example: generate MultiCharts alerts based on moving averages

The example indicator below generates an alert whenever an EMA crosses above or below a SMA. However, a common issue with moving averages is that they can whipsaw by crossing each other repeatedly in a short period of time (Pring, 2002). In the example indicator below we deal with that by waiting one additional bar, and then see whether the moving average cross is still valid. While this does introduce some lag, it (hopefully) also gives us more high-quality signals to work with.

An example of how the alerts and indicator look is given below. After discussing the code we’ll take a closer look at the script’s behaviour.

Eample alerts generated by the MultiCharts indicator Example chart with the moving average applied to it

Inputs:
    Price_Data(Close),
    Period_QuickMA(12),
    Period_SlowMA(36);

Variables:
    quickMA(0),
    slowMA(0),
    crossover(false),
    crossunder(false);

// Calculate the moving averages
quickMA = XAverage(Price_Data, Period_QuickMA);
slowMA  = AverageFC(Price_Data, Period_SlowMA);

// Plot the MAs
Plot1(quickMA, "Fast MA", red);
Plot2(slowMA, "Slow MA", blue);

// Monitor for a cross over or under
crossover  = quickMA crosses over slowMA;
crossunder = quickMA crosses under slowMA;

// Generate the alerts for the MA crosses
if (crossover[1] and (quickMA > slowMA)) then begin

    Alert("The " + NumToStr(Period_QuickMA, 0) + 
        "-bar MA crossed above the " +
        NumToStr(Period_SlowMA, 0) +
        " period average.");

end

else if (crossunder[1] and (quickMA < slowMA)) then begin

    Alert("The " + NumToStr(Period_QuickMA, 0) +
        " period EMA fell below the " +
        NumToStr(Period_SlowMA, 0) +
        "-bar SMA.");

end;

We begin by creating a couple of input options and variables:


Inputs:
    Price_Data(Close),
    Period_QuickMA(12),
    Period_SlowMA(36);

Variables:
    quickMA(0),
    slowMA(0),
    crossover(false),
    crossunder(false);

With the Price_Data input option we specify the kind of price data that the moving averages calculate on; with its Close default value, the moving averages start off computing on the instrument’s closing prices. The other two inputs, Period_QuickMA with a default of 12 and Period_SlowMA that starts at 36, will set the length of the moving averages. By creating input options for these settings, we can easily configure the indicator by hand without having to edit and recompile the script’s code.

The first two variables that we make are the quickMA and slowMA numerical values. These will hold later on the calculated values of the moving averages. The last two variables, crossover and crossunder, are true/false variables that are going to hold whether a cross over or under happened.

Next we calculate and plot the moving averages:


// Calculate the moving averages
quickMA = XAverage(Price_Data, Period_QuickMA);
slowMA  = AverageFC(Price_Data, Period_SlowMA);

// Plot the MAs
Plot1(quickMA, "Fast MA", red);
Plot2(slowMA, "Slow MA", blue);

We compute the Exponential Moving Average (EMA) with XAverage(). That function requires two parameters: a series of values to process and the number of bars to calculate on. Here we set them to the Price_Data input option (that holds the bar’s closing prices by default) and Period_QuickMA, the input with a default value of 12. We store the 12-bar EMA of closing prices in the quickMA variable for use later.

The Simple Moving Average (SMA) is computed with AverageFC(), and that function also requires two parameters: a data series to calculate on and the average’s length in number of bars. Here we set those parameters to Price_Data and Period_SlowMA, and we store the value of that 36-bar EMA of closing prices in the slowMA variable.

We display the moving averages on the chart with Plot1() and Plot2(). Both keywords accept a range of parameters to configure the plot. Here we set three: the plot’s value, its name, and colour (PowerLanguage Keyword Reference, 2016). To plot the EMA, we set Plot1() to display the values of the quickMA variable, name that plot “Fast MA”, and have it appear in the red standard MultiCharts colour. With Plot2() we plot the slowMA variable in the blue colour and name it “Slow MA”.

Then we figure out whether a moving average cross happened:


crossover  = quickMA crosses over slowMA;
crossunder = quickMA crosses under slowMA;

We set the crossover and crossunder variables here. By using these true/false variables to store whether there’s a cross over or under on the current bar, we can later on easily check whether a moving average cross happened on the previous bar.

To see if the 12-bar EMA (quickMA) crossed above the 36-bar SMA (slowMA), we use crosses over. That keyword combination returns true when, on the current bar, the value on its left is bigger than the value on its right while, on earlier bars, the left value was less than or equal to the right value (PowerLanguage Keyword Reference, 2016). That means quickMA crosses over slowMA returns true when the 12-bar EMA crossed above the 36-bar EMA on the current bar, and returns false when such a cross over didn’t happen. We store that true/false outcome in the crossover variable for use later on.

We update the crossunder variable similarly, except now we use the crosses under keyword combination. That returns true when the left value is less than the right value on the current bar, while previously the left value was bigger than or equal to the right value (PowerLanguage Keyword Reference, 2016). When that kind of cross under didn’t happen, crosses under returns false. In our case, with the quickMA variable on the left of crosses under and slowMA on the right, this returns true when the 12-bar EMA crossed below the 36-bar SMA on the current bar. When such a cross under didn’t happen, false is returned. Regardless of which value is returned, we store it in the crossunder variable for use later on.

We end the indicator’s code with an if/else statement. The first part of that if/else statement is the if keyword with the following code:


if (crossover[1] and (quickMA > slowMA)) then begin

    Alert("The " + NumToStr(Period_QuickMA, 0) + 
        "-bar MA crossed above the " +
        NumToStr(Period_SlowMA, 0) +
        " period average.");

end

This if statement’s condition uses two expressions to check whether a crossover happened on the previous bar while the fast moving average is currently still above the slower one. We combine those expressions with the and logical keyword. That keyword returns true when the value on its left and the value on its right are both true too. When one or both values are false, then the result combined with and is false too (PowerLanguage Keyword Reference, 2016).

To check if there was a crossover on the previous bar, we use the crossover variable with a value of 1 between the square brackets ([ and ]) directly behind that variable. That gives us the variable’s value as it was on the close of the previous bar. (crossover[3], on the other hand, would return the variable’s value from 3 bars ago.) Since crossover is already a true/false variable, crossover[1] returns true when the 12-bar EMA crossed above the 36-bar SMA on the previous bar. Without such a moving average cross, crossover[1] returns false.

To see whether the faster moving average is still above the slower one, we check whether the quickMA variable’s value is greater than (>) the slowMA variable. When that evaluates to true, we know that the 12-bar EMA is currently above the 36 period SMA.

Now when both of these true/false expressions are true, the if statement’s condition is true too (due to the and logical keyword). The code inside the if statement then runs, and that code generates an alert programmatically with Alert() (PowerLanguage Keyword Reference, 2016).

Inside the parentheses of the Alert() keyword we specify an alert message that contains literal text (like "The ") as well as dynamic numerical values. We combine those different textual strings with the + operator. To make the alert message more meaningful, we include the length of the moving averages by using the Period_QuickMA and Period_SlowMA inputs.

We use the NumToStr() keyword to convert those numerical values to text. That keyword works with two parameters. The first is a number to convert to text; the other is a numerical value that sets how many decimals that converted number should get (PowerLanguage Keyword Reference, 2016). In our case, we use the Period_QuickMA and Period_SlowMA inputs as the first and 0 as the second parameter. That translates those numerical input options to a 0-decimal string.

We conclude the programming example with the second part of the if/else statement. That else if portion generates an alert for when the fast moving average crosses below the slower one:


else if (crossunder[1] and (quickMA < slowMA)) then begin

    Alert("The " + NumToStr(Period_QuickMA, 0) +
        " period EMA fell below the " +
        NumToStr(Period_SlowMA, 0) +
        "-bar SMA.");

end;

This part is practically the same as previously. Again, the if statement’s condition contains two expressions. The first checks whether a cross under happened on the previous bar (in which case crossunder[1] returns true). The second expression uses quickMA < slowMA to evaluate whether the current value of the 12-bar EMA is less than (<) the 36-bar SMA.

When both expressions evaluate to true, the result combined with and is true too and the code inside the if statement executes. That code uses the Alert() keyword to generate an alert. The alert message that we specify with that keyword contains static text and dynamic values. Those latter values are, just like previously, the length of the fast (Period_QuickMA) and slow (Period_SlowMA) moving averages. And so the alert message says that the faster moving average dropped below the quicker one and tells us the current settings of these moving averages.

Firing MultiCharts alerts based on a moving average cross

Let’s see how our indicator looks on the chart and the alerts it generates. Before it can generate those alerts, though, we need to enable the script’s alert setting like so:

Configuring the alert settings of the MultiCharts example indicator

We enable the indicator’s alerts with the ‘Enable Alerts’ checkbox. With the ‘Once Per Bar’ radio button we specify that an alert should happen at most once every price bar. This prevents the indicator from generating multiple alerts per bar.

Those multiple alerts can happen when there’s a moving average cross on the previous bar, while on the current bar during several price updates the faster moving average is still above (or below) the slower one. (Other ways to prevent several alerts quickly after each other include limiting the number of alerts per bar and keeping a certain number of seconds between alerts.)

The indicator itself looks like this when added to a chart:

Chart showing the example indicator added to a MultiCharts chart

Now when the moving averages cross above each other on the previous bar and then confirm that signal on the current bar like this:

Example chart of a movign average crossover in MultiCharts

Then the indicator generates the following alert:

Example alert generated for the moving average crossover

Likewise, when the faster moving average drops below the slower on and then confirms that signal on the subsequent bar like so:

Example MultiCharts chart with a moving average crossunder

Then the indicator fires an alert like the following:

Example of a moving average cross under alert

While in this article we triggered alerts with plotted moving average lines, we can also trigger alerts based on trend lines. That’s something we discuss in firing alerts based on trend lines and generating semi-automatic MultiCharts alerts.

Summary

Whenever the script’s ‘Enable Alerts’ checkbox is on, the Alert() keyword can generate an alert programmatically. One way to trigger alerts is by using moving averages. We calculate a Simple Moving Average (SMA) with the AverageFC() function, whereas the XAverage() function computes the value of an Exponential Moving Average (EMA). Both functions require two parameters: a series of values to process (like Close for the instrument’s closing prices) and the number of bars to calculate on. To see whether one moving average crossed another, we can use the crosses over and crosses under keyword combinations. crosses over returns true when, on the current bar, the value on its left is greater than the value on its right while previously that left value was less than the right value. Likewise, crosses under returns true when, on the current bar, the value left of this keyword combination is less than its right value while earlier that left value was bigger than the right value. Whenever such a crossover or crossunder happens, we can generate an alert with Alert(). We can make those alerts more helpful by including numerical values. For that we’ll need to translate those numbers to text with NumToStr(), a keyword that requires two parameters: the number to convert to a string and the amount of decimals that the converted number should get.

Learn more:


References

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

Pring, M.J. (2002). Technical Analysis Explained (4th edition). New York, NY: McGraw-Hill.

PowerLanguage Keyword Reference (2016). Retrieved on May 25, 2016, from http://www.multicharts.com/trading-software/images/c/c6/PowerLanguage_Keyword_Reference.pdf

Visit Kodify.net for more helpful coding articles.