Programmatically generating MultiCharts alerts is only possible after we’ve manually enabled the script’s alert setting. That means when we forget that setting, our indicator or signal doesn’t fire alerts – even when the code is fully correct. So how do we prevent overlooking that important ‘Enable Alerts’ option?

In this article:

Creating a notifying text box when MultiCharts alerts are disabled

We generate MultiCharts alerts programmatically with Alert() (PowerLanguage Keyword Reference, 2016), but that keyword only works when the script’s alerts are enabled. Then, depending on the manual alert settings, alerts can appear as a notification window, audio alert, and/or email alert (MultiCharts Wiki, 2013).

Unfortunately, it’s currently not possible to enable or disable alerts with programming code. And so we’ll have to set the ‘Enable Alerts’ checkbox by hand (see image below) for each chart, portfolio strategy, or Scanner/Watchlist where the script operates.

Example of an indicator with the alert setting disabled

A risk of having to set that option by hand is forgetting to do so. In that case, our script cannot generate alerts when its alert conditions do happen.

So how can we prevent forgetting that option? One approach is triggering an error when alerts are disabled. Such a red error message with accompanying ‘ding’ sound for sure gets our attention, but also disables the script. That can be a bit too much, however, when we use the script’s data or plots during trading.

A friendlier approach is to place a text box on the chart that says the script’s alerts are disabled. That way the script keeps running, but with a notification that’s hard to miss. To implement that programmatically, we’ll need to do a couple of things.

First, we’ll have to programmatically check whether the script’s alerts are enabled. There are two PowerLanguage keywords for that (PowerLanguage Keyword Reference, 2016):

  • The AlertEnabled keyword returns true when the ‘Enable Alerts’ setting is enabled and false when the script’s alerts are disabled.
  • The CheckAlert keyword returns true when the script’s alerts are enabled and the script calculates on the last bar of the data series. When the ‘Enable Alerts’ option is disabled or when the bar isn’t the last, then CheckAlert returns false.

And so with AlertEnabled we check the status of the ‘Enable Alerts’ setting on every bar whereas CheckAlert only does so for the last bar.

The other puzzle piece is creating the text box. There are several PowerLanguage keywords for that, including Text_New_DT(). That keyword draws a text box with a certain message at the specified time and price coordinate (PowerLanguage Keyword Reference, 2016). Once it makes a text box, Text_New_DT() returns an ID number needed to modify the text box afterward. We typically store that value in a variable for easy access later on.

A feature of Text_New_DT() is that it uses DateTime values to specify the text box’s time axis location. The numerical values of that format consist out of two parts: an integer that represents the number of days since January 1, 1900, and a decimal that indicates the portion of the day passed since midnight (PowerLanguage Keyword Reference, 2016). Combined, that makes those DateTime values represent both a date and time of day.

Let’s look at the programming example to see how we can create a notifying text box whenever the script’s ‘Enable Alerts’ setting is off.

Example: make a text box when the script’s alerts are disabled

In the example indicator below we place a text box in the chart’s lower left corner whenever the script’s alerts are disabled. To address scrolling the chart (which moves the text box out of view), we periodically update the script so that the text box always moves back to its lower left corner. We’ll also generate a basic, time-based example alert.

The image below shows how that text box looks. After discussing the code we’ll explore how the indicator behaves when alerts are enabled and disabled.

Example of the notification text box appearing on a MultiCharts chart

[RecoverDrawings = false];

Variables:
    IntrabarPersist textBoxID(0);

if (LastBarOnChart_s and CheckAlert = false) then begin
    
    // Create the notifying text box
    if (textBoxID = 0) then begin
    
        textBoxID = Text_New_DT(GetAppInfo(aiLeftDispDateTime), 
            GetAppInfo(aiLowestDispValue), 
            "\n  The script's alerts are disabled  \n");
        
        // Change the text box's appearance
        Text_SetStyle(textBoxID, 0, 1);
        Text_SetBorder(textBoxID, true);
        Text_SetSize(textBoxID, 10);
        Text_SetColor(textBoxID, black);
        Text_SetBGColor(textBoxID, yellow);
    
    end 
    
    // If the text box is already made, we only 
    // need to update its location
    else if (textBoxID > 0) then begin
    
        Text_SetLocation_DT(textBoxID, 
            GetAppInfo(aiLeftDispDateTime),
            GetAppInfo(aiLowestDispValue));
    
    end;

end;

// Recalculate the script every second
RecalcLastBarAfter(1);

// Generate an alert when the market closes
if (Time = 2200) then
    Alert("The trading day ended. The closing price is " + 
        NumToStr(Close, 1) + ".");

The first thing we do is set the RecoverDrawings attribute to false. By default, MultiCharts removes all drawings (arrows, text boxes, and trend lines) that are made during an intra-bar script calculation. In our case, that means that unless our text box is created when the bar closes, it’s automatically removed by MultiCharts. To make our text box persist regardless of when we make it, we set RecoverDrawings to false (MultiCharts Wiki, 2014).

Next we create a variable:


Variables:
    IntrabarPersist textBoxID(0);

We use the textBoxID variable later to track the text box’s identifier, which we need to store in a variable if we want to access the text box after making it. We’ll also use this variable later on to figure out whether the text box has already been made or not.

We mark the textBoxID variable as IntrabarPersist. With that keyword placed before a variable, the variable remembers any value assigned to it during an intra-bar script calculation (PowerLanguage Keyword Reference, 2016). By default, PowerLanguage variables only keep the values we store in them when the bar closes, and not retain values from one intra-bar script calculation to the next. Since our script also has the possibility to create the text box during an intra-bar script calculation, we mark the textBoxID variable as IntrabarPersist.

Next is an if statement in which the majority of the script’s code is placed in:


if (LastBarOnChart_s and CheckAlert = false) then begin
    
    // ..

end;

This if statement’s condition evaluates two expressions combined with and. That logical keyword returns true when the value on its left and the value on its right are true too; otherwise, when one or both values are false, the result combined with and is false too (MultiCharts Wiki, 2012).

The first expression here is LastBarOnChart_s, a standard function that returns true when the script calculates on the last bar of the data series. By using this function we ensure that the text box is initially drawn around the last bar of the chart (where we’ll spend most of our time). The other expression evaluates whether CheckAlert is false, which it is when on the script’s alerts are disabled on the last bar of the data series (PowerLanguage Keyword Reference, 2016).

Combined, the if statement’s code only executes when the current bar is the last and the ‘Enable Alerts’ option is turned off. In that situation, the code inside the if statement begins with creating the text box:


if (textBoxID = 0) then begin

    textBoxID = Text_New_DT(GetAppInfo(aiLeftDispDateTime), 
        GetAppInfo(aiLowestDispValue), 
        "\n  The script's alerts are disabled  \n");
    
    // Change the text box's appearance
    Text_SetStyle(textBoxID, 0, 1);
    Text_SetBorder(textBoxID, true);
    Text_SetSize(textBoxID, 10);
    Text_SetColor(textBoxID, black);
    Text_SetBGColor(textBoxID, yellow);

end 

To prevent making multiple text boxes, this if statement checks whether the textBoxID variable is equal to (=) 0. That value is the variable’s default value. Inside the if statement we make a text box and update the value of textBoxID to the numerical identifier of that text drawing. That also means, whenever the variable’s value is still 0, that we haven’t made a text box yet.

When that’s the case, we create one with Text_New_DT(). That keyword requires three parameters (PowerLanguage Keyword Reference, 2016). The first is the text box’s date and time coordinate in DateTime format. When placing a drawing in the chart’s lower left corner, that DateTime value has to be of the leftmost bar in the current chart view. We get that value with the GetAppInfo() keyword and the aiLeftDispDateTime parameter (PowerLanguage Keyword Reference, 2016).

The second parameter of Text_New_DT() is the price value of the text box. To put the drawing in the lower left, we have to use the lowest value of the chart’s price scale in the current chart window. We get that value with the GetAppInfo() keyword and the aiLowestDispValue parameter (PowerLanguage Keyword Reference, 2016). Combined with the DateTime value of the leftmost bar, that gives us the chart’s lower left corner.

The third parameter of Text_New_DT() is the text box’s message, which we set here to “The script’s alerts are disabled”. To place that line a bit away from the box’s left and right border, we place two places before and after this sentence. We also add the \n escape character, which inserts a new line in the text box (like the Enter key does). That gives room above and below the text line which makes the alert box more prominent (see the example image above or further down below).

We store the numerical, drawing-specific ID number returned by Text_New_DT() into the textBoxID variable. That has two reasons. First, we can now use that variable to access and modify the text box we’ve just made. Second, because textBoxID is now different than zero, this if statement’s code doesn’t execute the next time the script calculates – and that creates our text box only once.

This also shows why we’ve set textBoxID to IntrabarPersist. If we didn’t do that, the variable’s value won’t remember the text box ID whenever we made the drawing and updated its variable during an intra-bar script calculation. Without IntrabarPersist, the variable would only remember the drawing’s ID when we created the text box at the exact moment the bar closes. Since that doesn’t happen in 95%+ of the time, our script would make multiple text boxes because the variable didn’t properly update. We prevent that by using IntrabarPersist.

After making the text box, we use the textBoxID variable and several keywords to change the drawing’s appearance. With Text_SetStyle() we change the box’s alignment while Text_SetBorder() enables a border around the text box with the same colour as the text. The Text_SetSize() keyword changes the text box’s font size, while Text_SetColor() and Text_SetBGColor() change the text and background colour (PowerLanguage Keyword Reference, 2016).

While the code inside the if statement creates a text box if there wasn’t one already, there’s also an else if portion that updates the location of an existing text box:


else if (textBoxID > 0) then begin

    Text_SetLocation_DT(textBoxID, 
        GetAppInfo(aiLeftDispDateTime),
        GetAppInfo(aiLowestDispValue));

end;

The reasoning behind updating the text box’s location is the following. Initially, we placed the text box in the chart’s lower left corner. But as new real-time bars form or when we scroll the chart to historical bars, the text box isn’t placed in the chart’s lower left anymore (but ‘moves out of view’ instead). And so to keep it visible in the current chart view, we’ll need to update its location every so often.

To see whether we’ve already made the text box, we check here if the textBoxID variable returns a value greater than (>) 0. Since we stored the text box’s identifier in that variable, it does hold a value bigger than 0 when we’ve made the text box. In that case, we update the text box’s location with the Text_SetLocation_DT() keyword.

That keyword requires three parameters: the drawing-specific ID number of the text box whose location has to be updated, alongside the DateTime and price value of the new location (PowerLanguage Keyword Reference, 2016). We set those parameters to the textBoxID variable, and the GetAppInfo() with the aiLeftDispDateTime and aiLowestDispValue parameters. Because those latter two return the values based on the current chart view, we use the same parameters of GetAppInfo() as when we made the text box.

The remaining code of the indicator is placed outside the if statement that checks whether the bar is the last one and alerts are disabled. That remaining code first recalculates the script periodically:


RecalcLastBarAfter(1);

The RecalcLastBarAfter() keyword triggers a periodic script calculation after the number of seconds we specified between its parentheses (PowerLanguage Keyword Reference, 2016). With a parameter of 1, our indicator will calculate at least once per second.

Now why recalculate the script periodically? We don’t know how often a new price update (and thereby a script calculation) happens. Since we need those calculations to update the text box’s location, the text box can easily move out of view whenever we scroll the chart to the left or right. By periodically recalculating the script, however, the text box smoothly updates to the chart’s lower left corner every second or so.

With those calculations the indicator can even draw the text box when the market is closed. That way the notification that alerts are disabled can appear before trading begins, which allows us to enable the script’s alert setting in a timely fashion.

We end the example indicator with generating an alert programmatically:


if (Time = 2200) then
    Alert("The trading day ended. The closing price is " + 
        NumToStr(Close, 1) + ".");

This if statement’s condition evaluates whether the bar’s closing time (Time) equals (=) 2200 (meaning, 10 p.m.). With this we generate a basic alert message whenever the instrument that the example indicator calculates on has closed.

When the bar’s time is indeed 22:00, we use Alert() to generate an alert programmatically. Inside that keyword’s parentheses we specify an alert message containing a static string combined with a dynamic numerical value. We format that latter with NumToStr(), a keyword that accepts two parameters: a numerical value to convert to a string alongside the number of decimals that converted value should get (PowerLanguage Keyword Reference, 2016). Here we set those arguments to the bar’s closing price (Close) and 1, which matches the number of decimals of the instrument that we’re adding the example script to (see images below).

Example: notify disabled MultiCharts alerts with a text box

Let’s see how the above example indicator works. First we add the script to the chart with the ‘Enable Alerts’ setting disabled:

Starting with the script's alerts disabled first

That prompts the indicator to create the following text box:

Example of the notifying text box on the MultiCharts chart

Now when we enable the script’s alert settings to the following:

Enabling the alerts of the MultiCharts example indicator

Then the indicator doesn’t plot the notifying text box anymore:

Example MultiCharts chart without the text box

Once the alerts are enabled, the script can generate the following basic alert messages:

Examples of the alert messages generated by the script

For a more attention-grabbing approach in case the ‘Enable Alerts’ option is turned off, see generating an error message when the script’s alerts are disabled.

Summary

We generate MultiCharts alerts programmatically with Alert(). To have that keyword trigger actual alerts, we have to enable the script’s alert setting. With the AlertEnabled and CheckAlert keywords we programmatically check if that ‘Enable Alerts’ option is turned off or on. Since we cannot set that option with code, we have to remember to configure that option by hand for each chart that the script is added to. By creating a text box on the chart when we forget to enable that option we can make sure we turn ‘Enable Alerts’ on. One keyword for making a text box is Text_New_DT(), which requires the text box’s specified time (in DateTime format) and price coordinate alongside a text message. That keyword also returns a drawing-specific ID number, which we have to store in a variable should we want to access the text box later on. When placing a text box in the chart’s lower left corner, we use the GetAppInfo(aiLeftDispDateTime) keyword for the date and time of the leftmost price bar of the current chart view. And GetAppInfo(aiLowestDispValue) gets us the lowest price of the values currently shown on the chart’s price axis. To keep the text box from scrolling out of view when new price bars form, we’ll have to update its location periodically with the Text_SetLocation_DT() keyword.

Learn more:


References

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

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, January 23). RecoverDrawings. Retrieved on June 12, 2016, from https://www.multicharts.com/trading-software/index.php/RecoverDrawings

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.