Close pending orders near open positions
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
Replies
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
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