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.

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...
- CTrade - Sell
- CTrade - OrderOpen
- Data Structures - Trade Request Result Structure
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={};
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); }
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.

You are missing trading opportunities:
- Free trading apps
- Over 8,000 signals for copying
- Economic news for exploring financial markets
Registration
Log in
You agree to website policy and terms of use
If you do not have an account, please register