Modifying the pending order
Modifying the pending order
16 Jul 2020, 15:32
Dear All,
I have the following code in my Cbot which enable to modify the pending order by maintain the distance of pip step. But please help me to modify the code to allow changes to be made if the distance is less than pip step and modify the distance only if the distance is more than pip step.
if (constantDistanceHedge)
{
foreach (var order in PendingOrders)
{
if (order.Label == label && order.SymbolName == SymbolName && order.Comment != "Initial Order" && order != null)
{
var targetPrice = order.TradeType == TradeType.Buy ? Symbol.Bid : Symbol.Ask;
if ((targetPrice - order.TargetPrice) / Symbol.PipSize > Pipstep * Symbol.PipSize && order.TradeType == TradeType.Sell)
{
ModifyPendingOrderAsync(order, targetPrice - Pipstep * Symbol.PipSize);
}
else if ((order.TargetPrice - targetPrice) / Symbol.PipSize > Pipstep * Symbol.PipSize && order.TradeType == TradeType.Buy)
{
ModifyPendingOrderAsync(order, targetPrice + Pipstep * Symbol.PipSize);
}
}
}
Available for any clarifications
Thanks in Advance
R. Vadivelan
Replies
PanagiotisCharalampous
17 Jul 2020, 08:51
Hi Vadivelan,
Personally I did not understand what are you trying to do. It would be easier if you provided the complete cBot code and backtesting examples of what does the cBot do at the moment and what should it do instead.
Best Regards,
Panagiotis
@PanagiotisCharalampous
velu130486
17 Jul 2020, 14:21
RE:
Hi Panagiotis,
Please find the Cbot which I had developed with a consultant. There is no major problem in the Cbot, but I want to make the changes/update only in the section constantDistanceHedge.
If this option is not enabled then the distance between market position and pending order will remain fixed, If I enable this option to yes, then the distance between market position and pending order is keep on updated with the distance of certain pips or based on ATR.
Now I want to adjust the gap only if the distance is more than the hedge gap, if it is less than hedge gap then the order price should remain fixed. Let say Buy position is created at 119.60 and I enabled the constantDistanceHedge with 20 pips.
As soon as the Buy position is created at 119.60 Cbot will create the pending sell order at 119.40 (i.e.) with the distance of 20 pips. If the price moves up I want the pending order price to be adjusted, but the price goes in opposite, I would like to keep the position at the same price so that it gets triggered to form a hedge.
Currently with constantDistanceHedge mode enabled gap will be adjusted in both direction, (i.e.) when the price goes down the position will also be moved down which means the position will not triggered.
Please let me know if I am not clear.
using System;
using System.Linq;
using cAlgo.API;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;
using cAlgo.Indicators;
namespace cAlgo.Robots
{
[Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
public class VadivelanRangeBot : Robot
{
[Parameter("Label Prefix", DefaultValue = "VRB")]
public string label { get; set; }
[Parameter("Running Mode", DefaultValue = RunningLevel.Standard)]
public RunningLevel runningMode { get; set; }
[Parameter("Initial orders pips away", DefaultValue = 5, MinValue = 1)]
public double initialOrderPipsAway { get; set; }
[Parameter("Hedge Gap Type", Group = "Hedge Gap", DefaultValue = GapType.ATR)]
public GapType gapType { get; set; }
[Parameter("Hedge Gap ATR Multiplier", Group = "Hedge Gap", DefaultValue = 3, MinValue = 1, Step = 0.1)]
public double hedgeGapMultiplier { get; set; }
[Parameter("Hedge order pips away", Group = "Hedge Gap", DefaultValue = 20, MinValue = 1)]
public double hedgeOrderPipsAway { get; set; }
[Parameter("Enable Constant Distance Hedge", DefaultValue = false)]
public bool constantDistanceHedge { get; set; }
[Parameter("Max Equity Drawdown %", DefaultValue = 10, MinValue = 1)]
public double maxEquityDrawdown { get; set; }
[Parameter("Stop Loss Type", DefaultValue = StopLossType.ATR)]
public StopLossType stoplossType { get; set; }
[Parameter("Stop Loss (pips)", DefaultValue = 100, MinValue = 1, Step = 1)]
public double stopLoss { get; set; }
[Parameter("Enable Add Spread to SL", DefaultValue = false)]
public bool enableAddSpread { get; set; }
[Parameter("Volume (lots)", DefaultValue = 0.1, MinValue = 0.01, Step = 0.01)]
public double volume { get; set; }
[Parameter("ATR Risk (%)", DefaultValue = 1, MinValue = 0.5)]
public double atrRiskPercentage { get; set; }
[Parameter("Take Profit Type", DefaultValue = TakeProfitType.SLMultiplier)]
public TakeProfitType takeProfitType { get; set; }
[Parameter("Take Profit (pips)", DefaultValue = 100, MinValue = 1, Step = 1)]
public double takeProfit { get; set; }
[Parameter("Take Profit (SL Multiplier)", DefaultValue = 1, MinValue = 1)]
public double takeProfitMultiplier { get; set; }
[Parameter("Type", Group = "Trailing Stop", DefaultValue = TrailingStopType.ATR)]
public TrailingStopType trailingStopType { get; set; }
[Parameter("ATR TSL Periods", Group = "Trailing Stop", DefaultValue = 21)]
public int atrPeriods { get; set; }
[Parameter("ATR TSL Multiplier", Group = "Trailing Stop", DefaultValue = 3)]
public double ATRMultiplier { get; set; }
[Parameter("Resume Bot", DefaultValue = false)]
public bool resumeBot { get; set; }
private bool isExecuting = false;
private double sellEntryPrice;
private double buyEntryPrice;
private double maxEquity;
private double stopLimitRangePips;
public double ATRMinimuStopLoss;
private AverageTrueRange atr;
private RelativeStrengthIndex rsi;
protected override void OnStart()
{
Print("The number of Digits the current symbol has is: {0}", Symbol.Digits);
label = label + SymbolName + TimeFrame;
atrRiskPercentage = atrRiskPercentage / 100;
stopLimitRangePips = 100;
ATRMinimuStopLoss = 5;
Positions.Opened += PositionsOnOpened;
volume = Symbol.QuantityToVolumeInUnits(volume);
volume = Symbol.NormalizeVolumeInUnits(volume);
maxEquityDrawdown = maxEquityDrawdown / 100;
maxEquity = Account.Equity;
atr = Indicators.AverageTrueRange(atrPeriods, MovingAverageType.Simple);
rsi = Indicators.RelativeStrengthIndex(MarketSeries.Close, 14);
if (!resumeBot)
{
isExecuting = true;
PlaceInitialTrades(TradeType.Buy);
PlaceInitialTrades(TradeType.Sell);
}
}
protected override void OnTick()
{
if (Account.Equity > maxEquity)
{
maxEquity = Account.Equity;
}
if ((maxEquity - Account.Equity) / maxEquity >= maxEquityDrawdown)
{
CloseAllOrders();
CloseAllPositions();
Print("Max Drawdown Hit - Bot Shutdown");
Stop();
}
Chart.DrawStaticText("MaxEquity", "Max Equity: $" + maxEquity, VerticalAlignment.Top, HorizontalAlignment.Right, Color.LimeGreen);
int orderCount = CountOrders();
int positionCount = CountPositions();
if (orderCount + positionCount == 0 && !isExecuting)
{
isExecuting = true;
PlaceInitialTrades(TradeType.Buy);
PlaceInitialTrades(TradeType.Sell);
return;
}
if (constantDistanceHedge)
{
foreach (var order in PendingOrders)
{
if (order.Label == label && order.SymbolName == SymbolName && order.Comment != "Initial Order" && order != null)
{
var targetPrice = order.TradeType == TradeType.Buy ? Symbol.Bid : Symbol.Ask;
if ((targetPrice - order.TargetPrice) / Symbol.PipSize > GapTypePips() * Symbol.PipSize && order.TradeType == TradeType.Sell)
{
ModifyPendingOrderAsync(order, targetPrice - GapTypePips() * Symbol.PipSize);
}
else if ((order.TargetPrice - targetPrice) / Symbol.PipSize > GapTypePips() * Symbol.PipSize && order.TradeType == TradeType.Buy)
{
ModifyPendingOrderAsync(order, targetPrice + GapTypePips() * Symbol.PipSize);
}
}
}
}
DisplayChartInfo();
ATRTrailingStop();
MomentumTrailingStop();
}
protected override void OnStop()
{
// Put your deinitialization logic here
}
private void PositionsOnOpened(PositionOpenedEventArgs args)
{
var position = args.Position;
if (position.Label == label && position.SymbolName == SymbolName)
{
if (stoplossType == StopLossType.None)
{
ModifyPosition(position, null, position.TakeProfit);
}
if (position.TradeType == TradeType.Sell)
{
sellEntryPrice = position.EntryPrice;
}
else
{
double newStopLoss = ATRSLPips() + addSpreadToStopLoss();
newStopLoss = Math.Round(newStopLoss, 0);
buyEntryPrice = position.EntryPrice;
}
isExecuting = false;
if (position.Comment != null)
{
string comment = position.Comment;
{
if (comment == "Initial Order")
{
CloseAllOrders();
if (runningMode == RunningLevel.Standard)
{
double newStopLoss = ATRSLPips() + addSpreadToStopLoss();
newStopLoss = Math.Round(newStopLoss, 0);
volume = CalculateVolume(newStopLoss);
double entryPrice = position.TradeType == TradeType.Buy ? Symbol.Bid - GapTypePips() * Symbol.PipSize : Symbol.Bid + GapTypePips() * Symbol.PipSize;
PlaceTrade(position.TradeType == TradeType.Buy ? TradeType.Sell : TradeType.Buy, entryPrice);
return;
}
if (runningMode == RunningLevel.TrendMode)
{
return;
}
if (runningMode == RunningLevel.TrendModePlusHedge)
{
double newStopLoss = ATRSLPips() + addSpreadToStopLoss();
newStopLoss = Math.Round(newStopLoss, 0);
volume = CalculateVolume(newStopLoss);
double entryPrice = position.TradeType == TradeType.Buy ? Symbol.Bid - (GapTypePips() * 2) * Symbol.PipSize : Symbol.Bid + (GapTypePips() * 2) * Symbol.PipSize;
PlaceTrade(position.TradeType == TradeType.Buy ? TradeType.Sell : TradeType.Buy, entryPrice);
entryPrice = position.TradeType == TradeType.Buy ? Symbol.Bid + (GapTypePips()) * Symbol.PipSize : Symbol.Bid - (GapTypePips() * Symbol.PipSize);
PlaceTrade(position.TradeType, entryPrice);
return;
}
}
}
}
}
}
private void CloseAllOrders()
{
foreach (var order in PendingOrders)
{
if (order.Label == label && order.SymbolName == SymbolName)
{
CancelPendingOrderAsync(order);
}
}
}
private void CloseAllPositions()
{
foreach (var position in Positions)
{
if (position.Label == label && position.SymbolName == SymbolName && position != null)
{
ClosePositionAsync(position);
}
}
}
private int CountOrders()
{
int count = 0;
foreach (var order in PendingOrders)
{
if (order.Label == label && order.SymbolName == SymbolName)
{
count++;
}
}
return count;
}
private int CountPositions()
{
var positions = Positions.FindAll(label, SymbolName);
return positions.Length;
}
private void PlaceInitialTrades(TradeType tradeType)
{
double currentPrice = tradeType == TradeType.Buy ? Symbol.Bid : Symbol.Ask;
double newStopLoss = ATRSLPips() + addSpreadToStopLoss();
newStopLoss = Math.Round(newStopLoss, 0);
volume = CalculateVolume(newStopLoss);
double entryPrice = tradeType == TradeType.Sell ? currentPrice - initialOrderPipsAway * Symbol.PipSize - addSpreadToStopLoss() * Symbol.PipSize : currentPrice + initialOrderPipsAway * Symbol.PipSize + addSpreadToStopLoss() * Symbol.PipSize;
if (currentPrice < entryPrice && tradeType == TradeType.Sell || currentPrice > entryPrice && tradeType == TradeType.Buy)
{
PlaceLimitOrderAsync(tradeType, SymbolName, volume, entryPrice, label, newStopLoss, TakeProfit(), null, "Initial Order");
}
else if (currentPrice > entryPrice && tradeType == TradeType.Sell || currentPrice < entryPrice && tradeType == TradeType.Buy)
{
PlaceStopLimitOrderAsync(tradeType, SymbolName, volume, entryPrice, stopLimitRangePips, label, newStopLoss, TakeProfit(), null, "Initial Order");
}
}
private void PlaceTrade(TradeType tradeType, double entryPrice)
{
double currentPrice = tradeType == TradeType.Buy ? Symbol.Bid : Symbol.Ask;
double newStopLoss = ATRSLPips() + addSpreadToStopLoss();
newStopLoss = Math.Round(newStopLoss, 0);
volume = CalculateVolume(newStopLoss);
if (currentPrice < entryPrice && tradeType == TradeType.Sell || currentPrice > entryPrice && tradeType == TradeType.Buy)
{
PlaceLimitOrderAsync(tradeType, SymbolName, volume, entryPrice, label, newStopLoss, TakeProfit());
}
else if (currentPrice > entryPrice && tradeType == TradeType.Sell || currentPrice < entryPrice && tradeType == TradeType.Buy)
{
PlaceStopLimitOrderAsync(tradeType, SymbolName, volume, entryPrice, stopLimitRangePips, label, newStopLoss, TakeProfit());
}
}
private void ATRTrailingStop()
{
if (trailingStopType != TrailingStopType.ATR)
{
Print("ATR TS false");
return;
}
var positions = Positions.FindAll(label, SymbolName);
if (positions.Length > 0)
{
double atrPips = (atr.Result.LastValue / Symbol.PipSize) * ATRMultiplier;
atrPips = Math.Round(atrPips, 1);
Print(atrPips);
foreach (var position in positions)
{
if (position.TradeType == TradeType.Buy && Symbol.Bid - (atrPips * Symbol.PipSize) > position.StopLoss)
{
//Print("Old sl price: " + position.StopLoss);
ModifyPosition(position, Symbol.Bid - (atrPips * Symbol.PipSize), position.TakeProfit);
//Print("New sl price: " + position.StopLoss);
}
else if (position.TradeType == TradeType.Sell && Symbol.Ask + (atrPips * Symbol.PipSize) < position.StopLoss)
{
//Print("Old sl price: " + position.EntryPrice);
ModifyPosition(position, Symbol.Ask + (atrPips * Symbol.PipSize), position.TakeProfit);
//Print("New sl price: " + position.StopLoss);
}
}
}
}
private void MomentumTrailingStop()
{
if (trailingStopType != TrailingStopType.Momentum)
{
return;
}
var positions = Positions.FindAll(label, SymbolName);
{
if (positions.Length > 0)
{
foreach (var position in positions)
{
if (position.TradeType == TradeType.Buy && position.StopLoss < position.EntryPrice)
{
var newStopLossPrice = Symbol.Ask - (Symbol.PipSize * stopLoss);
if (newStopLossPrice > position.StopLoss)
{
ModifyPosition(position, newStopLossPrice, position.TakeProfit);
}
}
else if (position.TradeType == TradeType.Sell && position.StopLoss > position.EntryPrice)
{
var newStopLossPrice = Symbol.Bid + (Symbol.PipSize * stopLoss);
if (newStopLossPrice < position.StopLoss)
{
ModifyPosition(position, newStopLossPrice, position.TakeProfit);
}
}
}
}
}
}
private double addSpreadToStopLoss()
{
if (enableAddSpread)
{
var spread = Math.Round(Symbol.Spread / Symbol.PipSize, 1);
Print("Spread added to stop loss (", spread, ")");
return spread;
}
return 0;
}
private void DisplayChartInfo()
{
double rsiValue = Math.Round(rsi.Result.LastValue, 1);
double atrPips = Math.Round(atr.Result.LastValue / Symbol.PipSize, 1);
double atrPipsMultiplied = Math.Round(atrPips * ATRMultiplier, 1);
Chart.DrawStaticText("DisplayInfo", "ATR Pips: " + atrPips + "\nATR Pips X: " + atrPipsMultiplied + "\nRSI: " + rsiValue, VerticalAlignment.Bottom, HorizontalAlignment.Right, Color.BlanchedAlmond);
}
private double CalculateVolume(double stopLoss)
{
if (stoplossType != StopLossType.ATR)
{
return volume;
}
var riskPerTrade = (Account.Equity) * (atrRiskPercentage);
double totalSLPipValue = (stopLoss + Symbol.Spread) * Symbol.PipValue;
if (totalSLPipValue / Account.Equity > atrRiskPercentage)
{
Print("ATR lot size is larger than atr risk %, bot stopped. Account capital too small to trade this instrument at this risk level");
Print("Total position SL size $" + totalSLPipValue);
Stop();
return -1;
}
double calculatedVolume = riskPerTrade / totalSLPipValue;
double normalizedCalculatedVolume = Symbol.NormalizeVolumeInUnits(calculatedVolume, RoundingMode.Down);
return normalizedCalculatedVolume;
}
private double GapTypePips()
{
if (gapType == GapType.ATR)
{
return ATRPips();
}
else
{
return hedgeOrderPipsAway;
}
}
private double ATRSLPips()
{
if (stoplossType != StopLossType.ATR)
{
return stopLoss;
}
double atrPips = (atr.Result.LastValue / Symbol.PipSize) * ATRMultiplier;
atrPips = Math.Round(atrPips, 1);
if (atrPips < ATRMinimuStopLoss)
{
atrPips = ATRMinimuStopLoss;
}
return atrPips;
}
private double ATRPips()
{
double atrPips = (atr.Result.LastValue / Symbol.PipSize) * hedgeGapMultiplier;
atrPips = Math.Round(atrPips, 1);
if (atrPips < ATRMinimuStopLoss)
{
atrPips = ATRMinimuStopLoss;
}
return atrPips;
}
private double? TakeProfit()
{
if (takeProfitType == TakeProfitType.None)
{
return null;
}
if (takeProfitType == TakeProfitType.SLMultiplier && stoplossType != StopLossType.None)
{
return Math.Round(stopLoss * takeProfitMultiplier, 1);
}
return Math.Round(takeProfit, 1);
}
public enum StopLossType
{
Manual,
ATR,
None
}
public enum TakeProfitType
{
Manual,
SLMultiplier,
None
}
public enum GapType
{
Manual,
ATR
}
public enum TrailingStopType
{
Momentum,
ATR,
None
}
public enum RunningLevel
{
Standard,
TrendMode,
TrendModePlusHedge
}
}
}
PanagiotisCharalampous said:
Hi Vadivelan,
Personally I did not understand what are you trying to do. It would be easier if you provided the complete cBot code and backtesting examples of what does the cBot do at the moment and what should it do instead.
Best Regards,
Panagiotis
Thanks and Regards
R. Vadivelan
PanagiotisCharalampous
20 Jul 2020, 08:40
Hi Vadivelan,
From first glance, I do not see any problem in the code. If this has been developed by a consultant, it would be better to talk to them.
Best Regards,
Panagiotis
@PanagiotisCharalampous
velu130486
20 Jul 2020, 08:48
RE:
Hi Panagiotis,
There is no problem in the code, only thing I need to make the changes as below to suit my requirement,
I want to adjust the gap only if the distance is more than the hedge gap, if it is less than hedge gap then the order price should remain fixed.
Let say Buy position is created at 119.60 and I enabled the constantDistanceHedge with 20 pips. As soon as the Buy position is created at 119.60 Cbot will create the pending sell order at 119.40 (i.e.) with the distance of 20 pips. If the price moves up I want the pending order price to be adjusted, but the price goes in opposite, I would like to keep the position at the same price so that it gets triggered to form a hedge.
if (constantDistanceHedge)
{
foreach (var order in PendingOrders)
{
if (order.Label == label && order.SymbolName == SymbolName && order.Comment != "Initial Order" && order != null)
{
var targetPrice = order.TradeType == TradeType.Buy ? Symbol.Bid : Symbol.Ask;
if ((targetPrice - order.TargetPrice) / Symbol.PipSize > Pipstep * Symbol.PipSize && order.TradeType == TradeType.Sell)
{
ModifyPendingOrderAsync(order, targetPrice - Pipstep * Symbol.PipSize);
}
else if ((order.TargetPrice - targetPrice) / Symbol.PipSize > Pipstep * Symbol.PipSize && order.TradeType == TradeType.Buy)
{
ModifyPendingOrderAsync(order, targetPrice + Pipstep * Symbol.PipSize);
}
}
}
PanagiotisCharalampous said:
Hi Vadivelan,
From first glance, I do not see any problem in the code. If this has been developed by a consultant, it would be better to talk to them.
Best Regards,
Panagiotis
PanagiotisCharalampous
20 Jul 2020, 09:16
Hi Vadivelan,
If you are looking for somebody to develop the logic for you then unfortunately I cannot help you. I cannot engage in custom development requests.
Best Regards,
Panagiotis
@PanagiotisCharalampous
velu130486
20 Jul 2020, 09:47
RE:
Hi Panagiotis,
Thanks for your reply and understand your position, I will try to fix it by myself.
PanagiotisCharalampous said:
Hi Vadivelan,
If you are looking for somebody to develop the logic for you then unfortunately I cannot help you. I cannot engage in custom development requests.
Best Regards,
Panagiotis
velu130486
17 Jul 2020, 08:46
RE:
Dear All,
Could you please help me to solve the below problem.
velu130486 said:
Thanks in Advance
R. Vadivelan