Self-learning the MQL5 language from scratch - page 52

 

Pay attention to the filter by symbol and by wizard in the position loop. If there is no filter, but you trawl all open positions on all symbols, and this is bad.

So, at first glance, everything seems to be fine.

Совершение сделок - Торговые операции - Справка по MetaTrader 5
Совершение сделок - Торговые операции - Справка по MetaTrader 5
  • www.metatrader5.com
Торговая деятельность в платформе связана с формированием и отсылкой рыночных и отложенных ордеров для исполнения брокером, а также с управлением текущими позициями путем их модификации или закрытия. Платформа позволяет удобно просматривать торговую историю на счете, настраивать оповещения о событиях на рынке и многое другое. Открытие позиций...
 
Andrei Novichkov:

Pay attention to the filter by symbol and by wizard in the position loop. If there is no filter, but you trawl all open positions on all symbols, and this is bad.

So, everything seems to be OK at first sight.

Thank you very much, Andrey! I understand everything about Magic because several positions may be opened for one symbol, but another question has arisen. Will the Expert Advisor go through the open positions for all symbols at once, if it is not explicitly pointed to the current symbol? And this despite the fact that it is set for a certain currency pair, for example, EURUSD? Honestly, I do not quite understand this point.

Regards, Vladimir.

 
MrBrooklin:

Thank you very much, Andrey! I understand everything about Magic, because several positions may be opened on one symbol, but I have another question. Will the EA look through the open positions for all symbols at once, if it is not explicitly pointed to the current symbol? And this despite the fact that it is set for a certain currency pair, for example, EURUSD? Honestly, I do not quite understand this point.

Sincerely, Vladimir.


Yes. It is set in all open positions for all symbols.
Consistently for all open positions.
Here is a simple trawl in the textbook.

https://book.mql4.com/ru/build/trading
 
MrBrooklin:

So, on the basis of the read literature, I wrote a short algorithm for creating an Expert Advisor with the trailing stop function:

  1. Let's create an Expert Advisor to automate work on trailing (tracking) level Stop Loss of an already open position with specified Take Profit and Stop Losslevels .
  2. In the Expert Advisor, create a block of input parameters with two parameters: set "trailing level" and set "trailing step".
  3. When new quotes come in, process them with OnTick( ) function. Trailing works only when a new tick comes for the current symbol.
  4. Let's create and run a loop to search all positions.
  5. If we suddenly find no open positions, we return to the loop
  6. We refresh the quotes.
  7. If there is an open position, we continue.
  8. We define the type of an open position: Buy or Sell.
  9. If there is an open Buyposition , we define where the current price is located relatively to the open position .
  10. If the current price is higher than the price at which the position is opened, we check at what level it has risen.
  11. If the current price has reached the "trailing level" defined in the input parameters, we move theStop Loss to the level without the loss that equals the opening price of theBuy position. Otherwise we do nothing.
  12. If the current price exceeds the Trailing Stop level by the value equal to the Trailing Stop level, theStop Loss is moved from the opening price level of Buy position by the value equal to the Trailing Stop level and so on until the price reaches the Take Profit level specified for this position .
  13. If the price turns and re aches the level ofStop Lossalready moved , the position is closed .
  14. If the position isSell, we define where the current price is relative to the open position .
  15. If the current price is lower than the price of the open position, we check at what level it has fallen.
  16. If the current price has reached the trailing level specified in the input parameters, we move Stop Loss to the level without the loss equal to the opening price of theSell position. Otherwise we do nothing.
  17. If the current price exceeds the Trailing Stop level by the value equal to the Trailing Stop level, theStop Loss is moved from the opening Sell position level by the value equal to the Trailing Stop level and so on until the price reaches the Take Profit level specified for that position .
  18. If the price turns and reaches the level ofStop Loss, the position is closed .

Please review the algorithm and give me some hints on what points have been missed.

Sincerely, Vladimir.

The theory is not bad, now let's focus on the practice. Will it work?

 
Aliaksandr Hryshyn:

Good on the theory, now the practice. Can you do it?

I'll try. But you understand that this requires an entirely different level of knowledge, and I don't have it yet.

Regards, Vladimir.

 
Aleksey Masterov:

Yes. On all the open poses on all the symbols...
Consistently across all open poses.
Here's a simple trawl already in the textbook.

https://book.mql4.com/ru/build/trading

Yes, Alexey, I've already seen this code. It's in the form of an include file. To be honest, I haven't found anything about the symbol in it, though I've viewed it several times. Perhaps I misunderstood something or am just searching poorly.

Sincerely, Vladimir.

 

For now, let's continue with the functions.

As I wrote earlier, functions are everywhere, you have to love them and you have to know how to write them. Functions, are our little fighters in solving global problems. If we were generals in an army, what kind of fighters would we want to control? Here's a rough list:

  • A fighter must clearly execute an order. The average intelligence level of an infantryman is not great. Therefore it is better to set clear and simple objectives for such fighters: "take a bunker", "get a tongue", "mine a bridge".
  • If the task is difficult don't look for a super clever fighter to accomplish it. It is better to divide the task into several subtasks and take two or three stupider but more efficient fighters. Let everyone solve their subtasks without any questions, or better yet let them be ignorant of the concept and the task as a whole. Then if someone is taken prisoner it will not be a problem, the whole plan will not be revealed.
  • A soldier must follow the order regardless of the surroundings: snow, rain, Paris and women - if such surroundings have no effect on the implementation of the order, then those conditions and the external environment must be ignored.
  • It happens that tasks can be difficult. They require many fighters to solve them. A general cannot be assigned to each fighter. Instead, you must assign a smarter soldier to lead several combatants. This group in turn unite with the same in a company of soldiers and appoint them a superior officer.

But we got sidetracked, let's move on to functions again.

If a function solves too many tasks as a whole - then following the analogy, it's a very clever fighter who, if something goes wrong with it, could ruin the whole enterprise. If you ask what such a function does, the answer could be long. If the result of this function suddenly stops being correct, it will be very difficult to find out what causes an error in it (because there are many tasks, much code, a lot of calls to subprocedures and where exactly the error is difficult to understand).

If a function calculates correct results on Mondays, Wednesdays and Sundays and on the rest days depending on our "mood", can we rely on this function? Imagine that the OrderSend function, say, opens positions only on Thursdays and if some magic parameter with value 13 is defined. And this is not nonsense or fantasy at all. This behavior can be arranged at a click of fingers - it's enough to make the function dependent on some parameters in the external environment.

Suppose the function:

double sum(double a, double b)
{
   return a+b;
}

will always return the sum of two values, regardless of the external environment. It means that even if we copy this function into another script or Expert Advisor, it will work perfectly well there. This function can be written once and used in many of our programs by just obtuse copying. We will always be able to rely on its result knowing that its operation does not depend on anything. Such functions, the result of which does not depend on their environment, are called side-effect-free or pure functions. If we strive to write pure functions, we soon get a lot of them. This means you can combine them into a file and include them in your new projects. This is called code reuse. We don't do the work twice. Instead, we use already written functions that we know and whose reliability has been tested more than once.

Let's look at the anti-example now:

double c = 0.0;
double sum(double a, double b)
{
   return a+b+c;
}

The result seems to be the same, because c is always zero. Or is it not always? What if someone changes c somewhere? What then? What if someone somewhere also uses the external variable c, but for his own purposes, and he has a variable c of a different type, let's say string? Combining these two functions is no longer possible (the compiler will not allow to declare two variables with the same name). Their common dependencies are also difficult to solve. I don't know what to do with it at all. For example, I still don't know a reliable and easy way to make such functions work together.

Even if there is no other function and only one function reads an external variable, it is not so easy to copy it elsewhere. We have to copy both this function and its dependency. But what if we copy these functions into a common file? We get 50 or 100 of these functions there. And each of them copies with itself a heap of its own dependent variables. We get a tangle of related variables with unclear functions. But what is it all for? What problems does it solve? Why create unnecessary dependencies when you can do without them in the vast majority of cases?

Functions have one more surprising feature. Functions are self-descriptive. In other words, you don't have to draw a scheme, just choose good names and divide the general algorithm into functions. Here is an example:

void OnTick()
{
   if(SelectFirstPendingOrder(ORDER_TYPE_BUY))
       CancelSelectPendingOrder();
}

I don't know what this code does, because the functions are not even written. But if I were to read it, it would probably mean that if the first <first> pending order with direction ORDER_TYPE_BUY is successfully selected, it would be canceled (the first function selects, the second one cancels). Since the code would run every tick, no matter how many pending orders there were, each one would be cancelled sooner or later. This also means that any attempt to place a pending buy order would be suppressed - the order would be immediately removed. At the same time, the sell orders will be placed without any problems.

There are only two lines of code and two functions. And the algorithm is non-trivial, and what is more important, it is reliable.

When speaking of MCL, we should mention a bit more about pure functions. Since it is an application language, it is difficult to write anything without relying on data provided by the terminal. After all, this is the main task: to properly interact with the trading environment. Formally, any trading environment is changeable: prices, number of orders, balance changes, etc., etc. Therefore, any function interacting with such a changeable trading environment is not clear. Because the external trading environment can also be considered as some global variable, which is constantly changing. But when we write OrdersTotal(), we do not expect that this function will always return the same value. Instead, we expect it to return the number of pending orders that will naturally vary. Therefore, in MQL, we will consider the functions as clean and reusable, even in case they call functions of external API, like OrdersTotal(). It will be our reasonable indulgence.

 
Vasiliy Sokolov:

Let's continue with the functions...

Thank you very much, Vasily, for the priceless knowledge you share not only with me, but also with those novice programmers who read or will read this topic!

With the same great respect, Vladimir.

 

I continue studying the MQL5 programming language. While there were no serious remarks on the code writing algorithm of Trailing_Stop Expert Advisor (I remember about the symbol and Magic, I will add it to the algorithm later!), I created input parameters for the EA and wrote the code of the loop that starts the search of open positions.

When I ran the Expert Advisor I saw a problem - in the "Experts" tab of the trading terminal 2 identical messages "A loop has started" appear on every tick, despite the fact that the trading terminal has only one chart of the currency pair EURUSD and only one position is opened on it. And these messages have the same exact time of output.

I fought till midnight but could not win. I cannot understand what the problem is.


The code of the Expert Advisor is written in English, while the comments are in Russian in order to make the process easier. In this EA, I tried to describe everything, as I promised earlier, in a way understandable to a 1st grade student of a programming school.

Regards, Vladimir.

//+------------------------------------------------------------------+
//|                                                Trailing_Stop.mq5 |
//|                        Copyright 2020, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2020, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"

input ushort TrailingLevel=100; //Уровень трейлинга (для включения)
input ushort TrailingStep=10;   //Шаг трейлинга (для перемещения)
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---

   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---

  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
   /* Для цикла for создаем локальную переменную i и присваиваем ей значение "торговая функция PositionsTotal",
      которая возвращает нам количество открытых позиций*/
   int i=PositionsTotal();
   /* Разберемся, что такое оператор for.
      Оператор for состоит из трех Выражений и выполняемого Оператора:
      for(Выражение_1; Выражение_2; Выражение_3)
         Оператор;
      Выражение_1 описывает инициализацию цикла. За инициализацию цикла будет отвечать "Торговая функция PositionsTotal".
      Выражение_2 проверяет условия завершения цикла. Если оно истинно, то выполняется Оператор в теле цикла for.
      Все повторяется до тех пор, пока Выражение_2 не станет ложным. Если оно ложно, цикл заканчивается
      и управление передается следующему оператору.
      Выражение_З вычисляется после каждой итерации (т.е. после каждого повторения действия).
   */
   for(i; i>=0; i--) //запускаем цикл перебора открытых позиций (i) от максимума до нуля (i>=0) с шагом минус 1 (i--)
      Print("Запущен цикл");
  }
//+------------------------------------------------------------------+
//| Timer function                                                   |
//+------------------------------------------------------------------+
void OnTimer()
  {
//---

  }
//+------------------------------------------------------------------+
 
MrBrooklin:


i equals the number of open positions, so many cycles will be with printing

Print("Запущен цикл");
you need to remove the "=" sign in
   for(i; i>=0; i--)
why do you need to go through the loop when the number of open positions is 0. this zero call is where the second print is coming from
Reason: