Close pending orders near open positions

Created at 20 Nov 2017, 14:43
How’s your experience with the cTrader Platform?
Your feedback is crucial to cTrader's development. Please take a few seconds to share your opinion and help us improve your trading experience. Thanks!
AR

armstr.tradie

Joined 30.03.2016

Close pending orders near open positions
20 Nov 2017, 14:43


Hello,

I'm trying to create a grid type bot using pending orders. The problem I have at present is that my bot creates orders too close to already open positions. I wish to have a gap between my orders to avoid having multiple open positions at a similar price level.

Below is the code I have attempted to create to try and remove pending orders that are too close to an already open position. My bot creates pending orders in a simple uniform manner - for example, an order every 10 pips. What I do not wish to have is the bot creating a new order less than 10 pips away from a current open position. So there is only one trade every 10 pips in the current trend direction.

 

[Parameter("Trader Min Seperation", DefaultValue = 9)]
public double MinPipDistance { get; set; }      
  
#######################################################################################
        
        protected void PositionExistsBuy()
        {
            var longPosition = Positions.Find(Label, Symbol, TradeType.Buy);
            var MinBuyDistance = longPosition.EntryPrice + MinPipDistance * Symbol.PipSize;

            foreach (var order in PendingOrders)
            {
                if (order.TradeType == TradeType.Buy)
                {
                    if (order.TargetPrice < MinBuyDistance)
                    {
                        CancelPendingOrder(order);
                    }
                }
            }
        }

        protected void PositionExistsSell()
        {
            var shortPosition = Positions.Find(Label, Symbol, TradeType.Sell);
            var MinSellDistance = shortPosition.EntryPrice - MinPipDistance * Symbol.PipSize;

            foreach (var order in PendingOrders)
            {
                if (order.TradeType == TradeType.Sell)
                {
                    if (order.TargetPrice > MinSellDistance)
                    {
                        CancelPendingOrder(order);
                    }
                }
            }
        }

At present, the bot runs and creates the various pending orders in a grid just fine. But, it then stops the bot. I'm unsure where to go from here.

Note: It has separate conditions for buy and sell because in some circumstances I do not worry about having a buy or sell position at the same price level to act as a hedging position. 

Thank you


@armstr.tradie
Replies

PanagiotisCharalampous
20 Nov 2017, 14:55

Hi armstr.tradie,

Unfortunately the information you provide is not enough for us to help you. Could you please provide a complete cBot (it doesn't need to be the original, just one the reproduces the same behavior or error messages)?

Best Regards,

Panagiotis


@PanagiotisCharalampous

armstr.tradie
21 Nov 2017, 10:29

Thank you Panagiotis for your very quick reply.

Here is the code for my bot. As you can see it is based on a renko indicator. The indicator referenced in the bot is this one: /algos/indicators/show/1086 - full credit to 'tmc' who created it. The renko system helps set the price level and trend of the bot. 

using System;
using System.Linq;
using cAlgo.API;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;
using cAlgo.Indicators;

namespace cAlgo.Robots
{
    [Robot()]
    public class RENKO : Robot
    {
        //################################################## - Bot Label - ##################################################

        [Parameter(DefaultValue = "Abot")]
        public string Label { get; set; }

        //################################################## - RENKO details - #############################################

        [Parameter(DefaultValue = 250)]
        public double RenkoPips { get; set; }

        //public double RenkoPips = 50;

        public int BricksToShow = 10000;

        private Renko renko;

        //################################################## - Other parameters - #############################################

        [Parameter(DefaultValue = 1000)]
        public int Volume { get; set; }

        [Parameter("Take Profit (pips)", DefaultValue = 2000)]
        public double TakeProfit { get; set; }

        [Parameter("Stop Loss (pips)", DefaultValue = 1000)]
        public double StopLoss { get; set; }

        //################################################## - Dynamic stops - #############################################

        [Parameter("Break Even Trigger", DefaultValue = 200)]
        public double SL1Trigger { get; set; }

        [Parameter("Break Even", DefaultValue = 25)]
        public double SL1 { get; set; }

        [Parameter("Trailing Stop Trigger", DefaultValue = 1000)]
        public double SL2Trigger { get; set; }

        [Parameter("Trailing Stop Level", DefaultValue = 500)]
        public double SL2 { get; set; }

        //################################################## - Buy/Sell range - #############################################

        // Sets the level at which pending trades are separated from one another.
        [Parameter("Order Price Level", DefaultValue = 100)]
        public double TP1 { get; set; }

        // How many orders to be made when the bot runs.
        [Parameter("Number of Orders", DefaultValue = 31)]
        public int HowMuchPositions { get; set; }

        // Option to possible have multiple orders at the same level.
        [Parameter("Multiply Orders x ...", DefaultValue = 1)]
        public double MaxPendingOrders { get; set; }

        // Option designed to stop double-up of trades near a similar price level. 
        [Parameter("Minimum Trade Separation", DefaultValue = 90)]
        public double MinPipDistance { get; set; }

        //################################################## - OnStart - ##################################################

        protected override void OnStart()
        {
            renko = Indicators.GetIndicator<Renko>(RenkoPips, BricksToShow, 3, "SeaGreen", "Tomato");
        }

        //################################################## - OnTick - ##################################################

        protected override void OnTick()
        {
            BuyAndSell();
            BreakEven();
            TrailingStop();
            PositionExistsBuy();
            PositionExistsSell();
        }

        //################################################## - Buy & Sell Details - ##################################################

        protected void BuyAndSell()
        {
            double rClose = renko.Close.Last(0);
            double rOpen = renko.Open.Last(0);

            double Close = MarketSeries.Close.LastValue;
            double Open = MarketSeries.Open.LastValue;

            var MaxOrders = PendingOrders.Count < MaxPendingOrders;

            // Setup pending BUY
            if (Close > rOpen)
            {
                ClosePendingSell();
                if (MaxOrders)
                {
                    for (double i = 1; i < HowMuchPositions; i++)
                    {
                        PlaceStopOrder(TradeType.Buy, Symbol, Volume, rOpen + TP1 * i * Symbol.PipSize, Label, StopLoss, TakeProfit);

                    }
                }
            }

            // Setup pending SELL
            else if (Close < rOpen)
            {
                ClosePendingBuy();
                if (MaxOrders)
                {
                    for (double j = 1; j < HowMuchPositions; j++)
                    {
                        PlaceStopOrder(TradeType.Sell, Symbol, Volume, rOpen - TP1 * j * Symbol.PipSize, Label, StopLoss, TakeProfit);

                    }
                }
            }
        }

        //################################################## - Pending Order Close Logic - ##################################################

        protected void ClosePendingSell()
        {
            foreach (var order in PendingOrders)
            {
                if (order.TradeType == TradeType.Sell)
                    CancelPendingOrderAsync(order);
            }
        }

        protected void ClosePendingBuy()
        {
            foreach (var order in PendingOrders)
            {
                if (order.TradeType == TradeType.Buy)
                    CancelPendingOrderAsync(order);
            }
        }

        //################################################## - Removal of trade double up logic - ##################################################

        protected void PositionExistsBuy()
        {
            var longPosition = Positions.Find(Label, Symbol, TradeType.Buy);
            var MinBuyDistance = longPosition.EntryPrice + MinPipDistance * Symbol.PipSize;

            foreach (var order in PendingOrders)
            {
                if (order.TradeType == TradeType.Buy)
                {
                    //var pipDistance = Math.Abs((order.TargetPrice + longPosition.EntryPrice) / Symbol.PipValue);
                    if (order.TargetPrice < MinPipDistance)
                    {
                        CancelPendingOrder(order);
                    }
                }
            }
        }

        protected void PositionExistsSell()
        {
            var shortPosition = Positions.Find(Label, Symbol, TradeType.Sell);
            var MinSellDistance = shortPosition.EntryPrice - MinPipDistance * Symbol.PipSize;

            foreach (var order in PendingOrders)
            {
                if (order.TradeType == TradeType.Sell)
                {
                    //var pipDistance = Math.Abs((order.TargetPrice - shortPosition.EntryPrice) / Symbol.PipValue);
                    if (order.TargetPrice > MinPipDistance)
                    {
                        CancelPendingOrder(order);
                    }
                }
            }
        }

        //################################################## - Stop Loss Details - ##################################################

        protected void BreakEven()
        {
            double rClose = renko.Close.Last(0);
            double rOpen = renko.Open.Last(0);
            double Close = MarketSeries.Close.LastValue;

            var positions = Positions.FindAll(Label);
            if (positions == null)
                return;

            foreach (var position in positions)
            {
                if (position.Pips >= SL1Trigger)
                {
                    if (position.TradeType == TradeType.Buy)
                    {
                        var newStopLoss = position.EntryPrice + SL1 * Symbol.PipSize;
                        if (position.StopLoss < newStopLoss)
                            ModifyPosition(position, newStopLoss, position.TakeProfit);
                    }
                    else if (position.TradeType == TradeType.Sell)
                    {
                        var newStopLoss = position.EntryPrice - SL1 * Symbol.PipSize;
                        if (position.StopLoss > newStopLoss)
                            ModifyPosition(position, newStopLoss, position.TakeProfit);
                    }
                }
            }
        }

        protected void TrailingStop()
        {
            double rClose = renko.Close.Last(0);
            double rOpen = renko.Open.Last(0);
            double Close = MarketSeries.Close.LastValue;

            var positions = Positions.FindAll(Label);
            if (positions == null)
                return;

            foreach (var position in positions)
            {
                if (position.Pips >= SL2Trigger)
                {
                    if (position.TradeType == TradeType.Buy)
                    {
                        var newStopLoss2 = Symbol.Bid - SL2 * Symbol.PipSize;
                        if (position.StopLoss < newStopLoss2)
                            ModifyPosition(position, newStopLoss2, position.TakeProfit);
                    }
                    else if (position.TradeType == TradeType.Sell)
                    {
                        var newStopLoss2 = Symbol.Ask + SL2 * Symbol.PipSize;
                        if (position.StopLoss > newStopLoss2)
                            ModifyPosition(position, newStopLoss2, position.TakeProfit);

                    }
                }
            }
        }
    }
}

Thank you again for your help. 


@armstr.tradie

PanagiotisCharalampous
21 Nov 2017, 16:42

Dear armstr.tradie,

Your code throws an exception at the following sections

            var longPosition = Positions.Find(Label, Symbol, TradeType.Buy);
            var MinBuyDistance = longPosition.EntryPrice + MinPipDistance * Symbol.PipSize;
            var shortPosition = Positions.Find(Label, Symbol, TradeType.Sell);
            var MinSellDistance = shortPosition.EntryPrice - MinPipDistance * Symbol.PipSize;

In both cases you should check if longPosition/shortPosition are not null before proceeding. Let me know if this helps.

Best Regards,

Panagiotis


@PanagiotisCharalampous

armstr.tradie
21 Nov 2017, 20:37

Thanks again Panagiotis for the quick reply,

I've added 'not null' logic in the code, as you can see below. 

protected void PositionExistsBuy()
        {
            var longPosition = Positions.Find(Label, Symbol, TradeType.Buy);
            var MinBuyDistance = longPosition.EntryPrice + MinPipDistance * Symbol.PipSize;

            foreach (var order in PendingOrders)
            {
                if (longPosition != null)
                {
                    if (order.TradeType == TradeType.Buy)
                    {
                        //var pipDistance = Math.Abs((order.TargetPrice + longPosition.EntryPrice) / Symbol.PipValue);
                        if (order.TargetPrice < MinPipDistance)
                        {
                            CancelPendingOrder(order);
                        }
                    }
                }
            }
        }

        protected void PositionExistsSell()
        {
            var shortPosition = Positions.Find(Label, Symbol, TradeType.Sell);
            var MinSellDistance = shortPosition.EntryPrice - MinPipDistance * Symbol.PipSize;

            foreach (var order in PendingOrders)
            {
                if (shortPosition != null)
                {
                    if (order.TradeType == TradeType.Sell)
                    {
                        //var pipDistance = Math.Abs((order.TargetPrice - shortPosition.EntryPrice) / Symbol.PipValue);
                        if (order.TargetPrice > MinPipDistance)
                        {
                            CancelPendingOrder(order);
                        }
                    }
                }
            }
        }

Unfortunately,  again I get the same issue. It starts the robot, creates a series of pending orders, closes them, and then stops the bot.

Perhaps taking a different approach may be better?. My understanding of C# is not as advanced as others - so I more than welcome any other ideas that could help.

Thank you


@armstr.tradie

PanagiotisCharalampous
22 Nov 2017, 11:17

Hi armstr.tradie,

You have placed the check in the wrong place. See the full source code for the cBot below

using System;
using System.Linq;
using cAlgo.API;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;
using cAlgo.Indicators;

namespace cAlgo.Robots
{
    [Robot()]
    public class RENKO : Robot
    {
        //################################################## - Bot Label - ##################################################

        [Parameter(DefaultValue = "Abot")]
        public string Label { get; set; }

        //################################################## - RENKO details - #############################################

        [Parameter(DefaultValue = 250)]
        public double RenkoPips { get; set; }

        //public double RenkoPips = 50;

        public int BricksToShow = 10000;

        private Renko renko;

        //################################################## - Other parameters - #############################################

        [Parameter(DefaultValue = 1000)]
        public int Volume { get; set; }

        [Parameter("Take Profit (pips)", DefaultValue = 2000)]
        public double TakeProfit { get; set; }

        [Parameter("Stop Loss (pips)", DefaultValue = 1000)]
        public double StopLoss { get; set; }

        //################################################## - Dynamic stops - #############################################

        [Parameter("Break Even Trigger", DefaultValue = 200)]
        public double SL1Trigger { get; set; }

        [Parameter("Break Even", DefaultValue = 25)]
        public double SL1 { get; set; }

        [Parameter("Trailing Stop Trigger", DefaultValue = 1000)]
        public double SL2Trigger { get; set; }

        [Parameter("Trailing Stop Level", DefaultValue = 500)]
        public double SL2 { get; set; }

        //################################################## - Buy/Sell range - #############################################

        // Sets the level at which pending trades are separated from one another.
        [Parameter("Order Price Level", DefaultValue = 100)]
        public double TP1 { get; set; }

        // How many orders to be made when the bot runs.
        [Parameter("Number of Orders", DefaultValue = 31)]
        public int HowMuchPositions { get; set; }

        // Option to possible have multiple orders at the same level.
        [Parameter("Multiply Orders x ...", DefaultValue = 1)]
        public double MaxPendingOrders { get; set; }

        // Option designed to stop double-up of trades near a similar price level. 
        [Parameter("Minimum Trade Separation", DefaultValue = 90)]
        public double MinPipDistance { get; set; }

        //################################################## - OnStart - ##################################################

        protected override void OnStart()
        {
            renko = Indicators.GetIndicator<Renko>(RenkoPips, BricksToShow, 3, "SeaGreen", "Tomato");
        }

        //################################################## - OnTick - ##################################################

        protected override void OnTick()
        {
            BuyAndSell();
            BreakEven();
            TrailingStop();
            PositionExistsBuy();
            PositionExistsSell();
        }

        //################################################## - Buy & Sell Details - ##################################################

        protected void BuyAndSell()
        {
            double rClose = renko.Close.Last(0);
            double rOpen = renko.Open.Last(0);

            double Close = MarketSeries.Close.Last(0);
            double Open = MarketSeries.Open.Last(0);

            var MaxOrders = PendingOrders.Count < MaxPendingOrders;
            // Setup pending BUY
            if (Close > rOpen)
            {
                ClosePendingSell();
                if (MaxOrders)
                {
                    for (double i = 1; i < HowMuchPositions; i++)
                    {
                        PlaceStopOrder(TradeType.Buy, Symbol, Volume, rOpen + TP1 * i * Symbol.PipSize, Label, StopLoss, TakeProfit);

                    }
                }
            }

            // Setup pending SELL
            else if (Close < rOpen)
            {
                ClosePendingBuy();
                if (MaxOrders)
                {
                    for (double j = 1; j < HowMuchPositions; j++)
                    {
                        PlaceStopOrder(TradeType.Sell, Symbol, Volume, rOpen - TP1 * j * Symbol.PipSize, Label, StopLoss, TakeProfit);
                    }
                }
            }
        }

        //################################################## - Pending Order Close Logic - ##################################################

        protected void ClosePendingSell()
        {
            foreach (var order in PendingOrders)
            {
                if (order.TradeType == TradeType.Sell)
                    CancelPendingOrderAsync(order);
            }
        }

        protected void ClosePendingBuy()
        {
            foreach (var order in PendingOrders)
            {
                if (order.TradeType == TradeType.Buy)
                    CancelPendingOrderAsync(order);
            }
        }

        //################################################## - Removal of trade double up logic - ##################################################

        protected void PositionExistsBuy()
        {
            var longPosition = Positions.Find(Label, Symbol, TradeType.Buy);
            if (longPosition != null)
            {
                var MinBuyDistance = longPosition.EntryPrice + MinPipDistance * Symbol.PipSize;

                foreach (var order in PendingOrders)
                {

                    if (order.TradeType == TradeType.Buy)
                    {
                        //var pipDistance = Math.Abs((order.TargetPrice + longPosition.EntryPrice) / Symbol.PipValue);
                        if (order.TargetPrice < MinPipDistance)
                        {
                            CancelPendingOrder(order);
                        }
                    }
                }
            }
        }

        protected void PositionExistsSell()
        {
            var shortPosition = Positions.Find(Label, Symbol, TradeType.Sell);
            if (shortPosition != null)
            {
                var MinSellDistance = shortPosition.EntryPrice - MinPipDistance * Symbol.PipSize;

                foreach (var order in PendingOrders)
                {

                    if (order.TradeType == TradeType.Sell)
                    {
                        //var pipDistance = Math.Abs((order.TargetPrice - shortPosition.EntryPrice) / Symbol.PipValue);
                        if (order.TargetPrice > MinPipDistance)
                        {
                            CancelPendingOrder(order);
                        }
                    }
                }
            }
        }

        //################################################## - Stop Loss Details - ##################################################

        protected void BreakEven()
        {
            double rClose = renko.Close.Last(0);
            double rOpen = renko.Open.Last(0);
            double Close = MarketSeries.Close.LastValue;

            var positions = Positions.FindAll(Label);
            if (positions == null)
                return;

            foreach (var position in positions)
            {
                if (position.Pips >= SL1Trigger)
                {
                    if (position.TradeType == TradeType.Buy)
                    {
                        var newStopLoss = position.EntryPrice + SL1 * Symbol.PipSize;
                        if (position.StopLoss < newStopLoss)
                            ModifyPosition(position, newStopLoss, position.TakeProfit);
                    }
                    else if (position.TradeType == TradeType.Sell)
                    {
                        var newStopLoss = position.EntryPrice - SL1 * Symbol.PipSize;
                        if (position.StopLoss > newStopLoss)
                            ModifyPosition(position, newStopLoss, position.TakeProfit);
                    }
                }
            }
        }

        protected void TrailingStop()
        {
            double rClose = renko.Close.Last(0);
            double rOpen = renko.Open.Last(0);
            double Close = MarketSeries.Close.LastValue;

            var positions = Positions.FindAll(Label);
            if (positions == null)
                return;

            foreach (var position in positions)
            {
                if (position.Pips >= SL2Trigger)
                {
                    if (position.TradeType == TradeType.Buy)
                    {
                        var newStopLoss2 = Symbol.Bid - SL2 * Symbol.PipSize;
                        if (position.StopLoss < newStopLoss2)
                            ModifyPosition(position, newStopLoss2, position.TakeProfit);
                    }
                    else if (position.TradeType == TradeType.Sell)
                    {
                        var newStopLoss2 = Symbol.Ask + SL2 * Symbol.PipSize;
                        if (position.StopLoss > newStopLoss2)
                            ModifyPosition(position, newStopLoss2, position.TakeProfit);

                    }
                }
            }
        }
    }
}

I hope this helps!

Best Regards,

Panagiotis


@PanagiotisCharalampous

armstr.tradie
15 Dec 2017, 00:06

It worked!

Thank you, Panagiotis for your help. Sorry for the late reply. 

With a bit of tweaking of the code I was able to get it to work in a satisfactory manner. 

Here is my code for others to use if they are interested. Please suggest any improvements.

 

//Sets the minimum distance between a pending order and an open position.

        [Parameter("Minimum Trade Separation", DefaultValue = 3)]
        public double MinPipDistance { get; set; }
//Removes any pending order at the same level or near an already existing position of the same TradeType

        protected void PositionExists()
        {
            var longPosition = Positions.Find(Label, Symbol, TradeType.Buy);
            var shortPosition = Positions.Find(Label, Symbol, TradeType.Sell);

            if (longPosition != null)
            {
                var MinBuyDistance = longPosition.EntryPrice + MinPipDistance * Symbol.PipSize;

                foreach (var order in PendingOrders)
                {
                    if (order.TradeType == TradeType.Buy)
                    {
                        if ((order.TargetPrice >= longPosition.EntryPrice) && (order.TargetPrice < MinBuyDistance))
                        {
                            CancelPendingOrder(order);
                        }
                    }
                }
            }

            else if (shortPosition != null)
            {
                var MinSellDistance = shortPosition.EntryPrice - MinPipDistance * Symbol.PipSize;

                foreach (var order in PendingOrders)
                {
                    if (order.TradeType == TradeType.Sell)
                    {
                        if ((order.TargetPrice <= shortPosition.EntryPrice) && (order.TargetPrice > MinSellDistance))
                        {
                            CancelPendingOrder(order);
                        }
                    }
                }
            }
        }

Thank you again Panagiotis for your help. You have made using cAlgo that much easier and I very grateful for all your time and help. 


@armstr.tradie