In MultiCharts .NET we can retrieve the most recently active trend line and then remove it from the chart. But what if there are multiple trend lines, and we don’t want to remove the last one but the first?
Creating trend lines in MultiCharts .NET and removing the first line
To draw trend lines we use DrwTrendLine.Create()
, a method that returns a reference to the line made (MultiCharts, 2014; PowerLanguage .NET Help, n.d.). When put into an ITrendLineObject
variable, that reference allows access to the line’s properties and methods. One of those methods is Delete()
which removes the trend line (MultiCharts, 2014).
But this also means that, without a trend line reference, we cannot remove a line. Granted, the DrwTrendLine.Active
property returns the most recently active trend line (see PowerLanguage .NET Help, n.d.), but that won’t help with multiple trend lines.
Luckily, we can retrieve the chart’s trend lines with DrwTrendLine.GetTrendLineObjects()
(PowerLanguage .NET Help, n.d.). This method returns a collection that implements IEnumerable<T>
, which is a type-safe collection interface that can be enumerated (that is, looped over) (Liberty & MacDonald, 2009). The <T>
signals it’s generic: this T
can be replaced with whichever type the collection should hold (Stellman & Greene, 2010). In our case we’ll use IEnumerable<ITrendLineObject>
: a collection object with trend line reference variables. To see how we can carry that out for removing a line, let’s examine the programming example.
Example: removing the first trend line with each mouse click
The indicator draws five trend lines. When added to an AEX index future chart, it looks like:

Each click on the chart with Control held down removes the oldest trend line. So after one click, the chart becomes:

And each successive mouse with Control removes another line:



Until finally all trend lines are removed:

Programmatically removing the first line in MultiCharts .NET
The MultiCharts .NET indicator’s programming code is the following:
[SameAsSymbol(true), UpdateOnEveryTick(false), MouseEvents(true)] public class Example_RemoveFirstTrendLine : IndicatorObject { public Example_RemoveFirstTrendLine(object _ctx) : base(_ctx) { } protected override void CalcBar() { int barsTillLast = Bars.FullSymbolData.Count - Bars.FullSymbolData.Current; ITrendLineObject trendLine; ChartPoint startPoint = new ChartPoint( Bars.Time[20], Bars.Close[20]); ChartPoint endPoint = new ChartPoint( Bars.Time[0], Bars.Close[0]); // Create several trend lines on historical bars if (barsTillLast == 40) { trendLine = DrwTrendLine.Create(startPoint, endPoint); trendLine.Size = 5; trendLine.Color = Color.GreenYellow; } else if (barsTillLast == 30) { trendLine = DrwTrendLine.Create(startPoint, endPoint); trendLine.Size = 3; trendLine.Style = ETLStyle.ToolDashed; trendLine.Color = Color.ForestGreen; } else if (barsTillLast == 20) { trendLine = DrwTrendLine.Create(startPoint, endPoint); trendLine.Size = 2; trendLine.Color = Color.Magenta; } else if (barsTillLast == 10) { trendLine = DrwTrendLine.Create(startPoint, endPoint); trendLine.Size = 4; trendLine.Color = Color.SaddleBrown; } else if (barsTillLast == 1) { trendLine = DrwTrendLine.Create(startPoint, endPoint); trendLine.Size = 3; trendLine.Color = Color.SteelBlue; } } protected override void OnMouseEvent(MouseClickArgs arg) { // Remove the 1st line with each click + Control if (arg.keys == Keys.Control) { // Get all trend lines made by the current script IEnumerable<ITrendLineObject> allTrendLines = DrwTrendLine.GetTrendLineObjects(EDrawingSource.CurrentTech); // Remove the collection's first trend line if (allTrendLines.Count() > 0) { allTrendLines.ElementAt(0).Delete(); } } } }
We define three MultiCharts .NET class attributes first. SameAsSymbol
set to true displays the indicator on the data series instead of creating a subchart. With UpdateOnEveryTick
set to false the indicator calculates on bar close instead of calculating on every real-time tick. And the third attribute, MouseEvents
, we enable mouse click processing.
Drawing MultiCharts .NET trend lines programmatically
Next in the example is the CalcBar()
method that’s executed on every price bar of the data series (MultiCharts, 2014). In it we create the barsTillLast
integer variable to hold the number of bars till the last. This variable’s value is computed by subtracting Bars.FullSymbolData.Current
(the bar number that the script is currently calculated on; see PowerLanguage .NET Help, n.d.) from the data series’ total number of bars (returned by the Bars.FullSymbolData.Count
property; see MultiCharts, 2014).
Then we declare an ITrendLineObject
variable named trendLine
that’s used when drawing the trend lines. For the line’s begin and end chart coordinates two ChartPoint
struct variables are made. The first, startPoint
, is set to the time and close of 20 bars ago (Bars.Time[20]
and Bars.Close[20]
). The second chart location, endPoint
, is initialised to the current bar’s time and close (Bars.Time[0]
and Bars.Close[0]
).
An if/else statement then evaluates if the amount of bars till the data series’ last bar equals (==
) 40, 30, 20, 10, or 1. When one of these five conditions occurs, we call DrwTrendLine.Create()
to draw a trend line and pass in the startPoint
and endPoint
variables for the line’s begin and end point. The trendLine
variable is assigned the value returned by DrwTrendLine.Create()
. We then use this variable to change the trend line’s appearance by setting different values to its Size
, Color
, and Style
properties.
By the way, we prevent the last trend line from being drawn repeatedly in real-time by drawing it on the bar preceding the last price bar, instead of creating it on the last bar of the chart (when barsTillLast
equals 0).
Removing the first trend line on the chart with a mouse click
The code for removing the chart’s first trend line is 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 set to true.
This method’s if statement evaluates whether the arg.keys
variable (which returns the key pressed during the click) equals (==
) the Keys.Control
value. This Keys
enumeration originates from the System.Windows.Forms
namespace that we added to the top of the indicator’s code with the using
directive (see full code example below).
When Control was pressed during the mouse click, we retrieve the script’s trend lines by calling DrwTrendLine.GetTrendLineObjects()
with the CurrentTech
value (from the EDrawingSource
enumeration) passed in. This causes that method to return a collection with all trend lines created by the script itself (see PowerLanguage .NET Help, n.d.), which we assign to the IEnumerable<ITrendLineObject>
collection named allTrendLines
. To prevent having to qualify the IEnumerable<T>
interface with its namespace, we added System.Collections.Generics
with a using
directive to the top of the indicator’s code.
A nested if statement then checks if the number of elements in the allTrendLines
collection (returned by its Count()
method; see Microsoft Developer Network, n.d.) is greater than (>
) 0. In that case we use ElementAt()
(a method that returns the element at the specified position; Albahari & Albahari, 2012), to access the collection’s first item (which has an index of 0). By calling that item’s Delete()
method we remove the trend line.
DrwTrendLine.GetTrendLineObjects()
is affected by operations performed on the trend lines (MultiCharts Support, personal communication, May 28, 2015). When lines are removed, the first element in the collection returned by DrwTrendLine.GetTrendLineObjects()
might not be the line that’s drawn first. By verifying with Count()
if the trend line collection contains at least one element, we prevent an ArgumentOutOfRangeException
error. That exception is thrown when an argument is outside a given range (Dorman, 2010). In this case, using ElementAt()
to access the first element when allTrendLines
is empty (that happens when all lines are already removed) triggers that exception:

We also discuss removing trend lines in removing a trend line and deleting a trend line object completely. In removing all trend lines we use a collection returned by DrwTrendLine.GetTrendLineObjects()
to remove all trend lines from the chart.
Summary
The DrwTrendLine.Create()
method draws trend lines while DrwTrendLine.GetTrendLineObjects()
returns a collection of trend lines on the chart. This latter method requires an EDrawingSource
value (which specifies the lines to include) and returns an IEnumerable<ITrendLineObject>
collection. Accessing an individual line from that collection is possible with the ElementAt()
method together with a zero-based index number. That way we can access the line’s Delete()
method to remove the line. With the collection’s Count()
method we can check if the collection’s length also includes the element we want to access.
Complete MultiCharts .NET indicator example
using System; using System.Drawing; using System.Linq; using PowerLanguage.Function; using System.Windows.Forms; // Added for the Keys enumeration using System.Collections.Generic; // Added for the IEnumerablecollection namespace PowerLanguage.Indicator { [SameAsSymbol(true), UpdateOnEveryTick(false), MouseEvents(true)] public class Example_RemoveFirstTrendLine : IndicatorObject { public Example_RemoveFirstTrendLine(object _ctx) : base(_ctx) { } protected override void CalcBar() { int barsTillLast = Bars.FullSymbolData.Count - Bars.FullSymbolData.Current; ITrendLineObject trendLine; ChartPoint startPoint = new ChartPoint( Bars.Time[20], Bars.Close[20]); ChartPoint endPoint = new ChartPoint( Bars.Time[0], Bars.Close[0]); // Create several trend lines on historical bars if (barsTillLast == 40) { trendLine = DrwTrendLine.Create(startPoint, endPoint); trendLine.Size = 5; trendLine.Color = Color.GreenYellow; } else if (barsTillLast == 30) { trendLine = DrwTrendLine.Create(startPoint, endPoint); trendLine.Size = 3; trendLine.Style = ETLStyle.ToolDashed; trendLine.Color = Color.ForestGreen; } else if (barsTillLast == 20) { trendLine = DrwTrendLine.Create(startPoint, endPoint); trendLine.Size = 2; trendLine.Color = Color.Magenta; } else if (barsTillLast == 10) { trendLine = DrwTrendLine.Create(startPoint, endPoint); trendLine.Size = 4; trendLine.Color = Color.SaddleBrown; } else if (barsTillLast == 1) { trendLine = DrwTrendLine.Create(startPoint, endPoint); trendLine.Size = 3; trendLine.Color = Color.SteelBlue; } } protected override void OnMouseEvent(MouseClickArgs arg) { // Remove the 1st line with each click + Control if (arg.keys == Keys.Control) { // Get all trend lines made by the current script IEnumerable<ITrendLineObject> allTrendLines = DrwTrendLine.GetTrendLineObjects(EDrawingSource.CurrentTech); // Remove the collection's first trend line if (allTrendLines.Count() > 0) { allTrendLines.ElementAt(0).Delete(); } } } } }
Want to learn more about C#, the programming language that drives MultiCharts .NET? Checkout my C# programming tutorials.
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.
Liberty, J. & MacDonald, B. (2009). Learning C# 3.0: Master the Fundamentals of C# 3.0. Sebastopol, CA: O’Reilly Media.
Microsoft Developer Network (n.d.). Enumerable.Count<TSource> Method (IEnumerable<TSource>). Retrieved on May 21, 2015, from https://msdn.microsoft.com/en-us/library/vstudio/bb338038%28v=vs.100%29.aspx
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.
Visit Kodify for more helpful coding articles.