After creating a trend line it’s accessible through its ITrendLineObject variable in order to do things like relocating, removing, or visually changing a trend line. But how to work with a trend line that we haven’t assigned to a variable?

Creating and selecting a trend line in MultiCharts .NET

The DrwTrendLine.Create() method draws a trend line and returns a reference to the line just created (MultiCharts, 2014; PowerLanguage .NET Help, n.d.). When that returned value is assigned to an ITrendLineObject interface variable, we can access the line’s properties and methods through that variable. But what if we don’t have a line’s reference stored in a variable?

A trend line is also accessible through the DrwTrendLine.Active property that returns the ITrendLineObject reference of the active trend line (see MultiCharts, 2014; PowerLanguage .NET Help, n.d.). A drawing (trend line, arrow, or text box) is considered to be ‘active’ when it was created or moved last, or when selected by a mouse click (MultiCharts, 2014).

When an active trend line couldn’t be found, DrwTrendLine.Active returns null (see PowerLanguage .NET Help, n.d.). This value of null means the reference doesn’t point to anything (Stephens, 2014) — so it’s empty with no connection to a trend line. Situations in which DrwTrendLine.Active returns null are when the active trend line is removed or when no trend lines have been made.

Example: selecting a trend line and relocating it

The example indicator draws a trend line that’s 20 bars long and ends 10 bars before the last bar, like on this EUR/USD chart:

Selecting a MultiCharts .NET trend line - before

Once the bar closes, the line is selected with DrwTrendLine.Active and both its visual appearance and location are changed. That looks as follows:

Selecting a MultiCharts .NET trend line - after

Programmatically selecting the active trend line in MultiCharts .NET

The indicator’s programming code is the following:

[SameAsSymbol(true)]
public class Example_SelectTrendLine : IndicatorObject
{
    public Example_SelectTrendLine(object _ctx) : base(_ctx) { }

    bool isAlreadyMoved;

    protected override void CalcBar()
    {
        // Create the trend line
        if (Bars.FullSymbolData.Current == Bars.FullSymbolData.Count - 10)
        {
            DrwTrendLine.Create(
                new ChartPoint(Bars.Time[30], Bars.Close[10]),
                new ChartPoint(Bars.Time[0], Bars.Close[0])
                );
        }

        // Select and adjust the trend line
        if (Bars.LastBarOnChart && Bars.Status == EBarState.Close && 
            !isAlreadyMoved)
        {
            ITrendLineObject activeTrendLine = DrwTrendLine.Active;

            if (activeTrendLine != null)
            {
                activeTrendLine.Size  = 2;
                activeTrendLine.Color = Color.SlateBlue;

                activeTrendLine.Begin = new ChartPoint(
                    Bars.FullSymbolData.Time[40],
                    Bars.FullSymbolData.Close[40]
                    );

                isAlreadyMoved = true;
            }
        }
    }
}

We first set the SameAsSymbol attribute to true to display the indicator on the data series instead of in a separate subchart. Then a Boolean variable (isAlreadyMoved) is declared, which we’ll use later to prevent the line’s begin point from being changed on every bar close.

Creating a trend line in MultiCharts .NET

Next is the CalcBar() method that consists out of two parts: the first creates the trend line while the second selects and modifies it.

The trend line is drawn 10 bars before the last bar on the chart. To do so, an if statement checks if Bars.FullSymbolData.Current (which returns the current bar number; MultiCharts, 2014) equals (==) 10 minutes the last bar on the chart. That latter value is retrieved with the Bars.FullSymbolData.Count property (MultiCharts, 2014).

When that condition evaluates to true, DrwTrendLine.Create() is called to draw the line. In it, we initialise two ChartPoint structs. The first marks the line’s starting point and is set to the time of 30 bars ago (Bars.Time[30]) with the close of 10 bars ago (Bars.Close[10]). This deliberate 20-bar difference gives a wrongly placed trend line that we’ll fix later on. The line’s end point is set to the current bar’s time and close.

Programmatically selecting a trend line

The next part of CalcBar() is the second if statement, which evaluates three conditions before selecting and adjusting the trend line.

The first condition evaluates if the current bar is the last, in which case Bars.LastBarOnChart returns true (PowerLanguage .NET Help, n.d.). The second checks whether the script is calculated on bar close by comparing the Bars.Status property with the EBarState.Close enumerated value (see MultiCharts, 2014). The last condition inspects, with the logical not operator (!), if the isAlreadyMoved variable is false; that way we only move the trend line once.

When all three evaluate to true, we begin with selecting the active trend line. For this we declare an ITrendLineObject interface variable named activeTrendLine and set it to the value returned by the DrwTrendLine.Active property. However, when an active trend line couldn’t be located, this property returns null (see PowerLanguage .NET Help, n.d.).

That’s why we first check if activeTrendLine is unequal to (!=) null before using it to access the trend line’s properties. Otherwise, the NullReferenceException is triggered (see Stellman & Greene, 2010).

Modifying a selected trend line in MultiCharts .NET

When our trend line variable (activeTrendLine) is different than null, we change the line’s appearance by assigning new values to the Size and Color properties.

To relocate the line’s starting point we assign a new ChartPoint struct to its Begin property, which is a ChartPoint too (see PowerLanguage .NET Help, n.d.). This new starting point is set to 40 bars ago. Because the original begin point had its time set to 30 bars ago, but was drawn 10 bars before the last bar, 40 bars back on the last bar retrieves the correct price data. We fetch data from that historical bar with the Bars.FullSymbolData property, which can access any price bar of the primary data series (see PowerLanguage .NET Help, n.d.) regardless of the MaxBarsBack limitation.

Once we’ve modified and relocated the trend line, the isAlreadyMoved variable is set to true. Since the if statement requires that this variable is false, setting it to true makes sure the line’s location is updated only once.

See retrieving all trend lines from the chart for how to work with a collection of trend line references. Those references can be managed with a generic list or put into a dictionary.

Summary

The DrwTrendLine.Create() method draws trend lines and returns a reference to the line made. When we don’t assign that reference to an ITrendLineObject variable or when the line is drawn manually, we can use the DrwTrendLine.Active property to retrieve a reference to the chart’s active trend line. And with that reference we can access the line’s properties and methods to work with it. DrwTrendLine.Active considers a line active when it’s created or moved last, or when it’s selected with a mouse click. This property can also return null, in which case it didn’t succeed in selecting an active trend line.

Complete MultiCharts .NET indicator example

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

namespace PowerLanguage.Indicator
{
    [SameAsSymbol(true)]
    public class Example_SelectTrendLine : IndicatorObject
    {
        public Example_SelectTrendLine(object _ctx) : base(_ctx) { }

        bool isAlreadyMoved;

        protected override void CalcBar()
        {
            // Create the trend line
            if (Bars.FullSymbolData.Current == Bars.FullSymbolData.Count - 10)
            {
                DrwTrendLine.Create(
                    new ChartPoint(Bars.Time[30], Bars.Close[10]),
                    new ChartPoint(Bars.Time[0], Bars.Close[0])
                    );
            }

            // Select and adjust the trend line
            if (Bars.LastBarOnChart && Bars.Status == EBarState.Close && 
                !isAlreadyMoved)
            {
                ITrendLineObject activeTrendLine = DrwTrendLine.Active;

                if (activeTrendLine != null)
                {
                    activeTrendLine.Size  = 2;
                    activeTrendLine.Color = Color.SlateBlue;

                    activeTrendLine.Begin = new ChartPoint(
                        Bars.FullSymbolData.Time[40],
                        Bars.FullSymbolData.Close[40]
                        );

                    isAlreadyMoved = true;
                }
            }
        }
    }
}

References

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

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

Stephens, R. (2014). C# 5.0 Programmer Reference. Indianapolis, IN: John Wiley & Sons.