In MultiCharts .NET we can draw trend lines with mouse clicks. But how can we use mouse clicks to draw lines on an indicator’s subchart?

Creating lines with mouse clicks in an indicator’s subchart

The DrwTrendLine.Create() method draws a trend line and returns a reference to the line made (MultiCharts, 2014; PowerLanguage .NET Help, n.d.). That ITrendLineObject reference, when assigned to a variable, provides access to the trend line’s methods and properties. With that variable we can change a line’s location, its visual appearance, or remove the line.

There are several versions of DrwTrendLine.Create() available. One version can draw trend lines in an indicator’s subchart when the method is called with two ChartPoint struct values (for the line’s begin and end point) and a Boolean true value (see PowerLanguage .NET Help, n.d.).

Those ChartPoint chart coordinates are often determined programmatically, as we for example did with recent highs and lows. But we can also draw trend lines between manual mouse clicks. In order to so do, we need to set the MouseEvents attribute to true (to enable mouse clicks) and implement the OnMouseEvent() method (for processing the clicks on the chart; see PowerLanguage .NET Help, n.d.).

By the way, mouse clicks in an indicator’s subchart aren’t registered in MultiCharts .NET (see Henry MultiCharts, 2013a). And so using mouse clicks to draw trend lines in an indicator’s subchart requires that those clicks occurred on one of the chart’s data series.

Drawing trend lines on an indicator’s subchart

When the example indicator is added to CME’s EUR/USD (6E) future, nothing yet happens:

Drawing lines in a subchart with mouse clicks - before

Clicking a few times on the data series with Control held down draws lines like the following:

Drawing lines in a subchart with mouse clicks - after

Programmatically drawing indicator trend lines with mouse clicks

We achieve the above effect with the following code:

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

    private IPlotObject momentumPlot, zeroLine;
    private VariableSeries<Double> momentumData;
    private ChartPoint startPoint, endPoint;

    protected override void Create()
    {
        momentumPlot = AddPlot(new PlotAttributes(
            "Momentum", EPlotShapes.Line, Color.Black));

        zeroLine = AddPlot(new PlotAttributes(
            "ZeroLine", EPlotShapes.Line, Color.Gray));

        momentumData = new VariableSeries<Double>(this);
    }

    protected override void CalcBar()
    {
        momentumData.Value = Bars.Close.Momentum(12);

        momentumPlot.Set(momentumData[0]);
        zeroLine.Set(0);
    }

    protected override void OnMouseEvent(MouseClickArgs click)
    {
        if (click.keys == Keys.Control)
        {
            int barsAgo = Bars.FullSymbolData.Count - 
                click.bar_number;

            // A first click with Control sets the begin point
            if (startPoint.Price == 0)
            {
                startPoint = new ChartPoint(
                    Bars.FullSymbolData.Time[barsAgo],
                    momentumData[barsAgo]);
            }
            else
            {
                // Determine the end coordinate and draw the line
                endPoint = new ChartPoint(
                    Bars.FullSymbolData.Time[barsAgo],
                    momentumData[barsAgo]);

                ITrendLineObject momentumLine = 
                    DrwTrendLine.Create(startPoint, endPoint, true);

                momentumLine.Size  = 2;
                momentumLine.Color = Color.Orange;

                startPoint.Price = 0;
            }
        }
    }
}

Here we first define two attributes. MouseEvents set to true enables mouse click processing. And RecoverDrawings set to false prevents intra-bar generated drawings from being removed (MultiCharts, 2014).

Then we declare two IPlotObject variables (momentumPlot and zeroLine) that are used for displaying the momentum values in the subchart. A VariableSeries<Double> named momentumData is also declared, which allows for accessing historical values for previous bars (see Henry MultiCharts, 2013b). That allows us to retrieve historical momentumData values for the trend line’s coordinates. Two ChartPoint struct variables (startPoint and endPoint) are also declared. These will hold the line’s begin and end coordinates.

Creating the indicator plots and setting their values

The two plots are created in the Create() method with AddPlot(): momentumPlot is named “Momentum” and set to a black line, while zeroLine is described as “ZeroLine” and set to grey. An instance of VariableSeries<Double> is also made here.

In the CalcBar() method the double variable series’ value (momentumData.Value) is set to momentum over the last 12 bars, returned by the Momentum() extension method. Then we specify the value of the plot lines with their Set() method: momentumPlot is set to momentumData[0] (the current value of the double variable series) and zeroLine is given a value of zero.

Processing mouse clicks in a MultiCharts .NET indicator

Next is the OnMouseEvent() method in which we use the MouseClickArgs struct variable (named click here) to access the click’s data (see PowerLanguage .NET Help, n.d.).

This method starts with an if statement that evaluates whether the pressed keyboard key during the click (click.keys) equals (==) the Control key (Keys.Control). This Keys enumeration originates from the System.Windows.Forms namespace, which is added to the top of the file with the using keyword (see full code example below).

When such a click with Control happens, the if statement’s code is executed. That starts with declaring and initialising the barsAgo integer variable, which holds the difference between the number of bars on the chart (returned by Bars.FullSymbolData.Count) and the clicked-on bar number (click.bar_number). By knowing how many bars ago the click happened we can determine the line’s coordinates.

Drawing trend lines based on mouse clicks

An if/else statement then inspects whether the line’s starting point doesn’t have a price value yet, in which case the startPoint.Price property equals zero. That means this startPoint variable hasn’t been assigned an actual chart location yet, and so we create a new ChartPoint struct value first.

That chart location has its time coordinate set to Bars.FullSymbolData.Time and its price coordinate to momentumData, both specified with the number of bars ago the click happened (barsAgo). The benefit of using the Bars.FullSymbolData property is that we can access any bar of the data series with it (see PowerLanguage .NET Help, n.d.), regardless of where we click or what the script’s MaxBarsBack setting is.

The if/else statement’s else part is executed when startPoint.Price has a nonzero value. We then set the line’s ending point (endPoint) to the same data as the startPoint variable previously. After that we declare an ITrendLineObject variable (momentumLine) and assign it the value returned by the DrwTrendLine.Create() method. In that method we pass the startPoint and endPoint chart coordinates (which at that point hold the mouse click locations) together with a true value to draw the trend line on the indicator’s subchart.

The trend line’s visual appearance is then changed by setting its Size and Color properties to new values. To make sure that the following trend lines have the correct begin point, we reset the startPoint.Price property to 0. That way, when a next click occurs, the if statement is triggered that generates a new startPoint chart coordinate.

Other MultiCharts .NET examples of trend lines and mouse clicks include mouse clicks to lock/unlock a trend line and drawing trend lines with mouse clicks.

Summary

The DrwTrendLine.Create() method draws trend lines. One version of this overloaded method requires two ChartPoint struct values (that is, chart coordinates) and a Boolean value. That latter indicates if the trend line needs to be drawn on the indicator’s subchart (when true) or on the script’s data series (false). In the OnMouseEvent() method a click’s MouseClickArgs variable holds information about the mouse click. With that data we can determine chart coordinates in a subchart, and then draw trend lines between them.

Complete MultiCharts .NET indicator example

using System;
using System.Drawing;
using System.Linq;
using PowerLanguage.Function;
using System.Windows.Forms;         // For the Keys enumeration

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

        private IPlotObject momentumPlot, zeroLine;
        private VariableSeries<Double> momentumData;
        private ChartPoint startPoint, endPoint;

        protected override void Create()
        {
            momentumPlot = AddPlot(new PlotAttributes(
                "Momentum", EPlotShapes.Line, Color.Black));

            zeroLine = AddPlot(new PlotAttributes(
                "ZeroLine", EPlotShapes.Line, Color.Gray));

            momentumData = new VariableSeries<Double>(this);
        }

        protected override void CalcBar()
        {
            momentumData.Value = Bars.Close.Momentum(12);

            momentumPlot.Set(momentumData[0]);
            zeroLine.Set(0);
        }

        protected override void OnMouseEvent(MouseClickArgs click)
        {
            if (click.keys == Keys.Control)
            {
                int barsAgo = Bars.FullSymbolData.Count - 
                    click.bar_number;

                // A first click with Control sets the begin point
                if (startPoint.Price == 0)
                {
                    startPoint = new ChartPoint(
                        Bars.FullSymbolData.Time[barsAgo],
                        momentumData[barsAgo]);
                }
                else
                {
                    // Determine the end coordinate and draw the line
                    endPoint = new ChartPoint(
                        Bars.FullSymbolData.Time[barsAgo],
                        momentumData[barsAgo]);

                    ITrendLineObject momentumLine = 
                        DrwTrendLine.Create(startPoint, endPoint, true);

                    momentumLine.Size  = 2;
                    momentumLine.Color = Color.Orange;

                    startPoint.Price = 0;
                }
            }
        }
    }
}

References

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

Henry MultiCharts (2013a, November 8). Capture Mouse Events – forum discussion. Retrieved on February 23, 2015, from http://www.multicharts.com/discussion/viewtopic.php?f=19&t=45617#p99689

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

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