With a trend line’s PriceValue() method we can determine a line’s historical and future price values. But how can we apply this method so that price bars above and below a line are painted in different colours?

Making MultiCharts .NET trend lines and colouring price bars

The DrwTrendLine.Create() method draws trend lines in MultiCharts .NET. This method can be used in different ways (see the essentials of drawing trend lines). But each version of this method requires at least two ChartPoint structs (for the line’s begin and end point) and returns a reference to the line created (MultiCharts, 2014; PowerLanguage .NET Help, n.d.). When we assign that returned value to an ITrendLineObject variable, the line’s properties and methods are accessible through that variable.

One trend line method is PriceValue(), which returns a line’s price value for a specific DateTime value on the chart (MultiCharts, 2014; PowerLanguage .NET Help, n.d.). With this method we can, for example, calculate a line’s historical and future trend line values.

PriceValue() can also be used to determine if a bar has closed above or below a trend line. By colouring these price bars we can visually highlight how the bar closed in relation to the trend line. Creating such paint bars requires a combination of four indicator plots: one for the bar’s open, high, low, and close (Henry MultiCharts, 2012). Let’s look at the example to see how we can combine paint bars with mouse clicks that draw a trend line.

Example: colour the price bars above and below a trend line

When the example indicator is added to the chart, like to the following E-mini Dow Jones future chart, it initially does nothing:

MultiCharts .NET price chart - before drawing trend lines

After clicking two times on the chart with Control held down a trend line is drawn between those two mouse click locations. Then all bars that closed above the line are coloured green and those below it red:

Colouring price bars above & below a MultiCharts .NET line

Programmatically colour a trend line’s price bars in MultiCharts .NET

The programming example looks as follows:

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

    private IPlotObject plotHigh, plotLow, plotOpen, plotClose;
    private ChartPoint beginPoint, endPoint;

    protected override void Create()
    {
        plotHigh  = AddPlot(new PlotAttributes("High", 
            EPlotShapes.BarHigh, Color.Black));

        plotLow   = AddPlot(new PlotAttributes("Low", 
            EPlotShapes.BarLow, Color.Black));

        plotOpen  = AddPlot(new PlotAttributes("Open", 
            EPlotShapes.LeftTick, Color.Black));

        plotClose = AddPlot(new PlotAttributes("Close", 
            EPlotShapes.RightTick, Color.Black));
    }

    protected override void StartCalc()
    {
        beginPoint = new ChartPoint();
        endPoint   = new ChartPoint();

        ExecInfo.MaxBarsBack = 100;
    }

    protected override void CalcBar() { }

    int barNumBegin, barNumEnd;

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

            // When we don't have a begin point for the line, make one
            if (beginPoint.Price == 0)
            {
                beginPoint = new ChartPoint(
                    Bars.FullSymbolData.Time[barsAgo],
                    Bars.FullSymbolData.Close[barsAgo]
                    );

                barNumBegin = arg.bar_number;
            }
            else if (endPoint.Price == 0)
            {
                endPoint = new ChartPoint(
                    Bars.FullSymbolData.Time[barsAgo],
                    Bars.FullSymbolData.Close[barsAgo]
                    );

                // Create and adjust the trend line
                ITrendLineObject trendLine = DrwTrendLine.Create(
                    beginPoint, endPoint);

                trendLine.Size  = 2;
                trendLine.Color = Color.LimeGreen;

                barNumEnd = arg.bar_number;

                // Loop through all bars with the line on them
                int barBegin = Bars.FullSymbolData.Current - barNumBegin;
                int barEnd   = Bars.FullSymbolData.Current - barNumEnd;

                for (int i = barBegin; i >= barEnd; i--)
                {
                    if (Bars.FullSymbolData.Close[i] > 
                        trendLine.PriceValue(Bars.FullSymbolData.Time[i]))
                    {
                        // Create green paint bars
                        plotHigh.Set(i + 1, Bars.FullSymbolData.High[i], 
                            Color.ForestGreen);
                        plotLow.Set(i + 1, Bars.FullSymbolData.Low[i], 
                            Color.ForestGreen);
                        plotOpen.Set(i + 1, Bars.FullSymbolData.Open[i], 
                            Color.ForestGreen);
                        plotClose.Set(i + 1, Bars.FullSymbolData.Close[i], 
                            Color.ForestGreen);
                    }
                    else
                    {
                        // Make red paint bars
                        plotHigh.Set(i + 1, Bars.FullSymbolData.High[i], 
                            Color.Firebrick);
                        plotLow.Set(i + 1, Bars.FullSymbolData.Low[i], 
                            Color.Firebrick);
                        plotOpen.Set(i + 1, Bars.FullSymbolData.Open[i], 
                            Color.Firebrick);
                        plotClose.Set(i + 1, Bars.FullSymbolData.Close[i], 
                            Color.Firebrick);
                    }
                }
            }
        }
    }
}

We begin with defining three class attributes. SameAsSymbol set to true plots the indicator on the data series and not in a separate subchart. With MouseEvents set to true the script processes mouse clicks. And setting RecoverDrawings to false prevents intra-bar generated trend lines from being removed automatically (MultiCharts, 2014).

Then we declare four IPlotObject variables (plotHigh, plotLow, plotOpen, and plotClose) that we’ll use to colour the price bars. We also declare two ChartPoint struct variables (beginPoint and endPoint). These variables will hold the line’s begin and end point.

Creating the paint bar plot and setting up the indicator

Next is the Create() method in which we create four different plots, one for each part of a price bar. The plot’s type is set through with an EPlotShapes enumerated value (see MultiCharts, 2014): the high and low plots are set to BarHigh and BarLow, respectively. LeftTick and RightTick specify the bar’s open and closing price, and correspond to the small ticks you’d see in an OHLC chart.

In the StartCalc() method we set the beginPoint and endPoint ChartPoint variables to their initial values. The benefit of doing this here is that turning the indicator off and back on again will execute StartCalc() and so these chart locations will be reset. This allows for drawing a new trend line after switching the script off and on.

In StartCalc() we also assign a value to the ExecInfo.MaxBarsBack property to explicitly set the indicator’s MaxBarsBack value (see PowerLanguage .NET Help, n.d.). By default, the ‘maximum number of bars a study will reference’ option is set to auto-detect, which causes the script to be recalculated if the initial MaxBarsBack value proves to be insufficient (MultiCharts Wiki, 2012). For this script, it means we would need to click repeatedly before the line is drawn, and so we set the MaxBarsBack explicitly.

Processing mouse clicks to draw a trend line

Next we declare two integer variables (barNumBegin and barNumEnd) that will hold the absolute bar numbers of the trend line’s begin and end point. We then arrive at the OnMouseEvent() method, which processes the registered mouse clicks on the chart (see PowerLanguage .NET Help, n.d.).

This method begins with an if statement that checks whether the keyboard key pressed during the click (retrievable with the arg.keys variable) equals the Control key (Keys.Control). This latter value originates from the System.Windows.Forms namespace that we added with a using statement to the top of the indicator (see full code example below).

When that if statement evaluates to true, we first determine how many bars ago the click occurred. For that we subtract the click’s bar number (arg.bar_number) from Bars.FullSymbolData.Count, a property that returns the total number of bars on the chart (see MultiCharts, 2014). We store that calculated value in the barsAgo variable which we’ll use to access the price and time data of the clicked-on bar.

Defining the line’s begin point with a ChartPoint struct

An if/else statement then evaluates whether the Price property of the beginPoint ChartPoint struct variable equals (==) 0, which it does when we haven’t stored a chart coordinate in this variable yet. So in that case we assign a new ChartPoint chart location to the beginPoint variable, set to the time and close of the number of bars ago that the click happened (barsAgo). That bar’s data is accessed through Bars.FullSymbolData since we can access any price bar of the data series with this property (PowerLanguage .NET Help, n.d.).

We then assign the barNumBegin variable the clicked-on bar number (arg.bar_number). This variable is used later on to determine how many bars ago the first click happened.

Creating the line’s end point and drawing the trend line

Next is the else if part that verifies if the endPoint.Price property equals 0, which happens when the line’s starting point is assigned a chart location but the ending point not. And so we assign the endPoint variable the chart coordinate of the time and close of the clicked-on bar.

Now that both chart coordinates (beginPoint and endPoint) hold bar data from where the mouse clicks happened, we can draw a trend line between them. For that we call the DrwTrendLine.Create() method and pass in the beginPoint and endPoint variables. The value returned by this method is assigned to an ITrendLineObject variable named trendLine, which we can use to access the trend line’s properties and methods afterward.

That trend line variable is then used to change the line’s visual appearance by assigning new values to the line’s Size and Color properties. We then store the clicked-on bar number in the barNumEnd variable so we can calculate how many bars ago the second mouse click happened.

Colouring price bars above and below a trend line

The last part of the OnMouseEvent() method starts with creating two integer variables: barBegin and barEnd. Both have their value based on the current bar number (returned by Bars.FullSymbolData.Current) minus the clicked-on bar number (which we stored in the barNumBegin and barNumEnd variables). This way we know how many bars ago the line started and how many bars ago it ended (both calculated relative to the current bar).

We then implement a for loop, which starts at the number of bars ago that the line began (barBegin) and continues till the bar where the line ended (barEnd). With each loop cycle the postfix decrement operator (--) decreases the i loop variable with one so that all price bars are looped over.

Inside the loop, an if/else statement checks if a bar closed above or below the trend line’s price value for that bar. We access the bar’s closing price with the Bars.FullSymbolData.Close property together with the i loop variable inside square brackets ([ and ]). The trend line’s price value belonging to that bar is retrieved with the line’s PriceValue() method, in which we pass the price bar’s DateTime value (Bars.FullSymbolData.Time[i]).

Whether a bar closes above the trend line or not, the Set() method is called for each of the four plots with three arguments passed in: the number of bars ago the plot needs to be plotted, the plot’s value (set with one of the Bars.FullSymbolData properties), and its colour (see PowerLanguage .NET Help, n.d.). The difference is that the if code block plots green bars (Color.ForestGreen) while the else part plots with red (Color.Firebrick).

The first argument (the number of bars ago to plot the bar) is set to i + 1 as opposed to just i. This + 1 is a workaround needed since the example chart’s session is closed. According to MultiCharts Support (personal communication, May 28, 2015), this is not a bug but caused by the different stages that CalcBar() and OnMouseEvent() are called with real-time versus historical data.

Once the for loop ends, all price bars that closed above our manually drawn trend line are coloured green and those that closed below it are made red.

For more examples that use PriceValue() to get a trend line’s price value for a certain DateTime value, see get the price value of a trend line, working with a trend line’s future values, and calculating how long before a trend line reaches a future target. The submitting market orders based on a trend line article also uses PriceValue().

Summary

Trend lines are made with DrwTrendLine.Create(). This method returns a reference that, when stored in an ITrendLineObject variable, provides access to the trend line’s PriceValue() method. With that method we can determine a trend line’s price value for a given DateTime value. By comparing a bar’s closing price with the value returned by PriceValue() for that bar’s time, we can determine whether a bar closed above or below the trend line. We can then colour that price bar by creating four indicator plots that are set to a bar’s open, high, low, and close.

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

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

        private IPlotObject plotHigh, plotLow, plotOpen, plotClose;
        private ChartPoint beginPoint, endPoint;

        protected override void Create()
        {
            plotHigh  = AddPlot(new PlotAttributes("High", 
                EPlotShapes.BarHigh, Color.Black));

            plotLow   = AddPlot(new PlotAttributes("Low", 
                EPlotShapes.BarLow, Color.Black));

            plotOpen  = AddPlot(new PlotAttributes("Open", 
                EPlotShapes.LeftTick, Color.Black));

            plotClose = AddPlot(new PlotAttributes("Close", 
                EPlotShapes.RightTick, Color.Black));
        }

        protected override void StartCalc()
        {
            beginPoint = new ChartPoint();
            endPoint   = new ChartPoint();

            ExecInfo.MaxBarsBack = 100;
        }

        protected override void CalcBar() { }

        int barNumBegin, barNumEnd;

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

                // When we don't have a begin point for the line, make one
                if (beginPoint.Price == 0)
                {
                    beginPoint = new ChartPoint(
                        Bars.FullSymbolData.Time[barsAgo],
                        Bars.FullSymbolData.Close[barsAgo]
                        );

                    barNumBegin = arg.bar_number;
                }
                else if (endPoint.Price == 0)
                {
                    endPoint = new ChartPoint(
                        Bars.FullSymbolData.Time[barsAgo],
                        Bars.FullSymbolData.Close[barsAgo]
                        );

                    // Create and adjust the trend line
                    ITrendLineObject trendLine = DrwTrendLine.Create(
                        beginPoint, endPoint);

                    trendLine.Size  = 2;
                    trendLine.Color = Color.LimeGreen;

                    barNumEnd = arg.bar_number;

                    // Loop through all bars with the line on them
                    int barBegin = Bars.FullSymbolData.Current - barNumBegin;
                    int barEnd   = Bars.FullSymbolData.Current - barNumEnd;

                    for (int i = barBegin; i >= barEnd; i--)
                    {
                        if (Bars.FullSymbolData.Close[i] > 
                            trendLine.PriceValue(Bars.FullSymbolData.Time[i]))
                        {
                            // Create green paint bars
                            plotHigh.Set(i + 1, Bars.FullSymbolData.High[i], 
                                Color.ForestGreen);
                            plotLow.Set(i + 1, Bars.FullSymbolData.Low[i], 
                                Color.ForestGreen);
                            plotOpen.Set(i + 1, Bars.FullSymbolData.Open[i], 
                                Color.ForestGreen);
                            plotClose.Set(i + 1, Bars.FullSymbolData.Close[i], 
                                Color.ForestGreen);
                        }
                        else
                        {
                            // Make red paint bars
                            plotHigh.Set(i + 1, Bars.FullSymbolData.High[i], 
                                Color.Firebrick);
                            plotLow.Set(i + 1, Bars.FullSymbolData.Low[i], 
                                Color.Firebrick);
                            plotOpen.Set(i + 1, Bars.FullSymbolData.Open[i], 
                                Color.Firebrick);
                            plotClose.Set(i + 1, Bars.FullSymbolData.Close[i], 
                                Color.Firebrick);
                        }
                    }
                }
            }
        }
    }
}

References

Henry MultiCharts (2012, August 1). PaintBar – forum discussion. Retrieved on March 22, 2015, from http://www.multicharts.com/discussion/viewtopic.php?f=19&t=10683#p52423

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

MultiCharts Wiki (2012, February 23). How Scripts Work. Retrieved on March 22, 2015, from http://www.multicharts.com/trading-software/index.php/How_Scripts_Work

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