Situation
You want to create a strategy that averages down an open, losing position by doubling the position size.

Programming example

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

namespace PowerLanguage.Strategy
{
    [IOGMode(IOGMode.Disabled)]
    public class StrategyExample_AveragingDown : SignalObject
    {
        private IOrderMarket buyOrder, sellOrder;
        int orderSize            = 0;
        int maxEntriesInPosition = 10;
        int maxOrderSize         = 1000;

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

        protected override void Create()
        {
            buyOrder = OrderCreator.MarketNextBar(new SOrderParameters(Contracts.UserSpecified, EOrderAction.Buy));
            sellOrder = OrderCreator.MarketNextBar(new SOrderParameters(Contracts.UserSpecified, EOrderAction.Sell));
        }

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

        protected override void CalcBar()
        {
            // Open the position with the first, initial trade
            if ((StrategyInfo.MarketPosition == 0) && (Bars.CurrentBar % 5 == 0))
            {
                Output.WriteLine("{0} - Opening a position with 1 contract.",
                    Bars.TimeValue.ToString("dd-MM-yy HH:mm:ss"));

                buyOrder.Send(1);
            }

            // If the open position is losing money, double the position size
            if ((Bars.CurrentBar % 20 != 0) && (CurrentPosition.OpenProfit < 0) &&
                    (Positions[0].OpenTrades.Count < maxEntriesInPosition))
            {
                // Double the current position size, but don't let the order size 
                // be larger than the user-defined maximum order size
                orderSize = Math.Min(CurrentPosition.OpenLots, maxOrderSize);

                Output.WriteLine("{0} - Current position size: {1}. Buying an additional {2} contract(s).",
                    Bars.TimeValue.ToString("dd-MM-yy HH:mm:ss"),
                    CurrentPosition.OpenLots,
                    orderSize);

                buyOrder.Send(orderSize);
            }

            // Close an open long position every 20 bars
            if ((StrategyInfo.MarketPosition > 0) && (Bars.CurrentBar % 20 == 0))
            {
                Output.WriteLine("{0} - Sending SELL order for {1} contract(s).",
                    Bars.TimeValue.ToString("dd-MM-yy HH:mm:ss"),
                    CurrentPosition.OpenLots);

                sellOrder.Send(CurrentPosition.OpenLots);
            }
        }
    }
}

Output of the code example

Applied to a chart the example looks like:

Example of an averaging down strategy in MultiCharts .NET

With an output similar to the following:

17-10-13 23:59:00 - Opening a position with 1 contract.
18-10-13 00:05:00 - Current position size: 1. Buying an additional 1 contract(s).
18-10-13 00:15:00 - Current position size: 2. Buying an additional 2 contract(s).
18-10-13 00:40:00 - Current position size: 4. Buying an additional 4 contract(s).
18-10-13 00:45:00 - Current position size: 8. Buying an additional 8 contract(s).
18-10-13 00:50:00 - Current position size: 16. Buying an additional 16 contract(s).
18-10-13 00:55:00 - Current position size: 32. Buying an additional 32 contract(s).
18-10-13 01:00:00 - Current position size: 64. Buying an additional 64 contract(s).
18-10-13 01:15:00 - Sending SELL order for 128 contract(s).
18-10-13 01:40:00 - Opening a position with 1 contract.
18-10-13 01:45:00 - Current position size: 1. Buying an additional 1 contract(s).
18-10-13 01:50:00 - Current position size: 2. Buying an additional 2 contract(s).
18-10-13 02:10:00 - Current position size: 4. Buying an additional 4 contract(s).
18-10-13 02:15:00 - Current position size: 8. Buying an additional 8 contract(s).
18-10-13 02:45:00 - Current position size: 16. Buying an additional 16 contract(s).
18-10-13 02:50:00 - Current position size: 32. Buying an additional 32 contract(s).
18-10-13 02:55:00 - Sending SELL order for 64 contract(s).
18-10-13 03:20:00 - Opening a position with 1 contract.
18-10-13 03:35:00 - Current position size: 1. Buying an additional 1 contract(s).
18-10-13 03:40:00 - Current position size: 2. Buying an additional 2 contract(s).
18-10-13 03:45:00 - Current position size: 4. Buying an additional 4 contract(s).
18-10-13 04:15:00 - Current position size: 8. Buying an additional 8 contract(s).
18-10-13 04:20:00 - Current position size: 16. Buying an additional 16 contract(s).
18-10-13 04:35:00 - Sending SELL order for 32 contract(s).

MultiCharts .NET programming example

We start with initializing the orders with the order parameter set to Contracts.UserSpecified:

protected override void Create()
{
    buyOrder = OrderCreator.MarketNextBar(new SOrderParameters(Contracts.UserSpecified, EOrderAction.Buy));
    sellOrder = OrderCreator.MarketNextBar(new SOrderParameters(Contracts.UserSpecified, EOrderAction.Sell));
}

This enables us to determine the order size programmatically instead of using the setting in the Strategy Properties window (meaning, the standard Contracts.Default).

Opening the initial long position in MultiCharts .NET

In the CalcBar() method (see here to learn more about these methods) we open the position with an initial trade:

// Open the position with the first, initial trade
if ((StrategyInfo.MarketPosition == 0) && (Bars.CurrentBar % 5 == 0))
{
    Output.WriteLine("{0} - Opening a position with 1 contract.",
        Bars.TimeValue.ToString("dd-MM-yy HH:mm:ss"));

    buyOrder.Send(1);
}

Two expressions are evaluated for this if statement. The market position (StrategyInfo.MarketPosition), which returns the current number of open contracts, needs to be zero (meaning no open position). Then the modulus operator checks if the current bar number is evenly divisible into 5 with no remainder, meaning that for every fifth bar this expression is true.

When both expressions are true, a little information is written to the output tab of the PowerLanguage Editor and the buy order with a quantity of 1 is submitted.

Averaging down in a MultiCharts .NET trading strategy

In the second code segment the actual averaging down happens:

// If the open position is losing money, double the position size
if ((Bars.CurrentBar % 20 != 0) && (CurrentPosition.OpenProfit < 0) &&
        (Positions[0].OpenTrades.Count < maxEntriesInPosition))
{
    // Double the current position size, but don't let the order size 
    // be larger than the user-defined maximum order size
    orderSize = Math.Min(CurrentPosition.OpenLots, maxOrderSize);

    Output.WriteLine("{0} - Current position size: {1}. Buying an additional {2} contract(s).",
        Bars.TimeValue.ToString("dd-MM-yy HH:mm:ss"),
        CurrentPosition.OpenLots,
        orderSize);

    buyOrder.Send(orderSize);
}

The three expressions here need to evaluate to true before this whole if statement returns true. First, the bar number should not divide evenly into 20, since that would conflict with the submitting of the sell order (see also further below). The second expression checks whether the open profit of the position (CurrentPosition.OpenProfit) is below zero (i.e. losing money).

The third and last expression checks if the number of open trades in the current position (Positions[0]) is less than the maximum allowable amount of entries (for which the variable maxEntriesInPosition was assigned a value of 10 in line 14). This prevents that strategy builds up a huge position.

If those three expressions are true, the order size is calculated. Since we want to double the position size, the additional buy order will need to have the same size as the current position (returned with the CurrentPosition.OpenLots property).

To prevent the strategy from sending a large order, Math.Min from the C# Math class is used to ensure that the order size is the smallest of the current position size and the variable maxOrderSize, which was assigned a value of 1,000 in line 15.

Note that for additional long or short entries in the same direction, you’ll need to allow this in the Strategy Properties window.

Closing the averaged down trading position

The last code segment is used to close the position:

// Close an open long position every 20 bars
if ((StrategyInfo.MarketPosition > 0) && (Bars.CurrentBar % 20 == 0))
{
    Output.WriteLine("{0} - Sending SELL order for {1} contract(s).",
        Bars.TimeValue.ToString("dd-MM-yy HH:mm:ss"),
        CurrentPosition.OpenLots);

    sellOrder.Send(CurrentPosition.OpenLots);
}

Two expressions need to be true before the sell order for the current position size is submitted: there needs to be an open position and the bar number needs to divide evenly into 20. This second expression ensures that the example orders are kept open for no longer than twenty bars.

The last expression is also mutually exclusive with the if statement for sending an additional long order (line 42). This prevents that, in the case of this example, both an additional buy order for a number of contracts and a sell order for the same amount of contracts are submitted on the same bar, which would give a remaining open long position.