invalid stops

 

Hello;


I get almost every time an error "invalid stops" when I test my EA. I think it's weird that it's not happening 100% of the times, sometimes the order go through. So, I try to figure out, what the difference when the order is taken and when he is rejected because my stops.

How can I find where the issue is? What things should I check/add/code to have valid stops?


I checked the actual value of SL/TP, but they show positive value with the correct number of digit every time.

I tried to make them lower/higher to be sure that they are not too close from the entry price, but the result is the same.


The code :

double currentAsk = SymbolInfoDouble(_Symbol,SYMBOL_ASK); 
double StopLoseUSD = NormalizeDouble(xxxx,Digits()); 
double TakeProfitUSD = NormalizeDouble(xxxx,Digits());
double SizeReel = NormalizeDouble(xxxx,Digits());

myTradingControlPanel.PositionOpen(_Symbol,ORDER_TYPE_BUY,SizeReel,currentAsk,StopLoseUSD,TakeProfitUSD);

The error :

2023.01.26 18:13:27.434 Core 01 2022.11.12 02:14:40   failed market buy 0.18 BTCUSD sl: 17498.47 tp: 16756.34 [Invalid stops]

2023.01.26 18:13:27.434 Core 01 2022.11.12 02:14:40   CTrade::OrderSend: market buy 0.18 BTCUSD sl: 17498.47 tp: 16756.34 [invalid stops]

 
Your T/P is below your S/L. That is incorrect. For a buy, your T/P should be above the open price and your S/L below your open price. Not the other way round.
failed market buy 0.18 BTCUSD sl: 17498.47 tp: 16756.34 [Invalid stops]
 

But besides the obvious error above, you should also always normalise prices based on tick size. Don't use the "NormalizeDouble". Also verify your Stops Level too.

Forum on trading, automated trading systems and testing trading strategies

Tick size vs Point(), can be a little tricky in Multicurrency EA

Fernando Carreiro, 2022.03.09 12:11

Tick Size and Point Size can be very different especially on stocks and other symbols besides forex.

Always use Tick Size to adjust and align your prices, not the point size. In essence, make sure that your price quotes, are properly aligned to the Tick size (see following examples).

...
double tickSize = SymbolInfoDouble( _Symbol, SYMBOL_TRADE_TICK_SIZE );
...
double normalised_price = round( price / tick_size ) * tick_size;
...
// Or use a function
double Round2Ticksize( double price )
{
   double tick_size = SymbolInfoDouble( _Symbol, SYMBOL_TRADE_TICK_SIZE );
   return( round( price / tick_size ) * tick_size );
};

Forum on trading, automated trading systems and testing trading strategies

Can anyone tell me what this BS is on Mt4 with not being able to put limit orders 20 points near the current price?

Lorentzos Roussos, 2023.01.02 18:52

You can see it programmatically (if the broker has set it) with this script 

#property strict
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
  int sylimit=(int)SymbolInfoInteger(_Symbol,SYMBOL_TRADE_STOPS_LEVEL);
  int milimit=(int)MarketInfo(_Symbol,MODE_STOPLEVEL);
  int limit=MathMax(sylimit,milimit);
  Comment("Limit in points "+IntegerToString(limit));
  }
//+------------------------------------------------------------------+


SYMBOL_TRADE_STOPS_LEVEL

Minimal indention in points from the current close price to place Stop orders

int


StopLevel Minimum Distance Limitation.

A trade operation will not be performed if any of the following conditions is disrupted.

Order Type
Open Price StopLoss (SL) TakeProfit (TP)
Buy
Modification is prohibited
Bid-SL StopLevel TP-Bid StopLevel
Sell
Modification is prohibited SL-Ask StopLevel Ask-TP StopLevel
BuyLimit
Ask-OpenPriceStopLevel OpenPrice-SL StopLevel TP-OpenPrice StopLevel
SellLimit
OpenPrice-Bid StopLevel SL-OpenPrice StopLevel OpenPrice-TP StopLevel
BuyStop
OpenPrice-Ask StopLevel OpenPrice-SL StopLevel TP-OpenPrice StopLevel
SellStop
Bid-OpenPrice StopLevel SL-OpenPrice StopLevel OpenPrice-TP StopLevel

FreezeLevel Limitation (Freezing Distance).

Market orders can not be closed if the StopLoss and TakeProfit values violate the FreezLevel parameter requirements.
StopLoss or TakeProfit orders can not be modified if StopLoss or TakeProfit values violate the StopLevel parameter requirements.
Pending orders can not be deleted or modified if the declared open price violates the FreezeLevel parameter requirements.

Order Type
Open Price StopLoss (SL) TakeProfit (TP)
Buy
Modification is prohibited Bid-SL > FreezeLevel TP-Bid > FreezeLevel
Sell
Modification is prohibited SL-Ask > FreezeLevel Ask-TP > FreezeLevel
BuyLimit
Ask-OpenPrice > FreezeLevel Regulated by the StopLevel parameter
Regulated by the StopLevel parameter
SellLimit
OpenPrice-Bid > FreezeLevel Regulated by the StopLevel parameter Regulated by the StopLevel parameter
BuyStop
OpenPrice-Ask > FreezeLevel Regulated by the StopLevel parameter Regulated by the StopLevel parameter
SellStop
Bid-OpenPrice > FreezeLevel Regulated by the StopLevel parameter Regulated by the StopLevel parameter
 
Fernando Carreiro #:
You T/P is below your S/L. That is incorrect. For a buy, your T/P should be above the open price and your S/L below your open price. Not the other way round.

Indeed, I didn't even notice that, but I don't see how this value can be like that. For this simple EA, I just took the EMA300 for SL and the EMA100 for TP and before that I checked that the EMA100 is indeed greater than the EMA300.


I go through some other error in the rapport, and here is another one :


2023.01.26 18:07:49.394 Core 01 2022.12.05 17:08:40   failed market buy 1.71 BTCUSD sl: 17047.18 tp: 17169.85 [Invalid stops]

2023.01.26 18:07:49.394 Core 01 2022.12.05 17:08:40   CTrade::OrderSend: market buy 1.71 BTCUSD sl: 17047.18 tp: 17169.85 [invalid stops]

2023.01.26 18:07:49.394 Core 01 2022.12.05 17:09:40   failed market buy 1.71 BTCUSD sl: 17039.98 tp: 17162.56 [Invalid stops]

2023.01.26 18:07:49.394 Core 01 2022.12.05 17:09:40   CTrade::OrderSend: market buy 1.71 BTCUSD sl: 17039.98 tp: 17162.56 [invalid stops]

2023.01.26 18:07:49.394 Core 01 2022.12.05 17:10:40   market buy 1.71 BTCUSD sl: 17019.86 tp: 17139.36 (17085.03 / 17094.03 / 17085.03)

2023.01.26 18:07:49.394 Core 01 2022.12.05 17:10:40   deal #10 buy 1.71 BTCUSD at 17094.03 done (based on order #12)

2023.01.26 18:07:49.394 Core 01 2022.12.05 17:10:40   deal performed [#10 buy 1.71 BTCUSD at 17094.03]

2023.01.26 18:07:49.394 Core 01 2022.12.05 17:10:40   order performed buy 1.71 at 17094.03 [#12 buy 1.71 BTCUSD at 17094.03]

2023.01.26 18:07:49.394 Core 01 2022.12.05 17:10:40   CTrade::OrderSend: market buy 1.71 BTCUSD sl: 17019.86 tp: 17139.36 [done at 17094.03]


The EA tried 2 time to pass a trade, it failed because invalid stops, and on the third time the order pass. But all the value are similar between all the three attempt...


 
CrokCrypto #:Indeed, I didn't even notice that, but I don't see how this value can be like that. For this simple EA, I just took the EMA300 for SL and the EMA100 for TP and before that I checked that the EMA100 is indeed greater than the EMA300.

But that is not what is happening. You also don't mention checking where the current price is at in relation to the moving averages. So, you will need to fix the logic of your code.

 
Fernando Carreiro #:

But that is not what is happening. You also don't mention checking where the current price is at in relation to the moving averages. So, you will need to fix the logic of your code.

Here is the code so far :

I check if it's an uptrend or downtrend (from ema100, 200 and 300), then check if theses ema are not too close from each other, then if the price hit the ema200, I enter a trade with the ema300 as SL and the ema100 as TP.

Just want to practice code logic here, but obviously I miss a bunch of things…

I changed the code for open a trade, in order to get the retcode : 10013 is it now.


   if(EMA100M5DataTable[0] > EMA200M5DataTable[0] && EMA200M5DataTable[0] > EMA300M5DataTable[0]) // Uptrend
      {
      if((EMA100M5DataTable[0]-EMA200M5DataTable[0])/EMA200M5DataTable[0] > 0.0025 && (EMA200M5DataTable[0]-EMA300M5DataTable[0])/EMA200M5DataTable[0] > 0.0025 && (EMA100M5DataTable[0]-EMA200M5DataTable[0])/EMA200M5DataTable[0] > (EMA200M5DataTable[0]-EMA300M5DataTable[0])/EMA200M5DataTable[0]) // No range
         {
         if(currentAsk < EMA200M5DataTable[0] && currentAsk > EMA200M5DataTable[0]*0.9995) // Price hit EMA200 in a uptrend
            {
            if(PositionSelect(_Symbol) == false) // Don't have an open position
               {
               StopLoseUSD = NormalizeDouble(EMA300M5DataTable[0],Digits()); // Stop Lose price
               StopLosePer = (currentAsk-EMA300M5DataTable[0])/currentAsk; // Stop Lose %
               TakeProfitUSD = NormalizeDouble(EMA100M5DataTable[0],Digits()); // Take Profit price
               Size = capital*leviermax/currentAsk; // Size of the position with full leverage
               SizeMax = (dailylossmax*0.475)/StopLosePer/currentAsk; // Size max of the position (risk management)
               if(SizeMax <= Size)
                  {
                  SizeReel = NormalizeDouble(SizeMax,Digits()); // Size of the position cut to 2 decimals
                  }
                  else
                  {
                  SizeReel = NormalizeDouble(Size,Digits()); // Size of the position cut to 2 decimals
                  }
               //myTradingControlPanel.PositionOpen(_Symbol,ORDER_TYPE_BUY,SizeReel,currentAsk,StopLoseUSD,TakeProfitUSD,"Long hit 200EMA"); // Open Position
               MqlTradeRequest request;
               request.action = TRADE_ACTION_DEAL;
               request.symbol = _Symbol;
               request.volume = SizeReel;
               request.type = ORDER_TYPE_BUY;
               request.type_filling = ORDER_FILLING_FOK; 
               request.price = currentAsk;
               request.sl = StopLoseUSD;
               request.tp = TakeProfitUSD;
               MqlTradeResult result;
                  
               myTradingControlPanel.OrderSend(request,result);
               Print(result.retcode);
                }
             }
          }
       }
   
   if(EMA100M5DataTable[0] < EMA200M5DataTable[0] && EMA200M5DataTable[0] < EMA300M5DataTable[0]) // Downtrend
      {
      if((EMA200M5DataTable[0]-EMA100M5DataTable[0])/EMA200M5DataTable[0] > 0.0025 && (EMA300M5DataTable[0]-EMA200M5DataTable[0])/EMA200M5DataTable[0] > 0.0025 && (EMA200M5DataTable[0]-EMA100M5DataTable[0])/EMA200M5DataTable[0] > (EMA300M5DataTable[0]-EMA200M5DataTable[0])/EMA200M5DataTable[0]) // No range
         {
         if(currentBid > EMA200M5DataTable[0] && currentBid < EMA200M5DataTable[0]*1.0005) // Price hit EMA200 in a downtrend
            {
            if(PositionSelect(_Symbol) == false) // Don't have an open position
               {
               StopLoseUSD = NormalizeDouble(EMA300M5DataTable[0],Digits()); // Stop Lose price
               StopLosePer = -(currentBid-EMA300M5DataTable[0])/currentBid; // Stop Lose %
               TakeProfitUSD = NormalizeDouble(EMA100M5DataTable[0],Digits()); // Take Profit price
               Size = capital*leviermax/currentBid; // Size of the position with full leverage
               SizeMax = (dailylossmax*0.475)/StopLosePer/currentBid; // Size max of the position (risk management)
               if(SizeMax <= Size)
                  {
                  SizeReel = NormalizeDouble(SizeMax,Digits()); // Size of the position cut to 2 decimals
                  }
                  else
                  {
                  SizeReel = NormalizeDouble(Size,Digits()); // Size of the position cut to 2 decimals
                  }
               //myTradingControlPanel.PositionOpen(_Symbol,ORDER_TYPE_BUY,SizeReel,currentBid,StopLoseUSD,TakeProfitUSD,"Short hit 200EMA"); // Open Position
               MqlTradeRequest request;
               request.action = TRADE_ACTION_DEAL;
               request.symbol = _Symbol;
               request.volume = SizeReel;
               request.type = ORDER_TYPE_SELL;
               request.type_filling = ORDER_FILLING_FOK; 
               request.price = currentBid;
               request.sl = StopLoseUSD;
               request.tp = TakeProfitUSD;
               MqlTradeResult result;
                  
               myTradingControlPanel.OrderSend(request,result);   
               Print(result.retcode);
                }
             }
          }
       }
 
CrokCrypto #: Here is the code so far :
               StopLosePer = (currentAsk-EMA300M5DataTable[0])/currentAsk; // Stop Lose %

You buy at the Ask and sell at the Bid. Pending Buy Stop orders become market orders when hit by 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 at 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, average maximum spread = 134.
    My EURCHF shows average spread = 18 points, average maximum spread = 106.
    (your broker will be similar).
              Is it reasonable to have such a huge spreads (20 PIP spreads) in EURCHF? - General - MQL5 programming forum (2022)

 
William Roeder #:

You buy at the Ask and sell at the Bid. Pending Buy Stop orders become market orders when hit by 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 at 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, average maximum spread = 134.
    My EURCHF shows average spread = 18 points, average maximum spread = 106.
    (your broker will be similar).
              Is it reasonable to have such a huge spreads (20 PIP spreads) in EURCHF? - General - MQL5 programming forum (2022)


My SL/TP price are the EMA300 price and the EMA100 price. I don't use currentAsk to calculate my SL/TP (the code line you took, I use it for determining my SL % and so my possible position size).

The spread on this chart is a constant : 9$.

 
Fernando Carreiro #:

But besides the obvious error above, you should also always normalise prices based on tick size. Don't use the "NormalizeDouble". Also verify your Stops Level too.


I changed it. I use this function has you linked it in your answer. Still the same problem, tho.

double Round2Ticksize( double price )
{
   double tick_size = SymbolInfoDouble( _Symbol, SYMBOL_TRADE_TICK_SIZE );
   return( round( price / tick_size ) * tick_size );
};
 

I up my topic because I'm still completely stuck : I get the error invalid request 10013 all the way. And after hours watching documentation and my code, I can't see why it's not working. Before this EA I did something a bit similar it was working, when I compare the 2, I don't see difference in my way of sending order, so I don't understand why this very simple code doesn't work properly.


I posted the full code a few comments up, please, is there anyone seeing what I'm missing about this ordersend request?

Reason: