10015 Invalid price

 
I got stuck trying to BUY/SELL STOP LIMIT orders. When I send this type of order, it always comes back with error 10015 (Invalid price). I've been looking at this for a few hours now and still can't figure out where the problem is. The problem is not in the "normalization" of the prices, because I always adjust the prices according to the tick size. Nor do I see the problem in the "layout" of the current price, opening price and stoplimit price. I hope I understand correctly that for a SELL STOP LIMIT order the stoplimit price must be below the current price (Bid) and the opening price above the stoplimit price. See https://www.metatrader5.com/en/terminal/help/trading/general_concept#pending_order.
Below is a listing of the trade request that I enter into OrderSend and the trade result that is returned. Right at the beginning you can see the Bid and tick size to make the information complete. Stops level and Freeze level is 0. For simplicity, I did not set either SL or TP.


Bid:        22066.4
Open Price: 22060.9
Stoplimit:  22055.4
Tick size:  0.1

Trade request:
   request.action          : TRADE_ACTION_PENDING
   request.magic           : 202502
   request.order           : n/a
   request.symbol          : NSDQ_ecn
   request.volume          : 0.50
   request.price           : 22060.9
   request.stoplimit       : 22055.4
   request.sl              : n/a
   request.tp              : n/a
   request.deviation       : 10
   request.type            : ORDER_TYPE_SELL_STOP_LIMIT
   request.type_filling    : ORDER_FILLING_IOC
   request.type_time       : ORDER_TIME_GTC
   request.expiration      : n/a
   request.comment         : Example
   request.position        : n/a
   request.position_by     : n/a

Trade result:
   result.retcode          : 10015
   result.deal             : n/a
   result.order            : n/a
   result.volume           : n/a
   result.price            : n/a
   result.bid              : n/a
   result.ask              : n/a
   result.comment          : Invalid price
   result.request_id       : n/a
   result.retcode_external : 0 
Basic Principles - Trading Operations - MetaTrader 5 Help
Basic Principles - Trading Operations - MetaTrader 5 Help
  • www.metatrader5.com
Before you proceed to study the trade functions of the platform, you must have a clear understanding of the basic terms: order, deal and position...
 
Petr Nosek:
I got stuck trying to BUY/SELL STOP LIMIT orders. When I send this type of order, it always comes back with error 10015 (Invalid price). I've been looking at this for a few hours now and still can't figure out where the problem is. The problem is not in the "normalization" of the prices, because I always adjust the prices according to the tick size. Nor do I see the problem in the "layout" of the current price, opening price and stoplimit price. I hope I understand correctly that for a SELL STOP LIMIT order the stoplimit price must be below the current price (Bid) and the opening price above the stoplimit price. See https://www.metatrader5.com/en/terminal/help/trading/general_concept#pending_order.
Below is a listing of the trade request that I enter into OrderSend and the trade result that is returned. Right at the beginning you can see the Bid and tick size to make the information complete. Stops level and Freeze level is 0. For simplicity, I did not set either SL or TP.

hi , did you reset the request structure ? request={};

 
Lorentzos Roussos #:

hi , did you reset the request structure ? request={};

I reset the request using ZeroMemory. But this has no effect, because I assign a value to each item before sending it. Those values that are "n/a" in the output are assigned 0.

 

To give you an idea, here is a relevant piece of code:

void OnTick()
  {
   MqlTick
      tick;
   if(!::SymbolInfoTick(_Symbol, tick))
      return;
   int
      digits = (int)::SymbolInfoInteger(_Symbol, SYMBOL_DIGITS);
   double
      spread = tick.ask - tick.bid,
      tickSize = ::SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE);
   MqlTradeRequest
      request = {};
   ::ZeroMemory(request);
   request.action       =  TRADE_ACTION_PENDING;
   request.magic        =  202502;
   request.order        =  0;
   request.symbol       =  _Symbol;
   request.volume       =  0.5;
   request.price        =  ::NormalizeDouble(::MathRound((tick.bid - spread * 5.0) / tickSize) * tickSize, digits);
   request.stoplimit    =  ::NormalizeDouble(::MathRound((tick.bid - spread * 10.0) / tickSize) * tickSize, digits);
   request.sl           =  0.0;
   request.tp           =  0.0;
   request.deviation    =  10;
   request.type         =  ORDER_TYPE_SELL_STOP_LIMIT;
   request.type_filling =  ORDER_FILLING_IOC;
   request.type_time    =  ORDER_TIME_GTC;
   request.expiration   =  0;
   request.comment      =  "Example";
   request.position     =  0;
   request.position_by  =  0;
   MqlTradeResult
      result = {};
   ::ZeroMemory(result);
   ::PrintFormat("Bid: %.*f ; Price: %.*f ; Stoplimit: %.*f ; SL: %.*f ; TP: %.*f ; Spread: %.*f ; Tick size: %.*f",
      digits, tick.bid, digits, request.price, digits, request.stoplimit, digits, request.sl, digits, request.tp, digits, spread, digits, tickSize);
   if(!::OrderSend(request, result))
      ::Print("Send SELL STOP LIMIT failed with return code: " + (string)result.retcode);
  }
 
Petr Nosek #:

To give you an idea, here is a relevant piece of code:

This works 

added :

  • Checking the stop level limit of the broker
  • Filling function 
  • Removed the empty values excluding the sl + tp
  • The stoplimit price above the ask

void OnTick()
  {
  static bool PLACED=false;
  if(!PLACED){
  PLACED=true;
  ResetLastError();
  double minimum_allowed=_Point*((int)SymbolInfoInteger(_Symbol,SYMBOL_TRADE_STOPS_LEVEL));
  if(GetLastError()==0){
   MqlTick
      tick;
   if(!::SymbolInfoTick(_Symbol, tick))
      return;
   int
      digits = (int)::SymbolInfoInteger(_Symbol, SYMBOL_DIGITS);
   double
      spread = tick.ask - tick.bid,
      tickSize = ::SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE);
   double distance=spread*5.0;
   double distance2=2.0;
   if(distance<=minimum_allowed){
     Print("Adjusting distance as it is less than allowed");
     distance=NormalizeDouble(minimum_allowed*1.5,_Digits);
     }
   distance2*=distance;
   MqlTradeRequest
      request = {};
   ::ZeroMemory(request);
   request.action       =  TRADE_ACTION_PENDING;
   request.magic        =  202502;
   request.symbol       =  _Symbol;
   request.volume       =  0.5;
   request.price        =  NormalizeDouble(tick.bid-distance,_Digits);//::NormalizeDouble(::MathRound((tick.bid - spread * 5.0) / tickSize) * tickSize, digits);
   request.stoplimit    =  NormalizeDouble(tick.ask+distance2,_Digits);
   request.sl           =  0.0;
   request.tp           =  0.0;
   request.type         =  ORDER_TYPE_SELL_STOP_LIMIT;
   request.type_filling =  GetFillingA(_Symbol,ORDER_TYPE_SELL_STOP_LIMIT);
   request.type_time    =  ORDER_TIME_GTC;
   request.comment      =  "Example";
   MqlTradeResult
      result = {};
   ::ZeroMemory(result);
   ::PrintFormat("Bid: %.*f ; Price: %.*f ; Stoplimit: %.*f ; SL: %.*f ; TP: %.*f ; Spread: %.*f ; Tick size: %.*f",
      digits, tick.bid, digits, request.price, digits, request.stoplimit, digits, request.sl, digits, request.tp, digits, spread, digits, tickSize);
   if(!::OrderSend(request, result))
      ::Print("Send SELL STOP LIMIT failed with return code: " + (string)result.retcode);
  }else{Print("Cannot acquire limit");}
  }
  }
//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
//---
   
  }
//+------------------------------------------------------------------+
ENUM_ORDER_TYPE_FILLING GetFillingA( const string Symb, const uint Type = ORDER_FILLING_FOK )
{
  const ENUM_SYMBOL_TRADE_EXECUTION ExeMode = (ENUM_SYMBOL_TRADE_EXECUTION)::SymbolInfoInteger(Symb, SYMBOL_TRADE_EXEMODE);
  const int FillingMode = (int)::SymbolInfoInteger(Symb, SYMBOL_FILLING_MODE);

  return((FillingMode == 0 || (Type >= ORDER_FILLING_RETURN) || ((FillingMode & (Type + 1)) != Type + 1)) ?
         (((ExeMode == SYMBOL_TRADE_EXECUTION_EXCHANGE) || (ExeMode == SYMBOL_TRADE_EXECUTION_INSTANT)) ?
           ORDER_FILLING_RETURN : ((FillingMode == SYMBOL_FILLING_IOC) ? ORDER_FILLING_IOC : ORDER_FILLING_FOK)) :
          (ENUM_ORDER_TYPE_FILLING)Type);
}
 
Lorentzos Roussos #:

This works 

added :

  • Checking the stop level limit of the broker
  • Filling function 
  • Removed the empty values excluding the sl + tp
  • The stoplimit price above the ask

I get it now. The problem was not the Stops Level (which is 0 at my broker), but my misunderstanding of the principle of Stop Limit orders. 

We need to assign the "trigger" price to request.price and the "opening" price of the limit order to request.stoplimit.

Thanks for the kick.