2

I'm trying to ADD a stop loss to my open market orders in MetaTrader 4 when a position gets 100 pips "to the good" which is to be equal to the Order Open Price;

OrderStopLoss() == OrderOpenPrice()

But this isn't happening.

I've added Print() & GetLastError() functions and nothing is coming up in the journal, so it must be something in my coding - but cannot see what would be wrong.

OK this is what I have so far, one for loop for the buy, one for the sell. I've also Normalized the "doubles" as I have been advised to do & have also declared the BuyMod & SellMod to "true" at the very top. This should ensure that the default won't resort to false. I also thought it might be helpful if I told you I have the MetaEditor version 5 build 1241:)

The following code I have is the following;

/*Breakeven Order Modification*/
bool BuyMod               =  true;
bool SellMod              =  true;
                for(int b = OrdersTotal()-1;b>=0;b--)
                {
                if(OrderSelect(b,SELECT_BY_POS,MODE_TRADES))
                   {
                   double   aBidPrice   =  MarketInfo(Symbol(),MODE_BID);
                   double   anOpenPrice =  OrderOpenPrice();
                   double   aNewTpPrice =  OrderTakeProfit();
                   double   aCurrentSL  =  OrderStopLoss();
                   double   aNewSLPrice =  anOpenPrice;
                   double   pnlPoints   =  (aBidPrice - anOpenPrice)/_Point;
                   double   stopPoints  =  (aBidPrice - aNewSLPrice)/_Point;
                   int      stopLevel   =  int(MarketInfo(Symbol(),MODE_STOPLEVEL));
                   int      aTicket     =  OrderTicket();
                   if(OrderType() == OP_BUY)
                   if(stopPoints >= stopLevel)
                   if(aTicket > 0)
                   if(pnlPoints >= breakeven)
                   if(aNewSLPrice != aCurrentSL)
                      {
                      BuyMod = OrderModify(OrderTicket(),OrderOpenPrice(),NormalizeDouble(aNewSLPrice,Digits),NormalizeDouble(aNewTpPrice,Digits),0,buycolor);
                      SendMail("Notification of Order Modification for Ticket#"+IntegerToString(OrderTicket(),10),"Good news! Order Ticket#"+IntegerToString(OrderTicket(),10)+"has been changed to breakeven");
                      }
                   }
                }
                for(int s = OrdersTotal()-1; s>=0; s--)
                {
                if(OrderSelect(s,SELECT_BY_POS,MODE_TRADES))
                   {
                   double   anAskPrice  =  MarketInfo(Symbol(),MODE_ASK);
                   double   anOpenPrice =  OrderOpenPrice();
                   double   aNewTpPrice =  OrderTakeProfit();
                   double   aCurrentSL  =  OrderStopLoss();
                   double   aNewSLPrice =  anOpenPrice;
                   double   pnlPoints   =  (anOpenPrice - anAskPrice)/_Point;
                   double   stopPoints  =  (aNewSLPrice - anAskPrice)/_Point;
                   int      stopLevel   =  int(MarketInfo(Symbol(),MODE_STOPLEVEL));
                   int      aTicket     =  OrderTicket();
                   if(OrderType()== OP_SELL)
                   if(stopPoints >= stopLevel)
                   if(pnlPoints >= breakeven)
                   if(aNewSLPrice != aCurrentSL)
                   if(aTicket > 0)
                      {
                      SellMod = OrderModify(OrderTicket(),OrderOpenPrice(),NormalizeDouble(aNewSLPrice,Digits),NormalizeDouble(aNewTpPrice,Digits),0,sellcolor);
                      SendMail("Notification of Order Modification for Ticket#"+IntegerToString(OrderTicket(),10),"Good news! Order Ticket#"+IntegerToString(OrderTicket(),10)+"has been changed to breakeven");
                      }
                   }
                }

trading algorithmic-trading mql4 metatrader4

shareeditdeleteflag

edited just now

asked 2 days ago

Todd Gilbey 264

You might want to know, StackOverflow does not promote duplicate questions. ( see the

Community
  • 1
  • 1
  • On updated code-segment: the **`tp`** issue is still there, the **`Print()`** right after `OrderModify()` is still missing. – user3666197 Apr 20 '16 at 17:45
  • While StackOverflow is not a Do-a-Homework site, let me propose a few directions for the solution **in the update below** – user3666197 Apr 20 '16 at 18:28
  • I'm sorry, what tp issue & I want to Print all errors when the Order Modify fails. The reason I'm just so confused right now is because this is the same format as with the OrderClose & there were no issues. I have a fully coded strategy which is extremely profitable. Now I'm adding this piece to it & I don't see why this so stupidly hard to implement. –  Apr 20 '16 at 18:30
  • The **`tp`** issue was explained in your 2nd or 3rd question on this same subject >>> http://stackoverflow.com/a/36743552/3666197 Plus your updated code still does zero self-diagnostics on values used in a `OrderModify()` call and `GetLastError()`. There could hardly be other method to diagnose the root cause of the trouble than to perform these two steps. Or hire some professional service in this field to cover your issues by knowledge outsourcing. Having a few hundreds man*years experience in the team, no one can have the same, identical knowledgebase. But one sure can buy the missing parts. – user3666197 Apr 20 '16 at 22:49
  • Let me also remark, that **`OrderClose()`** has by far a very different function call signature, than that of **`OrderModify()`**. Check the `MQL4` IDE documentation and review carefully the differences. – user3666197 Apr 20 '16 at 23:14
  • Thanks, will do :) –  Apr 21 '16 at 07:03

3 Answers3

1

Besides meeting an MQL4 syntax-rules,
there are more conditions:


A first hidden trouble is in number rounding issues.

MetaQuotes, Inc., recommends wherever possible, to normalise float values into a proper price-representation.

Thus,
wherever a price goes into a server-side instruction { OrderSend(), OrderModify(), ... } one shall always prepare such aPriceDOMAIN value
by a call to NormalizeDouble( ... , _Digits ), before a normalised price hits any server-side instruction call.

May sound rather naive, but this saves you issues with server-side rejections.

Add NormalizeDouble() calls into your code on a regular base as your life-saving vest.


A second, even a better hidden trouble is in STOP_ZONE-s and FREEZE_ZONE-s

While not visible directly, any Broker set's in their respective Terms & Conditions these parameters.

In practice,
this means, if you instruct { OrderSend() | OrderModify() } to set / move aPriceDOMAIN level to be setup too close to current actual Ask/Bid ( violating a Broker-forbidden STOP_ZONE )
or
to delete / modify aPriceDOMAIN level of TP or SL, that are already set and is right now, within a Broker-forbidden FREEZE_ZONE distance from actual Ask/Bid,
such instruction will not be successfully accepted and executed.

So besides calls to the NormalizeDouble(), always wait a bit longer as the price moves "far" enough and regularly check for not violating forbidden STOP_ + FREEZE_ zones before ordering any modifications in your order-management part of your algotrading projects.

Anyway, Welcome to Wild Worlds of MQL4

Update: while StackOverflow is not a Do-a-Homework site, let me propose a few directions for the solution:

for ( int b = OrdersTotal() - 1; b >= 0; b-- ) // ________________________ // I AM NOT A FAN OF db.Pool-looping, but will keep original approach for context purposes
{     if (  ( OrderSelect( b, SELECT_BY_POS, MODE_TRADES ) ) == true )
      {    // YES, HAVE TO OPEN A CODE-BLOCK FOR if()-POSITIVE CASE:
           // ------------------------------------------------------
              double aBidPRICE   = MarketInfo( Symbol(), MODE_BID );       // .UPD
              double anOpenPRICE     = OrderOpenPrice();                   // .SET FROM a db.Pool Current Record
              double aNewTpPRICE     = OrderTakeProfit();                  // .SET FROM a db.Pool Current Record
              double aCurrentSlPRICE = OrderStopLoss();                    // .SET FROM a db.Pool Current Record
              double aNewSlPRICE     = anOpenPRICE;                        // .SET
              double  pnlPOINTs      = ( aBidPRICE - anOpenPRICE )/_Point; // .SET
              double stopPOINTs      = ( aBidPRICE - aNewSlPRICE )/_Point; // .SET
           // ------------------------------------------------------------ // .TEST
              if (                        OP_BUY    == OrderType()        )
                   if (                   Period()  == OrderMagicNumber() )
                        if (             stopPOINTa >  stopLevel          )
                             if (         pnlPOINTs >= breakeven          )
                                  if (  aNewSlPRICE != aCurrentSlPRICE    )
                                  {  // YES, HAVE TO OPEN A BLOCK {...}-CODE-BLOCK FOR THE if()if()if()if()-chain's-POSITIVE CASE:
                                     // -------------------------------------------------------------------------------------------
                                        int aBuyMOD = OrderModify( OrderTicket(),
                                                                   OrderOpenPrice(),
                                                                   NormalizeDouble( aNewSlPRICE, Digits ),
                                                                   NormalizeDouble( aNewTpPRICE, Digits ),
                                                                   0,
                                                                   buycolor
                                                                   );
                                        switch( aBuyMOD )
                                        {   case ( NULL  ): { ...; break; } // FAIL ( ANALYSE ERROR )
                                            default:        { ...; break; } // PASS OrderModify()
                                        }
      }
}
user3666197
  • 1
  • 6
  • 50
  • 92
  • The NormalamizeDouble sounds like a plan, but my broker StopLevels range from 20-30 whereas I code the breakeven to be 100 pips to the good, way above the stop levels. But I'll give Normalize double a try.Thank you :) –  Apr 19 '16 at 08:11
  • A `STOPLEVEL` of about 20-30 means, that your code has to wait, till **`Ask`** / **`Bid`** has reached those another 20-30 points farther from the new level you would like to set ( **so to overcome the current `OrderOpenPrice()` next 20-30 points farther "to the good way"** ) before the Broker confirms & accepts such setting to be executed. – user3666197 Apr 19 '16 at 11:29
  • OK, so just so I'm clear, if I set the Breakeven value to 100 points, this means that I would need to wait 120-130 pips before the stop loss value is to be moved to the open price? –  Apr 20 '16 at 09:07
  • **Global Variables** double pnlPoints; double price,sl,tp; double point; int stopLevel; int cmd; double newSL; **Local Declarations** pnlPoints = 0 point = MarletInfo((Symbol(),MODE_POINT)); pnlPoints = 0; point = MarketInfo(Symbol(),MODE_POINT); stopLevel = int(MarketInfo(Symbol(),MODE_STOPLEVEL)+MarketInfo(Symbol(),MODE_SPREAD)); sl = NormalizeDouble(OrderStopLoss(),Digits); tp = OrderTakeProfit(); cmd = OrderType(); –  Apr 20 '16 at 10:35
  • Right, you need to wait 100 + STOPLEVEL points for an actual XTO price ( Ask for OP_SELL ) allows you to move the SL -100 points closer ( to an actual XTO price trailing SL proximity, that is greater of equal to a Broker-defined STOPLEVEL distance ), while not touching at the same time any of the FREEZELEVEL zones. – user3666197 Apr 20 '16 at 12:24
  • @ToddGilbey do not hesitate to rather post an additional update ( identified as #Update# to keep the Questions original context and additions ). All code proposals & revisions are not easy to read / follow in unformatted comments, ok? – user3666197 Apr 20 '16 at 12:38
  • I tried but there's a character restriction so couldn't do this. –  Apr 20 '16 at 12:54
  • Sorry, could you clarify, what restriction do you mean, Todd? – user3666197 Apr 20 '16 at 14:28
  • Well the "Add Comment" box will only give me 585 characters –  Apr 20 '16 at 15:42
  • Sure, **do not [ add a comment ]** but **rather [ edit ] the original question** – user3666197 Apr 20 '16 at 17:29
  • Ah that makes sense. Sorry I'm very new to this website so I'm still learning the ropes. The original code has been edited. –  Apr 20 '16 at 17:41
0

The problem is in your call to a built-in OrderModify() function.

OrderStopLoss() == OrderModify() will evaluate as false which in turn will evaluate as 0 since == is a comparison operator.

An OrderStopLoss() is a call to another built-in function (not a variable), you can't save anything to it so OrderStopLoss() = 4 wouldn't work either.

From the MQL4 documentation:

bool  OrderModify( int        ticket,      // ticket 
                   double     price,       // price 
                   double     stoploss,    // stop loss 
                   double     takeprofit,  // take profit 
                   datetime   expiration,  // expiration 
                   color      arrow_color  // color 
                   );

In your case that would be the following, assuming ModBuy is already defined somewhere in the code:

ModBuy = OrderModify(  OrderTicket(),      // <-ticket from record OrderSelect()'d
                       OrderOpenPrice(),   // <-price  from current record
                       OrderOpenPrice(),   // <-price  from current record
                       OrderTakeProfit(),  // <-TP     from current record
                       0,                  // ( cannot set P/O expiration for M/O )
                       buycolor            // ( set a color for a GUI marker )
                       );

Or you could just use any other valid value instead of the second OrderOpenPrice() to set a new stoploss.

user3666197
  • 1
  • 6
  • 50
  • 92
  • Thanks for your reply, I've changed the "double stoploss" to the OrderOpenPrice() & its still not adding a stoploss to the position when the position reached 100 pips to the good. Its as if something is being blocked from being read by the system. Added GetLastError() - nothing, Looked in the Journal - nothing. The code might as well just not be there. Right now I'm at the end of my tether with this - I just cannot workout why this is not doing what I've programmed it to do. The bool =ModBuy is in the Global Variables. –  Apr 18 '16 at 12:35
  • ModBuy = OrderModify(0,0,OrderOpenPrice(),0,0,buycolor); –  Apr 18 '16 at 13:00
0

I'm really sorry, I'm new to Stackoverflow, this is the revised code I now have based on everyone's comments & recommendation's below

 **Local Declarations**
  pnlPoints            =  0;
  point                =  MarketInfo(Symbol(),MODE_POINT);
  stopLevel            =  int(MarketInfo(Symbol(),MODE_STOPLEVEL)+MarketInfo (Symbol(),MODE_SPREAD));
  sl                   =  NormalizeDouble(OrderStopLoss(),Digits);
  tp                   =  OrderTakeProfit();
  cmd                  =  OrderType();
  breakeven            =  100;

  **Global Variables**
  double   pnlPoints;
  double   price,sl,tp;
  double   point;
  int      stopLevel;
  int      cmd;
  int      breakeven;
  double   newSL;
                for(int b = OrdersTotal()-1; b>=0; b--)
                {
                if((OrderSelect(b,SELECT_BY_POS,MODE_TRADES))==true)
                price = MarketInfo(Symbol(),MODE_BID);
                newSL = NormalizeDouble(OrderOpenPrice(),Digits);
                pnlPoints = (price - OrderOpenPrice())/point;
                   {
                   if(OrderType()==OP_BUY)
                      if(OrderMagicNumber() == Period())
                         if((price-newSL)/point>=stopLevel)
                            if(pnlPoints>=breakeven)
                               if(sl!=newSL)
                                  ModBuy = OrderModify(OrderTicket(),OrderOpenPrice(),newSL,tp,buycolor);
                                   else if(ModBuy == false)
                                   {
                                   Print("OrderModify failed with error #",GetLastError());
                                   }
                   }              
                }
  • You might want to know, that `OrderModify()` call-signature used here ( and copied elsewhere further, by me too, corrected just recently ) was wrong. **`MQL4`** documentation requires to include also an OrderExpiration value in the call, even though the Order is currently not a pending order any more. Check the documentation and the IDE tooltip, which helps one remind the order of the function call parameters. – user3666197 Apr 20 '16 at 22:58
  • I think it's something specific to me and my account that's preventing this from happening - there's no reason why this isn't happening. –  Apr 20 '16 at 23:01