Trailing Stop
Trailing Stop
03 Feb 2021, 00:17
Hi, Can someone help me with the working TRAILING STOP (with step) for the following cBot please.
[Parameter("Place Test Buy Order", Group = "Backtest", DefaultValue = false)]
public bool PlaceTestBuy { get; set; }
[Parameter("Place Test Sell Order", Group = "Backtest", DefaultValue = false)]
public bool PlaceTestSell { get; set; }
[Parameter("Comment ID", DefaultValue = "Robot")]
public string CommentID { get; set; }
[Parameter("Stop-Loss in Pips", DefaultValue = 0)]
public double SLPips { get; set; }
[Parameter("Stop-Loss in Cash", DefaultValue = 0)]
public double SLCash { get; set; }
[Parameter("Take-Profit in Pips", DefaultValue = 0)]
public double TPPips { get; set; }
[Parameter("Take-Profit in Cash", DefaultValue = 0)]
public double TPCash { get; set; }
[Parameter("Move SL to Breakeven after Pips", DefaultValue = 0)]
public double BreakevenAfterPips { get; set; }
[Parameter("Trailing-Stop in Pips", DefaultValue = 0)]
public double TSLPips { get; set; }
[Parameter("Trailing-Stop in Cash", DefaultValue = 0)]
public double TSLCash { get; set; }
[Parameter("Update Stop-Loss on New Bar Only", DefaultValue = true)]
public bool UpdateSLOnBar { get; set; }
[Parameter("Manage Manual Orders", DefaultValue = false)]
public bool HandleManualOrders { get; set; }
[Parameter("Orders' Distance in Pips", DefaultValue = 0)]
public double OrdersDistancePips { get; set; }
[Parameter("Orders' Distance in Cash", DefaultValue = 0)]
public double OrdersDistanceCash { get; set; }
[Parameter("Trading hours", DefaultValue = "hh:mm-hh:mm")]
public string TradingHoursString { get; set; }
public DateTime[] TradingTimes;
protected override void OnStart()
{
Positions.Opened += MarketOrderOpened;
PendingOrders.Filled += PendingOrderFilled;
char[] separator =
{
'-'
};
// Check if a trading range was given as parameter.
if (TradingHoursString != "" && TradingHoursString != "hh:mm-hh:mm")
{
// Save the trading range as DateTime array with 2 elements.
string[] bounds = TradingHoursString.Split(separator);
TradingTimes = new DateTime[]
{
DateTime.Parse(bounds[0]),
DateTime.Parse(bounds[1])
};
}
// For debugging.
//ExecuteMarketOrder(TradeType.Buy, SymbolName, 100000, null, 0, 0, CommentID);
//ExecuteMarketOrder(TradeType.Sell, SymbolName, 100000, null, 0, 0, CommentID);
if (PlaceTestBuy)
ExecuteMarketOrder(TradeType.Buy, Symbol.Name, 1000, "", 10, null, CommentID);
if (PlaceTestSell)
ExecuteMarketOrder(TradeType.Sell, Symbol.Name, 1000, "", 10, null, CommentID);
}
protected override void OnTick()
{
if (!UpdateSLOnBar)
{
foreach (Position pos in Positions)
{
if (HandleManualOrders || pos.Label == "Robot Placed")
{
if (pos.Comment == CommentID || CommentID == "")
{
if (pos.SymbolName == SymbolName)
{
// This order is controlled by this robot.
UpdateStopLoss(pos);
}
}
}
}
}
}
protected override void OnBar()
{
if (UpdateSLOnBar)
{
foreach (Position pos in Positions)
{
if (HandleManualOrders || pos.Label == "Robot Placed")
{
if (pos.Comment == CommentID || CommentID == "")
{
if (pos.SymbolName == SymbolName)
{
// This order is controlled by this robot.
UpdateStopLoss(pos);
}
}
}
}
}
}
protected override void OnStop()
{
// Put your deinitialization logic here
}
protected void MarketOrderOpened(PositionOpenedEventArgs args)
{
if (args.Position.Label == "Robot Placed")
{
if (args.Position.Comment == CommentID || CommentID == "")
{
if (args.Position.SymbolName == Bars.SymbolName)
{
if (isTradingTime(Time))
{
PlaceStopOrderInDistance(args.Position);
}
}
}
if (HandleManualOrders)
{
double stopLossPips;
double takeProfitPips;
double VolumeInUnits = args.Position.VolumeInUnits;
if (SLPips != 0)
{
stopLossPips = SLPips;
}
else if (SLCash != 0)
{
stopLossPips = Math.Round(SLCash / (Symbol.PipValue * VolumeInUnits), 1);
}
else
{
stopLossPips = 0;
}
if (TPPips != 0)
{
takeProfitPips = TPPips;
}
else if (TPCash != 0)
{
takeProfitPips = Math.Round(TPCash / (Symbol.PipValue * VolumeInUnits), 1);
}
else
{
takeProfitPips = 0;
}
double newstoploss = args.Position.TradeType == TradeType.Buy ? args.Position.EntryPrice - stopLossPips * Symbol.PipSize : args.Position.EntryPrice + stopLossPips * Symbol.PipSize;
double newtakeprofit = args.Position.TradeType == TradeType.Buy ? args.Position.EntryPrice + takeProfitPips * Symbol.PipSize : args.Position.EntryPrice - takeProfitPips * Symbol.PipSize;
ModifyPosition(args.Position, newstoploss, newtakeprofit);
}
}
}
protected void PendingOrderFilled(PendingOrderFilledEventArgs args)
{
if (args.PendingOrder.Comment == CommentID)
{
if (args.PendingOrder.SymbolName == Bars.SymbolName || CommentID == "")
{
if (isTradingTime(Time))
{
PlaceStopOrderInDistance(args.Position);
}
}
}
}
protected void PlaceStopOrderInDistance(Position pos)
{
double targetPrice;
double stopLossPips;
double takeProfitPips;
double VolumeInUnits = pos.VolumeInUnits;
if (OrdersDistancePips != 0)
{
if (pos.TradeType == TradeType.Buy)
{
targetPrice = pos.EntryPrice + OrdersDistancePips * Symbol.PipSize;
}
else
{
targetPrice = pos.EntryPrice - OrdersDistancePips * Symbol.PipSize;
}
}
else if (OrdersDistanceCash != 0)
{
if (pos.TradeType == TradeType.Buy)
{
targetPrice = pos.EntryPrice + OrdersDistanceCash;
}
else
{
targetPrice = pos.EntryPrice - OrdersDistanceCash;
}
}
else
{
return;
}
if (SLPips != 0)
{
stopLossPips = SLPips;
}
else if (SLCash != 0)
{
stopLossPips = Math.Round(SLCash / (Symbol.PipValue * VolumeInUnits), 1);
}
else
{
stopLossPips = 0;
}
if (TPPips != 0)
{
takeProfitPips = TPPips;
}
else if (TPCash != 0)
{
takeProfitPips = Math.Round(TPCash / (Symbol.PipValue * VolumeInUnits), 1);
}
else
{
takeProfitPips = 0;
}
TradeResult result = PlaceStopOrder(pos.TradeType, pos.SymbolName, VolumeInUnits, targetPrice, "Robot Placed", stopLossPips, takeProfitPips, null, CommentID);
if (result.IsSuccessful)
{
Print("Pending order placed.");
}
else
{
Print(string.Format("Pending order could not be placed. Error: {1}", pos.Id, result.Error));
}
}
public void UpdateStopLoss(Position pos)
{
if (pos.TradeType == TradeType.Buy)
{
// Check if trailing stop can be updated.
if (TSLPips != 0 && (Bars.ClosePrices.LastValue - pos.StopLoss) / Symbol.PipSize >= TSLPips)
{
TradeResult result = ModifyPosition(pos, Bars.ClosePrices.LastValue - TSLPips * Symbol.PipSize, pos.TakeProfit);
if (result.IsSuccessful)
{
Print(string.Format("Position {0}: Trailing stop-loss updated", pos.Id));
}
else
{
Print(string.Format("Position {0}: Trailing stop-loss could not be updated. Error: {1}", pos.Id, result.Error));
}
return;
}
if (TSLCash != 0 && (Bars.ClosePrices.LastValue - pos.StopLoss) * pos.VolumeInUnits >= TSLCash)
{
double newstoploss = Bars.ClosePrices.LastValue - TSLCash / pos.VolumeInUnits;
TradeResult result = ModifyPosition(pos, newstoploss, pos.TakeProfit);
if (result.IsSuccessful)
{
Print(string.Format("Position {0}: Trailing stop-loss updated", pos.Id));
}
else
{
Print(string.Format("Position {0}: Trailing stop-loss could not be updated. Error: {1}", pos.Id, result.Error));
}
return;
}
// Check if stoploss can be moved to breakeven.
if (BreakevenAfterPips != 0 && pos.GrossProfit / Symbol.PipSize >= BreakevenAfterPips && pos.StopLoss < pos.EntryPrice)
{
TradeResult result = ModifyPosition(pos, pos.EntryPrice, pos.TakeProfit);
if (result.IsSuccessful)
{
Print(string.Format("Position {0}: Stop-loss moved to break even", pos.Id));
}
else
{
Print(string.Format("Position {0}: Stop-loss could not be moved to break even. Error: {1}", pos.Id, result.Error));
}
return;
}
}
else if (pos.TradeType == TradeType.Sell)
{
// Check if trailing stop can be updated.
if (TSLPips != 0 && (pos.StopLoss - Bars.ClosePrices.LastValue) / Symbol.PipSize >= TSLPips)
{
TradeResult result = ModifyPosition(pos, Bars.ClosePrices.LastValue + TSLPips * Symbol.PipSize, pos.TakeProfit);
if (result.IsSuccessful)
{
Print(string.Format("Position {0}: Trailing stop-loss updated", pos.Id));
}
else
{
Print(string.Format("Position {0}: Trailing stop-loss could not be updated. Error: {1}", pos.Id, result.Error));
}
return;
}
if (TSLCash != 0 && (pos.StopLoss - Bars.ClosePrices.LastValue) * pos.VolumeInUnits >= TSLCash)
{
double newstoploss = Bars.ClosePrices.LastValue + TSLCash / pos.VolumeInUnits;
TradeResult result = ModifyPosition(pos, newstoploss, pos.TakeProfit);
if (result.IsSuccessful)
{
Print(string.Format("Position {0}: Trailing stop-loss updated", pos.Id));
}
else
{
Print(string.Format("Position {0}: Trailing stop-loss could not be updated. Error: {1}", pos.Id, result.Error));
}
return;
}
// Check if stoploss can be moved to breakeven.
if (BreakevenAfterPips != 0 && pos.GrossProfit / Symbol.PipSize > BreakevenAfterPips && pos.StopLoss > pos.EntryPrice)
{
TradeResult result = ModifyPosition(pos, pos.EntryPrice, pos.TakeProfit);
if (result.IsSuccessful)
{
Print(string.Format("Position {0}: Stop-loss moved to break even", pos.Id));
}
else
{
Print(string.Format("Position {0}: Stop-loss could not be moved to break even. Error: {1}", pos.Id, result.Error));
}
return;
}
}
}
public bool isTradingTime(DateTime presentTime)
{
if (TradingTimes == null)
{
return true;
}
else
{
if (TradingTimes[0].Hour < presentTime.Hour || (TradingTimes[0].Hour == presentTime.Hour && TradingTimes[0].Minute <= presentTime.Minute))
{
// The present time is greater than the starting time of the i-th trading time range.
if (TradingTimes[1].Hour > presentTime.Hour || (TradingTimes[1].Hour == presentTime.Hour && TradingTimes[1].Minute > presentTime.Minute))
{
// The present time is lower than the end time of the i-th trading time range.
return true;
}
}
}
return false;
}
}
}
PanagiotisCharalampous
03 Feb 2021, 08:32
Hi lattymor,
If you need somebody to help you with your development, you can also consider posting a Job.
Best Regards,
Panagiotis
Join us on Telegram
@PanagiotisCharalampous