When we enable the alerts of a MultiCharts indicator or signal, we can choose whether those alerts should fire once per bar or possibly with every price update. But how do we programmatically combine those two alert options in the same script?

In this article:

Generating MultiCharts alerts with the bar’s recent price status

In MultiCharts, we generate alerts programmatically with the Alert() keyword (MultiCharts Wiki, 2012a), which does require that the script’s manual alert setting is enabled. Then, depending on the manual alert settings, the alerts appear as notification windows, audio alerts, and/or email alerts (MultiCharts Wiki, 2013). If we miss an alert, we can find a log of all programmatically generated alerts in the ‘Alerts’ tab of the Order and Position Tracker window.

We enable the alerts of an indicator or signal with the ‘Enable Alerts’ checkbox. And with the ‘Alert Conditions Check’ option we configure how often the alert may fire:

Enabling the alerts of a MultiCharts indicator or strategy by hand

These options allow the script to generate an alert once per bar (‘On Bar Close’ and ‘Once Per Bar’) or possibly with every price update (‘Every Tick’). While we can use these options to limit the number of alerts fired per bar, it also limits us.

One thing we cannot configure by hand is how different alerts generated by the same script should be treated. For example, what if we want to generate one alert only when the bar closes (‘On Bar Close’) while another alert may fire as soon as its alert condition happens (‘Every Tick’)?

Luckily, we can programmatically implement that in PowerLanguage. For that we need to distinguish between when the script performs an intra-bar calculation and when it calculates on bar close. We do that with BarStatus, a keyword that returns a numerical value that indicates the status of the most recent price update of the data series that the script calculates on (MultiCharts Wiki, 2014).

The values that BarStatus can return are (MultiCharts Wiki, 2014):

  • When the script processes the bar’s opening tick, BarStatus returns 0.
  • If the processed tick is inside the price bar, BarStatus returns 1.
  • And when the current tick marks the closing tick of the price bar, BarStatus returns 2.
  • In rare cases, BarStatus returns -1. That occurs when the price bar has already closed, but the script still performs a calculation. Such a calculation happens when prices of an additional data series are processed by the script, a broker event happens, or a periodic script recalculation occurs (Henry MultiCharts, 2015).

With these different BarStatus values we can figure out whether the script calculates during an intra-bar price update or with the closing tick of the bar. We can then use that information to programmatically generate an alert during those two kinds of script calculations. And that way we combine an alert that may only fire on bar close with another alert that can generate with each tick, without being limited by the manual ‘Alert Conditions Check’ option.

Let’s see how this would look like in a full programming example.

Example: firing opening range alerts during the bar and when it closes

In the example indicator below plot the highest high and lowest low of the instrument’s opening range. Now when an intra-bar price forms a higher high or lower low inside that opening range, then we trigger an intra-bar alert. The other alert that the indicator generates is an alert on bar close, and that alert fires when the bar formed a new high or low inside the opening range.

The image below gives an example of the two different alerts generated by the script. After discussing the code, we’ll look at configuring the indicator, how it appears on the chart, and what other alerts it generates.

Examples of the alerts generated by the MultiCharts example indicator

Inputs:
    Start_Opening_Range(800),
    End_Opening_Range(1000);
    
Variables:
    openRangeHigh(0),
    openRangeLow(0);

if (Time > Start_Opening_Range) and (Time <= End_Opening_Range) then begin

    // Reset variables
    if (Time[1] = Start_Opening_Range) then begin
        openRangeHigh = 0;
        openRangeLow  = 99999;
    end;

    // Update variables
    openRangeHigh = MaxList(High, openRangeHigh);
    openRangeLow  = MinList(Low,  openRangeLow);

    // Plot opening range's high and low
    Plot1(openRangeHigh, "Open range high", Green);
    Plot2(openRangeLow,  "Open range low",  Magenta);
    
    SetPlotWidth(1, 7);
    SetPlotWidth(2, 7);

    // Generate an intra-bar alert
    if (BarStatus = 1) then begin
    
        if (Close = openRangeHigh) then
            Alert("New opening range high")
        else if (Close = openRangeLow) then
            Alert("New low in the opening range");

    end;
    
    // Generate on bar close alert (if applicable)
    if (BarStatus = 2) then begin
    
        if (High = openRangeHigh) then
            Alert("This bar reached a new opening range high")
        else if (Low = openRangeLow) then
            Alert("This bar had a new lowest low in the opening range");
    
    end;

end;

We start with making two input options and as many variables:


Inputs:
    Start_Opening_Range(800),
    End_Opening_Range(1000);
    
Variables:
    openRangeHigh(0),
    openRangeLow(0);

Input options allow us to easily change values used in the script without having to edit and change the script’s source code. We give the first input, Start_Opening_Range, a default value of 800 while the other (End_Opening_Range) is given a default value of 1000. Based on how we’re going to use these inputs, those values correspond to 8:00 and 10:00 o’clock in the morning.

Then we create two numerical variables: openRangeHigh and openRangeLow. We’ll use these to track the highest high and lowest low during the opening range, and we plot those values and also use them for generating alerts.

The rest of the indicator’s code is inside the following if statement:


if (Time > Start_Opening_Range) and (Time <= End_Opening_Range) then begin

    // ...

end;

This if statement evaluates two true/false expressions combined 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 two expressions are false, the result combined with and is false too (MultiCharts Wiki, 2012b).

That means the if statement’s code only executes when both expressions are true. And when that happens, the current bar’s time falls inside the opening range that we’ve defined with the Start_Opening_Range and End_Opening_Range input options.

With the first expression we check whether the bar’s time (Time) is greater than (>) the opening range input option (Start_Opening_Range). That Time keyword returns the current bar’s closing time in HHmm format (MultiCharts Wiki, 2012c). So when the bar closes at 9:45, Time returns 945 while a close at 20:15 makes the keyword return 2015.

Note: Because Time returns the bar’s closing time, we check whether this keyword has a value that’s greater than the Start_Opening_Range input option. Say our chart has a resolution of 30 minutes. Then the bar with a time stamp (Time) of 8:00 doesn’t fall inside the 8:00 till 10:00 opening range, but instead contains price action from 7:30 till 8:00. That’s why we require here that the bar’s time is greater than the Start_Opening_Range input option.

The second expression in this if statement’s condition is whether the bar’s time is less than or equal to (<=) the End_Opening_Range input variable, that we gave a default value of 1000 earlier. With that we require that the bar’s closing time is not beyond the opening range.

And so the first expression checks if the bar’s time is later than the start of the opening range, while the second makes sure that the bar isn’t beyond the end of the opening range. Combined, the if statement’s condition is only true when the bar falls inside the opening range and false when it doesn’t.

The code that’s executed when the bar falls inside the opening range begins with an if statement that reset the openRangeHigh and openRangeLow variables:


if (Time[1] = Start_Opening_Range) then begin
    openRangeHigh = 0;
    openRangeLow  = 99999;
end;

To correctly track the opening range’s highest high and lowest low, we reset the variables at the start of each opening range. To check if a new opening range began, we evaluate whether the previous bar’s closing time (Time[1]) equals (=) the start of the opening range (Start_Opening_Range). Since Time returns the bar’s closing time (PowerLanguage Keyword Reference, 2016), we in effect check whether the previous bar closed just at the start of our opening range. This does assume that the script runs on a time-based chart and that the bar’s closing time can equal 8:00 hour (the value of the Start_Opening_Range input).

When the previous bar was indeed the bar just before the opening range, we set the value of the openRangeHigh variable to 0 and give openRangeLow a value of 99999. This latter value seems random. But with that value, later on in the script the openRangeLow variable is correctly updated to either its current value or the bar’s low, whichever is less.

Next in the if statement that only executes when the bar falls inside the opening range, we update the variables that track the high and low of the opening range:


openRangeHigh = MaxList(High, openRangeHigh);
openRangeLow  = MinList(Low,  openRangeLow);

We set the openRangeHigh variable here to the value returned by MaxList(). That keyword accepts multiple numerical parameters, and returns the greatest of them (PowerLanguage Keyword Reference, 2016). Inside this keyword’s parentheses we pass in the high of the current bar (High) as well as the current value of openRangeHigh.

That means the new value of openRangeHigh because either its current value or the bar’s high, whichever is the greatest. This way the value of that variable can only increase, and with that we track the highest highs happening during the opening range.

We update the openRangeLow variable in the same way with MinList(). That keyword accepts multiple numerical parameters, and returns whichever of them is the lowest (PowerLanguage Keyword Reference, 2016). Since we use the low of the current bar (Low) and the value of openRangeLow with this keyword, the value that’s going to be stored in openRangeLow is either its current value or the bar’s low, whichever is less. That tracks the lowest low of the opening range.

Here we can also see why we reset the openRangeLow variable to 99999 instead of 0 earlier. Should we give openRangeLow a value of 0 at the start of each opening range, then this variable will never update with MinList() to the bar’s low since that price will never be less than 0. So with a high, arbitrary value of 99999 the openRangeLow is updated with the first low in the opening range, and then any new lower low during that opening range.

Next we plot the opening range’s highest high and lowest low:


Plot1(openRangeHigh, "Open range high", Green);
Plot2(openRangeLow,  "Open range low",  Magenta);

SetPlotWidth(1, 7);
SetPlotWidth(2, 7);

The Plot1() and Plot2() keywords plot numerical values on the chart and accept a range of parameters that configure the plot’s settings (PowerLanguage Keyword Reference, 2016). Here we use them with three parameters: the plot’s value, name, and colour. While we’re not going to use the plot name in this example, we have to set this parameter in order to set the plot’s colour.

We plot the openRangeHigh variable on the chart with Plot1(). We name this plot “Open range high” and set its colour to the Green MultiCharts standard colour. With the Plot2() statement we display the openRangeLow values on the chart. That plot appears in Magenta and is named “Open range low”.

Then we change the size of both plots with SetPlotWidth(). That keyword works with two parameters: the plot number and the width, ranging from 1 to 12, that plot should get (PowerLanguage Keyword Reference, 2016). Here we set both plots to a width that’s several steps bigger than the default size of 1.

Note: Because Plot1() and Plot2() are inside the if statement whose code only executes when the current bar falls inside the opening range, the highest high and lowest low only plot plotted during the opening range. After the opening range ends, the values aren’t plotted anymore (the images further down below show how those plotted lines look like).

Next we finally get to the code that generates alerts. First we have an alert that can possibly fire with each intra-bar price update:


if (BarStatus = 1) then begin

    if (Close = openRangeHigh) then
        Alert("New opening range high")
    else if (Close = openRangeLow) then
        Alert("New low in the opening range");

end;

This if statement’s condition evaluates whether the BarStatus keyword returns a value equal to (=) 1. That keyword returns such a value when the price update that’s currently processed by the script falls inside the bar, as opposed to being the bar’s opening or closing tick (PowerLanguage Keyword Reference, 2016).

During such an intra-bar price update, the nested if/else statement is executed. The if portion of that statement evaluates if the bar’s current price (Close) equals (=) the highest high of the opening range (openRangeHigh). While the Close keyword also returns the bar’s closing price, for price bars that are still developing it returns the current bar. That’s because as long as the bar hasn’t closed yet, each new price update extends the bar’s ‘closing’ price.

When the tick currently processed by the script is indeed the highest price of the opening range, we generate an alert programmatically with the Alert() keyword. Inside the parentheses of that keyword we specify an alert message saying that a new opening range high has been reached.

The else portion of the if/else statement is similar. Here we check whether the bar’s current price (Close) equals the lowest low of the opening range (openRangeLow). When it does, we use Alert() to generate an alert message with the appropriate alert message.

Since the code for those opening range high and low alerts is inside the if statement that executes with each intra-bar price update, these alerts can fire several times per bar. See limiting the number of alerts per bar for ways to prevent a script from firing too many alerts quickly after each other.

Next is another if statement. This one generates alerts that fire only when the bar closes:


if (BarStatus = 2) then begin

    if (High = openRangeHigh) then
        Alert("This bar reached a new opening range high")
    else if (Low = openRangeLow) then
        Alert("This bar had a new lowest low in the opening range");

end;

Now we check whether BarStatus returns a value equal to (=) 2. That keyword returns such a value when the price update currently processed is the bar’s closing tick (PowerLanguage Keyword Reference, 2016). During those calculations, the nested if/else statement executes.

The if potion of that if/else statement evaluates whether the bar’s high (High) reached the high of the opening range (openRangeHigh). When that happens, we know that the current bar formed a new high and we use Alert() to generate an alert message.

The else portion of the if/else statement is similar, and here we check whether the bar’s Low equals the openRangeLow variable. That’s the case when the bar formed a new low in the opening range, and we generate another alert message with Alert() in that case.

With the code of these latter two alerts inside the if statement that checks for a closed bar (BarStatus = 2), those alerts won’t fire more than once per bar (see Henry MultiCharts, 2015). And since these statements are also inside the if statement that checks whether the bar falls inside the opening range, the alerts won’t fire when the bar is outside the opening range that’s set with Start_Opening_Range and End_Opening_Range.

This ends our discussion of the programming example. But before we add the script to the chart, we first need to configure a manual setting so that it plots correctly.

Configuring the MultiCharts indicator’s plot options by hand

With the above code typed into the PowerLanguage Editor, we save and compile the script. To plot the indicator’s opening range high and low, we executed the Plot1() and Plot2() keywords only when the bar’s time was in the opening range (which we set to default values of 8:00 and 10:00). That way we didn’t plot the opening range high and low for bars outside of the opening range.

But a feature of Plot1() and Plot2() is that they draw a ‘connected line’ by default. That is, when we don’t plot values for a couple of bars and then resume plotting, then MultiCharts draws a line between the bars that do have a value plotted. In our case, that makes the programming example look like:

Connecting lines when plotting in MultiCharts

When a new opening range begins here, the line is connected with the values of the previous day’s opening range. That happens because we didn’t plot any values since that opening range. But with these ‘connected lines’ the chart becomes unpleasant and harder to read.

Luckily, MultiCharts has other plotting options too. But we cannot set those options programmatically. Instead, we need to manually configure the plots either in the MultiCharts program itself or in the PowerLanguage Editor.

To change the plot style in the PowerLanguage Editor, we right-click somewhere in the text editor and choose ‘PropertiesÂ…’:

Opening the 'Properties' window in the MultiCharts PowerLanguage code editor

This brings up a window with the script’s properties. There, in the ‘Chart Style’ tab, we set the ‘Type’ of each plot. To prevent a ‘connecting line’ like the one showed in the previous image, we set the type of both plots to ‘Point’ (instead of the default ‘Line’). That makes MultiCharts plots little dots instead of a consecutive line. (The ‘Cross’ option would have been fine too, and that would make the values appear on the chart as small + signs.)

Setting the MultiCharts plot's style to 'Point'

After setting both plots to ‘Point’, we save and recompile the script. Now when we add the indicator to the chart, it plots its values like:

Plotting data with breaks without a connecting line in MultiCharts

This way there’s no connecting line between the opening ranges. Now let’s see how the script generates its alerts.

Generating intra-bar and on bar close alerts

When we add our example indicator to a MultiCharts chart, we use the following manual alert settings:

Alert settings for the MultiCharts example indicator

Even though we set the ‘Alert Conditions Check’ option here to ‘Every Tick’, our indicator won’t fire alerts with every price update. That’s because we used the BarStatus keyword in the indicator’s code to determine when the alert should fire and when not.

We can configure the example indicator with the following input options:

Input options of the MultiCharts example indicator

And as we already saw above, the indicator itself looks like this:

Example chart with the information plotted by the script

The alerts that the indicator generates depend on whether the alert fired during an intra-bar calculation or when the price bar closed. In the first case, the alert message says there’s a new opening range high or low. In the second case, the message mentioned that the bar reached a new high or low.

Those different alert messages look like the following:

Example alerts generated by the MultiCharts script

In case we missed an alert, we can read up on the historical alerts generated by the script in the ‘Alerts’ tab of the Order and Position Tracker window:

The alert messages appearing in the MultiCharts Order and Position Tracker window

For other approaches that prevent too many alerts happening quickly after each other, see different ways to programmatically limit the number of MultiCharts alerts.

Summary

MultiCharts alerts are generated programmatically with Alert(). But before that keyword does its work, we need to enable the script’s alert setting. With another manual option (‘Alert Conditions Check’) we specify how often the script’s alerts may fire: either once per bar or possibly with every price update. However, it’s not possible to configure which of the script’s alerts should fire when. Luckily, we can programmatically combine an intra-bar alert with one that fires only on bar close. For that we use BarStatus, a keyword that returns a numerical value with the status of the current price update from the data series that the script calculates on. The values that BarStatus typically returns are 0 for the bar’s opening tick, 1 for when the current price update falls inside the price bar, and 2 for when the currently processed price update marks the bar’s closing price. By structuring the code with different if statements that evaluate the value of the BarStatus keyword, we can generate some alerts only when the bar closes while other alerts can fire with each price update.

Learn more:


References

Henry MultiCharts (2015, January 30). closing status of a bar sometimes takes too long – forum discussion. Retrieved on May 4, 2016, from http://www.multicharts.com/discussion/viewtopic.php?f=1&t=10642#p113092

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

MultiCharts Wiki (2012c, February 28). Time. Retrieved on May 13, 2016, from https://www.multicharts.com/trading-software/index.php/Time

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

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