This article summarises the most important points of the preceding MultiCharts .NET trend lines articles. Follow the links for in-depth explanations and more examples.

Introduction to trend lines in PowerLanguage .NET

There are a few steps for drawing MultiCharts .NET trend lines programmatically (see MultiCharts, 2014; PowerLanguage .NET Help, n.d.):

  • First the line’s begin and end points need to made. We use ChartPoint structs for that.
  • Then we draw the line with the DrwTrendLine.Create() method. There are several versions of this method, but all require at least two ChartPoint struct values that define the line’s starting and ending point.
  • Optionally, the value returned by DrwTrendLine.Create() can be assigned to an ITrendLineObject interface variable. That variable then allows access to the line’s properties and methods to work with the line or modify it.

Those trend line properties and methods are the following:

Member Description
Alert Retrieves or sets the trend line’s alert status. Possible values are EAlertType.Disabled (for disabling alerts), EAlertType.BreakoutIntraBar (for triggering alerts multiple times intra-bar), and EAlertType.BreakoutOnClose to generate alerts on bar close.
Begin This property returns or sets the trend line’s begin coordinates with a ChartPoint struct.
Color A trend line’s colour is retrieved or set with this property.
Delete() This method removes the trend line from the chart.
End With this property we get or set the trend line’s coordinates with a ChartPoint struct.
Exist A read-only property that returns a Boolean value that indicates if the trend line is located on the chart (when true). It returns false when the line has been removed, for example with Delete().
ExtLeft Returns a Boolean value that indicates if the trend line is extended to the left (true) or not (false). We can also enable or disable extension to the left with this property.
ExtRight Sets a line’s extend-to-the-right feature to enabled (true) or disabled (false). This property can also return a Boolean value with the current setting.
ID This property returns an integer with the drawing ID. When a trend line is deleted, its ID is made available for reuse (Henry MultiCharts, 2015). That means trend line IDs aren’t always numbered consecutive and the last line drawn may not have the highest ID number.
Locked This property locks a trend line so it can’t be moved accidentally (when set to true) or unlocks a line again (false).
PriceValue() This method returns the line’s price value for any DateTime value on the chart.
Size Gets or sets the trend line’s size with an integer. This property’s values range from 0 (the default, thinnest line) to 6 (thickest line).
Style This property gets or sets the style of the trend line with a value from the ETLStyle enumeration. Options are a solid (ETLStyle.ToolSolid), dashed (ETLStyle.ToolDashed, ETLStyle.ToolDashed2, and ETLStyle.ToolDashed3), or dotted (ETLStyle.ToolDotted) trend line.

The following is an example of creating a trend line and modifying it with the line’s properties:

// Define the line's start and end point
ChartPoint lineBegin = new ChartPoint(
    Bars.Time[10], Bars.Close[10]);

ChartPoint lineEnd = new ChartPoint(
    Bars.Time[0], Bars.Close[0]);

// Draw the line
ITrendLineObject theLine = 
    DrwTrendLine.Create(lineBegin, lineEnd);

// Adjust the line
theLine.Color = Color.LimeGreen;
theLine.Size  = 2;

When we draw a trend line with DrwTrendLine.Create(), both of its ChartPoint struct values need to use DateTime values or bar numbers for the time coordinate – but not a combination of these (MultiCharts Support, personal communication, March 25, 2015).

The different ways of drawing lines in MultiCharts .NET

The overloaded DrwTrendLine.Create() method can be used in three ways (PowerLanguage .NET Help, n.d.). First, it draws a trend line on price data when we provide it with two ChartPoint struct values for the line’s begin and end point:

ChartPoint beginPoint = new ChartPoint(
    Bars.Time[25], Bars.Low[25]);

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

DrwTrendLine.Create(beginPoint, endPoint);

With the same DrwTrendLine.Create() version we can also draw a trend line into the future. For that one or both ChartPoint structs need to be set to a future price bar:

ChartPoint lineStartPast = new ChartPoint(
    Bars.Time[10],
    Bars.Low.Lowest(10));

ChartPoint lineEndFuture = new ChartPoint(
    Bars.Time[0].AddMinutes(200),
    Bars.Low.Lowest(10));

ITrendLineObject futureLine = 
    DrwTrendLine.Create(lineStartPast, lineEndFuture);

The second version of DrwTrendLine.Create() draws trend lines on different data series. That requires an integer as third argument, like this:

// Draw the trend line first on the non-primary data series
ITrendLineObject lineOnData2 = DrwTrendLine.Create(
    new ChartPoint(BarsOfData(2).Time[12], BarsOfData(2).Close[12]),
    new ChartPoint(BarsOfData(2).Time[2], BarsOfData(2).Close[2]),
    2);

// Then draw the line on the first data series
ITrendLineObject lineOnData1 = DrwTrendLine.Create(
    new ChartPoint(BarsOfData(1).Time[10], BarsOfData(1).Close[10]),
    new ChartPoint(BarsOfData(1).Time[0], BarsOfData(1).Close[0]),
    1);

This feature also allows copying a trend line to another data series. Note, however, that the order in which trend lines are drawn on the data series matters: trend lines need to be drawn on non-primary data series before creating a line on the first data series (MultiCharts Support, personal communication, March 16, 2015).

The last version of the DrwTrendLine.Create() method has a Boolean value as third argument. With that we can draw a trend line in an indicator’s subchart (when true) or on the data series that we apply the script to (false). For instance:

// Draw the line on the subchart
ChartPoint trendLineBegin = new ChartPoint(
    Bars.Time[11], Bars.Close[1]);

ChartPoint trendLineEnd = new ChartPoint(
    Bars.Time[2], Bars.Close[1]);

ITrendLineObject lineOnSubchart =
    DrwTrendLine.Create(trendLineBegin, trendLineEnd, true);

// Draw the line on the price chart
ITrendLineObject lineOnPriceChart =
    DrwTrendLine.Create(trendLineBegin, trendLineEnd, false);

That overloaded version allows for drawing price data trend lines in a subchart and drawing subchart trend lines with indicator values.

More elaborative examples of trend lines are:

Programmatically accessing the chart’s active trend line

Before we can modify a trend line or retrieve its data, we need to programmatically access the line. One way to do that is by selecting the chart’s active trend line with the DrwTrendLine.Active property (PowerLanguage .NET Help, n.d.). For example:

ITrendLineObject activeLine = DrwTrendLine.Active;

// When the active line could be retrieved..
if (activeLine != null)
{
    // ..work with the line
    activeLine.Color = Color.Lavender;
}

MultiCharts .NET considers a trend line ‘active’ when it was created or moved last, or when it’s selected by a mouse click (MultiCharts, 2014). When DrwTrendLine.Active can’t find the chart’s active trend line, it returns null (see PowerLanguage .NET Help, n.d.).

That value of null means the trend line’s variable doesn’t point to a trend line object on the chart (see Stephens, 2014). Should we try to access the line’s properties and methods through such an ‘empty’ variable, a NullReferenceException is thrown (see Stellman & Greene, 2010). That’s why we checked in the above example if activeLine was unequal to (!=) null before using the line’s Color property.

Changing a trend line’s appearance in MultiCharts .NET

With programmatic access to a trend line, we can change the line’s appearance with the following properties (MultiCharts, 2014; PowerLanguage .NET Help, n.d.):

  • The Color property changes the line’s colour.
  • The Size property is used for changing the line’s size, and ranges from 0 (thinnest line) to 6 (thickest line).
  • Changing the line’s style is done by assigning an ETLStyle enumerated value to the line’s Style property. Possible values for this property are:
Formatting a trend line's style in MultiCharts .NET

An example of changing a line’s appearance is:

ITrendLineObject line = DrwTrendLine.Create(
    new ChartPoint(Bars.Time[10], Bars.High[10]),
    new ChartPoint(Bars.Time[5], Bars.Low[5]));

// Change the line's appearance
line.Size  = 2;
line.Style = ETLStyle.ToolDashed;
line.Color = Color.LawnGreen;

Modifying the location of an existing trend line

Another way we can work with a trend line is by changing its location programmatically. For instance:

ITrendLineObject trendLine = DrwTrendLine.Create(
    new ChartPoint(Bars.Time[5], Bars.Range(5)),
    new ChartPoint(Bars.Time[0], Bars.Range(0)));

// Update the line's location
trendLine.End = new ChartPoint(
    Bars.Time[1], Bars.Low[1]);

trendLine.Begin = new ChartPoint(
    Bars.Time[10], Bars.High[10]);

Note that, when we modify a line’s location, the End coordinate needs to be changed before the Begin coordinate is adjusted (Henry MultiCharts, 2014).

Locking and unlocking MultiCharts .NET trend lines

With the line’s Locked property we can lock or unlock a trend line on the chart (PowerLanguage .NET Help, n.d.). When a trend line is locked, an accidental mouse click cannot move the line. An example of this property is:

ChartPoint lockedBegin = new ChartPoint(
    Bars.Time[9], Bars.Close[9]);

ChartPoint lockedEnd = new ChartPoint(
    Bars.Time[3], Bars.Close[3]);

ITrendLineObject lockedLine =
    DrwTrendLine.Create(lockedBegin, lockedEnd);

// Lock the line
lockedLine.Locked = true;

// Allow the line to be moved again
lockedLine.Locked = false;

Continuing a trend line endlessly in one or both directions

With the line’s ExtLeft and ExtRight properties we extend a trend line in one or both directions. That’s done like this:

ITrendLineObject extendedLine = DrwTrendLine.Create(
    new ChartPoint(Bars.Time[10], Bars.Open[10]),
    new ChartPoint(Bars.Time[0], Bars.Open[0]));

// Extend in both directions
extendedLine.ExtLeft  = true;
extendedLine.ExtRight = true;

// Only extend to the right
extendedLine.ExtRight = true;
extendedLine.ExtLeft  = false;

Instead of extending a trend line indefinitely, we can also extend the trend line with just a few bars. Furthermore, with the ExtLeft and ExtRight properties we can also create horizontal and vertical lines that continue over the whole chart (and can even make a vertical line that extends to the indicator’s subchart).

We draw a horizontal trend line by setting the line’s ChartPoint struct values to the same price but different DateTime values. Likewise, creating a vertical trend line requires chart coordinates with identical DateTime values but different prices. An example of both is:

// Create a horizontal trend line
ITrendLineObject horizontalLine = DrwTrendLine.Create(
    new ChartPoint(Bars.Time[1], Bars.Close[0]),
    new ChartPoint(Bars.Time[0], Bars.Close[0]));

horizontalLine.ExtLeft  = true;
horizontalLine.ExtRight = true;

// Make a vertical line
ITrendLineObject verticalLine = DrwTrendLine.Create(
    new ChartPoint(Bars.Time[0], Bars.High[0]),
    new ChartPoint(Bars.Time[0], Bars.Low[0]));

verticalLine.ExtLeft  = true;
verticalLine.ExtRight = true;

Removing trend lines in MultiCharts .NET

After we’ve created a trend line (either by hand or programmatically), we can remove the trend line with its Delete() method (MultiCharts, 2014). And with the line’s Exist property we can verify whether the line is on the chart (PowerLanguage .NET Help, n.d.). For instance:

ChartPoint removedLineBegin = new ChartPoint(
    Bars.Time[7], Bars.Close[7]);

ChartPoint removedLineEnd = new ChartPoint(
    Bars.Time[1], Bars.Close[1]);

ITrendLineObject lineToRemove =
    DrwTrendLine.Create(removedLineBegin, removedLineEnd);

// Remove line from the chart
lineToRemove.Delete();

// Check if line is removed
if (!lineToRemove.Exist)
{
    Output.WriteLine("Trend line is removed");
}

To also remove the trend line object, all reference variables that point to this trend line object need to be set to null or to another object (Albahari & Albahari, 2012). For example:

// Create the trend line
ITrendLineObject lineToDelete = DrwTrendLine.Create(
    new ChartPoint(Bars.Time[0], Bars.High[0]),
    new ChartPoint(Bars.Time[0], Bars.Low[0]));

// Remove it from the chart
lineToDelete.Delete();

// Schedule the trend line object for removal
lineToDelete = null;

Working with a trend line’s price values programmatically

A line’s PriceValue() method allows us to retrieve the line’s price value for any DateTime value on the chart (see PowerLanguage .NET Help, n.d.). That allows for retrieving historical prices from a trend line and fetching a line’s future price values, like this:

ITrendLineObject priceValueLine = DrwTrendLine.Create(
    new ChartPoint(Bars.Time[10], Bars.Close[10]),
    new ChartPoint(Bars.Time[0], Bars.Close[0]));

// Print the line's price values
for (int i = 0; i < 10; i++)
{
    DateTime barDateTime = Bars.FullSymbolData.Time[i];
    DateTime futureBar   = Bars.Time[0].AddMinutes(i * 10);

    Output.WriteLine(
        "Time: {0}, historical price: {1}, future price: {2}",
        barDateTime,
        priceValueLine.PriceValue(barDateTime),
        priceValueLine.PriceValue(futureBar));
}

We used this method to colour price bars above and below the line, calculate how long before a line reaches a price target, and with submitting market orders based off a trend line.

Working with trend lines and alerts in MultiCharts .NET

With a trend line’s Alert property we can generate trend line alerts, which are triggered when the price crosses the trend line intra-bar (EAlertType.BreakoutIntrabar) or on bar close (EAlertType.BreakoutOnClose) (PowerLanguage .NET Help, n.d.). That same property can also turn off a trend line’s alert with EAlertType.Disabled. For instance:

ITrendLineObject alertLine = DrwTrendLine.Create(
    new ChartPoint(Bars.Time[10], Bars.Low[10]),
    new ChartPoint(Bars.Time[0], Bars.High[0]));

// Enable alerts - generated on bar close
alertLine.Alert = EAlertType.BreakoutOnClose;

// Disable alerts
alertLine.Alert = EAlertType.Disabled;

// Trigger alerts intra-bar
alertLine.Alert = EAlertType.BreakoutIntrabar;

What we cannot do with Alert, however, is create custom alert messages or limit the number of intra-bar alerts. Luckily, we can do both with the Alerts.Alert() method (MultiCharts, 2014). We examined that in generating custom alert messages on bar close and in triggering intra-bar alerts with trend lines.

Furthermore, with the help of the DrwTrendLine.Active property we can also trigger alerts with a manually drawn trend line. Another way a trend line can notify us is by alternating its colours.

Working with a collection of MultiCharts .NET trend lines

The DrwTrendLine.GetTrendLineObjects() method returns a collection of trend lines from the chart. The EDrawingSource enumerated value that’s passed into this method determines which lines are included in the returned collection (PowerLanguage .NET Help, n.d.):

  • With EDrawingSource.CurrentTech a collection of trend lines created by the current script is returned.
  • EDrawingSource.NotCurrentTechOrManual fetches a collection of lines that were not created by the current script or manually.
  • EDrawingSource.AnyTechOrManual causes the method to return a collection of trend lines made by any script or by hand.
  • With EDrawingSource.CurrentTechOrManual the returned collection consists out of lines that were created by the current script or manually.
  • EDrawingSource.NotCurrentTech returns all trend lines that were not created by the current script.
  • EDrawingSource.AnyTech returns a collection of trend lines created by any script.
  • And EDrawingSource.Manual returns all trend lines that were drawn manually. With this value we can retrieve all manual trend lines from the chart.

And so with DrwTrendLine.GetTrendLineObjects() we can retrieve and work with trend lines programmatically. An example of that is looping over a collection of trend lines, like this:

foreach (ITrendLineObject singleTrendLine in 
    DrwTrendLine.GetTrendLineObjects(EDrawingSource.AnyTechOrManual))
{
    Output.WriteLine("Line's begin price: {0} and end price: {1}",
        singleTrendLine.Begin.Price,
        singleTrendLine.End.Price);
}

Other examples of DrwTrendLine.GetTrendLineObjects() are selecting lines with a specific ID and changing particular trend lines based on their features. With DrwTrendLine.GetTrendLineObjects() we can also remove all trend lines from the chart and remove the first line with each mouse click.

Working with a custom trend line collection

We can also create our own collection of trend lines. One way to do so is by tracking trend lines with a variable series. A VariableSeries<T> class creates a series of variables that, just like the chart’s data series, provide access to values held on the close of previous bars (Henry MultiCharts, 2013; MultiCharts, 2014). As the <T> indicates, these variable series are both generic and type-safe: they can use any type, but once declared, a variable series can only hold values of that type (see Sempf, Sphar, & Davis, 2010).

An advantage of a variable series is that we can access lines that were drawn on previous bars, like the line from 7 bars ago in this example:

private VariableSeries<ITrendLineObject> trendLines;

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

protected override void CalcBar()
{
    ChartPoint beginPoint = new ChartPoint(
        Bars.Time[10], Bars.High[10]);

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

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

    // Change the line associated with the bar 7 bars ago
    trendLines[7].Color = Color.LightBlue;
}

We can also create our own trend line collection by putting trend lines in a generic list. The List<T> collection class is easy to use because it takes care of its own bookkeeping (that is, it resizes itself automatically) and adding elements to it simply requires calling the collection’s Add() method (Sharp, 2013). For example:

// using System.Collections.Generic;
private List<ITrendLineObject> trendLinesList;

protected override void StartCalc()
{
    trendLinesList = new List<ITrendLineObject>();
}

protected override void CalcBar()
{
    if (Bars.FullSymbolData.Current == (Bars.FullSymbolData.Count - 1))
    {
        for (int i = 0; i < 10; i++)
        {
            // Create the line's coordinates
            ChartPoint beginPoint = new ChartPoint(
                Bars.FullSymbolData.Time[i + 10],
                Bars.FullSymbolData.Close[i + 10]);

            ChartPoint endPoint = new ChartPoint(
                Bars.FullSymbolData.Time[i],
                Bars.FullSymbolData.Close[i]);

            // Add a trend line to the collection
            trendLinesList.Add(DrwTrendLine.Create(beginPoint, endPoint));
        }
    }
}

Other examples that use a List<T> are looping over MultiCharts .NET trend lines, removing all trend lines from the chart, and removing all manual trend lines.

Another C# collection is a Dictionary<TKey, TValue> class that associates a key with a value, and uses this key to retrieve the value associated with that key (just like a dictionary looks up the definition of a word) (Dorman, 2010; Liberty & MacDonald, 2009). A benefit of tracking trend lines with a dictionary is that we can store multiple groups of trend lines in one collection. For example:

// using System.Collections.Generic;
private Dictionary<int, ITrendLineObject> trendLines;

protected override void StartCalc()
{
    trendLines = new Dictionary<int, ITrendLineObject>();
}

protected override void CalcBar()
{
    if (Bars.FullSymbolData.Current == (Bars.FullSymbolData.Count - 1))
    {
        // Draw the trend lines
        for (int i = 0; i < 15; i++)
        {
            // Loop through each of the data series
            for (int j = 3; j > 0; j--)
            {
                ChartPoint beginPoint = new ChartPoint(
                    BarsOfData(j).FullSymbolData.Time[50 + (i * 3)],
                    BarsOfData(j).FullSymbolData.Close[50 + (i * 3)]);

                ChartPoint endPoint = new ChartPoint(
                    BarsOfData(j).FullSymbolData.Time[(i * 2)],
                    BarsOfData(j).FullSymbolData.Close[(i * 2)]);

                trendLines.Add((100 * j) + i,
                    DrwTrendLine.Create(beginPoint, endPoint, j));
            }
        }
    }
}

Summary

This concludes the chapter on working with trend lines in MultiCharts .NET. See all MultiCharts .NET programming articles to explore other topics.


References

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

Dorman, S. (2010). Sams Teach Yourself Visual C# 2010 in 24 Hours. Indianapolis, IN: Sams/Pearson Education.

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

Henry MultiCharts (2014, September 15). Simple drawing – forum discussion. Retrieved on July 5, 2015, from http://www.multicharts.com/discussion/viewtopic.php?f=19&t=47177#p108243

Liberty, J. & MacDonald, B. (2009). Learning C# 3.0: Master the Fundamentals of C# 3.0. Sebastopol, CA: O’Reilly Media.

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.

Sharp, J. (2013). Microsoft Visual C# 2013 Step by Step. Microsoft Press.

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.