Situation
You want to know how to use a take profit order in MultiCharts .NET that is a specified amount of ticks away from the entry price of the order.

Programming example

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

namespace PowerLanguage.Strategy
{
    [IOGMode(IOGMode.Enabled)]
    public class ExampleTakeProfit : SignalObject
    {
        private IOrderMarket buyOrder, sellTimeStopOrder;
        private IOrderPriced sellTPorder;
        private double takeProfitPrice;

        [Input]
        public int TakeProfitTicks { get; set; }

        public ExampleTakeProfit(object _ctx) : base(_ctx) { }

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

            sellTPorder = OrderCreator.Limit(new SOrderParameters(
                Contracts.Default, "TakeProfit", EOrderAction.Sell));

            sellTimeStopOrder = OrderCreator.MarketNextBar(new SOrderParameters(
                Contracts.Default, "TimeStop", EOrderAction.Sell));

            TakeProfitTicks = 200; // Default value
        }

        protected override void StartCalc()
        {
            Output.Clear();     // Clear Editor Output tab
        }

        protected override void CalcBar()
        {
            // When flat, enter a long position every fifth bar
            if ((StrategyInfo.MarketPosition == 0) && (Bars.CurrentBar % 5 == 0))
            {
                // Submit the order at the open of the bar
                if (Bars.Status == EBarState.Open)
                {
                    buyOrder.Send();

                    Output.WriteLine("{0} - Submitted buy order",
                        Bars.Time[0].ToString("d-M HH:mm"));
                }
            }

            // Management of open long position
            if (StrategyInfo.MarketPosition > 0)
            {
                // First, when the position is just opened,
                // we need to calculate the take profit price
                int barsInPosition = Bars.CurrentBar -
                    Positions[0].OpenTrades[0].EntryOrder.BarNumber;

                // When the position is just opened, calculate the take profit price
                if (barsInPosition == 0)
                {
                    takeProfitPrice = Positions[0].OpenTrades[0].EntryOrder.Price +
                        (TakeProfitTicks * (Bars.Info.MinMove / Bars.Info.PriceScale));

                    // Only output info to the Output log at the open
                    // of the bar (prevents cluttering the log)
                    if (Bars.Status == EBarState.Open)
                    {
                        Output.WriteLine("{0} - Take profit price: {1}",
                            Bars.Time[0].ToString("d-M HH:mm"),
                            takeProfitPrice);
                    }
                }

                // Submit take profit order as long as there is an open long position
                sellTPorder.Send(takeProfitPrice);

                if (Bars.Status == EBarState.Close)     // Prevents cluttering the output
                {
                    Output.WriteLine("{0} - Sending limit order @ {1}",
                        Bars.Time[0].ToString("d-M HH:mm"),
                        takeProfitPrice);
                }

                // To prevent positions that are never closed, exit after more than 5 bars
                if (barsInPosition > 5)
                {
                    sellTimeStopOrder.Send();

                    if (Bars.Status == EBarState.Open)  // Prevents cluttering the output
                    {
                        Output.WriteLine("{0} - Sending time stop order",
                            Bars.Time[0].ToString("d-M HH:mm"));
                    }
                }
            }
        }
    }
}

Output of programming example

Applied to a chart the strategy looks similar to:

Example of a take profit order in MultiCharts .NET

And with an output corresponding to the trades in the image above:

20-12 14:00 - Submitted buy order
20-12 14:00 - Sending limit order @ 1,36788
20-12 16:00 - Sending limit order @ 1,36788
20-12 23:59 - Submitted buy order
20-12 23:59 - Sending limit order @ 1,37008
23-12 02:00 - Sending limit order @ 1,37008
23-12 04:00 - Sending limit order @ 1,37008
23-12 06:00 - Sending limit order @ 1,37008
23-12 08:00 - Sending limit order @ 1,37008
23-12 10:00 - Sending limit order @ 1,37008
23-12 12:00 - Sending time stop order
23-12 20:00 - Submitted buy order
23-12 20:00 - Sending limit order @ 1,37198
23-12 22:00 - Sending limit order @ 1,37198
23-12 23:59 - Sending limit order @ 1,37198
24-12 02:00 - Sending limit order @ 1,37198
24-12 04:00 - Sending limit order @ 1,37198
24-12 06:00 - Sending limit order @ 1,37198
24-12 08:00 - Sending time stop order
24-12 16:00 - Submitted buy order
24-12 16:00 - Sending limit order @ 1,37023
24-12 18:00 - Sending limit order @ 1,37023
24-12 20:00 - Sending limit order @ 1,37023
24-12 22:00 - Sending limit order @ 1,37023
24-12 23:59 - Sending limit order @ 1,37023
25-12 23:59 - Sending limit order @ 1,37023
26-12 02:00 - Sending time stop order
26-12 10:00 - Submitted buy order
26-12 10:00 - Sending limit order @ 1,37056
26-12 12:00 - Sending limit order @ 1,37056
26-12 14:00 - Sending limit order @ 1,37056
26-12 16:00 - Sending limit order @ 1,37056
26-12 18:00 - Sending limit order @ 1,37056
26-12 20:00 - Sending limit order @ 1,37056
26-12 22:00 - Sending time stop order
27-12 06:00 - Submitted buy order

Take profit orders in MultiCharts .NET

Take profit orders are declared with the IOrderPriced order interface (see line 13 of the example) and the OrderCreator.Limit() method (lines 26-27) is used to create the actual order object (MultiCharts, 2013).

Furthermore, when submitting the limit order (line 80), the limit price will need to be passed into the Send() method.

MultiCharts .NET programming example

We start the example by declaring three order interface objects:

private IOrderMarket buyOrder, sellTimeStopOrder;
private IOrderPriced sellTPorder;

Here we see that regular market orders use the IOrderMarket order interface but that the take profit order (sellTPOrder) uses the IOrderPriced order interface.

Next the order objects are initialised in the Create() method:

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

    sellTPorder = OrderCreator.Limit(new SOrderParameters(
        Contracts.Default, "TakeProfit", EOrderAction.Sell));

    sellTimeStopOrder = OrderCreator.MarketNextBar(new SOrderParameters(
        Contracts.Default, "TimeStop", EOrderAction.Sell));

    TakeProfitTicks = 200; // Default value
}

To create a market order the OrderCreator.MarketNextBar() method is used while the limit order requires the use of the OrderCreator.Limit() method.

Both sell orders (sellTPorder and sellTimeStopOrder) use an additional string argument to specify the name of the order ("TakeProfit" and "TimeStop" respectively). This helps to keep both sell orders apart in the Performance Report or trading chart.

Opening a long position in MultiCharts .NET

In the CalcBar() override method a long position is opened when there is no open market position and when the bar number is evenly divisible by five:

// When flat, enter a long position every fifth bar
if ((StrategyInfo.MarketPosition == 0) && (Bars.CurrentBar % 5 == 0))
{
    // Submit the order at the open of the bar
    if (Bars.Status == EBarState.Open)
    {
        buyOrder.Send();

        Output.WriteLine("{0} - Submitted buy order",
            Bars.Time[0].ToString("d-M HH:mm"));
    }
}

If both conditions in the if statement evaluate to true, the market order will be send immediately at the open of the bar (when Bars.Status == EBarState.Open evaluates to true).

To keep track of the strategy, some information is printed to the PowerLanguage Editor output log.

Calculating the limit order price

The second part of the CalcBar() method deals with managing the open long position (meaning, when StrategyInfo.MarketPosition > 0, see line 56, evaluates to true):

// First, when the position is just opened,
// we need to calculate the take profit price
int barsInPosition = Bars.CurrentBar -
    Positions[0].OpenTrades[0].EntryOrder.BarNumber;

// When the position is just opened, calculate the take profit price
if (barsInPosition == 0)
{
    takeProfitPrice = Positions[0].OpenTrades[0].EntryOrder.Price +
        (TakeProfitTicks * (Bars.Info.MinMove / Bars.Info.PriceScale));

    // Only output info to the Output log at the open
    // of the bar (prevents cluttering the log)
    if (Bars.Status == EBarState.Open)
    {
        Output.WriteLine("{0} - Take profit price: {1}",
            Bars.Time[0].ToString("d-M HH:mm"),
            takeProfitPrice);
    }
}

Before the take profit price is calculated, the number of bars in the current position are determined. For this the bar number of the first open order (Positions[0].OpenTrades[0].EntryOrder.BarNumber) is subtracted from the current bar number (Bars.CurrentBar).

When the position is opened zero bars ago (meaning that it is opened on the current bar), the take profit limit price is calculated. First the price movement value of one tick is calculated (Bars.Info.MinMove / Bars.Info.PriceScale). This is subsequently multiplied by the amount of ticks we want to book as a profit (TakeProfitTicks).

We specified the TakeProfitTicks value as an input (see lines 16-17) and gave this a default value of 200 in line 32 (meaning, in the case of the EUR/USD symbol, 200 fractional pips or 20 whole pips).

Finally, this calculated amount of profit (in terms of price movement) is added to the entry price of the first order of the current open position (Positions[0].OpenTrades[0].EntryOrder.Price).

Once per bar, at the bar’s open, information about the take profit price is printed to the Output tab of the PowerLanguage Editor to keep track of the strategy (lines 69-76).

Submitting the take profit order

With the limit price calculated, the actual take profit order is submitted:

// Submit take profit order as long as there is an open long position
sellTPorder.Send(takeProfitPrice);

Note that the submitting of this order is dependent on a long market position (which we checked in the if statement in line 56). Managed orders, that are used in this example, are kept active as long as they are resubmitted. But when you stop resubmitting them, they will automatically be cancelled by MultiCharts .NET (Henry MultiCharts, 2013).

For our example this means that, as long as there is an open long position, the take profit order will be submitted (and kept active). But when the long position is closed, for example due to the time stop, the take profit order will be cancelled.

Another point to note is that this strategy uses intra-bar order generation (IOG; see line 9). This means that the take profit order will be submitted on the tick immediately after the position has been opened (in real-time trading) or as soon as the Bar Magnifier settings allow (during backtesting).

Should this strategy not have used IOG, the strategy would only have been recalculated on the bar close (MultiCharts, 2013) - which would give a relatively large time gap between the open of the position and the submitting of the limit order.

Adding a time stop in MultiCharts .NET

Just to prevent that the take profit order is never triggered in this example, a time stop based on the number of bars is added:

// To prevent positions that are never closed, exit after more than 5 bars
if (barsInPosition > 5)
{
    sellTimeStopOrder.Send();

    if (Bars.Status == EBarState.Open)  // Prevents cluttering the output
    {
        Output.WriteLine("{0} - Sending time stop order",
            Bars.Time[0].ToString("d-M HH:mm"));
    }
}

Here we submit the sell market order (line 92) as soon as there are more than five bars since the entry order.

Key points:

  • Take profit orders are declared with the IOrderPriced order interface;
  • These order objects are initialised with the OrderCreator.Limit() method;
  • When submitting the order with the Send() method, the limit price needs to be specified;
  • When using managed orders, the limit order is active as long as it is submitted on every CalcBar() calculation.
References

Henry MultiCharts (December 2013). MultiCharts .NET FAQ forum discussion topic. Retrieved from http://www.multicharts.com/discussion/viewtopic.php?f=19&t=45848#p100799

MultiCharts (April 2013). MultiCharts .NET Programming Guide (version 1.0). Retrieved from http://www.multicharts.com/downloads/MultiCharts.NET-ProgrammingGuide-v1.0.pdf