In MultiCharts .NET we can, for example, draw trend lines that highlight price action by placing them between pivot swing highs and lows. But how do we trade price action with trend lines?

Drawing MultiCharts .NET trend lines and generating trading orders

We draw MultiCharts .NET trend lines with DrwTrendLine.Create(), a method that returns a reference to the line made (MultiCharts, 2014; PowerLanguage .NET Help, n.d.). When that reference is assigned to an ITrendLineObject interface variable, the line’s properties and methods are accessible through that variable.

One of those methods is PriceValue(), which returns the line’s price value for any DateTime value on the chart (PowerLanguage .NET Help, n.d.). That method allows us to determine if a bar’s closing price crossed the trend line. When it does, we can generate a strategy order to open a position.

Generating a managed market order in MultiCharts .NET requires three things (MultiCharts, 2014): declaring an IOrderMarket interface variable, creating the order object in the Create() method with the OrderCreator.MarketNextBar() method, and then submitting the order itself by calling its Send() method. Let’s examine an example strategy to see how we can generate market orders based on a trend line.

Example: trading automatically with a MultiCharts .NET line

When the example strategy is added to an AUD/USD chart, it draws a horizontal trend line like:

Trading with a MultiCharts .NET trend line - 1

Then, when the price crosses above the trend line, a long position is opened:

Trading with a MultiCharts .NET trend line - 2

An exit long order is submitted after a couple of price bars:

Trading with a MultiCharts .NET trend line - 3

Another example of the strategy is generating a short order when the price drops below the trend line:

Trading with a MultiCharts .NET trend line - 4

That order is also closed a few bars later:

Trading with a MultiCharts .NET trend line - 5

The strategy continues to trade the horizontal trend line with each trend line crossing:

Trading with a MultiCharts .NET trend line - 6

Triggering trading orders with a programmatically drawn trend line

The programming example’s code is the following:

[IOGMode(IOGMode.Disabled)]
public class Example_TrendLineStrategy : SignalObject
{
    public Example_TrendLineStrategy(object _ctx) : base(_ctx) { }

    private IOrderMarket buyOrder;
    private IOrderMarket sellOrder;
    private IOrderMarket exitLongOrder;
    private IOrderMarket exitShortOrder;

    private ITrendLineObject trendLine;

    protected override void Create()
    {
        // Create the orders
        buyOrder = OrderCreator.MarketNextBar(new 
            SOrderParameters(Contracts.Default, EOrderAction.Buy));

        sellOrder = OrderCreator.MarketNextBar(new 
            SOrderParameters(Contracts.Default, EOrderAction.SellShort));

        exitLongOrder = OrderCreator.MarketNextBar(new 
            SOrderParameters(Contracts.Default, EOrderAction.Sell));

        exitShortOrder = OrderCreator.MarketNextBar(new 
            SOrderParameters(Contracts.Default, EOrderAction.BuyToCover));
    }

    protected override void StartCalc()
    {
        trendLine = null;
    }

    protected override void CalcBar()
    {
        // Only process real-time bars
        if (!Environment.IsRealTimeCalc ||
            Environment.ApplicationCode != EApplicationCode.Charting)
            return;

        // Create the trend line when this hasn't been done already
        if (trendLine == null)
        {
            ChartPoint beginPoint = new ChartPoint(
                Bars.Time[3], Bars.Close[0]);

            ChartPoint endPoint = new ChartPoint(
                Bars.Time[0], Bars.Close[0]);

            trendLine = DrwTrendLine.Create(beginPoint, endPoint);

            trendLine.Size     = 2;
            trendLine.Color    = Color.RoyalBlue;
            trendLine.ExtRight = true;
            trendLine.ExtLeft  = true;
        }

        // Get the trend line's price value
        double trendLinePrice = trendLine.PriceValue(Bars.Time[0]);

        // Only enter positions when there's none currently
        if (StrategyInfo.MarketPosition == 0)
        {
            // Enter long with a close above the trend line
            if ((Bars.Close[0] > trendLinePrice) &&
                (Bars.Close[1] < trendLinePrice))
            {
                buyOrder.Send();
            }
            // Enter short with a close below the line
            else if ((Bars.Close[0] < trendLinePrice) &&
                (Bars.Close[1] > trendLinePrice))
            {
                sellOrder.Send();
            }
        }

        // Manage open position
        if (StrategyInfo.MarketPosition != 0)
        {
            // Exit the position after 3 bars
            if (CurrentPosition.OpenTrades[0].EntryOrder.BarNumber + 3 == 
                Bars.CurrentBar)
            {
                exitLongOrder.Send();
                exitShortOrder.Send();
            }
        }
    }
}

We first set the IOGMode attribute to disabled to turn off intra-bar order generation and make the strategy calculate on bar close only. Then we create four IOrderMarket variables (buyOrder, sellOrder, exitLongOrder, and exitShortOrder), one for each of the four orders. We also declare an ITrendLineObject variable named trendLine that will provide access to the trend line later on.

Creating managed trading orders in MultiCharts .NET

Next in the Create() method the four orders are created. We do that with the OrderCreator.MarketNextBar() method to create a market order that’s sent at the open of the bar following the price bar that the order was generated on (MultiCharts, 2014).

The order settings are specified with a SOrderParameters struct (MultiCharts, 2014), and with its first argument of Contracts.Default we set each order’s position size to the default setting from the ‘Strategy Properties’ screen. A value from the EOrderAction enumeration specifies each order’s type: EOrderAction.Buy creates an enter long order, EOrderAction.SellShort marks an enter short order, EOrderAction.Sell is an exit long order, and EOrderAction.BuyToCover an exit short order (MultiCharts, 2014).

Reset the trend line variable and only execute code on real-time charts

In the StartCalc() method we set the trend line variable (trendLine) explicitly to null, its default value (Sempf, Sphar, & Davis, 2010) which indicates that this reference variable doesn’t point to an object (Stephens, 2014). For our example, it means the trend line variable isn’t associated with an actual trend line object on the chart. Since we only draw a trend line in the CalcBar() method when this variable is null (to prevent multiple lines from being drawn), resetting it in StartCalc() ensures that the script always draws the trend line, even when, for example, the strategy is turned off and back on again.

The CalcBar() method begins with an if statement that evaluates two conditions. The first is whether Environment.IsRealTimeCalc returns false, which this property does when the script is not calculated on real-time data (see MultiCharts, 2014). We test that condition with the logical not operator (!), which operates on a single value and evaluates to that value’s opposite. In other words, with the not operator the statement is true when the value is false, and vice versa (Liberty & MacDonald, 2009). The second condition checks if Environment.ApplicationCode returns a value unequal to (!=) EApplicationCode.Charting, which happens when the script is not executed on a chart (see PowerLanguage .NET Help, n.d.).

Both conditions are combined with the logical or operator (||) so that when one of them is true, the whole statement is true and we execute the return keyword to exit the CalcBar() method (see Dorman, 2010). Since we cannot draw trend lines in the Real-Time Market Scanner or Portfolio Trader and the strategy is intended for real-time data, the code in CalcBar() that’s below return is only executed on charts with real-time data.

Creating a horizontal trend line for order generation

We then check with an if statement whether trendLine equals (==) null, which it does when this reference variable doesn’t point to an object (Albahari & Albahari, 2012). In our example, this means trendLine isn’t associated with a trend line on the chart, which in our context also means we haven’t drawn a line yet.

And so when that if statement’s expression evaluates to true, we’re going to draw the trend line. First we create two ChartPoint struct variables to hold the coordinates of the line’s begin and end point. The first, beginPoint, is set to the time of 3 bars ago (Bars.Time[3]) and the current bar’s close (Bars.Close[0]). The second chart coordinate, endPoint, holds the current bar’s time and close (Bars.Time[0] and Bars.Close[0]). We set both coordinates to the same price value but different DateTime values to make a horizontal trend line.

With both ChartPoint chart locations defined, we call the DrwTrendLine.Create() method to draw a trend line. In it, we pass the beginPoint and endPoint variables to set the line’s begin and end point. The value returned by this method is put into the trendLine variable. We then use that variable to change the line’s visual appearance by setting its Size and Color properties to different values. And with the ExtRight and ExtLeft properties set to true we extend the trend line in both directions.

Submitting orders based on a trend line’s price value

The next part of CalcBar() submits orders when the price bar crosses the trend line. We first create a double variable (trendLinePrice) set to the line’s PriceValue() method, which returns the line’s price value for any DateTime value on the chart (PowerLanguage .NET Help, n.d.). By passing in the current bar’s date and time (Bars.Time[0]) in this method, we retrieve the line’s price value of the current bar with it. Since the trend line is horizontal, any other bar’s time would also suffice here.

To prevent pyramiding into a position, an if statement then checks if the strategy is flat. That is the case when the StrategyInfo.MarketPosition property equals (==) 0 (see MultiCharts, 2014). Inside that if statement is an if/else statement that compares the bar’s closing price against the trend line. When the current bar’s close (Bars.Close[0]) is above the trend line’s price value (trendLinePrice) and (&&) the previous bar (Bars.Close[1]) was below the trend line, we know the bar crossed above the line and so submit the enter long order (buyOrder) by calling its Send() method.

Likewise, the else if portion checks if the bar closes below the trend line while the previous bar was above it. When that happens, we enter a short position with the sellOrder order.

Exit trading positions in MultiCharts .NET after a few bars

In the last part of CalcBar() we manage the open position. An if statement first checks if StrategyInfo.MarketPosition is unequal to (!=) 0 so that its code block only executes when the strategy has an open position (see MultiCharts, 2014). We then use a nested if statement to check if the position has been open for 3 bars.

For that we retrieve the entry order’s bar number (EntryOrder.BarNumber) from the first open trade of the current position (CurrentPosition.OpenTrades[0]) (see MultiCharts, 2014; PowerLanguage .NET Help, n.d.). When that value plus 3 equals the current bar number (returned by the Bars.CurrentBar property; MultiCharts, 2014), we know the position has been open for three bars.

We then submit both the exit long (exitLongOrder) and exit short (exitShortOrder) orders by calling their Send() methods. Because these orders can only exit a long and short position respectively (see MultiCharts, 2014), we can submit both of them and they will not open a new position in another direction.

Other examples of trading with MultiCharts .NET trend lines are using a manually drawn trend lines as a stop-loss and highlighting a strategy’s stop-loss value with trend lines.

Summary

The DrwTrendLine.Create() method draws trend lines and returns a reference to the line made. When stored in an ITrendLineObject interface variable, that variable provides us access to the line’s properties and methods. One trend line method is PriceValue(), which returns the line’s price value for any DateTime value on the chart. By comparing the line’s price with the bar’s closing price, we can figure out if a bar crossed above or below the trend line. When it did, we can submit trading orders by calling an order’s Send() method.

Complete MultiCharts .NET trading strategy example

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

namespace PowerLanguage.Strategy
{
    [IOGMode(IOGMode.Disabled)]
    public class Example_TrendLineStrategy : SignalObject
    {
        public Example_TrendLineStrategy(object _ctx) : base(_ctx) { }

        private IOrderMarket buyOrder;
        private IOrderMarket sellOrder;
        private IOrderMarket exitLongOrder;
        private IOrderMarket exitShortOrder;

        private ITrendLineObject trendLine;

        protected override void Create()
        {
            // Create the orders
            buyOrder = OrderCreator.MarketNextBar(new 
                SOrderParameters(Contracts.Default, EOrderAction.Buy));

            sellOrder = OrderCreator.MarketNextBar(new 
                SOrderParameters(Contracts.Default, EOrderAction.SellShort));

            exitLongOrder = OrderCreator.MarketNextBar(new 
                SOrderParameters(Contracts.Default, EOrderAction.Sell));

            exitShortOrder = OrderCreator.MarketNextBar(new 
                SOrderParameters(Contracts.Default, EOrderAction.BuyToCover));
        }

        protected override void StartCalc()
        {
            trendLine = null;
        }

        protected override void CalcBar()
        {
            // Only process real-time bars
            if (!Environment.IsRealTimeCalc ||
                Environment.ApplicationCode != EApplicationCode.Charting)
                return;

            // Create the trend line when this hasn't been done already
            if (trendLine == null)
            {
                ChartPoint beginPoint = new ChartPoint(
                    Bars.Time[3], Bars.Close[0]);

                ChartPoint endPoint = new ChartPoint(
                    Bars.Time[0], Bars.Close[0]);

                trendLine = DrwTrendLine.Create(beginPoint, endPoint);

                trendLine.Size     = 2;
                trendLine.Color    = Color.RoyalBlue;
                trendLine.ExtRight = true;
                trendLine.ExtLeft  = true;
            }

            // Get the trend line's price value
            double trendLinePrice = trendLine.PriceValue(Bars.Time[0]);

            // Only enter positions when there's none currently
            if (StrategyInfo.MarketPosition == 0)
            {
                // Enter long with a close above the trend line
                if ((Bars.Close[0] > trendLinePrice) &&
                    (Bars.Close[1] < trendLinePrice))
                {
                    buyOrder.Send();
                }
                // Enter short with a close below the line
                else if ((Bars.Close[0] < trendLinePrice) &&
                    (Bars.Close[1] > trendLinePrice))
                {
                    sellOrder.Send();
                }
            }

            // Manage open position
            if (StrategyInfo.MarketPosition != 0)
            {
                // Exit the position after 3 bars
                if (CurrentPosition.OpenTrades[0].EntryOrder.BarNumber + 3 == 
                    Bars.CurrentBar)
                {
                    exitLongOrder.Send();
                    exitShortOrder.Send();
                }
            }
        }
    }
}

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.

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.