In MultiCharts .NET we can draw trend lines programmatically and trade of a trend line with market orders. But how do we generate stop-loss orders with a manually drawn trend line for a position that’s opened discretionary?

Drawing MultiCharts .NET trend lines and generating trading orders

Trend lines that are drawn programmatically with DrwTrendLine.Create() return a reference to the trend line made (MultiCharts, 2014; PowerLanguage .NET Help, n.d.). With that reference put in an ITrendLineObject interface variable we can access the line’s methods and properties. That way a line can be relocated, extended, removed, or even traded with market orders programmatically.

But when a line is drawn manually, the script doesn’t have a reference to the trend line object on the chart. Luckily, the DrwTrendLine.Active property returns a reference to the recently active trend line (see MultiCharts, 2014; PowerLanguage .NET Help, n.d.), which is the line that’s created or moved last, or is selected by a mouse click (MultiCharts, 2014).

We’ll use that property as the first step in applying a trend line as a stop-loss order. The two other required steps are having the strategy take over a manually entered position and then submit the stop-loss orders programmatically. A strategy takes ownership of a manually opened position with the ChangeMarketPosition() method, which doesn’t send out orders but instead syncs the strategy’s position with the one at the broker (MultiCharts, 2014; MultiCharts Wiki, 2014). That way a position that’s opened manually becomes manageable by a trading strategy, provided that automated trading is enabled on the chart.

When submitting stop-loss orders based on a trend line we need to know the price at which to submit them. For that we use a line’s PriceValue() method, which returns the line’s price value for any DateTime value on the chart (PowerLanguage .NET Help, n.d.). To generate the MultiCharts .NET stop-loss order itself three steps are required (MultiCharts, 2014): declaring an IOrderPriced interface variable, creating the stop-loss order with the OrderCreator.Stop() method, and submitting the order itself by calling its Send() method. Let’s look at the programming example for how to implement all of this.

Example: using a MultiCharts .NET trend line as a stop loss

Our example strategy works as follows. First we add it to a 5-minute EUR/USD chart followed by turning on ‘Automated Order Execution’ (the green SA button):

Using a MultiCharts .NET trend line as a stop-loss - Step 1

Then we open a position manually by, for example, clicking on the ‘Buy Mkt’ button in the Chart Trading Panel:

Using a MultiCharts .NET trend line as a stop-loss - Step 2

After that we draw a manual trend line that’s going to act as the stop loss, like so:

Using a MultiCharts .NET trend line as a stop-loss - Step 3

When the price bar closes, the strategy access the trend line, changes its visual appearance, then takes ownership of the manually opened position, and finally submits a stop-loss order:

Using a MultiCharts .NET trend line as a stop-loss - Step 4

The stop-loss order is updated on every bar with the current trend line price value. Since our trend line slopes upward, the stop-loss order increases with every new bar:

Using a MultiCharts .NET trend line as a stop-loss - Step 5 Using a MultiCharts .NET trend line as a stop-loss - Step 6

And as soon as the price drops below the trend line, the position is closed:

Using a MultiCharts .NET trend line as a stop-loss - Step 7

Likewise, the example also manages short positions. Here we’ve opened a short position on a AUD/USD chart:

Using a MultiCharts .NET trend line as a stop-loss - Step 8

Then we draw a trend line that’s going to act as a stop loss:

Using a MultiCharts .NET trend line as a stop-loss - Step 9

As soon as the strategy accesses the trend line, it changes its appearance. And when the market position is retrieved, a stop-loss order is submitted:

Using a MultiCharts .NET trend line as a stop-loss - Step 10

This stop-loss order behaves like a trailing stop loss due to the line’s downward slope:

Using a MultiCharts .NET trend line as a stop-loss - Step 11 Using a MultiCharts .NET trend line as a stop-loss - Step 12

And the position is closed when the price crossed the trend line:

Using a MultiCharts .NET trend line as a stop-loss - Step 13

Exit trading positions with a stop-loss trend line in MultiCharts .NET

The trading strategy’s code looks as follows:

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

    private IOrderPriced exitLongStop;
    private IOrderPriced exitShortStop;

    private ITrendLineObject trendLine;

    protected override void Create()
    {
        // Create the stop orders
        exitLongStop = OrderCreator.Stop(new 
            SOrderParameters(Contracts.UserSpecified, EOrderAction.Sell));

        exitShortStop = OrderCreator.Stop(new 
            SOrderParameters(Contracts.UserSpecified, EOrderAction.BuyToCover));
    }

    protected override void CalcBar()
    {
        // Sync with broker position
        if (StrategyInfo.MarketPosition == 0 &&
            StrategyInfo.MarketPositionAtBroker != 0)
        {
            ChangeMarketPosition(
                StrategyInfo.MarketPositionAtBroker - 
                    StrategyInfo.MarketPosition,
                StrategyInfo.AvgEntryPriceAtBroker);
        }

        // Only execute remainer of CalcBar() with an open position
        if (StrategyInfo.MarketPosition == 0)
            return;

        // Select trend line
        trendLine = DrwTrendLine.Active;

        // Proceed when a line was found
        if (trendLine != null)
        {
            // Change the line's appearance for confirmation
            trendLine.Size     = 2;
            trendLine.Color    = Color.DodgerBlue;
            trendLine.ExtRight = true;

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

            // Submit the stop-loss orders
            if (StrategyInfo.MarketPosition > 0)
            {
                exitLongStop.Send(trendLinePrice, CurrentPosition.OpenLots);
            }
            else if (StrategyInfo.MarketPosition < 0)
            {
                exitShortStop.Send(trendLinePrice, CurrentPosition.OpenLots);
            }
        }
    }
}

We first turn off intra-bar order generation by setting the IOGMode attribute to disabled so that the strategy only calculates on bar close. While this introduces a lag when submitting the stop-loss order, it also lets us better see how the strategy behaves on the chart.

Then we create two IOrderPriced interface variables (exitLongStop and exitShortStop) which are used to work with the order object later on. We’ll use the trendLine ITrendLineObject variable to hold the reference to the manual trend line.

Creating managed stop-loss orders in MultiCharts .NET

In the Create() method, that’s executed one time immediately after an instance of the script is made (MultiCharts, 2014), we create the two stop-loss orders with OrderCreator.Stop(). This method creates a price stop order that’s generated on bar close and submitted at the open of the next bar (MultiCharts, 2014).

The order settings are specified with a SOrderParameters struct (MultiCharts, 2014). We use that to set the orders’ size to Contracts.UserSpecified so that the position size can be set programmatically (see PowerLanguage .NET Help, n.d.). The order type is set with the EOrderAction enumeration: the exit long order is set to EOrderAction.Sell and the exit short order is marked EOrderAction.BuyToCover (MultiCharts, 2014).

Let a trading strategy take over a manual position programmatically

Next is the CalcBar() method that begins with an if statement that evaluates two conditions. The first is whether the trading strategy is flat, in which case the StrategyInfo.MarketPosition property equals (==) 0 (see MultiCharts, 2014). The second condition tests if StrategyInfo.MarketPositionAtBroker is unequal to (!=) 0. That property returns the position size for the chart’s instrument at the broker (MultiCharts, 2014). When both of these conditions evaluate to true, there’s a mismatch with the trading strategy being flat while there’s an open position at the broker.

To remedy that situation, we use ChangeMarketPosition() to sync the broker’s position with the trading strategy’s position (MultiCharts, 2014). This method has several versions, and the one we use here requires two arguments: the number of contracts to change the strategy’s position for and the entry price for the strategy position. We set the first to the difference between the strategy’s current position (StrategyInfo.MarketPosition) and the position at the broker (StrategyInfo.MarketPositionAtBroker). The second argument is set to the StrategyInfo.AvgEntryPriceAtBroker property that returns the average entry price of the chart instrument’s open position (PowerLanguage .NET Help, n.d.).

The next if statement in CalcBar() evaluates whether the strategy’s current position (StrategyInfo.MarketPosition) equals (==) 0, and executes the return keyword when that’s the case. This keyword returns code execution to the calling method (Dorman, 2010), meaning the current method is exited when return is come across. And so all the code in CalcBar() that’s below return is only executed when there’s an open position.

Accessing a manually drawn trend line programmatically

That code first assigns the trendLine variable the value returned by the DrwTrendLine.Active property, which returns a reference to the chart’s active trend line (MultiCharts, 2014; PowerLanguage .NET Help, n.d.).

But when an active trend line couldn’t be located, this property returns null. Such a value indicates that the reference variable doesn’t point to anything (Stephens, 2014), which means here that the trendLine variable isn’t connected with a trend line object. The next if statement checks whether this variable is unequal to (!=) null. We perform that check because trying to access a line’s properties and methods through trendLine while this variable is in fact null triggers a NullReferenceException (see Stellman & Greene, 2010).

When trendLine is different than null, we first change the line’s visual appearance by setting its Size and Color properties to new values. That also gives us a visual confirmation that the strategy succeeded in accessing the trend line. To continue the line indefinitely to the right, regardless of how many new price bars form, we extend the trend line by setting its ExtRight property to true.

Retrieving a line’s price value and submitting stop-loss orders

Next we retrieve the trend line’s price value with the PriceValue() method, in which we pass the DateTime value of the current bar (Bars.Time[0]) so that it returns the line’s price value for that bar (see PowerLanguage .NET Help, n.d.). The value returned by this method is assigned to the trendLinePrice variable. That makes this variable always holds the trend line’s price value for the current bar since it’s assigned a value each time the script calculates.

An if/else statement then checks if the strategy is long (indicated by StrategyInfo.MarketPosition being greater than 0) or short, in which case StrategyInfo.MarketPosition is (<) 0 (MultiCharts, 2014).

When the strategy is long, we submit the exitLongStop order by calling its Send() method. The overloaded version we use here requires two arguments: the stop order’s price and the position size of the order (PowerLanguage .NET Help, n.d.). With the trendLinePrice variable we set the stop’s price to the trend line’s price value, and so our stop is filled at this price or lower (see MultiCharts, 2014). We specify the order size with CurrentPosition.OpenLots, a property that returns the position size of the strategy’s current position (MultiCharts, 2014). With this property we ensure the stop-loss order is always submitted for the complete position.

When the strategy is short (the else if part) the exit short order is submitted with its Send() method, and so this short position will be closed at the trendLinePrice price or worse (that is, higher) (MultiCharts, 2014). Since this order’s size is also set to CurrentPosition.OpenLots, the strategy will be flat after this order is executed.

Tip: The stop orders are submitted with Send() as long as there’s an open position. We do that because, in order to keep an open order active in MultiCharts .NET, it needs to be resubmitted every time the strategy calculates (e.g., see MultiCharts Wiki, 2012); otherwise, the order is cancelled.

Other strategy examples that use trend lines are submitting market orders with a trend line and visually highlighting stop-loss orders with trend lines.

Summary

DrwTrendLine.Active is a property that returns a reference to the chart’s active trend line. When that reference is stored in an ITrendLineObject variable, that variable can be used in a strategy to access that line’s properties and methods. One of those methods is PriceValue(), which returns the line’s price value for any DateTime value on the chart. With that we’re able to submit stop-loss orders for the trend line’s price value of the chart. After a trading strategy has synced a manually opened position with ChangeMarketPosition(), we can trade that position by calling the orders’ 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_TrendLineStopLoss : SignalObject
    {
        public Example_TrendLineStopLoss(object _ctx) : base(_ctx) { }

        private IOrderPriced exitLongStop;
        private IOrderPriced exitShortStop;

        private ITrendLineObject trendLine;

        protected override void Create()
        {
            // Create the stop orders
            exitLongStop = OrderCreator.Stop(new 
                SOrderParameters(Contracts.UserSpecified, EOrderAction.Sell));

            exitShortStop = OrderCreator.Stop(new 
                SOrderParameters(Contracts.UserSpecified, EOrderAction.BuyToCover));
        }

        protected override void CalcBar()
        {
            // Sync with broker position
            if (StrategyInfo.MarketPosition == 0 &&
                StrategyInfo.MarketPositionAtBroker != 0)
            {
                ChangeMarketPosition(
                    StrategyInfo.MarketPositionAtBroker - 
                        StrategyInfo.MarketPosition,
                    StrategyInfo.AvgEntryPriceAtBroker);
            }

            // Only execute remainer of CalcBar() with an open position
            if (StrategyInfo.MarketPosition == 0)
                return;

            // Select trend line
            trendLine = DrwTrendLine.Active;

            // Proceed when a line was found
            if (trendLine != null)
            {
                // Change the line's appearance for confirmation
                trendLine.Size     = 2;
                trendLine.Color    = Color.DodgerBlue;
                trendLine.ExtRight = true;

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

                // Submit the stop-loss orders
                if (StrategyInfo.MarketPosition > 0)
                {
                    exitLongStop.Send(trendLinePrice, CurrentPosition.OpenLots);
                }
                else if (StrategyInfo.MarketPosition < 0)
                {
                    exitShortStop.Send(trendLinePrice, CurrentPosition.OpenLots);
                }
            }
        }
    }
}

References

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

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 19). Buy. Retrieved on June 15, 2015, from http://www.multicharts.com/trading-software/index.php/Buy

MultiCharts Wiki (2014, January 23). ChangeMarketPosition. Retrieved on June 15, 2015, from https://www.multicharts.com/trading-software/index.php/ChangeMarketPosition

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.