Trailing Stop Issue

 

Trailing stop issue. 


I've been trying to solve this problem for a few days now but cannot see the problem.


Searched the internet, forums, and youtube without any success. 


ApplyTrailingStop function does not work properly. I cannot find out why so. 


I think it may have to do with the condition "OrderOpenPrice<buyStopLoss" and vice versa for the sell condition. 


The code runs without that specific condition, but it is not how I want the code to function. 


I want the SL moved when it's greater than the opening price to cover for potential losses. Without that specific condition it modifies my SL straightaway.


Help would be greatly appreciated as this is my last resort of finding a solution to my problem. 




/*
   Split week part 1. 
   Only allows trades on TUe, Wed, Thu 
   Entry looks for the highest high and the highest close before a buy is initiated. 
   with the reverse for a sell short signal. 
   Added condition is a volatility filter, designed to ignore signals during high volatility. 
*/

#property copyright "Jeremy van der Heyden"
#property link      "https://www.mql5.com"
#property version   "1.00"
#property strict

input int                              InpBarsBack                = 15; // lookback for recent highest and lowest prices. 
input int                              InpATRPeriod               = 14;

input int                              InpMagicNumber             = 202201162;
input string                           InpTradeComment            = __FILE__;

input double                           InpRiskPercentage          = 0.01;
input int                              InpMaxLossInPips           = 60;

input double                           InpATRMultSL               = 2.0;
input double                           InpATRMultTP               = 4.0;
input double                           InpSLPoints                = 300;


double RiskAmount = AccountEquity()*InpRiskPercentage;
double StopLoss;

int OnInit()  {

   double point = SymbolInfoDouble(Symbol(), SYMBOL_POINT);
   RiskAmount   = RiskAmount*point;
   StopLoss     = InpSLPoints*point;
  
   return(INIT_SUCCEEDED);
}

void OnDeinit(const int reason)  {

   
}

void OnTick()  {
   
   if (CheckIfTradingAllowed()) {
      if (NewBar()) {
         if (!CheckIfOpenOrders(InpMagicNumber)) {
         
         double HighestValue        = iHigh(Symbol(), Period(), iHighest(Symbol(), Period(), MODE_HIGH, InpBarsBack, 1));
         double LowestValue         = iLow(Symbol(), Period(), iLowest(Symbol(), Period(), MODE_LOW, InpBarsBack, 1));
         double HighestCloseValue   = iClose(Symbol(), Period(), iHighest(Symbol(), Period(), MODE_CLOSE, InpBarsBack, 1));
         double LowestCloseValue    = iClose(Symbol(), Period(), iLowest(Symbol(), Period(), MODE_CLOSE, InpBarsBack, 1));
         
         double CurrentClose        = iClose(Symbol(), Period(), 1);
         double CurrentHigh         = iHigh(Symbol(), Period(), 1);
         double CurrentLow          = iLow(Symbol(), Period(), 1);
         
         double ATRValue            = iATR(Symbol(), Period(), InpATRPeriod, 1)*InpATRMultSL;
         double ATRInPips           = ATRValue*10000; //number of pips in integer amount. 
         ATRInPips                  = NormalizeDouble(ATRInPips, Digits());


         
         bool BuyCondition          = (CurrentHigh>=HighestValue && CurrentClose >=HighestCloseValue && ATRInPips<InpMaxLossInPips);
         bool SellCondition         = (CurrentLow<=LowestValue && CurrentClose<=LowestCloseValue && ATRInPips<InpMaxLossInPips);
         
            if (BuyCondition) {
               OpenOrder(ORDER_TYPE_BUY);
               ApplyTrailingStop(Symbol(), InpMagicNumber, StopLoss);
            } else 
            if (SellCondition) {
               OpenOrder(ORDER_TYPE_SELL);
               ApplyTrailingStop(Symbol(), InpMagicNumber, StopLoss);
            }
         
         }
      }
   }
   return;
}

bool NewBar() {

   datetime             now      = iTime(Symbol(), Period(), 0);
   static datetime      prev     = now;
   if (prev==now) return(false);
   prev=now;
   return(true);

}

bool CheckIfOpenOrders(int magicNumber) {

   int cnt     = OrdersTotal();
   for (int i=cnt-1; i>=0; i--) {
      if (OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) {
         if (OrderMagicNumber()==magicNumber) return(true);
      }
   }
   return(false);

}

bool CheckIfTradingAllowed() {

   if (DayOfWeek()>=2 && DayOfWeek()<4) return(true);
   else {
      return(false);
   }

}

bool OpenOrder(ENUM_ORDER_TYPE orderType) {

   int Ticket;
   double OpenPrice        = 0;
   double StopLossPrice    = 0;
   double TakeProfitPrice  = 0;
   
   double ATRValue         = iATR(Symbol(), Period(), InpATRPeriod, 1);
   double ATRSLValue       = ATRValue*InpATRMultSL;
   double ATRTPValue       = ATRValue*InpATRMultTP;
   
   double LotSize          = RiskAmount/ATRSLValue;
   
   if (orderType==ORDER_TYPE_BUY) {
      OpenPrice            = Ask;
      StopLossPrice        = OpenPrice-ATRSLValue;
      TakeProfitPrice      = OpenPrice+ATRTPValue;
   } else 
   if (orderType==ORDER_TYPE_SELL) {
      OpenPrice            = Bid;
      StopLossPrice        = OpenPrice+ATRSLValue;
      TakeProfitPrice      = OpenPrice-ATRTPValue;
   } else {
      return(false);
   }

   Ticket = OrderSend(Symbol(), orderType, LotSize, OpenPrice, 2, StopLossPrice, TakeProfitPrice, InpTradeComment, InpMagicNumber);
   
   return(Ticket>0);
}

void ApplyTrailingStop(string symbol, int magicNumber, double stopLoss) {

   // need the number of digits for the particular symbol. as we normalize. 
   // static as we don't want to waste time calculating it every time. 
   static int     digits   = (int)SymbolInfoInteger(symbol, SYMBOL_DIGITS);
   
   // trailing from the close price as we close trades at the closing price. 
   // the bid is the closing price for a buy trade. 
   double buyStopLoss      = NormalizeDouble(SymbolInfoDouble(symbol, SYMBOL_BID)-stopLoss, digits);
   double sellStopLoss     = NormalizeDouble(SymbolInfoDouble(symbol, SYMBOL_ASK)+stopLoss, digits);;
   
   // need to loop through the ea and find which trades have been placed by this EA
   int count      = OrdersTotal();
   for (int i = count-1; i>=0; i--) {
      if (OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) {
         if (OrderSymbol()==symbol && OrderMagicNumber()==magicNumber) {
            // the stoploss has to be better than the orderopen price so for a buy above and for a sell below the open price. 
            // and if the stop loss has not been set yet or the stoploss is better than the current stop loss. 
            if (OrderType()==ORDER_TYPE_BUY  && OrderOpenPrice()<buyStopLoss && (OrderStopLoss()==0 || buyStopLoss>OrderStopLoss())) {
               if (OrderModify(OrderTicket(), OrderOpenPrice(), buyStopLoss, OrderTakeProfit(), OrderExpiration())) {}
            } else 
            if (OrderType()==ORDER_TYPE_SELL  && OrderOpenPrice()>sellStopLoss && (OrderStopLoss()==0 || sellStopLoss<OrderStopLoss())) {
               if (OrderModify(OrderTicket(), OrderOpenPrice(), sellStopLoss, OrderTakeProfit(), OrderExpiration())) {}
            }
                    
          }  
         }
      }
}
Discover new MetaTrader 5 opportunities with MQL5 community and services
Discover new MetaTrader 5 opportunities with MQL5 community and services
  • www.mql5.com
MQL5: language of trade strategies built-in the MetaTrader 5 Trading Platform, allows writing your own trading robots, technical indicators, scripts and libraries of functions
 
jeremy van:

I've been trying to solve this problem for a few days now but cannot see the problem.

Searched the internet, forums, and youtube without any success. 

ApplyTrailingStop function does not work properly. I cannot find out why so. 

  1. You can't see the problem, so that is your problem.

    Use the debugger or print out your variables, including _LastError and prices and find out why. Do you really expect us to debug your code for you?
              Code debugging - Developing programs - MetaEditor Help
              Error Handling and Logging in MQL5 - MQL5 Articles (2015)
              Tracing, Debugging and Structural Analysis of Source Code - MQL5 Articles (2011)
              Introduction to MQL5: How to write simple Expert Advisor and Custom Indicator - MQL5 Articles (2010)

  2.    Ticket = OrderSend(Symbol(), orderType, LotSize, OpenPrice, 2, StopLossPrice, TakeProfitPrice, InpTradeComment, InpMagicNumber);
                    
    

    Check your return codes, and report your errors (including market prices and your variables). Don't look at GLE/LE unless you have an error. Don't just silence the compiler (MT5/MT4+strict), it is trying to help you.
              What are Function return values ? How do I use them ? - MQL4 programming forum (2012)
              Common Errors in MQL4 Programs and How to Avoid Them - MQL4 Articles (2014)

  3. Your code
       if (DayOfWeek()>=2 && DayOfWeek()<4) return(true);
       else {
          return(false);
       }
    Simplified
       return DayOfWeek()>=2 && DayOfWeek()<4;
              Increase Order after stoploss - MQL4 programming forum #1.3 (2017)
  4. Don't hard code constants. Use the proper enumerations. ENUM_DAY_OF_WEEK

  5.    if (orderType==ORDER_TYPE_BUY) {

    There is no such constant(s) in MT4. List of MQL4 Constants - MQL4 Reference

    Use the correct Trade operation enumeration.

  6.       OpenPrice            = Ask;
          StopLossPrice        = OpenPrice-ATRSLValue;
          TakeProfitPrice      = OpenPrice+ATRTPValue;

    You buy at the Ask and sell at the Bid. Pending Buy Stop orders become market orders when hit and open at the Ask.

    1. Your buy order's TP/SL (or Sell Stop's/Sell Limit's entry) are triggered when the Bid / OrderClosePrice reaches it. Using Ask±n, makes your SL shorter and your TP longer, by the spread. Don't you want the specified amount used in either direction?

    2. Your sell order's TP/SL (or Buy Stop's/Buy Limit's entry) will be triggered when the Ask / OrderClosePrice reaches it. To trigger close to a specific Bid price, add the average spread.
                MODE_SPREAD (Paul) - MQL4 programming forum - Page 3 #25

    3. The charts show Bid prices only. Turn on the Ask line to see how big the spread is (Tools → Options (control+O) → charts → Show ask line.)
      Most brokers with variable spreads widen considerably at end of day (5 PM ET) ± 30 minutes. My GBPJPY shows average spread = 26 points, but average maximum spread = 134 (your broker will be similar).

 
William Roeder #:
  1. You can't see the problem, so that is your problem.

    Use the debugger or print out your variables, including _LastError and prices and find out why. Do you really expect us to debug your code for you?
              Code debugging - Developing programs - MetaEditor Help
              Error Handling and Logging in MQL5 - MQL5 Articles (2015)
              Tracing, Debugging and Structural Analysis of Source Code - MQL5 Articles (2011)
              Introduction to MQL5: How to write simple Expert Advisor and Custom Indicator - MQL5 Articles (2010)

  2. Check your return codes, and report your errors (including market prices and your variables). Don't look at GLE/LE unless you have an error. Don't just silence the compiler (MT5/MT4+strict), it is trying to help you.
              What are Function return values ? How do I use them ? - MQL4 programming forum (2012)
              Common Errors in MQL4 Programs and How to Avoid Them - MQL4 Articles (2014)

  3. Your code
    Simplified
              Increase Order after stoploss - MQL4 programming forum #1.3 (2017)
  4. Don't hard code constants. Use the proper enumerations. ENUM_DAY_OF_WEEK

  5. There is no such constant(s) in MT4. List of MQL4 Constants - MQL4 Reference

    Use the correct Trade operation enumeration.

  6. You buy at the Ask and sell at the Bid. Pending Buy Stop orders become market orders when hit and open at the Ask.

    1. Your buy order's TP/SL (or Sell Stop's/Sell Limit's entry) are triggered when the Bid / OrderClosePrice reaches it. Using Ask±n, makes your SL shorter and your TP longer, by the spread. Don't you want the specified amount used in either direction?

    2. Your sell order's TP/SL (or Buy Stop's/Buy Limit's entry) will be triggered when the Ask / OrderClosePrice reaches it. To trigger close to a specific Bid price, add the average spread.
                MODE_SPREAD (Paul) - MQL4 programming forum - Page 3 #25

    3. The charts show Bid prices only. Turn on the Ask line to see how big the spread is (Tools → Options (control+O) → charts → Show ask line.)
      Most brokers with variable spreads widen considerably at end of day (5 PM ET) ± 30 minutes. My GBPJPY shows average spread = 26 points, but average maximum spread = 134 (your broker will be similar).


Thank you very much for the quick reply. Will start implementing all the things you said and find the solution. 
 

Hey Roeder, 


Because of your helpful tips I was able to find the issue with the logic of the code using print statements to see if the values are being printed correctly at the correct time. 


The issue had to do with the ApplyTrailingStop function being called within the if-buy and if-sell condition causing it to be run once rather with every new bar forming as I intended.  


I wouldn't have been able to see that issue if it wasn't for the print statements which caught my attention to the function being called once. 


Simply putting the ApplyTrailingStop function within the NewBar section solved the issue. 


Thanks a lot again. 


Jeremy 

Reason: