Typical mistakes and how to deal with them when dealing with the trading environment

 
In this thread we will discuss common mistakes made when working with the trading environment of the terminal in some algorithms, methods of their elimination and avoidance in the future.
 
OK.
Just as an introduction:
The Expert Advisor analyses the direction (or profit, ... ) of the last closed order. The last order was closed 2 days ago.
The trader set the history depth to 1 day.
OrdersHistoryTotal() does not see that order.
The solution?
 
Andrei Fandeev:
Ok.
Just as an introduction:
The Expert Advisor analyzes the direction (or profit, ... ) of the last closed order. The last order was closed 2 days ago.
And the trader set the history depth to 1 day.
OrdersHistoryTotal() does not see that order.
Solution?

For MT4 - in my opinion, unambiguously, give the user a warning when launching the EA to use the required depth of history.

MT5 allows loading the history to the required depth.

 
Artyom Trishkin:

For MT4 - in my opinion, unambiguously, give the user a warning when launching the EA to use the required depth of history.

Relying on the user is a bad idea. There needs to be a check.
Artem, in MT4 I haven't found Get for getting the value of set history depth.
Is it really impossible to get it programmatically?

 
Andrei Fandeev:

Relying on the user is a bad idea. You need a check.
Artem, in MT4 I couldn't find Get to get the value of the set history depth.
Is it really impossible to get it programmatically?

Indeed.

 

There are two paradigms for working with the trading environment and writing EAs.

  1. Event inputs (OnTick, OnTimer, etc.) depend on each other. There is information that MUST have between events (not for speed, like cache, but for usability). For example, we need to save OrderSendAsync result and use it in OnTradeTransaction. Caches are NOT mandatory information and are used only for speeding up. That's why we don't consider them right away.
  2. Event inputs (OnTick, OnTimer etc.) are NOT dependent on each other. Each input is from scratch. Roughly like a Script that you run yourself on each event.
In MT4 you could probably solve everything through the second option. MT5 is not so clear-cut.


Advantages of the second option over the first

  • You can terminate the algorithm at any place (normal and abnormal).
  • You can start/continue the algorithm at any place.
  • High reliability.


Disadvantages

  • In Tester will be inferior to the first variant in terms of performance.
  • The logic "from scratch" makes you write somewhat "illogical" code, which takes some getting used to at the first stage.

 

How do I compare trading environment APIs? Introduce a wide variety of different TSs. And let's imagine our ideal virtual API, which would allow with minimal effort to embody the TS in a reliable code.

If it is possible to create this very ideal virtual API as a wrapper from a real API, then the original API is excellent. Despite even how much effort and time it takes to create a wrapper.


MT4 and MT5 are excellent APIs by this criterion. Only the source APIs are difficult, but they allow (no architectural/technical constraints) to write a great wrapper and therefore are good.

So when they say that MT5 is more complex than MT4 - they mean that they haven't met an MT5 wrapper yet (maybe it hasn't been written yet) that is as usable as the MT4 wrapper they use.


Generally speaking, both platforms allow you to create a single high-level API (wrapper) from low-level APIs. So the complexity of their trading environment APIs is equal!

 

MT4 has a pretty high-level API, so few people try to write a universally more user-friendly wrapper. But that's not the case with MT5 - the original low-level API just REQUIRES to write some kind of wrapper. So there's not much point in discussing features of each wrapper in this thread. Rather, it's important to show that a wrapper will still be required. What features of a low-level API do need to be considered when writing a high-level API.

В общем, обе платформы позволяют из низкоуровневых API создать единый высокоуровневый API (обертка). Так что сложности API торговых окружений у них равны!

Based on this statement, we need to learn how to write MT5 code which is not inferior to MT4 code in terms of usability. API wrappers may be different (syntax usually), but architecturally MT5 should not be inferior to MT4, otherwise the highlighted statement is lost. Therefore, the more cumbersome MT5 code should not be seen as a reason to criticize, but as a help to stitch it into a no less user friendly wrapper than MT4.

 
Let's take a simple MT4-template TS

Forum on trading, automated trading systems and testing trading strategies

Organizing an order loop

fxsaber, 2018.02.15 23:19

// Шаблон большинства ТС

#property strict // обязательно

// Сигнал на покупку
bool BuySignal( const string Symb ) { return(true); }

// Сигнал на продажу
bool SellSignal( const string Symb ) { return(false); }

// Находит ордер соответствующего типа
bool OrdersScan( const string Symb, const int Type )
{
  for (int i = OrdersTotal() - 1; i >= 0; i--)
    if (OrderSelect(i, SELECT_BY_POS) && (OrderType() == Type) && (OrderSymbol() == Symb))
      return(true);    
    
  return(false);  
}

// Торговое действие на сигнал
bool Action( const string Symb, const int Type, const double Lots = 1 )
{
  bool Res = true;    
  
  // Закрыли противоположные сигналу позиции
  while ((OrdersScan(Symb, 1 - Type)) && (Res = OrderClose(OrderTicket(), OrderLots(), OrderClosePrice(), 100)));

  // Открыли позицию по сигналу
  return(Res && !OrdersScan(Symb, Type) && OrderSend(Symb, Type, Lots, SymbolInfoDouble(Symb, Type ? SYMBOL_BID : SYMBOL_ASK), 100, 0, 0));
}

// Шаблон торговой стратегии
void Strategy( const string Symb )
{
  if (BuySignal(Symb))
    Action(Symb, OP_BUY);
  else if (SellSignal(Symb))
    Action(Symb, OP_SELL);
}

void OnTick()
{
  Strategy(_Symbol);
}

It doesn't show the convenience of MT4 in the slightest, it just serves as a baseline point of comparison. It's that lower bar of usability that an MT5 wrapper should be able to hold. The template is written based on the second paradigm.


It would seem that we write the same thing on MT5

Forum on trading, automated trading systems and testing trading strategies

Organizing an order overflow cycle

fxsaber, 2018.02.15 22:30

// Шаблон большинства ТС

#include <Trade/Trade.mqh>

// Сигнал на покупку
bool BuySignal( const string Symb ) { return(true); }

// Сигнал на продажу
bool SellSignal( const string Symb ) { return(false); }

// Находит позицию соответствующего типа
bool PositionsScan( const string Symb, const ENUM_POSITION_TYPE Type )
{
  for (int i = PositionsTotal() - 1; i >= 0; i--)
    if ((PositionGetSymbol(i) == Symb) && (PositionGetInteger(POSITION_TYPE) == Type))
      return(true);    
    
  return(false);  
}

// Торговое действие на сигнал
bool Action( const string Symb, const ENUM_POSITION_TYPE Type, const double Lots = 1 )
{
  static CTrade Trade;    
  bool Res = true;    
  
  // Закрыли противоположные сигналу позиции
  while ((PositionsScan(Symb, (ENUM_POSITION_TYPE)(1 - Type))) && (Res = Trade.PositionClose(PositionGetInteger(POSITION_TICKET))));

  // Открыли позицию по сигналу
  return(Res && !PositionsScan(Symb, Type) && (Type ? Trade.Sell(Lots, Symb) : Trade.Buy(Lots, Symb)));
}

// Шаблон торговой стратегии
void Strategy( const string Symb )
{
  if (BuySignal(Symb))
    Action(Symb, POSITION_TYPE_BUY);
  else if (SellSignal(Symb))
    Action(Symb, POSITION_TYPE_SELL);
}

void OnTick()
{
  Strategy(_Symbol);
}

For some reason some people write more code for the same TS. But in fact this code does just as well. Most TCs only require writing BuySignal and SellSignal. Nothing else is needed.

The example template is specifically written with SB. So question to MT5 experts, is the code correct?


The function that shows the need of wrapper is marked in red. Its problem is described here. Someone will recall that this is the ancient problem of position reopening that was solved using Sleep in ancient times, waiting for the position to open after OrderSend. But in fact, this problem has nothing to do with OrderSend. You need to know how to correctly read the trading environment.

 
fxsaber:

You need to be able to read the trading environment correctly.

Getting it right with a simple example

// Возвращает количество позиций по символу
int GetAmountPositions( const string Symb )
{
  int Res = 0;
  
  for (int i = PositionsTotal() - 1; i >= 0; i--)
    if (PositionGetSymbol(i) == Symb)
      Res++;
      
  for (int i = OrdersTotal() - 1; i >= 0; i--)
    if (OrderGetTicket(i) && (OrderGetInteger(ORDER_TYPE) <= ORDER_TYPE_SELL) &&
        !OrderGetInteger(ORDER_POSITION_ID) && (OrderGetString(ORDER_SYMBOL) == Symb))
      Res++;  

/*
  for (int i = OrdersTotal() - 1; i >= 0; i--)
    if (OrderSelect(i, SELECT_BY_POS) && (OrderType() <= OP_SELL) && (OrderSymbol() == Symb))
      Res++;
*/      
  return(Res);
}

The point in a nutshell is this: if there is a market order, consider it a "position" as well. In quotes, because it's a wrapped position. The highlighted code usually doesn't appear anywhere. But it avoids re-opening positions. The most interesting thing here is highlighted in red. The necessity of this chip is not immediately apparent.

The matter is that there are so-called closing market orders. The same SL/TP. Obviously, we would not like to see such market orders as "positions". And we would not like to see those orders that we have placed to close as well. So the highlighted condition is the appropriate filter.


ZZZ paste this code here and check the result on the demo server.

 
fxsaber:

The right option using a simple example

The point in brief is this: if there is a market order, consider it a "position" as well. In quotes, because it's a wrapped position. The highlighted code usually doesn't appear anywhere. But it avoids re-opening positions. The most interesting thing here is highlighted in red. The necessity of this chip is not immediately apparent.

The matter is that there are so-called closing market orders. The same SL/TP. Obviously, we would not like to see such market orders as "positions". And we would not like to see those orders that we have placed to close as well. So the highlighted condition is the appropriate filter.


HZ paste this code here and check the result on the demo server.

Question: what will happen if after sending a trade order until the next tick the market order is not placed by the server?

Reason: