We can configure MultiCharts alerts to fire once per bar or with every real-time price tick. But how do we ensure that alerts fire at the right time, even when our instrument currently doesn’t have that many real-time price updates?

In this article:

Generating MultiCharts alerts independent from real-time prices

Programmatically generating MultiCharts alerts is done with the Alert() keyword (PowerLanguage Keyword Reference, 2016), but that does require that we’ve enabled the script’s alert setting. Then, depending how how we’ve configured the alert settings, alerts can appear as notification windows, audio alerts, and/or email alerts (MultiCharts Wiki, 2013).

While most alerts are based on the instrument’s prices or volume, some alerts depend on time – like when generating an alert 45 seconds before the market closes. MultiCharts scripts, however, typically only execute when there’s incoming price data (MultiCharts Wiki, 2016). That can be problematic, since we don’t know beforehand if our instrument has enough price updates to have the time-based alert happen at the right time.

When our indicator or signal calculates on an instrument that has low liquidity (like after the regular trading session), we might run into situations in which the script only calculates every 30 or 60 seconds (or even later). In that case, our time-based alert fires with a considerable delay – or not at all. In addition, this situation isn’t limited to time-based alerts. If we for instance trigger alerts based on possible data feed issues, we also cannot rely on price updates to initiate a script calculation.

So how to calculate a script independent from incoming ticks? For that we use RecalcLastBarAfter(), a keyword that requires a certain number of seconds between its parentheses and then triggers a script calculation on the last bar every number of seconds (MultiCharts Wiki, 2014). For instance, RecalcLastBarAfter(3) makes the script calculate every 3 seconds in addition to the real-time calculations caused by price updates.

Since those additional time-based calculations trigger the same kind of script update as a new tick does, they’re a perfect way to simulate an active market when our script in fact calculates on a slow instrument. To see the effect of RecalcLastBarAfter() when generating alerts, let’s first look at a programming example without a periodic recalculation. Then we look at a second example that uses the keyword for generating up-to-date alerts.

Example: triggering time-based alerts without periodic calculations

The goal of the example indicator below is to generate an alert 30 seconds before the bar closes. We can use these alerts as a notification that the bar is about to close, so we can be ready to submit an order or closely monitor the bar for a confirmation of a signal.

In the example below we’ll focus on how to implement such time-based alerts. The image below shows two alerts generated by the indicator. After discussing the code, we’ll take a closer look at the script’s behaviour and what’s wrong with the alerts it generates.

Example of the alert messages generated by the script

Inputs:
    Seconds_Before_Close(30);

Variables:
    secondsLeft(0),
    IntrabarPersist alertGenerated(false);

if (CheckAlert) then begin  
    
    // Calculate the number of seconds till the bar closes
    secondsLeft = (DateTime - ComputerDateTime) / 
        ELTimeToDateTime_s(1);
    
    // Generate the alert when the bar almost closes
    if (secondsLeft <= Seconds_Before_Close) and
        (alertGenerated = false) then begin
    
        Alert("Notification: the price bar closes in " +
            NumToStr(secondsLeft, 0) + " seconds.");
        
        alertGenerated = true;
    
    end;
    
    // Reset the variable so that alerts can be
    // generated again on the next bar
    if (BarStatus = 2) then
        alertGenerated = false;

end;

We first make the Seconds_Before_Close numerical input and give it a default value of 30. We use this input’s value later when triggering the alerts. With the standard value of 30, an alert is generated when the bar closes in 30 seconds or less.

Then we make two variables:


Variables:
    secondsLeft(0),
    IntrabarPersist alertGenerated(false);

The secondsLeft numerical variable will hold how many seconds are left till the current bar closes. The other variable, alertGenerated, is a true/false variable with a default of false. We use this one later on to prevent several alerts on the same bar.

Because our indicator processes every real-time tick (a requirement for generating alerts before the bar closes), we set alertGenerated to IntrabarPersist. When that keyword is placed before a variable, it ensures that the variable’s value can be updated during intra-bar script calculations (PowerLanguage Keyword Reference, 2016).

Without IntrabarPersist, PowerLanguage variables use their standard behaviour. With that behaviour variables only ‘remember’ the value stored in the variable when the bar closes. That would mean that when we update the alertGenerated variable during an intra-bar script calculation, it wouldn’t remember its new value. Instead, it would still hold the value it had on the previous closed price bar. That would be problematic because when we cannot update alertGenerated intra bar, then we cannot use this variable to prevent multiple alerts per bar. And so we use IntrabarPersist here.

Next up is an if statement that encapsulates all of the indicator’s code:


if (CheckAlert) then begin  
    
    // ...

end;

For the if statement condition, we evaluate CheckAlert. That keyword returns true when the script’s manual ‘Enable Alerts’ setting is enabled and when the current bar is the last on the chart (PowerLanguage Keyword Reference, 2016). In all other situations, CheckAlert returns false.

And so we use that keyword here to programmatically check if the script’s alerts are enabled, and to only execute the if statement’s code when that’s the case. That way that code only runs when there’s actually a possibility to generate an alert.

Inside the if statement, we begin with calculating how many seconds till the bar closes:


secondsLeft = (DateTime - ComputerDateTime) / 
    ELTimeToDateTime_s(1);

To calculate that amount of seconds, we first subtract the current computer time (ComputerDateTime) from the current bar’s closing price, which is returned by DateTime (PowerLanguage Keyword Reference, 2016).

The ComputerDateTime and DateTime keywords return a value in DateTime format, however. The integer portion of those numerical values represents the number of days since January 1, 1900. And the fractional portion specifies the time of day passed since midnight (PowerLanguage Keyword Reference, 2016). Combined, that makes a DateTime value represent a date and time of day. While this format does make it possible to calculate time differences (like we do here), those calculations do return a DateTime value and not a number of seconds.

To convert that DateTime difference to a number of seconds, we divide it by the DateTime value of 1 second. We get that latter with the ELTimeToDateTime_s() keyword and a value of 1 passed in between its parentheses (PowerLanguage Keyword Reference, 2016).

And so the time difference between the computer time (ComputerDateTime) and the bar’s closing time (DateTime) is translated into a seconds scale (with ELTimeToDateTime_s(1)). We then store that number of seconds in the secondsLeft variable for use later on.

Next in the CheckAlert if statement is another if statement for generating alerts programmatically:


if (secondsLeft <= Seconds_Before_Close) and
    (alertGenerated = false) then begin

    Alert("Notification: the price bar closes in " +
        NumToStr(secondsLeft, 0) + " seconds.");
    
    alertGenerated = true;

end;

This if statement’s condition 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. When the left value, right value, or both values are false, then the result combined by and is false too (PowerLanguage Keyword Reference, 2016). With that both expressions in our if statement’s condition have to be true before the code inside the if statement executes.

The first expression checks whether the number of seconds till the bar closes (secondsLeft) is less than or equal to (<=) the Seconds_Before_Close input option, which we gave a default value of 30 earlier. The other part of the if statement’s condition checks if the alertGenerated variable equals (=) false.

Combined, that means the current bar has to be within 30 seconds of closing but the indicator shouldn’t already have generated an alert on this bar. Now when that’s the case, we generate an alert programmatically with Alert(). The alert message that we specify here is a static text combined with a dynamic value convert to text.

That dynamic value is the number of seconds till the bar closes (secondsLeft), which we convert to a textual string here with NumToStr(). That keyword requires two parameters: the number to convert to text and how many decimals that converted number should get (PowerLanguage Keyword Reference, 2016). With those parameters set to secondsLeft and 0, the number of seconds till the bar closes appears as whole number in the alert message (see the images above and below for how the alert messages look like).

After generating the alert, we set the alertGenerated variable to true. This invalidates the if statement in which we generate the alert (since that if statement’s condition required alertGenerated to be false), and so the alert doesn’t happen again.

Now to have the alertGenerated variable only allow one alert per bar, we reset it to false once per bar:


if (BarStatus = 2) then
    alertGenerated = false;

With this if statement we check if the BarStatus keyword returns a value equal to (=) 2. That keyword returns that value when the current price update of the script’s data series is the bar’s closing tick (PowerLanguage Keyword Reference, 2016). When such an on-bar-close calculation happens, we set alertGenerated to false. That makes it possible for our indicator to generate an alert again on the next price bar.

Example: time-based MultiCharts alerts with a ‘slow’ script

Before we look at how the example indicator behaves, let’s first discuss what’s missing from its code. While the script generates time-based alerts (30 seconds before the bar closes), it currently can only calculate when there’s a new real-time tick.

As long as those price updates arrive in a consistent manner (like once every 1-2 seconds), the script doesn’t lag much and alerts happen in a timely fashion. But when the instrument trades slowly (like in extended trading hours), then we can expect much more time between ticks. So instead of the alert firing 30 seconds before the bar closes, we might get alerts 20 or 15 seconds before bar close.

To see how the example script behaves, we have to configure several settings by hand. First we need to set the instrument’s time zone to ‘Local’. That way the indicator can compare the bar’s closing time (DateTime) with the computer’s local time (ComputerDateTime). Without that ‘Local’ time zone setting, DateTime returns the bar’s closing time in exchange time. To configure this, we first right-click on the instrument’s name in the top of the chart and select ‘Format [instrument name]…’:

Opening the window with the instrument settings in MultiCharts

This opens the ‘Format Instrument’ window. Here we select the ‘Settings’ tab and there we can set the instrument to the ‘Local’ time zone with the ‘Time Zone’ option:

Configuring the time zone setting in MultiCharts

The second option that we have to set is ‘Update on every tick’. That makes the script process all real-time ticks, instead of calculating only when the bar closes. To configure that we right-click on the indicator’s name in the top of the chart and choose ‘Format [indicator name]…’. That brings up the ‘Format Study’ window, and there we enable the ‘Update on every tick’ setting in the ‘Properties’ tab:

Setting a MultiCharts indicator to calculate on every tick

The third and last option to configure is of course enabling the script’s alert setting. We do that in the same ‘Format Study’ window, but now we select the ‘Alerts’ tab. There we turn on the indicator’s alerts with ‘Enable Alerts’ and allow the alerts to generate during intra-bar calculations (‘Every Tick’):

Configuring the alerts of the MultiCharts example indicator

Optionally, in the same ‘Format Study’ window we also find the input options in the ‘Inputs’ tab:

Input options of the MultiCharts indicator

After confirming those different settings, the example indicator generates the following alerts:

Example of lagging MultiCharts alerts

Of these 5 example alerts, none generated around 30 seconds before the bar closes. One alert even triggered just 14 seconds before the bar closed. That’s a time window less than half of what we expected. Let’s see how periodic script recalculates make the indicator fire alerts that are much closer to the 30 second mark.

Example: up-to-date alerts with periodic MultiCharts script calculation

To generate alerts in a timely manner, the script needs to calculate periodically instead of relying on incoming price updates. That feature is added easily created by using RecalcLastBarAfter(). When we add that keyword to the script, its code becomes:


Inputs:
    Seconds_Before_Close(30);

Variables:
    secondsLeft(0),
    IntrabarPersist alertGenerated(false);

if (CheckAlert) then begin  
    
    // Calculate the number of seconds till the bar closes
    secondsLeft = (DateTime - ComputerDateTime) / 
        ELTimeToDateTime_s(1);
    
    // Generate the alert when the bar almost closes
    if (secondsLeft <= Seconds_Before_Close) and 
        (secondsLeft > 0) and (alertGenerated = false) then begin
    
        Alert("Notification: the price bar closes in " +
            NumToStr(secondsLeft, 0) + " seconds.");
        
        alertGenerated = true;
    
    end;
    
    // Reset the variable so that alerts can be
    // generated again on the next bar
    if (BarStatus = 2) then
        alertGenerated = false;

    // Recalculate the script on the last bar of
    // the chart every second
    RecalcLastBarAfter(1);
    
end;

Since the code is quite similar to the code we already discussed above, let’s look at the two things that are new. The first adjustment is with the if statement that generates alerts programmatically:


if (secondsLeft <= Seconds_Before_Close) and 
    (secondsLeft > 0) and (alertGenerated = false) then begin

    Alert("Notification: the price bar closes in " +
        NumToStr(secondsLeft, 0) + " seconds.");
    
    alertGenerated = true;

end;

The new code here is the second true/false expression in the if statement’s condition, which checks whether the secondsLeft variable has a value that’s greater than (>) 0. This prevents the script from generating an alert when there are 0 or less seconds till the bar closes.

Let’s step back to understand why we add that requirement. In MultiCharts, time-based bars close depending on price action, not clock time. To figure out which price update belongs to the current bar and which one belongs to a new bar, MultiCharts ‘waits’ till the next price update to mark the previous tick as the bar’s closing tick (MultiCharts Wiki, 2016).

Say we have an hourly chart with a bar that closes at 9:00. When the last price update happened at 8:59:52, there’s 8 seconds left till the bar’s closing time. When the next price update arrives at 9:00:03 (so beyond the bar’s closing time), MultiCharts marks the 8:59:52 price as the closing price and 9:00:03 is the new bar’s opening price.

But our updated script now performs periodic calculations every second. In that case, our indicator might calculate at 9:00:00 or 9:00:02. When we compare the computer’s time with the bar’s time during those calculations, there are 0 and -2 seconds left till the bar closes. While this seems odd, it simply happens because MultiCharts closes bars based on price updates, not on time.

Of course, it would also look strange when an alert fires and says that the bar closes in -2 seconds. By adding the secondsLeft > 0 expression to our if statement that generates alerts programmatically, we prevent that from happening.

The other change to the original script (that didn’t use periodic calculations) is the RecalcLastBarAfter() keyword:


RecalcLastBarAfter(1);

RecalcLastBarAfter() triggers a periodic script calculation, every number of seconds that’s specified between the keyword’s parentheses (see MultiCharts Wiki, 2014). Those time-based calculations are the same as when a new price update happens, so not a full script recalculation from the first bar to the last.

With a parameter of 1 here, our indicator calculates at least once per second. Since we placed RecalcLastBarAfter() inside the if statement that programmatically checks whether alerts are enabled, those periodic calculations only happen when the indicator’s ‘Enable Alerts’ option is enabled. That way the indicator doesn’t perform those addition once-per-second calculations when alerts are disabled.

Example: triggering time-based alerts with a periodically recalculated script

After making those two changes, we save and recompile the indicator. With the indicator calculating at least once per second, the alerts it generates look like:

Example of MultiCharts alerts generated up to date

These alerts much more up to date than previously: all of these alerts fired within 29 to 30 seconds of the bar closing, just as we specified with the ‘Seconds_Before_Close’ input option. And so our updated indicator, thanks to RecalcLastBarAfter(), notifies us with plenty of time before the bar closes.

Summary

The Alert() keyword generates alerts programmatically, provided we’ve enabled the script’s alert setting. Since indicators and signals calculate when there’s a new price update, the frequency with which alert fire indirectly depends on how often the instrument (on which the script calculates) receives a new tick. That won’t be a problem when alerts are based on price action (and thereby ticks), like with a moving average crossover. But for time-based alerts, our script might not update often enough to generate those alerts at the appropriate time. This issue especially happens with instruments that aren’t actively traded or during a slow period in the markets. Luckily, MultiCharts scripts can calculate independent from price updates with RecalcLastBarAfter(). For that we specify inside that keyword’s parentheses the maximum number of seconds between successive script calculations. The script processes those additional time-based calculations in the same way as new price updates. And with that the script is kept up to date and able to generate alerts at the right time.

Learn more:


References

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

MultiCharts Wiki (2014, September 3). RecalcLastBarAfter. Retrieved on June 17, 2016, from http://www.multicharts.com/trading-software/index.php/RecalcLastBarAfter

MultiCharts Wiki (2016, February 22). How Scripts Work. Retrieved on June 17, 2016, from http://www.multicharts.com/trading-software/index.php/How_Scripts_Work

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