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