Trend lines based on price data can be drawn on the data series or made in the indicator’s subchart. But how can we draw trend lines based on indicator values?

Drawing trend lines in an indicator’s subchart

The DrwTrendLine.Create() method draws a trend line and returns an ITrendLineObject interface reference to the line created (MultiCharts, 2014; PowerLanguage .NET Help, n.d.). That returned reference, when stored in a variable, allows access to the line’s properties and methods. With those we can manipulate a trend line, such as its location or visual appearance.

There are several versions of DrwTrendLine.Create(). One of them requires two ChartPoint structs (for the line’s begin and end point) and a Boolean (see PowerLanguage .NET Help, n.d.). That true/false value indicates if the line should be drawn on the data series (when false; the default behaviour) or on the indicator’s subchart (true).

Drawing a trend line based on an indicator also requires the indicator values themselves. That way we can create ChartPoint struct values that have with their price coordinate set to the values of our indicator. Such values are stored with variables series in MultiCharts .NET.

A VariableSeries<T> class creates a series of variables that, just like a chart’s data series, provide access to values held on the close of previous bars (Henry MultiCharts, 2013; MultiCharts, 2014). The T indicates that a variable series is both generic and type-safe: we can replace this T with any type, but once set, it can only hold values of that type (see Sempf, Sphar, & Davis, 2010). So for example a VariableSeries<double> can only hold double values.

Plotting RSI values and drawing a trend line on those values

The chart below shows the example indicator added to an E-mini S&P 500 future. In its subchart RSI values are plotted and is a trend line drawn based on those RSI values:

MultiCharts .NET trend line in a subchart

Drawing trend lines on an indicator in MultiCharts .NET

The code for this is the following:

[RecoverDrawings(false)]
public class Example_TrendLinesSubchartIndicator : IndicatorObject
{
    public Example_TrendLinesSubchartIndicator(object _ctx) : 
        base(_ctx) { }

    private Function.RSI rsiFunction;
    private VariableSeries<Double> rsiValues;
    private ITrendLineObject rsiTrendLine;
    private IPlotObject rsiPlot;

    protected override void Create()
    {
        // Create plot, function, and variable series
        rsiPlot     = AddPlot(new PlotAttributes(
            "RSI", EPlotShapes.Line, Color.Black));
        rsiFunction = new Function.RSI(this);
        rsiValues   = new VariableSeries<Double>(this);
    }

    protected override void StartCalc()
    {
        // Specify RSI function settings
        rsiFunction.price  = Bars.Close;
        rsiFunction.length = 14;
    }

    protected override void CalcBar()
    {
        // Store current RSI value in variable series
        // and set the plot's value
        rsiValues.Value = rsiFunction[0];
        rsiPlot.Set(rsiValues[0]);

        // Draw trend line based on RSI values
        if (Bars.LastBarOnChart && rsiTrendLine == null)
        {
            ChartPoint previousRSI = new ChartPoint(
                Bars.Time[30], rsiValues[30]);

            ChartPoint currentRSI  = new ChartPoint(
                Bars.Time[0], rsiValues[0]);

            rsiTrendLine = DrwTrendLine.Create(
                previousRSI, currentRSI, true);

            rsiTrendLine.Size  = 1;
            rsiTrendLine.Color = Color.DeepSkyBlue;
        }
    }
}

We start with setting the RecoverDrawings attribute to false so that intra-bar generated drawings aren’t removed (MultiCharts, 2014). Then we declare a RSI function for calculating the RSI values (named rsiFunction) and a variable series consisting out of doubles for holding the RSI value of each bar (rsiValues). We also declare a trend line reference for the line to be drawn (rsiTrendLine) and a plot for the RSI line itself (rsiPlot).

In the Create() method AddPlot() creates the RSI plot and sets it to a black line named “RSI”. Instances of the RSI function (RSI.Function) and the variable series (VariableSeries<Double>) are also created here. In the subsequent StartCalc() method the RSI function has the price on which it’s calculated set to the close of each bar (Bars.Close) and it’s length to 14 bars.

Drawing a trend line based on RSI values

Next in the example is the CalcBar() method. Here we set the current value of the double variable series (rsiValues.Value) to the RSI function’s value for the current bar (rsiFunction[0]). By doing this on every bar rsiValues also holds values of previous bars over time. The indicator’s plot line is subsequently set with its Set() method, in which we pass the RSI variable series’ value for the current bar (rsiValues[0]).

An if statement then checks whether the current bar is the last (Bars.LastBarOnChart will then return true; PowerLanguage .NET Help, n.d.) and if rsiTrendLine equals (==) null. This last condition happens when this reference variable doesn’t point to an object (Stephens, 2014), which in this context means we haven’t associated the rsiTrendLine variable with an actual trend line object on the chart.

When both of those conditions are true, we’re going to draw the trend line. We begin with creating two ChartPoint struct variables. The first (previousRSI) marks the line’s begin point and is set to the time (Bars.Time[30]) and RSI value (rsiValues[30]) of 30 bars ago. The second (currentRSI) is the line’s end point and set to the current bar’s data (Bars.Time[0] and rsiValues[0]).

DrwTrendLine.Create() is then called with three arguments: the line’s starting coordinate, its ending coordinate, and a value of true that indicates the line needs to be plotted in the indicator’s subchart. Since this method’s returned value is assigned to rsiTrendLine, we can now use that variable to change the trend line’s appearance through setting its Size and Color properties to different values.

To learn more about drawing trend lines see drawing in a subchart based on price data, snapping trend lines to indicator values with mouse clicks, and plotting trend lines on different data series.

Summary

Trend lines are made with DrwTrendLine.Create(). One version of this method requires the line’s begin and end coordinates together with a Boolean value for either drawing in the indicator’s subchart (when true) or on the data series (false, the default value). Creating lines on an indicator requires ChartPoint structs with their time coordinate set to a bar’s time (Bars.Time[0], for example) and their price coordinate holding the indicator’s value. For that latter we use a VariableSeries<T>, which creates a variable series that allows us to retrieve values from previous bars.

Complete MultiCharts .NET indicator example

using System;
using System.Drawing;
using System.Linq;
using PowerLanguage.Function;

namespace PowerLanguage.Indicator
{
    [RecoverDrawings(false)]
    public class Example_TrendLinesSubchartIndicator : IndicatorObject
    {
        public Example_TrendLinesSubchartIndicator(object _ctx) : 
            base(_ctx) { }

        private Function.RSI rsiFunction;
        private VariableSeries<Double> rsiValues;
        private ITrendLineObject rsiTrendLine;
        private IPlotObject rsiPlot;

        protected override void Create()
        {
            // Create plot, function, and variable series
            rsiPlot     = AddPlot(new PlotAttributes(
                "RSI", EPlotShapes.Line, Color.Black));
            rsiFunction = new Function.RSI(this);
            rsiValues   = new VariableSeries<Double>(this);
        }

        protected override void StartCalc()
        {
            // Specify RSI function settings
            rsiFunction.price  = Bars.Close;
            rsiFunction.length = 14;
        }

        protected override void CalcBar()
        {
            // Store current RSI value in variable series
            // and set the plot's value
            rsiValues.Value = rsiFunction[0];
            rsiPlot.Set(rsiValues[0]);

            // Draw trend line based on RSI values
            if (Bars.LastBarOnChart && rsiTrendLine == null)
            {
                ChartPoint previousRSI = new ChartPoint(
                    Bars.Time[30], rsiValues[30]);

                ChartPoint currentRSI  = new ChartPoint(
                    Bars.Time[0], rsiValues[0]);

                rsiTrendLine = DrwTrendLine.Create(
                    previousRSI, currentRSI, true);

                rsiTrendLine.Size  = 1;
                rsiTrendLine.Color = Color.DeepSkyBlue;
            }
        }
    }
}

References

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

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.

Stephens, R. (2014). C# 5.0 Programmer Reference. Indianapolis, IN: John Wiley & Sons.