Order Modify Error 130 still prevails when backtesting!

 

I know this is a common thread but I'm trying to modify my market order to breakeven (adding a stop loss to be equal to the order open price) when I make 100pips profit.
Everything is NormaliseDouble'd & there's even a mechanism that continues onto the next order select in the pool when a stop loss has already been added from a previous for loop (if(aNewSLPrice == aCurrentSL)continue;).

This means that there should be no Stoplevel violation anywhere. Here is the following code

The breakeven attribute is a global variable.

/*Breakeven Order Modification*/
                     for(int b = OrdersTotal()-1;b>=0;b--)
                     {
                     if(OrderSelect(b,SELECT_BY_POS,MODE_TRADES)==true)
                        {
                        double   aBidPrice   =  MarketInfo(Symbol(),MODE_BID);
                        double   anOpenPrice =  OrderOpenPrice();
                        double   aNewTpPrice =  OrderTakeProfit();
                        double   aCurrentSL  =  OrderStopLoss();
                        double   aNewSLPrice =  anOpenPrice;
                        int      stopLevel   =  int(MarketInfo(Symbol(),MODE_STOPLEVEL)+MarketInfo(Symbol(),MODE_SPREAD));
                        double   freezeLevel =  MarketInfo(Symbol(),MODE_FREEZELEVEL);
                        double   pnlPoints   =  NormalizeDouble(aBidPrice - anOpenPrice/_Point,Digits);
                        double   stopPoints  =  NormalizeDouble(aBidPrice - aNewSLPrice/_Point,Digits);
                        int      aTicket     =  OrderTicket();
                        if(OrderType() == OP_BUY)
                        if(stopPoints > stopLevel)
                        if(aTicket > 0)
                        if(pnlPoints > breakeven)
                        if(aNewSLPrice == aCurrentSL)continue;
                           {
                           BuyMod = OrderModify(OrderTicket(),NormalizeDouble(anOpenPrice,Digits),NormalizeDouble(aNewSLPrice,Digits),NormalizeDouble(aNewTpPrice,Digits),0,buycolor);
                           PrintFormat("TKT[%.2d]OP:[%7.5f]SL:[%7.5f]CurrentPrice:[%7.5f]Stoplevel:[%.3d]FreezeLevel:[%.3d]",aTicket,anOpenPrice,aCurrentSL,aBidPrice,stopLevel,freezeLevel);
                           SendMail("Notification of Order Modification for Ticket#"+IntegerToString(OrderTicket(),10),"Good news! Order Ticket#"+IntegerToString(OrderTicket(),10)+"has been changed to breakeven");
                           if(!BuyMod)
                              {
                              PrintFormat("Order modification for ticket %10d has failed to modify the order under the Error Code %5d. Check MQL4 Documentation",aTicket,GetLastError());
                              }
                           }
                        }
                     }
                     for(int s = OrdersTotal()-1; s>=0; s--)
                        {
                        if(OrderSelect(s,SELECT_BY_POS,MODE_TRADES)==true)
                           {
                           double   anAskPrice  =  MarketInfo(Symbol(),MODE_ASK);
                           double   anOpenPrice =  OrderOpenPrice();
                           double   aNewTpPrice =  OrderTakeProfit();
                           double   aCurrentSL  =  OrderStopLoss();
                           double   aNewSLPrice =  anOpenPrice;
                           double   pnlPoints   =  NormalizeDouble(anOpenPrice - anAskPrice/_Point,Digits);
                           double   stopPoints  =  NormalizeDouble(aNewSLPrice - anAskPrice/_Point,Digits);
                           int      stopLevel   =  int(MarketInfo(Symbol(),MODE_STOPLEVEL)+MarketInfo(Symbol(),MODE_SPREAD));
                           double   freezeLevel =  MarketInfo(Symbol(),MODE_FREEZELEVEL);
                           int      aTicket     =  OrderTicket();
                           if(OrderType()== OP_SELL)
                           if(stopPoints > stopLevel)
                           if(aTicket > 0)
                           if(pnlPoints > breakeven)
                           if(aNewSLPrice == aCurrentSL)continue;
                              {
                              SellMod = OrderModify(aTicket,NormalizeDouble(anOpenPrice,Digits),NormalizeDouble(aNewSLPrice,Digits),NormalizeDouble(aNewTpPrice,Digits),0,sellcolor);
                              PrintFormat("TKT[%.2d]OP:[%7.5f]SL:[%7.5f]CurrentPrice:[%7.5f]Stoplevel:[%.3d]FreezeLevel:[%.3d]",aTicket,anOpenPrice,aCurrentSL,anAskPrice,stopLevel,freezeLevel);
                              SendMail("Notification of Order Modification for Ticket#"+IntegerToString(OrderTicket(),10),"Good news! Order Ticket#"+IntegerToString(OrderTicket(),10)+"has been changed to breakeven");
                              if(!SellMod)
                                 {
                                 PrintFormat("Order modification for ticket %10d has failed to modify the order under the Error Code# %5d. Check MQL4 Documentation",aTicket,GetLastError());
                                 }
                              }
                           }
                        }
 
  1. Instead of Bid and Ask, consider using "OrderCurrentPrice()" instead.
  2. Your calculations are mixing units between points and prices and price deltas, so you will need to overhaul the code a bit before some of the other bugs can be fixed.
  3. Don't use NormaliseDouble(), rather align your priced with the TickSize as WHRoeder has explained here on many occasions. I don't remember the link but do a search and you will find it.
  4. You are also missing parenthesis for example in the calculation of the "stopPoints" where it should be something like "(aBidPrice - aNewSLPrice)/_Point" in order to properly get the value in Points.
  5. If "pnlPoints" and "stopPoints" are in points, then don't use "NormaliseDouble" because they don't have "Digits" and should in fact be an "int" (no need to be a "double").
  6. You compare "pnlPoints" and "breakeven" but I don't see its calculation anywhere.
  7. Also, as a sanity check, because the compiler many times messes this up, don't cascade "if"s one after the other without code block braces, except for the last one which is OK. You also have a "continue" statement which then invalidates the subsequent code block which will be executed almost always on opposite orders and when conditions are NOT met. Rather do something like this which will be easier to read:
    if( ... )
    {
       if( ... )
       {
          if( ... )
          {
             ...
          }
       }
    }
 
  1. double   pnlPoints   =  NormalizeDouble(aBidPrice - anOpenPrice/_Point,Digits);
                                             1.23456  - 1.23000    / 0.00001
                                             1.23456  -        123000
                                                    -122998.76544
  2. Do NOT use NormalizeDouble, EVER. For ANY Reason. It's a kludge, don't use it. It's use is always wrong
 
Thanks for this, all look good, some were more "d'oh" moments than others, as for the "breakeven" that is a global integer I have also used if statements without code-block braces elsewhere in the EA & that works fine.

I will read up on the articles you suggested as well as LotStep, Point, & Ticksize as well.

Many thanks for your help

Regards

T
 

PS: Symbolinfo.mqh is a class of MQL5, its compatible to MT4, at least it can be compiled. Take that class, create a global object like

CSymbolInfo __Symbol; 

and use the methods for

.Bid()

.Ask()

.NormalizePrice()

.LotsStep()

.LotsMin()

.LotsMax()

and its all done. There is no need to reinvent the same wheel all the time, if you dont want. And if you compare quotes which are stored in doubles, never use ==, instead use CompareDouble() which is part of stdlib.mqh.

Just another idea. 

 
FMIC:
  1. Instead of Bid and Ask, consider using "OrderCurrentPrice()" instead.
  2. Your calculations are mixing units between points and prices and pricedeltas, so you will need to overhaul the code a bit before some of the other bugscan be fixed.
  3. Don't use NormaliseDouble(), rather align your priced with the TickSize as WHRoeder has explained here on many occasions. I don't remember the link but do a search and you will find it.
  4. You are also missing parenthesis for example in the calculation of the "stopPoints" where it should be something like "(aBidPrice - aNewSLPrice)/_Point" in order to properly get the value in Points.
  5. If "pnlPoints" and "stopPoints" are in points, then don't use "NormaliseDouble" because they don't have "Digits" and should in fact be an "int" (no need to be a "double").
  6. You compare "pnlPoints" and "breakeven" but I don't see its calculation anywhere.
  7. Also, as a sanity check, because the compiler many times messes this up, don't cascade "if"s one after the other without code block braces, except for the last one which is OK. You also have a "continue" statement which then invalidates the subsequent code block which will be executed almost always on opposite orders and when conditions are NOT met. Rather do something like this which will be easier to read:


Thanks for explanation :) Whenever I change toe pnlPoints & stopPoints from double to integers, the error & warning section comes up with the "possible loss data due to type conversion". Could this be because there are double-formatted variables in the calculation by any chance - seeing as the anOpenprice & anAskPrice are double variables?;
double   pnlPoints   =  (anOpenPrice - anAskPrice)/_Point;
All the best

T
 
thecody1000:
Thanks for explanation :) Whenever I change toe pnlPoints & stopPoints from double to integers, the error & warning section comes up with the "possible loss data due to type conversion". Could this be because there are double-formatted variables in the calculation by any chance - seeing as the anOpenprice & anAskPrice are double variables?

Here is an example:

#define _ToPoints( dblPrice ) int( round( dblPrice / _Point ) )

double anClosePrice = OrderClosePrice();
int    pnlPoints    = _ToPoints( anOpenPrice - anClosePrice );
int    stopPoints   = _ToPoints( aNewSLPrice - anClosePrice );
int    spreadPoints = (int) MarketInfo( _Symbol, MODE_SPREAD );
int    mkStopLevel  = (int) MarketInfo( _Symbol, MODE_STOPLEVEL );
int    stopLevel    = mkStopLevel + spreadPoints;
 
  1. Always be very careful with #defines.
    _ToPoints(anOpenPrice - anClosePrice)                // becomes
    int( round( anOpenPrice - anClosePrice / _Point ) )  // which you pointed out was wrong.
    
    // Always parenthesize arguments
    #define _ToPoints( dblPrice ) int( round( (dblPrice) / _Point ) )

  2. I'd code it
    double            tick_size(void){  return MarketInfo(_Symbol, MODE_TICKSIZE); }
    double            min_lot(void){    return MarketInfo(_Symbol, MODE_MINLOT);   }
    double            lot_step(void){   return MarketInfo(_Symbol, MODE_LOTSTEP);  }
    PRICE             normalize_price(double p){
       return round_nearest(p, tick_size() );
    }
    
    double            round_down(    double v, double to){
                                                    return to * MathFloor(v / to); }
    double            round_up(      double v, double to){
                                                    return to * MathCeil( v / to); }
    double            round_nearest( double v, double to){
                                                    return to * MathRound(v / to); }
    int               to_points(double change){ return (int) round_nearest(change, _Point);
    
    

 

Looks good, but this also worked as well

 			int      pnlPoints   =  int(NormalizeDouble((anOpenPrice - anAskPrice)/_Point,Digits));
                           int      stopPoints  =  int(NormalizeDouble((aNewSLPrice - anAskPrice)/_Point,Digits));
                           int      stopLevel   =  int(MarketInfo(Symbol(),MODE_STOPLEVEL)+MarketInfo(Symbol(),MODE_SPREAD));
 
thecody1000:

I have already explained to you to not use NormalizeDouble here because Point values has no "Digits". Points are values are like 141231 for a price of 1.41231 - There are no decimal digits for points, so why would you want to Normalise an interger value with 4 or 5 decimal digits when it has none!
 
WHRoeder:
  1. Always be very careful with #defines.
  2. I'd code it
Thanks for the tips!
Reason: