How to keep a 10 pip profit gap between stop loss and current price as profits increase
BLOCK-TRAILING What you are looking for is called a Block-Trailing. Unlike a normal Trailing-Stop that comes with MT4, you (will) need:
- Only start-trailing upon x-pip profit.
- Block-size in pip (only jump SL after each block movement).
- Each SL adjustment needs to move by x-pips.
Note: A common problem that comes with this is when trader set the trail to be too close/tight to the current market. MT4 is not a HFT platform. Do not scalp it too close. Most brokers have a minimum Freeze and StopLoss distance. If you set it too near the price-edge, you will receive an "ERROR 130 Invalid Stop" error. Check your broker's setting in the Contract-Specification for the symbol.
Parameters
vsTicketIdsInCSV: List of OPENED TicketIDs to process (eg 123, 124, 123123, 1231 , 1)
viProfitToActivateBlockTrailInPip: Trailing will only start after OrderProfit > this pips.
viTrailShiftProfitBlockInPip: SL will jump each time profit increase by this number of pips.
viTrailShiftOnProfitInPip: Increase the SL by this number of pips.
Example:
viProfitToActivateBlockTrailInPip=100, viTrailShiftProfitBlockInPip=30, viTrailShiftOnProfitInPip=20.
The Block-Trailing will start when order is floating-profit by 130 pips (100+30). SL will be set to guarantee 20pip profit.
When floating-profit reach 160pips (100+30+30), SL will be set to guarantee 40pips (2x20pips).
I have added this to GitHub: https://github.com/fhlee74/mql4-BlockTrailer An ETH or BTC contribution will be appreciated.
Here is the full code for it:
//+------------------------------------------------------------------+
//| SO56177003.mq4 |
//| Copyright 2019, Joseph Lee, TELEGRAM @JosephLee74 |
//| http://www.fs.com.my |
//+------------------------------------------------------------------+
#property copyright "Copyright 2019, Joseph Lee, TELEGRAM @JosephLee74"
#property link "http://www.fs.com.my"
#property version "1.00"
#property strict
#include <stderror.mqh>
#include <stdlib.mqh>
//-------------------------------------------------------------------
// APPLICABLE PARAMETERS
//-------------------------------------------------------------------
extern string vsEAComment1 = "Telegram @JosephLee74"; // Ego trip
extern string vsTicketIdsInCSV = "123 , 124, 125 ,126 "; // List of OPENED TicketIDs to process.
extern int viProfitToActivateBlockTrailInPip = 10; // Order must be in profit by this to activate BlockTrail
extern int viTrailShiftProfitBlockInPip = 15; // For every pip in profit (Profit Block), shift the SL
extern int viTrailShiftOnProfitInPip = 10; // by this much
extern int viMaxSlippageInPip = 2; // Max Slippage (pip)
//-------------------------------------------------------------------
// System Variables
//-------------------------------------------------------------------
double viPipsToPrice = 0.0001;
double viPipsToPoint = 1;
int vaiTicketIds[];
string vsDisplay = "";
//-------------------------------------------------------------------
//+------------------------------------------------------------------+
//| EA Initialization function
//+------------------------------------------------------------------+
int init() {
ObjectsDeleteAll(); Comment("");
// Caclulate PipsToPrice & PipsToPoints (old sytle, but works)
if((Digits == 2) || (Digits == 3)) {viPipsToPrice=0.01;}
if((Digits == 3) || (Digits == 5)) {viPipsToPoint=10;}
// ---------------------------------
// Transcribe the list of TicketIDs from CSV (comma separated string) to an Int array.
string vasTickets[];
StringSplit(vsTicketIdsInCSV, StringGetCharacter(",", 0), vasTickets);
ArrayResize(vaiTicketIds, ArraySize(vasTickets));
for(int i=0; i<ArraySize(vasTickets); i++) {
vaiTicketIds[i] = StringToInteger(StringTrimLeft(StringTrimRight(vasTickets[i])));
}
// ---------------------------------
start();
return(0);
}
//+------------------------------------------------------------------+
//| EA Stand-Down function
//+------------------------------------------------------------------+
int deinit() {
ObjectsDeleteAll();
return(0);
}
//============================================================
// MAIN EA ROUTINE
//============================================================
int start() {
// ========================================
// Process all the tickets in the list
vsDisplay = "BLOCK-TRAILER v1.1 (Please note the Minimum Freeze/StopLoss level in Contract Specification to AVOID error 130 Invalid Stop when trailing).\n";
double viPrice = 0;
for(int i=0; i<ArraySize(vaiTicketIds); i++) {
if(OrderSelect( vaiTicketIds[i], SELECT_BY_TICKET, MODE_TRADES ))
if(OrderCloseTime() == 0 ) {
// Only work on Active orders
if(OrderType() == OP_BUY) {
RefreshRates();
double viCurrentProfitInPip = (Bid-OrderOpenPrice()) / viPipsToPrice;
double viNewSLinPip = ((viCurrentProfitInPip - viProfitToActivateBlockTrailInPip)/viTrailShiftProfitBlockInPip) * viTrailShiftOnProfitInPip;
double viSLinPrice = NormalizeDouble(OrderOpenPrice() + (viNewSLinPip * viPipsToPrice), Digits);
double viNewSLFromCurrentPrice = NormalizeDouble((Bid-viSLinPrice)/viPipsToPrice, 1);
vsDisplay = vsDisplay
+ "\n[" + IntegerToString(OrderTicket())
+ "] BUY: Open@ " + DoubleToStr(OrderOpenPrice(), Digits)
+ " | P/L: $" + DoubleToStr(OrderProfit(), 2)
+ " / " + DoubleToStr(viCurrentProfitInPip, 1) + "pips.";
if(viCurrentProfitInPip < (viProfitToActivateBlockTrailInPip+viTrailShiftProfitBlockInPip))
vsDisplay = vsDisplay + " " + int(((viProfitToActivateBlockTrailInPip+viTrailShiftProfitBlockInPip))-viCurrentProfitInPip) + " pips to start Trail.";
if(viCurrentProfitInPip >= (viProfitToActivateBlockTrailInPip+viTrailShiftProfitBlockInPip)) {
ResetLastError();
vsDisplay = vsDisplay + " TRAILING to [" + DoubleToStr(viSLinPrice, Digits) + " which is " + DoubleToStr(viNewSLFromCurrentPrice, 1) + " pips from Bid]";
if((viSLinPrice > OrderStopLoss()) || (OrderStopLoss() == 0))
if(OrderModify(OrderTicket(), OrderOpenPrice(), viSLinPrice, OrderTakeProfit(), OrderExpiration())) {
vsDisplay = vsDisplay + " --Trailed SL to " + DoubleToStr(viSLinPrice, Digits);
}
else {
int errCode = GetLastError();
Print(" --ERROR Trailing " + IntegerToString(OrderTicket()) + " to " + DoubleToStr(viSLinPrice, Digits) + ". [" + errCode + "]: " + ErrorDescription(errCode));
vsDisplay = vsDisplay + " --ERROR Trailing to " + DoubleToStr(viSLinPrice, Digits);
vsDisplay = vsDisplay + " [" + errCode + "]: " + ErrorDescription(errCode);
}
}
}
if(OrderType() == OP_SELL) {
RefreshRates();
double viCurrentProfitInPip = (OrderOpenPrice()-Ask) / viPipsToPrice;
double viNewSLinPip = int((viCurrentProfitInPip - viProfitToActivateBlockTrailInPip)/viTrailShiftProfitBlockInPip) * viTrailShiftOnProfitInPip;
double viSLinPrice = NormalizeDouble(OrderOpenPrice() - (viNewSLinPip * viPipsToPrice), Digits);
double viNewSLFromCurrentPrice = NormalizeDouble((viSLinPrice-Ask)/viPipsToPrice, 1);
vsDisplay = vsDisplay
+ "\n[" + IntegerToString(OrderTicket())
+ "] SELL: Open@ " + DoubleToStr(OrderOpenPrice(), Digits)
+ " | P/L: $" + DoubleToStr(OrderProfit(), 2)
+ " / " + DoubleToStr(viCurrentProfitInPip, 1) + "pips.";
if(viCurrentProfitInPip < (viProfitToActivateBlockTrailInPip+viTrailShiftProfitBlockInPip))
vsDisplay = vsDisplay + " " + int(((viProfitToActivateBlockTrailInPip+viTrailShiftProfitBlockInPip))-viCurrentProfitInPip) + " pips to start Trail.";
if(viCurrentProfitInPip >= (viProfitToActivateBlockTrailInPip+viTrailShiftProfitBlockInPip)) {
ResetLastError();
vsDisplay = vsDisplay + " TRAILING to [" + DoubleToStr(viSLinPrice, Digits) + " which is " + DoubleToStr(viNewSLFromCurrentPrice, 1) + " pips from Ask]";
if((viSLinPrice < OrderStopLoss()) || (OrderStopLoss()==0) )
if(OrderModify(OrderTicket(), OrderOpenPrice(), viSLinPrice, OrderTakeProfit(), OrderExpiration())) {
vsDisplay = vsDisplay + " --Trailed SL to " + DoubleToStr(viSLinPrice, Digits);
}
else {
int errCode = GetLastError();
Print(" --ERROR Trailing " + IntegerToString(OrderTicket()) + " to " + DoubleToStr(viSLinPrice, Digits) + ". [" + errCode + "]: " + ErrorDescription(errCode));
vsDisplay = vsDisplay + " --ERROR Trailing to " + DoubleToStr(viSLinPrice, Digits);
vsDisplay = vsDisplay + " [" + errCode + "]: " + ErrorDescription(errCode);
}
}
}
}
}
Comment(vsDisplay);
return(0);
}
And here is the screen shots showing how it works: