Once we’ve drawn a trend line in MultiCharts .NET we can put the trend line reference in a variable. But how do we associate lines with previous price bars so we can access trend lines that were drawn on a certain bar?

Drawing trend lines in MultiCharts .NET programmatically

The DrwTrendLine.Create() method draws trend lines and returns a reference to the line made (MultiCharts, 2014; PowerLanguage .NET Help, n.d.). With that reference assigned to an ITrendLineObject variable, the line’s properties and methods can be accessed through the variable. We can then change a line’s location, its visual appearance, or even remove the trend line.

But creating an ITrendLineObject interface variable for every programmatically drawn trend line becomes inconvenient quickly. We can, however, use one variable series to keep track of all our trend line reference variables.

Using the VariableSeries class to keep track of lines

The VariableSeries<T> class creates a series of variables that, just like a chart’s data series, provide access to values held on the close of previous bars (Henry MultiCharts, 2013; MultiCharts, 2014). Such a variable series is both generic and type-safe: its T can be replaced with any type, but once defined, it can only hold values of that type (see Sempf, Sphar, & Davis, 2010). And so VariableSeries<int> is variable series that can only hold integers.

Setting the current bar value of a VariableSeries<T> instance is done with its read/write Value property (PowerLanguage .NET Help, n.d.). This property doesn’t need to be assigned a value on every price bar; when a value isn’t assigned to the variable series, the value from the previous bar is simply repeated. Related to this is the disadvantage that only a bar’s last value is stored. So when we draw multiple trend lines on a bar and storing each ITrendLineObject reference in the variable series, we can only access the last value that’s assigned for that bar. Working with multiple trend lines without that limitation is possible by using a generic trend line list or tracking trend lines in a dictionary.

A VariableSeries<T> has the same length as the data series it’s associated with (see Henry MultiCharts, 2013). We retrieve a variable series’ values from previous bars with a non-negative integer between square brackets ([ and ]) after the variable series’ name, just like you’d access values from previous bars (like Bars.Close[4] and Bars.Low[1]). Let’s consider the programming example to see how we can use a variable series with trend lines.

Example: comparing a trend line with a line from several bars ago

The example indicator draws trend lines between a recent high and low. These lines are then compared with the variable series’ value of 10 bars ago to determine their colour. Added to a 60-minute EUR/USD chart, this looks like:

MultiCharts .NET trend lines in a variable series - 1

Or when added to a 5-minute E-mini S&P 500 future chart:

MultiCharts .NET trend lines in a variable series - 2

Using VariableSeries with MultiCharts .NET trend lines

The indicator’s code is:

[SameAsSymbol(true), UpdateOnEveryTick(false)]
public class Example_TrendLinesVariableSeries : IndicatorObject
{
    public Example_TrendLinesVariableSeries(object _ctx) : base(_ctx) { }

    private VariableSeries<ITrendLineObject> trendLines;

    protected override void Create()
    {
        trendLines = new VariableSeries<ITrendLineObject>(this);
    }

    protected override void CalcBar()
    {
        if (Bars.High[0] > Bars.High.Highest(10, 1))
        {
            ChartPoint beginPoint = new ChartPoint(
                Bars.FullSymbolData.Time[Bars.Low.LowestBar(10)],
                Bars.Low.Lowest(10));

            ChartPoint endPoint = new ChartPoint(
                Bars.Time[0], Bars.High[0]);

            // Set the variable series' current value
            trendLines.Value = DrwTrendLine.Create(beginPoint, endPoint);

            // Retrieve the current variable series' value to 
            // set the line's appearance
            trendLines[0].Size     = 2;
            trendLines.Value.Color = Color.Orange;

            // Compare the new line's starting point with the line
            // value of 10 bars ago to set the line's colour
            if (trendLines[10] != null && 
                trendLines[0].Begin.Price > trendLines[10].Begin.Price)
            {
                trendLines.Value.Color = Color.LimeGreen;
            }
        }
    }
}

We start by setting the SameAsSymbol attribute to true to display the indicator on the data series and not in a subchart. And with UpdateOnEveryTick set to false the indicator is calculated on bar close only. Since the indicator’s code evaluates the bar’s high, we don’t want every real-time tick that’s a new high to cause another line to be drawn.

Then we declare a variable series of type ITrendLineObject so it can hold trend line reference variables (VariableSeries<ITrendLineObject>). We instantiate this trendLines variable series in the Create() method with the new keyword. This method is executed once when the indicator is created (that is, added to a chart or market scanner) (MultiCharts, 2014).

Drawing lines between the highest high and lowest low

The CalcBar() method is the next part of the example. In it an if statement evaluates if the current bar’s high (Bars.High[0]) is greater than (>) the highest high of the preceding 10 bars. That latter value is returned by the Bars.High.Highest() extension method whose arguments are the length in bars and the bars back offset (PowerLanguage .NET Help, n.d.). We use an offset of 1 so that the current bar’s high is not included in the 10-bar high.

When the current bar forms a new high, we create two ChartPoint struct variables to hold the chart coordinates of the line we’re going to draw. The first, beginPoint, is set to the time and price of the bar with the lowest low of the last 10 bars. That bar’s DateTime value is retrieved by the Bars.FullSymbolData.Time property to access any bar on the chart (see PowerLanguage .NET Help, n.d.) and we use the Bars.Low.LowestBar() extension method here as the bar index. That method returns how many bars ago the lowest low of the last 10 bars occurred. The second ChartPoint variable, endPoint, is set to the time and high of the current bar (Bars.Time[0] and Bars.High[0]).

Then we call the DrwTrendLine.Create() method with the beginPoint and endPoint variables passed in to draw a trend line between them. This method returns an ITrendLineObject interface reference (see PowerLanguage .NET Help, n.d.) that we assign to the variable series with its Value property. This way the reference variable (needed to access the trend line object on the chart) is stored in the trendLines variable series for the current bar.

Referencing previous values of the trend line variable series

The last part of CalcBar() adjusts the line’s visual appearance. We do so with the current value of the variable series which holds the reference to the line we’ve just made. First, the line’s Size property is set to 2 with the trendLines variable series followed by a zero index between square brackets ([0]). That line reference can also be accessed with the Value property of the variable series, which we subsequently use to set the line’s colour to orange.

A nested if statement then compares the newest trend line with the line reference stored in the variable series 10 bars ago. First we evaluate if that value (trendLines[10]) is unequal to (!=) null. Then we check if the begin price coordinate of the recent line (trendLines[0].Begin.Price) is greater than (>) the begin price of the line reference in the variable series an arbitrary 10 bars ago (trendLines[10].Begin.Price).

By the way, that line might have been drawn earlier than 10 bars ago because a variable series just repeats its most recent value until a new value is assigned to it. When both conditions of our if statement are true, we know that the recently drawn trend line has a higher begin price than the line from at least 10 bars ago, and so we set its colour to green.

That check for inequality to null is necessary because of the following. A VariableSeries<T>’s default value depends on its type, and so for reference variables this will be null (see Sempf, Sphar, & Davis, 2010). That null value indicates that a variable doesn’t point to an object (Albahari & Albahari, 2012).

That default value of null triggers a NullReferenceException when we try to access a trend line variable through a variable series that isn’t there (meaning, is null) (Stellman & Greene, 2010). And so if we won’t check whether a value from our trendLines variable series is different than null, an ‘object reference not set to an instance of an object’-error message is triggered:

MultiCharts .NET variable series exception

So checking whether trendLines[10] is unequal to (!=) null before accessing that variable series’ value is important to prevent that error from being generated.

Other ways of working with multiple MultiCharts .NET trend lines are creating a generic list with trend lines and maintaining a dictionary of trend lines. See retrieving a collection of MultiCharts .NET trend lines for how to work with trend lines that are already on the chart.

Summary

Trend lines are drawn with DrwTrendLine.Create() and that method returns a reference to the line made. Keeping track of values from previous bars is possible with a VariableSeries<T> class, which creates a series of variables associated with the bars of a data series. We store values in a variable series with its Value property. A VariableSeries<ITrendLineObject> series holds trend line references of the current and previous price bars. We can access those trend lines with a non-negative integer placed between square brackets ([ and ]) following the variable series or by using its Value property to access the current bar’s value.

Complete MultiCharts .NET indicator example

using System;
using System.Drawing;
using System.Linq;
using PowerLanguage.Function;

namespace PowerLanguage.Indicator
{
    [SameAsSymbol(true), UpdateOnEveryTick(false)]
    public class Example_TrendLinesVariableSeries : IndicatorObject
    {
        public Example_TrendLinesVariableSeries(object _ctx) : base(_ctx) { }

        private VariableSeries<ITrendLineObject> trendLines;

        protected override void Create()
        {
            trendLines = new VariableSeries<ITrendLineObject>(this);
        }

        protected override void CalcBar()
        {
            if (Bars.High[0] > Bars.High.Highest(10, 1))
            {
                ChartPoint beginPoint = new ChartPoint(
                    Bars.FullSymbolData.Time[Bars.Low.LowestBar(10)],
                    Bars.Low.Lowest(10));

                ChartPoint endPoint = new ChartPoint(
                    Bars.Time[0], Bars.High[0]);

                // Set the variable series' current value
                trendLines.Value = DrwTrendLine.Create(beginPoint, endPoint);

                // Retrieve the current variable series' value to 
                // set the line's appearance
                trendLines[0].Size     = 2;
                trendLines.Value.Color = Color.Orange;

                // Compare the new line's starting point with the line
                // value of 10 bars ago to set the line's colour
                if (trendLines[10] != null && 
                    trendLines[0].Begin.Price > trendLines[10].Begin.Price)
                {
                    trendLines.Value.Color = Color.LimeGreen;
                }
            }
        }
    }
}

References

Albahari, J. & Albahari, B. (2012). C# 5.0 in a Nutshell: The Definitive Reference (5th edition). Sebastopol, CA: O’Reilly Media.

Henry MultiCharts (2013, May 31). VariableObject – why use it? – Forum discussion. Retrieved on May 29, 2015, from http://www.multicharts.com/discussion/viewtopic.php?f=19&p=70279#p70248

MultiCharts (2014). MultiCharts .NET Programming Guide (version 1.1). Retrieved from http://www.multicharts.com/downloads/MultiCharts.NET-ProgrammingGuide-v1.1.pdf

PowerLanguage .NET Help (n.d.). Retrieved on November 18, 2014, from http://www.multicharts.com/downloads/PowerLanguage.NET.chm

Sempf, B., Sphar, C., & Davis, S.R. (2010). C# 2010 All-In-One for Dummies. Hoboken, NJ: John Wiley & Sons.

Stellman, A. & Greene, J. (2010). Head First C#: A Brain-Friendly Guide (2nd edition). Sebastopol, CA: O’Reilly Media.