While we typically generate MultiCharts alerts based on price action, we can fire alerts based on anything that’s accessible in the code of an indicator or signal. So how do we generate alerts with trend lines?

In this article:

Generating MultiCharts alerts and drawing trend lines programmatically

We generate alerts programmatically with the Alert() keyword (Language Keyword Reference, 2016), although that does require that we manually enable the script’s alert setting. And depending on how we’ve configured the alert options, the alert appears as a notification window, audio alert, and/or email alert (MultiCharts Wiki, 2013).

Besides having an indicator or signal fire alerts, we can also generate alerts with manual drawings. The features with that are, however, a bit limited. For example, we can’t specify the message of an alert that’s fired by a trend line drawing and we also cannot limit how many of those alerts happen per bar.

But we can draw trend lines programmatically, and then use Alert() to generate alerts with those lines. That gives more control over when and how often the alert fires, what’s included in its alert message, and it even allow for filtering trend line alerts based on other values (like moving averages).

To have our script create a line and generate alerts with it, we first need to programmatically draw a trend line. One keyword for that is TL_New_s(), which draws a trend line on the chart where the script calculates and then returns a trend line ID number needed for further modify the line (PowerLanguage Keyword Reference, 2016). The keyword’s parameters are the date, time, and price of the line’s starting point and the date, time, and price of where the line should end.

After we make a trend line, we need to get its price value for specific bars. That way we can check if the current bar crossed above the line or not (and then generate an alert based on that). A keyword for retrieving the trend line’s price value is TL_GetValue_s(), whose parameters are the ID of the trend line alongside the date and time to get the trend line price value for.

Let’s look at an example indicator to see how we can use TL_New_s() and TL_GetValue_s() alongside Alert() for generating alerts based on programmatically drawn trend lines.

Example: trend lines and alerts based on high and low prices

The indicator below draws two horizontal trend lines to show yesterday’s high and low. We track those extreme prices while the day develops, and update the horizontal trend lines at the start of each calendar day. As soon as the price bar closes above or below the lines, we generate an alert programmatically.

The images below give a quick example of how the alerts and indicator look. After discussing the code we’ll take a closer look at the indicator’s appearance and the alerts it generates.

Example alert generated by the MultiCharts indicator Chart with the programmatically-drawn trend line in MultiCharts

Inputs:
    LineSize(2),
    DayHighColour(green),
    DayLowColour(red);
    
Variables:
    prevHighLine(0),
    prevLowLine(0),
    dayHigh(0),
    dayLow(0),
    prevDayHigh(0),
    prevDayLow(0);

// Create and change the trend line's appearance once
once begin

    prevHighLine = TL_New_s(Date[1], Time_s[1], Close,
        Date, Time_s, Close);
    prevLowLine = TL_New_s(Date[1], Time_s[1], Close,
        Date, Time_s, Close);

    // Change formatting of lines
    TL_SetExtRight(prevHighLine, true);
    TL_SetExtRight(prevLowLine, true);
    
    TL_SetSize(prevHighLine, LineSize);
    TL_SetSize(prevLowLine,  LineSize);
    
    TL_SetColor(prevHighLine, DayHighColour);
    TL_SetColor(prevLowLine,  DayLowColour);
    
end;

if (BarStatus = 2) then begin

    // Update the lines and values on the first bar of the day
    if (Date <> Date[1]) then begin
        
        // Update trend line locations
        TL_SetEnd_s(prevHighline, Date, Time_s, dayHigh);
        TL_SetBegin_s(prevHighLine, Date[1], Time_s[1], dayHigh);
    
        TL_SetEnd_s(prevLowLine, Date, Time_s, dayLow);
        TL_SetBegin_s(prevLowLine, Date[1], Time_s[1], dayLow);
    
        // Reset daily high and low
        dayHigh = High;
        dayLow  = Low;

    end 
    
    // Update the day high and low for all other bars
    else begin
        dayHigh = MaxList(dayHigh, High);
        dayLow  = MinList(dayLow, Low); 
    end;
    
    // Monitor for a cross above or below day high and low
    prevDayHigh = TL_GetValue_s(prevHighLine, Date, Time_s);
    prevDayLow  = TL_GetValue_s(prevLowLine, Date, Time_s);
    
    if (Close cross above prevDayHigh) then
        Alert("Bar crossed above yesterday's high")
    else if (Close cross under prevDayHigh) then
        Alert("Price dropped below yesterday's high")
    else if (Close cross above prevDayLow) then
        Alert("Bar crossed above yesterday's low")
    else if (Close cross under prevDayLow) then
        Alert("Bar fell below yesterday's low");
    
end;

We first create three input options: LineSize, DayHighColour, and DayLowColour. These are used later on to set the size and colour of the trend lines.

Then we make 6 numerical variables. Two are going to hold the trend line IDs (prevHighLine and prevLowLine). By storing those identifiers in a variable we can access and change the trend lines later on. With the dayHigh and dayLow variables we track the current day’s highest high and lowest low, while prevDayHigh and prevDayLow will hold those values from yesterday.

The script’s remaining code can be categorised in two parts. The first executes once and creates both trend lines with the proper formatting. The other part run each time a bar closes. That part collects the high and low data, updates the trend line locations, and generates alerts.

And so in the first part we first create both trend lines:


once begin

    prevHighLine = TL_New_s(Date[1], Time_s[1], Close,
        Date, Time_s, Close);
    prevLowLine = TL_New_s(Date[1], Time_s[1], Close,
        Date, Time_s, Close);

    TL_SetExtRight(prevHighLine, true);
    TL_SetExtRight(prevLowLine, true);
    
    TL_SetSize(prevHighLine, LineSize);
    TL_SetSize(prevLowLine,  LineSize);
    
    TL_SetColor(prevHighLine, DayHighColour);
    TL_SetColor(prevLowLine,  DayLowColour);
    
end;

We make these trend lines in a code block with the once keyword. That way all code between begin and end only executes once. By making and formatting the trend lines only once, our script is more efficient (in terms of memory usage and CPU) than repeatedly making trend lines. Since at this point we don’t know yesterday’s high and low yet, we’ll just use temporarily placeholders.

Those lines are made here with TL_New_s(), a keyword that requires the date, time (with seconds notation), and price value of the line’s begin and end point (PowerLanguage Keyword Reference, 2016). After making a line, TL_New_s() returns a trendline-specific ID number that we need to store if we want to access the trend line later on. (Here we put those ID numbers in the prevHighLine and prevLowLine variables.)

Since we create the trend lines once here to have them ready for later, we simply set both lines to the same coordinates. For the begin point we use the previous bar’s date (Date[1]) and time with seconds (Time_s[1]) alongside the current bar’s closing price (Close). The end coordinate of both lines is the date, time, and closing price of the current bar (Date, Time_s, and Close). Later on in the script we’ll update the lines to yesterday’s high and low.

Changing the formatting of both lines is up next. First we extend the trend lines indefinitely to the right. Because that makes the line cover all future price bars that form in the right of the chart, we only have to update the lines once per day to have them plot values for the whole day. (Without this, we’d have to manually extend the lines ourselves on every bar.)

We do that extension with the TL_SetExtRight() keyword that requires two parameters: the trend line ID and whether that line should extend to the right (true) or not (false) (PowerLanguage Keyword Reference, 2016). Since we want to extend both the high and low line (prevHighLine and prevLowLine), we use true for the second parameter.

The second visual change adjusts the trend line size. We do that with TL_SetSize(), a keyword that requires two parameters: the trend line ID and a numerical value between 0 to 6 that specifies that line’s new size (PowerLanguage Keyword Reference, 2016). With it we set the size of both the prevHighLine and prevLowLine lines to the value of the LineSize input option. With that input’s default value of 2, the lines become a bit bigger than default.

The last line setting that’s changed here is its colour. We do that programmatically with the TL_SetColor() keyword, which also requires two parameters: the trend line ID and whichever colour that line should get (PowerLanguage Keyword Reference, 2016). With it we set the colour of the prevHighLine and prevLowLine variables to the DayHighColour and DayLowColour inputs, which have default values of green and red.

After making and preparing the trend lines, the next part of the script begins. All code of that part is inside the following if statement:


if (BarStatus = 2) then begin

    // ...
    
end;

Here we evaluate whether the BarStatus keyword returns a value equal to (=) 2. That keyword returns such a value when the script calculates on the last price update of the bar (PowerLanguage Keyword Reference, 2016). This limits all calculations done inside the if statement to once per bar, when the bar closes.

That makes the indicator run more efficient. It also makes sense given that we work with yesterday’s high and low (which don’t change with each price update). And since we generate alerts programmatically inside this if statement, the alerts are limited to once per bar too.

During those on-bar-close calculations, we do two things. First, we update the trend lines’ location and track the current day’s high and low (which become the previous day’s high and low at the start of a new day). Second, we generate different alerts based on how the price bar crosses the lines.

And so we first update the lines and track the high and low prices. We do that in the following if/else statement:


if (Date <> Date[1]) then begin
    
    TL_SetEnd_s(prevHighline, Date, Time_s, dayHigh);
    TL_SetBegin_s(prevHighLine, Date[1], Time_s[1], dayHigh);

    TL_SetEnd_s(prevLowLine, Date, Time_s, dayLow);
    TL_SetBegin_s(prevLowLine, Date[1], Time_s[1], dayLow);

    dayHigh = High;
    dayLow  = Low;

end 

else begin
    dayHigh = MaxList(dayHigh, High);
    dayLow  = MinList(dayLow, Low); 
end;

The if statement’s condition evaluates whether the date of the current bar (Date) is unequal to (<>) that of the previous bar (Date[1]). This happens once per day, on the first bar of the day. Should the current bar indeed be the first of the day, the code below the if keyword executes. When it’s not, the else portion of the if/else statement runs.

When the current bar is the first of the calendar day, we need to do several things. First, we’ll need to update the location and price of both trend lines. Without that, the lines would still use prices from the day before yesterday and plotted in yesterday’s session instead of todays.

We can update a trend line’s location with TL_SetEnd_s() and TL_SetBegin_s(). Both keywords require four parameters: the ID of the trend line whose location to change alongside the date, time, and price of the new location (PowerLanguage Keyword Reference, 2016). The difference between the keywords is that TL_SetEnd_s() updates the line’s ending point whereas TL_SetBegin_s() relocates the line’s starting point (PowerLanguage Keyword Reference, 2016).

Note: When programmatically updating the location of a trend line, its end point has to be updated before we adjust the line’s begin point (MultiCharts Wiki, 2012a). That’s why we use the TL_SetEnd_s() keyword here before TL_SetBegin_s().

With TL_SetEnd_s() we first set the end location of the prevHighLine to the current bar’s date (Date) and time (Time_s) with the dayHigh price value. As we’ll see later, that dayHigh variable holds the highest high of the day. But because we haven’t updated this variable yet during the current script calculation and since the script calculates on the first bar of the day (Date <> Date[1]), that variable still holds yesterday’s highest high.

Next we use TL_SetBegin_s() to update the begin point of the prevHighLine trend line. We set the coordinates of that starting point to the previous bar’s date and time (Date[1] and Time_s[1]) alongside the dayHigh price value. This creates a small, horizontal trend line between the previous and current bar. But because we extended our trend line to the right earlier, we won’t see a small line but instead one that continues forever to the right.

After updating the highest high line we use the TL_SetEnd_s() and TL_SetBegin_s() keywords to update the lowest low line. We do this in practically the same way, except that now we use the prevLowLine variable for the trend line ID number and the dayLow variable to specify the low of the day.

The last part of the if statement’s code block sets the dayHigh and dayLow variables to the current bar’s high (High) and low (Low). This resets those variables at the start of the trading day and that makes they accurate track whichever high or low happens during the current day.

The else portion of the if/else statement contains the following:


else begin
    dayHigh = MaxList(dayHigh, High);
    dayLow  = MinList(dayLow, Low); 
end;

Whenever the if statement condition that checks whether the bar’s date differs from the previous bar (Date <> Date[1]) evaluates to false, the current bar is not the first of the day and this else code block executes. In this code segment we update the dayHigh and dayLow variables to track the highest high and lowest low as the day develops.

We set dayHigh to the value returned by MaxList(). That keyword accepts several numerical parameters and returns the largest of those values (PowerLanguage Keyword Reference, 2016). The values we put between its parentheses are the current value of dayHigh and the bar’s high (High). With this the dayHigh variable only gets a new value when the bar’s high is greater than the value it already holds. By doing that on every bar, the variable tracks the highest high.

The dayLow variable is updated likewise. Now we use MinList(), a keyword that accepts several numerical parameters and returns the lowest value of those (PowerLanguage Keyword Reference, 2016). With the dayLow and Low variables, the keyword either returns the dayLow value or the bar’s low whenever that bar reached a new lower low.

Next we generate alerts based on the trend lines’ value:


prevDayHigh = TL_GetValue_s(prevHighLine, Date, Time_s);
prevDayLow  = TL_GetValue_s(prevLowLine, Date, Time_s);

if (Close cross above prevDayHigh) then
    Alert("Bar crossed above yesterday's high")
else if (Close cross under prevDayHigh) then
    Alert("Price dropped below yesterday's high")
else if (Close cross above prevDayLow) then
    Alert("Bar crossed above yesterday's low")
else if (Close cross under prevDayLow) then
    Alert("Bar fell below yesterday's low");

Here we first update the prevDayHigh and prevDayLow variables to the trend line value on the current bar. For that we use the TL_GetValue_s() keyword, which requires three parameters: the trend line ID alongside the date and time (with seconds notation) to get the trend line price value of (PowerLanguage Keyword Reference, 2016). Because TL_GetValue_s() extrapolates the trend line values to bars on which the trend line isn’t drawn (PowerLanguage Keyword Reference, 2016), the keyword can get a line’s price values for any bar on the chart.

To get the price value of yesterday’s high line, we identify that line with the prevHighLine variable alongside the current bar’s date (Date) and time (Time_s). The value returned by TL_GetValue_s() is what we store in the prevDayHigh variable. Similarly, the prevDayLow variable is updated with the price value of the yesterday low line, except that now we use the prevLowLine variable to identify the trend line. Since both lines are horizontal, we could also use another bar’s date and time (instead of the current bar’s) to get the same trend line price value.

Then we use a cascaded if/else statement to determine whether the bar’s closing price (Close) crossed above or below the previous day’s high or low (that is, the trend line’s price values). The first condition we evaluate is whether the bar’s closing price crossed above (cross above) the previous day high (that we’ve just retrieved and stored in prevDayHigh).

That cross above keyword combination returns true when, on the current bar, the value to its left is greater than the value to its right while, on the previous bar, the left value was less than or equal to the right value (PowerLanguage Keyword Reference, 2016). For our case, that means cross above returns true whenever the bar’s closing price crossed (compared to the previous bar) the yesterday high.

In that situation, we generate an alert programmatically with Alert(). Inside that keyword’s parentheses we specify the alert message saying the bar crossed above yesterday’s high.

With the subsequent else if statement we check whether the bar’s close dropped below the previous day high (Close cross under prevDayHigh). That cross under keyword combination only returns true when, on the current bar, the value on its left is less than the value on its right while, on the previous bar, the left value was equal or more than the right value (PowerLanguage Keyword Reference, 2016). When the closing price indeed fell below yesterday’s high, we generate another alert message with the Alert() keyword.

With the second else if statement we again use the cross above keyword combination, but this time to check whether the bar’s closing price rose above yesterday’s low (prevDayLow). When that happens, we generate an alert message saying so. And with the fourth and last if statement we generate an alert whenever the bar’s closing price fell under (cross under) the previous day low.

Generating MultiCharts alerts based on trend lines

Let’s see how our above example performs on the chart. In order to have the indicator generate alerts, we first need to enable the script’s alerts manually with the ‘Enable Alerts’ checkbox option:

Configuring the alerts of the MultiCharts example indicator

In the same ‘Format Study’ window as where we specify the alert settings, we can also configure the three input options we’ve added to the code:

Example of the indicator's input options

The indicator looks as follows when added to the chart:

The MultiCharts example indicator added to a price chart

Here we see that the script draws its two trend lines. Both start at the beginning of the day and continue to the right of the chart. The green line shows the high of the previous calendar day while the red line marks that day’s low.

When new bars form, it looks like this when they cross the previous day high:

Example chart with price bars crossing the previous day high

Crossing yesterday’s high like that has the script generate an alert like the following:

Example alert when the price crosses yesterday's high in MultiCharts

The same thing happens when a bar drops below yesterday’s low. For instance, when we start with a chart like this:

Example chart with the MultiCharts indicator applied to it

And then when a price bar drops below the low of yesterday:

Example chart with he price dropping below yesterday's low

The indicator triggers an alert like the following:

Example alert when the price drops below yesterday's low in MultiCharts

For another example of combining alerts with trend lines, see generating a semi-automatic trend line alert with mouse clicks.

Summary

We generate MultiCharts alerts programmatically with the Alert() keyword, but for that we’ll need to enable the script’s alert setting by hand. While we can also generate alerts with manual drawings, for that we’d need to configure each drawing by hand and then we still get alerts without a meaningful message. An alternative is to draw trend lines programmatically, and then use Alert() to trigger alerts with a custom, meaningful message. We can draw trend lines with TL_New_s(), a keyword whose parameters specify the date, time, and price value of the line’s begin and end point. To generate alerts based on a trend line, we have to get the line’s value. We can then compare that price value with the bar’s closing price to see whether the bar crossed the line or not. The TL_GetValue_s() keyword returns the price value of a specific trend line for a certain date and time. That keyword does not require that the trend line is actually drawn on that time coordinate. Instead, it can extrapolate the trend line’s values to any date and time that’s on the chart by using the line’s slope.

Learn more:


References

MultiCharts Wiki (2012, May 2). TL SetEnd. Retrieved on July 23, 2016, from http://www.multicharts.com/trading-software/index.php/TL_SetEnd

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

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 for more helpful coding articles.