When we generate an alert in MultiCharts programmatically, we often use a custom alert message with the alert’s details. How do we include nicely formatted numerical values in those messages?

In this article:

Generating formatted alert messages in MultiCharts PowerLanguage

We programmatically generate alerts with Alert() (PowerLanguage Keyword Reference, 2016). But before this keyword can fire alerts, we do need to enable the alert settings. After that alerts can, depending on the alert configuration, appear as an audio alert, notification window, and/or email alert (MultiCharts Wiki, 2013).

The Alert() keyword can generate an alert without text, or have the alert include a static or dynamic alert message (PowerLanguage Keyword Reference, 2016). For a static alert message, we simply hard-code the message into the script’s code like this:


Alert("Three higher highs in a row with volume confirmation");

While informative, an alert message can provide more context by including dynamic numerical values. Let’s see how that works.

Creating MultiCharts alerts that have text and numerical values

To create a dynamic alert message, we typically combine a static string (meaning, a fixed text like "Three higher highs") with a numerical value (like a variable or the current bar’s high). We can combine those two together with the + operator or use the Text() keyword (MultiCharts Wiki, 2016; PowerLanguage Keyword Reference, 2016).

Adding different strings (that is, texts) in an alert message with + looks like:


Alert("Three " + "higher highs");

Or we can use the Text() keyword. In that case, we separate each of the different strings with a comma, and the keyword will combine them into one string (PowerLanguage Keyword Reference, 2016). For instance:


Alert(Text("Three ", "higher highs"));

Both approaches (+ or Text()) can also include numerical values. Those numbers can be anything that’s currently accessible in the script, like the bar’s closing price (Close), a custom variable (myRSIValue), or the strategy’s current market position (MarketPosition * CurrentContracts). For example:


Alert(Text("The bar's current closing price is: ", Close));

The alert that this code snippet generates looks like:

An alert message with a number that uses standard MultiCharts formatting

But there’s a problem with the numerical value here: while the ‘Price’ row of the alert says the EUR/CAD price is 1.44536, the price included in the alert message is rounded to two decimals (1.45). There are also 4 to 5 spaces before that number, even though we didn’t specify those.

Both differences happen because PowerLanguage, when automatically converting a number to a string, does that with two decimals and adds a few spaces.

Luckily, there are two ways in which we can convert a number to a string ourselves:

  • With two numbers and two colons placed behind the numerical value (like Close:1:5). The first number specifies the number of digits to the left of the decimal point, whereas the second specifies the number of digits to the right (TradeStation, 2007).
  • A more flexible approach that only focuses on the number of decimals is the NumToStr() keyword, which requires two parameters: the numerical value to convert to a string, and how many decimals that number should get (PowerLanguage Keyword Reference, 2016). For instance, NumToStr(Close, 5) converts the bar’s closing price to a string with a 5-decimal number.

Now let’s revisit the previous EUR/CAD example. To have this forex pair’s price appear with the right amount of decimals, we use NumToStr() in the alert message like this:


Alert("The bar's current closing price is: " + NumToStr(Close, 5));

With this code, the alert message appears as follows:

An alert message with the numerical value formatted to 5 decimals

Now the instrument’s price prints correctly, and that makes the alert message more meaningful and readable.

Note: Whether NumToStr() uses a point as the decimal separator (1.44530) or a comma (1,44530) depends on the regional settings of your Windows version.

Example: creating alert messages that include numerical values

In the example indicator below we use NumToStr() to format the numbers we include in the alert messages. Those alerts generate when the bar crosses above or below a 10-period EMA (Exponential Moving Average). The data that those messages include are the moving average’s value as well as the 10-bar Relative Strength Index (RSI).

The image below shows how those values appear in the alert message. After discussing the code we’ll take a closer look at the indicator’s behaviour and output.

Example of the formatted alerts generated by the MultiCharts indicator

Inputs:
    EMA_Length(10),
    RSI_Length(10);

Variables:
    emaValue(0),
    rsiValue(0);

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

// Plot the moving average
Plot1(emaValue, "EMA", green);
SetPlotWidth(1, 2);

// Check for alert conditions
if (Close cross over emaValue) then

    Alert("Bar crossed above EMA @ " + NumToStr(emaValue, 5) + 
        " with a RSI reading of " + NumToStr(rsiValue, 2))
        
else if (Close cross under emaValue) then

    Alert("Bar fell below EMA @ " + NumToStr(emaValue, 5) +
        " with the RSI at " + NumToStr(rsiValue, 2));

We start the example by making two input options and two variables:


Inputs:
    EMA_Length(10),
    RSI_Length(10);

Variables:
    emaValue(0),
    rsiValue(0);

The EMA_Length and RSI_Length input options set the length of the EMA and RSI. By using an input option for those settings we can easily change their length without having to edit and recompile the script’s code. We use the emaValue and rsiValue variables later on to hold the EMA and RSI values for easy access and to prevent unneeded calculations.

Then we compute the moving average and oscillator:


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

Calculating the Exponential Moving Average is done with the XAverage() function. This function operates on two parameters: a series of data to process and a numerical value sets the length of the average in bars. Here we set those parameters to the bar’s closing prices (Close) and the value of the EMA_Length input option, that we gave a default value of 10 earlier. We assign the moving average’s value to the emaValue variable to use later.

We use the RSI() function to compute the RSI, and this function also uses two parameters: a series of values to process and an integer that sets the oscillator’s length. Here we use the bar’s closing prices (Close) and the RSI_Length input, which also has a starting value of 10.

Next we plot the moving average on the chart for visual confirmation:


Plot1(emaValue, "EMA", green);
SetPlotWidth(1, 2);

Plotting a value is done with one of the PlotN keywords, which range from Plot1() to Plot999() (PowerLanguage Keyword Reference, 2016). Since we only have one value to plot, we use Plot1() (but using Plot3() or Plot59() would have been fine too).

The PlotN keywords have a range of parameters, and here we used the first three: the value to plot, the plot name, and the plot’s colour (PowerLanguage Keyword Reference, 2016). Though we have no use for the plot name, we do need to provide it in order to set the plot colour. We set our plot’s parameters to the emaValue variable that holds the 10-bar EMA, name the plot “EMA”, and set it to the green standard MultiCharts colour.

Then we use SetPlotWidth() to configure the plot’s width. This keyword accepts two parameters: a number that specifies which plot to change, and and another with the new plot size (which can range from 1 to 14) (PowerLanguage Keyword Reference, 2016). Here we set those arguments to 1 (to configure the first plot; Plot1()) and 2 to make that plot a bit bigger than the default size.

Then we have an if/else statement to generate the alerts conditionally. Its if portion has the following code:


if (Close cross over emaValue) then

    Alert("Bar crossed above EMA @ " + NumToStr(emaValue, 5) + 
        " with a RSI reading of " + NumToStr(rsiValue, 2))

This if statement’s condition evaluates whether the bar’s closing price (Close) crossed above the 10-bar EMA (which we computed earlier and stored in the emaValue variable). To translate that situation into PowerLanguage code we use cross over.

That keyword combination returns true when the value on its left (Close in this case) is greater than its right value (emaValue) on the current bar, while on the previous bar the left value was less than or equal to the right value (MultiCharts Wiki, 2012). In all other cases, cross over returns false.

When such a crossover happens, the Alert() keyword inside our if statement executes to generate an alert message (PowerLanguage Keyword Reference, 2016). In this keyword’s parentheses we create an alert message that contains static strings (like "Bar crossed above EMA @") and the values of the emaValue and rsiValue variables. We combine those different strings together with the + operator.

To print the variables correctly, we format emaValue and rsiValue to a string with the NumToStr() keyword. This way the RSI values displays in 2 decimals while the EMA value shows with 5 (because EUR/CAD uses 5 decimals, though this will differ if you add the script to another instrument).

The else part of the if/else statement looks similar with the following code:


else if (Close cross under emaValue) then

    Alert("Bar fell below EMA @ " + NumToStr(emaValue, 5) +
        " with the RSI at " + NumToStr(rsiValue, 2));

Now we’re using the cross under keyword to monitor whether the bar’s closing price (Close) dropped below the 10-bar EMA (emaValue). That keyword combination returns true when, on the current bar, the value on the left of cross under is below the value on its right while on the previous bar the left value was greater than or equal to the right value (MultiCharts Wiki, 2012). With that our if statement’s condition only evaluates to true when the bar dropped below the 10-bar EMA while still begin above or at that EMA previously.

When such a cross under happened, we execute Alert() to generate an alert message. Inside the alert message, we use + to combine static strings with the dynamic values of emaValue and rsiValue that we format to a string with NumToStr().

Now let’s see how those alerts look like, and how the indicator plots its data.

Generating MultiCharts alerts that include numerical values

When we add the above example script to a chart, we use the following manual alert settings:

Configuring the MultiCharts alert settings by hand

The example indicator plots its EMA values like this:

Example chart of the MultiCharts indicator

Now when the price bar crosses below that moving average, the script generates an alert like the following:

Example of the alert with the custom, formatted message

Likewise, when the bar crosses the moving average like so:

MultiCharts example chart with a moving average crossover

Then the script generates the following alert message:

Example alert by MultiCharts with formatted numerical values

This way of formatting numerical values with the NumToStr() keyword makes it possible to generate alert messages that provide more meaningful context and actionable data.

Summary

MultiCharts alerts are generated programmatically with Alert(), but before this keyword can fire alerts we do need to enable the script’s alert settings. The messages that Alert() generates can be empty, contain a static string (like "Opened new position"), or a combination of static text and dynamic values. Combining those different string pieces is done with + and Text(), while formatting numerical values to a string is performed with NumToStr(). That keyword requires two parameters: the number to convert to a string, and a number that specifies how many decimals the converted string should contain. This way we can include numerical values in alert messages with the exact amount of decimals we see fit.

Learn more:


References

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

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

MultiCharts Wiki (2016, February 22). Language Elements. Retrieved on September 7, 2016, from http://www.multicharts.com/trading-software/index.php/Language_Elements

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

TradeStation (2007). EasyLanguage Essentials: Programmers Guide. Retrieved from https://www.tradestation.com/~/media/Files/TradeStation/Education/University/School%20of%20EasyLanguage/Books/EL_Essentials.ashx