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:

  1. Only start-trailing upon x-pip profit.
  2. Block-size in pip (only jump SL after each block movement).
  3. 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: enter image description here