In MultiCharts .NET we can calculate historical trend line values for each bar and even extrapolate a trend line’s price values into the future. But how can we figure out how long it takes before a trend line reaches a target price?

Drawing trend lines in MultiCharts .NET and determining future price values

Drawing trend lines programmatically is done with the DrwTrendLine.Create() method. 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.). With that reference stored in an ITrendLineObject variable, a line’s properties and methods are accessible through that variable to do things like relocating or visually changing the line.

One of the trend line methods is PriceValue(), which returns the 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 future trend line values or determine a line’s historical prices. Another application of PriceValue() is figuring out how long it will take before a trend line reaches a certain price.

Example: how long before a EUR/USD line reaches a target?

The example indicator draws two trend lines: one that slopes downward and a horizontal trend line. This looks like the following when applied to an EUR/USD future (CME’s 6E) chart:

Example: how lonng before reaching a price target in MultiCharts .NET?

This chart is ‘shifted’ with additional empty space in the right margin. That’s needed since a line’s PriceValue() method can only calculate price values for DateTime values on the chart. And so with more empty chart space, we can calculate more future trend line values.

To change a chart’s right margin, right-click on the chart and select ‘Format Window’. Then move to the ‘X - Time Scale’ tab and adjust the ‘Chart Shift’ option. This option can be set with a number of bars or with a percentage — click on the ‘Bars’ button to toggle between these.

MultiCharts .NET 'Chart Shift' settings

After drawing the trend lines, the indicator calculates how long it takes before the red line reaches the target price (blue line). To verify and see its process, the script generates the following output to the PowerLanguage .NET Editor Output Window:

Time: 9-3 22:30, line's price value: 1,08516, bars: 1
Time: 9-3 23:00, line's price value: 1,08498, bars: 2
Time: 9-3 23:30, line's price value: 1,0848, bars: 3
Time: 10-3 00:00, line's price value: 1,08462, bars: 4
Time: 10-3 00:30, line's price value: 1,08444, bars: 5
Time: 10-3 01:00, line's price value: 1,08426, bars: 6
Time: 10-3 01:30, line's price value: 1,08408, bars: 7
Time: 10-3 02:00, line's price value: 1,0839, bars: 8
Time: 10-3 02:30, line's price value: 1,08372, bars: 9
Time: 10-3 03:00, line's price value: 1,08354, bars: 10
Time: 10-3 03:30, line's price value: 1,08336, bars: 11
Time: 10-3 04:00, line's price value: 1,08318, bars: 12
Time: 10-3 04:30, line's price value: 1,083, bars: 13
Time: 10-3 05:00, line's price value: 1,08282, bars: 14
Time: 10-3 05:30, line's price value: 1,08264, bars: 15
Time: 10-3 06:00, line's price value: 1,08246, bars: 16
Time: 10-3 06:30, line's price value: 1,08228, bars: 17
Time: 10-3 07:00, line's price value: 1,0821, bars: 18
Time: 10-3 07:30, line's price value: 1,08192, bars: 19
Time: 10-3 08:00, line's price value: 1,08174, bars: 20
Time: 10-3 08:30, line's price value: 1,08156, bars: 21
Time: 10-3 09:00, line's price value: 1,08138, bars: 22
Time: 10-3 09:30, line's price value: 1,0812, bars: 23
Time: 10-3 10:00, line's price value: 1,08102, bars: 24
Time: 10-3 10:30, line's price value: 1,08084, bars: 25
Time: 10-3 11:00, line's price value: 1,08066, bars: 26
Time: 10-3 11:30, line's price value: 1,08048, bars: 27
Time: 10-3 12:00, line's price value: 1,0803, bars: 28
Time: 10-3 12:30, line's price value: 1,08012, bars: 29
Time: 10-3 13:00, line's price value: 1,07994, bars: 30
Reaching the 1,08 future price takes 30 bars or 15 hours.

Calculating the time duration before a trend line reaches a price target

The example indicator has the following code:

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

    private ITrendLineObject trendLine, horizontalLine;

    protected override void CalcBar()
    {
        if (Bars.LastBarOnChart)
        {
            // Create the bearish trend line
            if (trendLine == null)
            {
                trendLine = DrwTrendLine.Create(
                    new ChartPoint(Bars.Time[22], Bars.Close[22]),
                    new ChartPoint(Bars.Time[2], Bars.Close[2])
                    );

                trendLine.Size     = 2;
                trendLine.Color    = Color.Crimson;
                trendLine.ExtRight = true;
            }

            // Draw the horizontal trend line
            if (horizontalLine == null)
            {
                horizontalLine = DrwTrendLine.Create(
                    new ChartPoint(Bars.Time[1], 1.08),
                    new ChartPoint(Bars.Time[0], 1.08)
                    );

                horizontalLine.Size     = 1;
                horizontalLine.Color    = Color.RoyalBlue;
                horizontalLine.ExtLeft  = true;
                horizontalLine.ExtRight = true;

                // Determine how long it takes to reach the future price
                HowLongTillPrice(trendLine, 1.08);
            }
        }
    }

    private void HowLongTillPrice(ITrendLineObject futureTrendLine, 
        double targetPrice)
    {
        DateTime futureTime      = Bars.Time[0];
        double currentPriceValue = futureTrendLine.PriceValue(futureTime);
        int barsInFuture         = 0;

        // Loop as long as the current PriceValue() is above the future price
        while (currentPriceValue > targetPrice)
        {
            futureTime = futureTime.AddMinutes(30);

            currentPriceValue = futureTrendLine.PriceValue(futureTime);

            barsInFuture++;

            Output.WriteLine("Time: {0}, line's price value: {1}, bars: {2}",
                futureTime.ToString("d-M HH:mm"),
                currentPriceValue,
                barsInFuture);
        }

        TimeSpan tradingTimeNeeded = futureTime - Bars.Time[0]; 

        Output.WriteLine(
            "Reaching the {0} future price takes {1} bars or {2} hours.",
            targetPrice,
            barsInFuture,
            tradingTimeNeeded.TotalHours);
    }
}

We begin with defining two attributes. RecoverDrawings set to false prevents intra-bar generated drawings from being removed (MultiCharts, 2014). And with setting SameAsSymbol to true the indicator is plotted on the data series and not in a separate subchart.

Then we declare two ITrendLineObject variables in the top of the indicator’s class: trendLine and horizontalLine. We’ll use both to work with the trend lines later on in the example.

Creating a bearish trend line in MultiCharts .NET

Next in the example is the CalcBar() method. This method contains an if statement to check whether the current bar is the last on the chart, in which case the Bars.LastBarOnChart property returns true (PowerLanguage .NET Help, n.d.).

When that condition evaluates to true, a nested if statement tests whether the trendLine reference variable equals (==) null. This null value, the default value of a reference variable, means it’s empty and doesn’t point to anything yet (Stellman & Greene, 2010). This way we check whether a trend line has already been associated with the trendLine variable or not.

When the trendLine variable is still empty, we create a trend line by calling the DrwTrendLine.Create() method inside the if statement. In it, we pass two ChartPoint structs: the first sets the line’s begin point and the second specifies the end point. Both are set to an arbitrary amount of bars back so that it fits the price action in the image above.

The value returned by DrwTrendLine.Create() is assigned to the trendLine variable. This makes trendLine different from null and so the if statement’s code will only be executed once. With this variable, we can now access the line’s properties to adjust the trend line’s visual appearance. We do that by setting its Size and Color properties to different values. And by assigning the ExtRight property a value of true we create an extended trend line in one direction.

Drawing a horizontal, price target line in MultiCharts .NET

The other part in the CalcBar() method is an if statement that checks whether the horizontalLine variable equals null. When it does, a line hasn’t been associated with this variable yet and so we create one.

And so we call the DrwTrendLine.Create() method with ChartPoint structs as arguments to set the line’s begin and end point. Both have the price coordinate set to the random target of 1.08 and the time coordinates are set to the previous (Bars.Time[1]) and current bar (Bars.Time[0]).

The value returned by DrwTrendLine.Create() is assigned to the horizontalLine variable, which we then use to change the line’s Size and Color properties. After that the trend line is extended in both directions by setting the ExtLeft and ExtRight properties to true.

We subsequently call the HowLongTillPrice() method to calculate how long it will take before a trend line reaches a certain price. We pass in two arguments when calling the method: the trendLine variable specifies the trend line to calculate the future values from and 1.08 is the target price level.

How long before a trend line reaches a certain price?

The last part of the programming example is the HowLongTillPrice() method. This method has two parameters: an ITrendLineObject variable named futureTrendLine that holds the trend line reference and a double variable with the target price (targetPrice).

We start this method with creating three variables. The DateTime variable named futureTime is initialised to the date and time of the current bar (Bars.Time[0]). This variable will be used to determine the time of future bars. The currentPriceValue variable is set to the trend line’s price value of the current bar, which is retrieved with the line’s PriceValue() method. The last variable is barsInFuture and this will hold the number of price bars needed to reach the target price.

Next is a while loop, which continues as long as the currentPriceValue variable is greater than (>) the targetPrice variable. Inside the loop the futureTime variable is incremented with 30 minutes (the chart’s time frame). We do this with the AddMinutes() method, which adds the specified number of minutes to the DateTime value it’s called on (Dorman, 2010).

After determining the time of the next price bar with AddMinutes(), the trend line price value for that DateTime value is retrieved by calling PriceValue() with the futureTime variable passed in. Then the barsInFuture variable has its value increased with 1 by the postfix increment operator (++), which is just a shorthand way to write barsInFuture = barsInFuture + 1 (Dorman, 2010). By increasing this variable with every loop cycle it holds the number of future bars needed to reach our target price once the loop ends.

The last statement in the while loop outputs data with Output.WriteLine(). Values that this method outputs are the time in the future (futureTime), the accompanying trend line price value for that time (currentPriceValue), and the number of bars into the future (barsInFuture). We format the futureTime variable to a string with the d-M HH:mm custom format specifiers. These represent the day of the month (1 through 31; d), the month from 1 to 12 (M), the hour with a 24-hour clock from 00 to 23 (HH), and mm expresses the minutes from 00 to 59 (Dorman, 2010).

Outputting the time till a trend line reaches the target price

After the while loop ends we create the tradingTimeNeeded variable of type TimeSpan, which is a data type that represents an elapsed time (Stephens, 2014). We assign to this variable the difference between futureTime (which, at that point, holds the time at which the trend line reaches the target price) and Bars.Time[0], which is the time of the current bar.

Then Output.WriteLine() is called to print to the Editor’s Output Window the price to reach (targetPrice), how many bars the trend line needs to reach that price (barsInFuture), and the number of hours before the trend line arrives at that point. This latter is returned by the tradingTimeNeeded variable’s TotalHours property, which returns a TimeSpan value expressed in whole and fractional hours (Microsoft Developer Network, n.d.).

And with that output, the example ends and we know how many bars and hours are needed before the trend line reaches our target price.

For more examples of working with a line’s PriceValue() method, see how to get a trend line’s price values for historical bars, getting future trend line values, colouring price bars above or below a trend line, and extending a trend line to its past and future values.

Summary

The DrwTrendLine.Create() method draws trend lines and returns a reference to the line created. When stored in an ITrendLineObject variable, we can use this reference to access a line’s PriceValue() method. That method returns a line’s price value for any DateTime value on the chart. With it we can determine at which DateTime value the trend line reaches some predefined price.

Complete MultiCharts .NET indicator example

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

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

        private ITrendLineObject trendLine, horizontalLine;

        protected override void CalcBar()
        {
            if (Bars.LastBarOnChart)
            {
                // Create the bearish trend line
                if (trendLine == null)
                {
                    trendLine = DrwTrendLine.Create(
                        new ChartPoint(Bars.Time[22], Bars.Close[22]),
                        new ChartPoint(Bars.Time[2], Bars.Close[2])
                        );

                    trendLine.Size     = 2;
                    trendLine.Color    = Color.Crimson;
                    trendLine.ExtRight = true;
                }

                // Draw the horizontal trend line
                if (horizontalLine == null)
                {
                    horizontalLine = DrwTrendLine.Create(
                        new ChartPoint(Bars.Time[1], 1.08),
                        new ChartPoint(Bars.Time[0], 1.08)
                        );

                    horizontalLine.Size     = 1;
                    horizontalLine.Color    = Color.RoyalBlue;
                    horizontalLine.ExtLeft  = true;
                    horizontalLine.ExtRight = true;

                    // Determine how long it takes to reach the future price
                    HowLongTillPrice(trendLine, 1.08);
                }
            }
        }

        private void HowLongTillPrice(ITrendLineObject futureTrendLine, double targetPrice)
        {
            DateTime futureTime      = Bars.Time[0];
            double currentPriceValue = futureTrendLine.PriceValue(futureTime);
            int barsInFuture         = 0;

            // Loop as long as the current PriceValue() is above the future price
            while (currentPriceValue > targetPrice)
            {
                futureTime = futureTime.AddMinutes(30);

                currentPriceValue = futureTrendLine.PriceValue(futureTime);

                barsInFuture++;

                Output.WriteLine("Time: {0}, line's price value: {1}, bars: {2}",
                    futureTime.ToString("d-M HH:mm"),
                    currentPriceValue,
                    barsInFuture);
            }

            TimeSpan tradingTimeNeeded = futureTime - Bars.Time[0]; 

            Output.WriteLine("Reaching the {0} future price takes {1} bars or {2} hours.",
                targetPrice,
                barsInFuture,
                tradingTimeNeeded.TotalHours);
        }

        //> Time: 9-3 22:30, line's price value: 1,08516, bars: 1
        //> Time: 9-3 23:00, line's price value: 1,08498, bars: 2
        //> Time: 9-3 23:30, line's price value: 1,0848, bars: 3
        //> Time: 10-3 00:00, line's price value: 1,08462, bars: 4
        //> Time: 10-3 00:30, line's price value: 1,08444, bars: 5
        //> Time: 10-3 01:00, line's price value: 1,08426, bars: 6
        //> Time: 10-3 01:30, line's price value: 1,08408, bars: 7
        //> Time: 10-3 02:00, line's price value: 1,0839, bars: 8
        //> Time: 10-3 02:30, line's price value: 1,08372, bars: 9
        //> Time: 10-3 03:00, line's price value: 1,08354, bars: 10
        //> Time: 10-3 03:30, line's price value: 1,08336, bars: 11
        //> Time: 10-3 04:00, line's price value: 1,08318, bars: 12
        //> Time: 10-3 04:30, line's price value: 1,083, bars: 13
        //> Time: 10-3 05:00, line's price value: 1,08282, bars: 14
        //> Time: 10-3 05:30, line's price value: 1,08264, bars: 15
        //> Time: 10-3 06:00, line's price value: 1,08246, bars: 16
        //> Time: 10-3 06:30, line's price value: 1,08228, bars: 17
        //> Time: 10-3 07:00, line's price value: 1,0821, bars: 18
        //> Time: 10-3 07:30, line's price value: 1,08192, bars: 19
        //> Time: 10-3 08:00, line's price value: 1,08174, bars: 20
        //> Time: 10-3 08:30, line's price value: 1,08156, bars: 21
        //> Time: 10-3 09:00, line's price value: 1,08138, bars: 22
        //> Time: 10-3 09:30, line's price value: 1,0812, bars: 23
        //> Time: 10-3 10:00, line's price value: 1,08102, bars: 24
        //> Time: 10-3 10:30, line's price value: 1,08084, bars: 25
        //> Time: 10-3 11:00, line's price value: 1,08066, bars: 26
        //> Time: 10-3 11:30, line's price value: 1,08048, bars: 27
        //> Time: 10-3 12:00, line's price value: 1,0803, bars: 28
        //> Time: 10-3 12:30, line's price value: 1,08012, bars: 29
        //> Time: 10-3 13:00, line's price value: 1,07994, bars: 30
        //> Reaching the 1,08 future price takes 30 bars or 15 hours.
    }
}

References

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

Microsoft Developer Network (n.d.). TimeSpan.TotalHours Property. Retrieved on March 12, 2015, from https://msdn.microsoft.com/en-us/library/system.timespan.totalhours%28v=vs.110%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.

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