Features of the mql5 language, subtleties and tricks - page 70

 

Forum on trading, automated trading systems and trading strategies testing

How do I identify a chart replacement?

fxsaber, 2018.02.08 12:39

void OnTick()
{  
  const long Chart = ChartID();
  string PrevSymbol = _Symbol;
  ENUM_TIMEFRAMES PrevTF = _Period;
    
  while (!IsStopped())
  {
    if ((PrevSymbol != ChartSymbol(Chart)) || (PrevTF != ChartPeriod(Chart))) // ноль указывать НЕЛЬЗЯ!
    {      
      PrevSymbol = ChartSymbol(Chart);
      PrevTF = ChartPeriod(Chart);
      
      Alert(PrevSymbol + " " + EnumToString(PrevTF));      
    }
    
    Sleep(0);
  }
}

Zero ChartID input parameter in some functions does not cause recalculation of values. If you want actual data of the current chart, you need to use the full ID.

 

Forum on trading, automated trading systems and testing trading strategies

POSITION_TICKET != POSITION_IDENTIFIER

fxsaber, 2018.02.12 20:14

Conclusions

If we assume that this is normal behavior of MT5, and not the peculiarities of the broker's hack, then

  • ORDER_STATE_PARTIAL does not exist in historical orders.
  • Executed orders always have the ORDER_STATE_FILLED status.
  • If partially executed, a corresponding new market order is created by the trade server (ORDER_REASON_CLIENT - even if the initial order is placed automatically (EXPERT)).
  • The old live order (the ticket does not change) remains pending with a reduced volume (ORDER_VOLUME_CURRENT).
  • In this case, the old live order gets the status ORDER_STATE_PARTIAL. Actually, this flag is the result of comparison of ORDER_VOLUME_CURRENT and ORDER_VOLUME_INITIAL.
  • All open positions get the ID == OrderTicket. Where OrderTicket - the tickets, generated by the trade server.
  • A trade always has exactly one historical order, and its status is ORDER_STATE_FILLED.
  • Each executed historical order has exactly one trade.
  • The ORDER_VOLUME_INITIAL of any executed order is equal to the volume that it was executed for. That is to say, even the initial order after the complete execution has an ORDER_VOLUME_INITIAL equal to the volume of the deal that it spawned.
  • The time of the initial order (that was partially executed) does not change and is not equal to the time of its trade.
  • In the history table there is a sorting by time of orders (ORDER_TIME_SETUP) but not by time of deals. So, if you do HistorySelect from DEAL_TIME, you may not get the corresponding order into the history table.
  • The HistorySelectByPosition always returns the necessary set of deals/orders.
  • You can calculate the slippage for any trade.

Disadvantages

  • The ORDER_REASON_PARTIAL, DEAL_REASON_PARTIAL and POSITION_REASON_PARTIAL are missing. These flags must be placed immediately after REASON_EXPERT in the corresponding enumerations.
  • The corresponding market orders in partial execution of limit orders may by their nature have negative slippage. It seems to be an error only in the order type and in fact there is no market order - it is only created inside MT5 and does not go outside.

ZZY Completely confirmed hypothesis.

Forum on trading, automated trading systems and testing trading strategies

POSITION_TICKET != POSITION_IDENTIFIER

Pavel Kolchin, 2018.02.12 13:31

(I'm not sure, it's hard to check, by analogy with partial position closing)

It all works like this:

1) pending order triggered partially - position with Position_ID = Order_Ticket1 is opened

2) the rest of the order is formed into a new order Order_Ticket2 and is waiting for its fulfillment, the new Order_Ticket2 != Order_Ticket1 since there cannot be two orders in the history with the same Order_Ticket

3) the remaining order is executed - the position with Position_ID = Order_Ticket2 is opened

there are two orders in the history, two positions in the terminal, everything corresponds

 

Forum on trading, automated trading systems and testing trading strategies

Discussion on "LifeHack for trader: mixing ForEach on defines (#define)"

fxsaber, 2018.02.14 10:54

Performance measurement

#define  BENCH(A)                                                              \
{                                                                             \
  const ulong StartTime = GetMicrosecondCount();                              \
  A;                                                                          \
  Print("Time[" + #A + "] = " + (string)(GetMicrosecondCount() - StartTime)); \
}

double GetAsk()
{
  static MqlTick tick = {0};
  
  return(SymbolInfoTick(Symbol(),tick) ? tick.ask : 0);
}

#define  AMOUNT 1 e6

void OnStart()
{
  double Sum = 0;
  
  BENCH(for (int i = 0; i < AMOUNT; i++) Sum += GetAsk())
  BENCH(for (int i = 0; i < AMOUNT; i++) Sum += SymbolInfoDouble(_Symbol, SYMBOL_ASK))
  
  Print(Sum);
}


Result

Time[for(inti=0;i<AMOUNT;i++)Sum+=GetAsk()] = 78952
Time[for(inti=0;i<AMOUNT;i++)Sum+=SymbolInfoDouble(_Symbol,SYMBOL_ASK)] = 162606

I was totally wrong! SymbolInfoDouble is twice as slow as SymbolInfoTick.

Forum on trading, automated trading systems and trading strategy testing

Discussion on "LifeHack for trader: mixing ForEach on defines (#define)"

fxsaber, 2018.02.14 11:58

Incompetent. Result in Tester.

2017.09.01 00:00:10   Time[for(inti=0;i<AMOUNT;i++)Sum+=GetAsk()] = 87424
2017.09.01 00:00:10   Time[for(inti=0;i<AMOUNT;i++)Sum+=SymbolInfoDouble(_Symbol,SYMBOL_ASK)] = 83410

Where performance is needed (Optimizer), it is better to use SymbolInfoDouble. On the real, it makes no difference.


ZZY Function speed measurements should be measured in an environment where performance is important - Tester.

 

Forum on trading, automated trading systems and trading strategies testing

Bugs, bugs, questions

fxsaber, 2018.02.12 23:10

Opening BUY position by hand on two trading demo servers


RoboForex-MetaTrader 5

2018.02.13 00:02:08.424 '8520459': market buy 1.00 GBPUSD
2018.02.13 00:02:10.101 '8520459': accepted market buy 1.00 GBPUSD
2018.02.13 00:02:10.101 '8520459': deal #90389019 buy 1.00 GBPUSD at 1.38387 done (based on order #107426544)
2018.02.13 00:02:10.101 '8520459': order #107426544 buy 1.00 / 1.00 GBPUSD at 1.38387 done in 1683.949 ms


FXOpen-MT5.

2018.02.13 00:00:25.780 '18000903': market buy 1.00 GBPUSD
2018.02.13 00:00:25.912 '18000903': accepted market buy 1.00 GBPUSD
2018.02.13 00:00:25.922 '18000903': market buy 1.00 GBPUSD placed for execution
2018.02.13 00:00:25.942 '18000903': order #896454 buy 1.00 / 1.00 GBPUSD at market done in 154.252 ms
2018.02.13 00:00:25.942 '18000903': deal #80559 buy 1.00 GBPUSD at 1.38387 done (based on order #896454)

The lines of the same color indicate the same thing. However, it's clearly seen that they are in different sequence. For Robo, the message about order execution comes after the trade execution. With open, it comes BEFORE! For this reason OrderSend returns luck, but no deal yet. I.e. we get unsynchronized OrderSend with the history

The code for FXOpen-MT5

#define  PRINT(A) Print(#A + " = " + (string)(A))

void OnStart()
{
  MqlTradeRequest Request = {0};
  
  Request.action = TRADE_ACTION_DEAL;
  Request.symbol = _Symbol;
  Request.volume = 1;
  Request.type_filling = ORDER_FILLING_IOC;
  
  MqlTradeResult Result;
  
  PRINT(OrderSend(Request, Result));
  PRINT(Result.deal);
}


Result

OrderSend(Request,Result) = true
Result.deal = 0


This situation has the following explanation

Forum on trading, automated trading systems and strategy testing

Bugs, bugs, questions

Rashid Umarov, 2018.02.15 06:25

If an order is sent to an external trading system, the MetaTrader 5 trading server does not wait for a response from it and immediately returns the result of the request as "order placed". For this reason, OrderSend will always return deal=0, as there is no information about the executed deal yet. Catch it in OnTrade or OnTradeTransaction.

An example of trade event listener is given in the article What to start with when creating a trading robot for MO EX - TradeTransactionListener.mq5

OrderSend - sends an order to execute a market trade.The order is placed- for that you need to read Result.order. But no one waits for the deal(s) - there may be a lot of them and the total time of their execution is not defined.

It depends on the specific implementation of the output on the broker's side. In the general case it is not defined.

So, I highly recommend to use the demo account on FXOpen-MT5 as a test for your code, because it is quite a different one compared to other demos.


For example, I suggest to try writing a script in MQL5 with such trading logic (MQL4-style is only for quick sense display)

void OnStart()
{
  OrderCloseBy(OrderSend(_Symbol, OP_BUY, 1, Ask, 0, 0, 0), OrderSend(_Symbol, OP_SELL, 1, Bid, 0, 0, 0));
}

It is not easy at all. I also recommend to try the mentioned demo server to work on partial execution.

 
fxsaber:
Deleted a post that explained one of the most common mistakes on MT5.
It's not among the deleted ones. That's strange. Can you post it again?
 
fxsaber:

The post was a big one. Didn't expect to be deleted. I'd like to hear the reason for deletion. Because getting deleted again is masochistic.

I'm telling you, it's not among the deleted. Maybe a glitch occurred?
 

Forum on trading, automated trading systems and trading strategies testing

Organizing an order loop

fxsaber, 2018.02.16 09:40

Everything is not okay at all in MT5. Example showing the problem.

// Пример неправильного считывания торгового окружения на каждом тике
// Скрипт эмулирует два тика ТС, которая должна открыть одну позицию, если ее нет.

#include <Trade/Trade.mqh>

// Возвращает количество позиций по символу
int GetAmountPositions( const string Symb )
{
  int Res = 0;
  
  // Этот MQL5-код с ошибкой
  for (int i = PositionsTotal() - 1; i >= 0; i--)
    if (PositionGetSymbol(i) == Symb)
      Res++;

/*
  // В MT4 такой код выполняется без ошибки
  for (int i = OrdersTotal() - 1; i >= 0; i--)
    if (OrderSelect(i, SELECT_BY_POS) && (OrderType() <= OP_SELL) && (OrderSymbol() == Symb))
      Res++;
*/      
  return(Res);
}

// Пример OnTick
void ExampleOnTick()
{
  static CTrade Trade;
  
  // Если нет позиции, открываем
  if (!GetAmountPositions(_Symbol))
    Trade.Buy(1);    
}

// Эмуляция прихода двух Tick-событий
void OnStart()
{
  ExampleOnTick(); 
  
  Sleep(10); // Между двумя тиками ~10 мс.
  
  ExampleOnTick();
}

What do you think, if you run this script on a symbol with no positions, what will happen in the end?

The correct answer is that one or two positions will be opened.

The reason why this happens. After the first OrderSend, a market order appears, and if a new tick comes before the moment of its execution, there is no position yet, so the second OrderSend is made.

Because of this, a seemingly normal MT5 pattern willnot work properly and, as a consequence, most of the MT5 Expert Advisors in codobase. In this case, an almost identical MT4-template will continue to work without any problems.

The idea of PositionsTotal, not bad at first glance, is somewhat overshadowed by the need in MT5 to also analyze OrdersTotal for market orders.

Be careful!

 
fxsaber:

Because of this, a seemingly normal MT5 pattern willnot work properly and, as a consequence, most MT5 EAs in kodobase.

As a proof of this statement we can take almost any Expert Advisor from MT5 kodobase. We will not go fishing for something, but we will take the most recent Expert Advisor at the moment. It is good that it was written by an author with a large MT5-experience of publications in QB.

The source code has the following strings (my comments are highlighted)

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//....
   int total=0; // для расчета количества открытых советником позиций
//....
//--- main cycle
   for(int i=PositionsTotal()-1;i>=0;i--)
      if(m_position.SelectByIndex(i)) // selects the position by index for further access to its properties
         if(m_position.Symbol()==m_symbol.Name() && m_position.Magic()==m_magic)
           {
            total++; // расчет количества открытых позиций
//....
   if(total==0) // Если нет открытых советником позиций
     {
      if(!RefreshRates())
        {
         PrevBars=iTime(1);
         return;
        }
      //--- open BUY 
      if(MACD_MAIN_2>MACD_SIGNAL_2 && MACD_MAIN_4<MACD_SIGNAL_4) // Сигнал на покупку
        {
         double sl=(InpStopLoss!=0)?m_symbol.Ask()-ExtStopLoss:0.0;
         double tp=(InpTakeProfit!=0)?m_symbol.Ask()+ExtTakeProfit:0.0;
         OpenBuy(sl,tp); // Отправка маркет-ордера на покупку
         return;
        }
      //--- open SELL
      if(MACD_MAIN_2<MACD_SIGNAL_2 && MACD_MAIN_4>MACD_SIGNAL_4) // Сигнал на продажу
        {
         double sl=(InpStopLoss!=0)?m_symbol.Bid()+ExtStopLoss:0.0;
         double tp=(InpTakeProfit!=0)?m_symbol.Bid()-ExtTakeProfit:0.0;
         OpenSell(sl,tp); // Отправка маркет-ордера на продажу
        }
     }
   return;
  }

We have an identical situation to the one described above.

Forum on trading, automated trading systems and testing trading strategies

Peculiarities of mql5 language, tips and tricks

fxsaber, 2018.02.16 19:52

After the first OrderSend a market order appears and if a new tick comes before its execution, there is no position yet and the second OrderSend is made.

The idea of PositionsTotal, which is not bad at first sight, is somewhat overshadowed by the necessity to analyze OrdersTotal for market orders in MT5.

It means that in the general case, the EA will open two, three, etc., instead of one position. Depending on how often ticks come and how long market orders are executed.


Since almost all MT5 EAs in kodobase are written with the same logic as the MT5 template, they also have the same bug that is contained in it. This is true of almost all MT5-advisors in KB, unfortunately.

MACD EA
MACD EA
  • votes: 4
  • 2018.02.15
  • Vladimir Karputov
  • www.mql5.com
При поступлении сигнала противоположная позиция закрывается. Также советник может закрывать половину позиции (параметр Profit for closing half of the position), может переводить позицию в безубыток (параметр Breakeven). Размер открываемой позиции может задавать вручную (параметр Lots) или в процентах риска от свободной маржи (параметр Risk in...
 

On a netting there may be an open position and several market orders of any direction on the same symbol at the same time. For example, a BUY position and a BUY order. True, I have not managed to find such a demo account, because there was a rule with asynchrony everywhere

Forum on trading, automated trading systems and trading strategies testing

Bugs, bugs, questions

fxsaber, 2018.02.14 08:58

The entire OnTradeTransaction event sequence comes after the OrderSend is completed.

EA

void OnTradeTransaction ( const MqlTradeTransaction &Trans, const MqlTradeRequest&, const MqlTradeResult& )
{ 
  static bool FirstRun = true;  
  static ulong StartTime;
  
  if (FirstRun)
  {
    StartTime = GetMicrosecondCount();
    
    FirstRun = false;
  }

  Print(EnumToString(Trans.type));
  Print((GetMicrosecondCount() - StartTime) / 1000);    
}

Sending trade order by hand.

Log

2018.02.14 09:41:46.671 '8854170': instant sell 1.00 EURUSD at 1.23673
2018.02.14 09:41:46.853 '8854170': accepted instant sell 1.00 EURUSD at 1.23673
2018.02.14 09:41:46.853 '8854170': deal #192088422 sell 1.00 EURUSD at 1.23673 done (based on order #208541700)
2018.02.14 09:41:46.853 '8854170': order #208541700 sell 1.00 / 1.00 EURUSD at 1.23673 done in 190.608 ms


Result of Expert Advisor

2018.02.14 09:41:46.853 TRADE_TRANSACTION_ORDER_ADD
2018.02.14 09:41:46.853 0
2018.02.14 09:41:46.853 TRADE_TRANSACTION_DEAL_ADD
2018.02.14 09:41:46.853 1
2018.02.14 09:41:46.853 TRADE_TRANSACTION_ORDER_DELETE
2018.02.14 09:41:46.853 1
2018.02.14 09:41:46.853 TRADE_TRANSACTION_HISTORY_ADD
2018.02.14 09:41:46.853 2
2018.02.14 09:41:46.853 TRADE_TRANSACTION_REQUEST
2018.02.14 09:41:46.853 2


We can perfectly see from the time column and the numeric values of the EA that the duration of trade order execution has no effect on the sequence of OnTradeTransaction events. All the asynchrony goes to hell! They have managed to screw it up so badly. Build 1755.

For example, when OrderSendAsync market order is placed in the Terminal, the market order doesn't even appear for a moment. Perhaps the developers decided to do this to speed things up a bit.

 

Forum on trading, automated trading systems and trading strategies testing

Discussion of the article "Visualizing trade strategy optimization in MetaTrader 5"

fxsaber, 2018.02.22 08:39

In frame mode, OnInit, OnDeinit, OnTick, OnTrade, OnTradeTransaction and OnTimer are ignored. Only OnChartEvent works.

Of course, because of the OnChartEvent exception it requires a mandatory check for the frame mode flag.

Reason: