After we’ve drawn a trend line in MultiCharts .NET we can remove it programmatically. But how can we remove all trend lines from the chart?

Creating MultiCharts .NET trend lines and removing them all

Trend lines are drawn programmatically with DrwTrendLine.Create(), a method that returns a reference to the line created (MultiCharts, 2014; PowerLanguage .NET Help, n.d.). When that reference is stored in an ITrendLineObject variable, we can access the line’s properties and methods through it. That way we can do things like relocating, extending, or removing a trend line. But tracking each trend line’s variable is inconvenient or simply not possible when trend lines are made by another script or manually. So how do we retrieve and remove all trend lines?

Retrieving all trend lines on the chart is done with the DrwTrendLine.GetTrendLineObjects() method. This method returns a collection of trend lines that implements the IEnumerable<T> interface so that they can be looped over with foreach (see PowerLanguage .NET Help, n.d.).

However, a foreach loop cannot add or remove items from the source collection (Dorman, 2010). One workaround is putting the items returned by DrwTrendLine.GetTrendLineObjects() in a collection type that can work with the for loop, which is a loop type that can change the collection it loops over (Sharp, 2013). A suitable collection type is List<T>, an easy-to-use generic list that can hold any type like int or ITrendLineObject (Stellman & Greene, 2010). Let’s examine the programming example to see how we can implement that for removing all trend lines.

Example: removing all MultiCharts .NET trend lines

When the example indicator is added to an E-mini S&P 500 future chart, nothing is drawn yet. But with a mouse click on the data series while Shift is held down, the script draws several connected trend lines:

Before removing all MultiCharts .NET trend lines

Then clicking with Control removes all lines:

After removing all MultiCharts .NET trend lines

Besides visually inspecting the chart, another way to verify that all trend lines are indeed removed is by right-clicking on the chart. When all drawings (in our case, trend lines) are removed from the chart, the ‘Format Drawings’ menu item is greyed out:

All trend lines removed from the MultiCharts .NET chart

Programmatically removing all MultiCharts .NET trend lines

The example’s programming code is the following:

[SameAsSymbol(true), RecoverDrawings(false), MouseEvents(true)]
public class Example_TrendLinesRemoveAll : IndicatorObject
{
    public Example_TrendLinesRemoveAll(object _ctx) : base(_ctx) { }

    protected override void CalcBar() { }

    protected override void OnMouseEvent(MouseClickArgs arg)
    {
        // Create the trend lines with a click + Shift
        if (arg.keys == Keys.Shift)
        {
            for (int i = 10; i <= 50; i += 10)
            {
                // Create the chart coordinates & draw the line
                ChartPoint begin = new ChartPoint(
                    Bars.FullSymbolData.Time[i], 
                    Bars.FullSymbolData.Close[i]);

                ChartPoint end = new ChartPoint(
                    Bars.FullSymbolData.Time[i - 10], 
                    Bars.FullSymbolData.Close[i - 10]);

                ITrendLineObject line = DrwTrendLine.Create(begin, end);

                // Change the line's appearance
                line.Size  = 2;
                line.Color = Color.BlueViolet;
                line.Style = ((i / 10) % 2 == 0) ? 
                    ETLStyle.ToolDashed : 
                    ETLStyle.ToolSolid;
            }
        }

        // Remove all trend lines with a click + Control
        if (arg.keys == Keys.Control)
        {
            List<ITrendLineObject> allTrendLines = new List<ITrendLineObject>();

            // Add all trend lines to a list..
            foreach (ITrendLineObject line in 
                DrwTrendLine.GetTrendLineObjects(EDrawingSource.AnyTechOrManual))
            {
                allTrendLines.Add(line);
            }

            // .. then remove everything from the list
            for (int i = 0; i < allTrendLines.Count; i++)
            {
                allTrendLines[i].Delete();
            }
        }
    }
}

We first define three MultiCharts .NET class attributes. With SameAsSymbol set to true the indicator is displayed on the data series and not in its own subchart. Setting RecoverDrawings to false prevents removal of intra-bar generated drawings (MultiCharts, 2014). And MouseEvents set to true enables mouse click processing.

Creating several trend lines on the MultiCharts .NET chart

The remaining code of the example is located in OnMouseEvent(), a method that’s executed with each mouse click on the chart (see PowerLanguage .NET Help, n.d.), provided that the MouseEvents attribute is enabled.

The OnMouseEvents() method begins with an if statement to see whether the keyboard key pressed during the click (accessible with the arg.keys variable) equals (==) the Shift key (Keys.Shift). This latter value originates from the System.Windows.Forms namespace, which we added with a using directive in the top of the file (see full code example below).

When that if statement’s condition evaluates to true, a for loop starts at 10 and continues as long as the i loop variable is less than or equal to (<=) 50. After each of the five loop cycles, i is incremented with 10 by the addition compound assignment operator (+=). That operator is just a shorthand way to write i = i + 10.

Inside the loop we create a ChartPoint struct variable named begin that has its coordinates set to the time (Bars.FullSymbolData.Time[i]) and close (Bars.FullSymbolData.Close[i]) of i bars ago. We also create a ChartPoint coordinate called end that’s set to the time and close of i - 10 bars ago. That makes the trend lines 10 bars long and drawn consecutively. By using the Bars.FullSymbolData property we can access any bar of the data series (see PowerLanguage .NET Help, n.d.) without needing to consider our indicator’s MaxBarsBack value.

Once both ChartPoint chart coordinates are defined, we call DrwTrendLine.Create() to draw a trend line between the begin and end variables. We assign the value returned by this method to an ITrendLineObject variable named line, which we then use to change the line’s visual appearance by assigning new values to the Size, Color, and Style properties.

We set the Style property’s ETLStyle value with the conditional operator (?:). This operator evaluates a conditional expression and returns the first value when the condition is true or the second when it’s false (Liberty & MacDonald, 2009). The condition evaluated here uses the modulus operator (%) to see if the i loop variable, after dividing by 10, is evenly divisible by 2. In that case the Style property is set to a dashed line (ETLStyle.ToolDashed); otherwise, it’s set to a solid line (ETLStyle.ToolSolid).

Removing all MultiCharts .NET trend lines on the chart

The other if statement in OnMouseEvent() verifies if the keyboard key pressed during the click is the Control key (Keys.Control). When it is, we declare and initialise a generic list of trend line objects (List<ITrendLineObject>) and name it allTrendLines. This collection type is located in the System.Collections.Generic namespace, which we added to the top of th indicator’s source code with the using keyword (see full code example below).

Then a foreach loop iterates over the collection returned that’s by DrwTrendLine.GetTrendLineObjects(). This loop has its type set to an ITrendLineObject element named line, and so we use that line variable inside the loop to access the collection’s current element. The collection that this foreach loop goes through is given by the DrwTrendLine.GetTrendLineObjects() method with the EDrawingSource.AnyTechOrManual value passed in. That latter enumerated value makes this method return all programmatic and manual drawn trend lines from the chart (see PowerLanguage .NET Help, n.d.). See working with a collection of trend lines for more on EDrawingSource.

Inside the foreach loop we use the Add() method from the allTrendLines list to add the collection’s current item to that list. By doing so each of the collection’s trend lines is added to the allTrendLines list once the foreach loop ends.

With all trend lines collected in the list, it’s time to remove them. We do that with a for loop that begins at 0 and continues as long as the i loop variable is less than (<) the list length (which is returned by the non-zero based allTrendLines.Count property). After each loop cycle, the i variable is increased with one by the postfix increment operator (++). In this context, that operator is just a shorthand way to write i = i + 1 (Dorman, 2010).

Inside that for loop, we access the individual elements from the list with the i variable (so allTrendLines[i] to access the current element inside the loop) and then remove the trend line by calling its Delete() method (see MultiCharts, 2014). And so when the for loop ends, all trend lines are removed from the chart.

More examples of removing trend lines are removing a trend line, scheduling a trend line object for deletion, and removing the first line from the chart. To learn more about working with a trend line collection, see retrieving a collection of MultiCharts .NET trend lines and managing trend lines with a custom generic list.

Summary

The DrwTrendLine.Create() method draws trend lines. All trend lines on the chart, whether programmatically or manually drawn, can be retrieved with DrwTrendLine.GetTrendLineObjects(). That method returns a collection that we can loop over with foreach, but that loop type cannot remove elements from the collection it goes through. And so to remove lines from the IEnumerable<ITrendLineObject> collection object returned by DrwTrendLine.GetTrendLineObjects(), we need to convert that collection to another type like List<T>.

Full MultiCharts .NET indicator example

using System;
using System.Drawing;
using System.Linq;
using PowerLanguage.Function;
using System.Windows.Forms;         // Added for Keys enumeration
using System.Collections.Generic;   // Added for List

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

        protected override void CalcBar() { }

        protected override void OnMouseEvent(MouseClickArgs arg)
        {
            // Create the trend lines with a click + Shift
            if (arg.keys == Keys.Shift)
            {
                for (int i = 10; i <= 50; i += 10)
                {
                    // Create the chart coordinates & draw the line
                    ChartPoint begin = new ChartPoint(
                        Bars.FullSymbolData.Time[i], 
                        Bars.FullSymbolData.Close[i]);

                    ChartPoint end = new ChartPoint(
                        Bars.FullSymbolData.Time[i - 10], 
                        Bars.FullSymbolData.Close[i - 10]);

                    ITrendLineObject line = DrwTrendLine.Create(begin, end);

                    // Change the line's appearance
                    line.Size  = 2;
                    line.Color = Color.BlueViolet;
                    line.Style = ((i / 10) % 2 == 0) ? 
                        ETLStyle.ToolDashed : 
                        ETLStyle.ToolSolid;
                }
            }

            // Remove all trend lines with a click + Control
            if (arg.keys == Keys.Control)
            {
                List<ITrendLineObject> allTrendLines = new List<ITrendLineObject>();

                // Add all trend lines to a list..
                foreach (ITrendLineObject line in 
                    DrwTrendLine.GetTrendLineObjects(EDrawingSource.AnyTechOrManual))
                {
                    allTrendLines.Add(line);
                }

                // .. then remove everything from the list
                for (int i = 0; i < allTrendLines.Count; i++)
                {
                    allTrendLines[i].Delete();
                }
            }
        }
    }
}

References

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

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

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.