Self-learning the MQL5 language from scratch - page 71

 
MrBrooklin:

Igor, the desire to learn MQL5 language is not lost, on the contrary, it only increases. I'm just torn, why I'm so dumb and cannot understand simple things with this loop operator. The main thing is that without the loop operator the code works perfectly, but with the loop it is a complete mess. I will get to the bottom of this anyway. However I've got much less time for self-study since the quarantine period is over and I've got rare moments to study the language at work. Mostly I study the language in the evening and late at night.

I need to solve 2 tasks to finally get down to writing the Trailing Stop code:

  1. I need to write a code with the use of the for loop operator to search all open positions for all symbols, and if there are none, then open a Buy position in the interval from 09:00:00 to 09:01:00, and at 23:50:00 close it forcibly, if during the trading day did not trigger a stop loss. Without the for loop operator, as I wrote before, everything works perfectly. Now I want to achieve the same result, but with using loop.
  2. Write 2 functions that determine the direction of position opening by the first tick that appears in the time frame from 09:00:00 to 09:01:00. If the first tick is upwards, a Buy position should open; if the first tick is downwards, the Sell position should open accordingly. It's not a strategy, it's just my "want" not to use the random condition.
Sincerely, Vladimir.

Vladimir, you are getting into some kind of weird stuff. You have been given a template: https://www.mql5.com/ru/forum/352460/page58#comment_18726492 You ignored it and decided to go ahead with your wits. This way is difficult and may take years. On your way, study C, C++, Rust, C#, polymorphism, inheritance, dereferencing of pointers, dynamic type conversion: Check or drive. You must take the shortest way to the aim. If you want trailing, write trailing. You don't need to study C and C++ to do it. This all as an elective if you feel like it.

The situation with the for loop is illustrative. It's a powerful construction that must be applied to the right place. You have netting and an auxiliary algorithm. That's why there is no enumeration of positions, there are no mages, so you don't have this loop. Of course, everything will work without it, but the loop only produces oil. But you stubbornly try to use it, it seems to be an end in itself: to use as much and as much as possible, to have as much as possible.

 
Vasiliy Sokolov:

Vladimir, you are getting into a bit of a rut. You were given a template: https://www.mql5.com/ru/forum/352460/page58#comment_18726492 You ignored it and decided to go ahead with your mind. This road is difficult and may take years. On your way, study C, C++, Rust, C#, polymorphism, inheritance, dereferencing of pointers, dynamic type conversion: Check or drive. You must take the shortest way to the aim. If you want trailing, write trailing. You don't need to study C and C++ to do it. This all as an elective if you feel like it.

The situation with the for loop is illustrative. It's a powerful construction that must be applied to the right place. You have netting and an auxiliary algorithm. That's why there is no enumeration of positions, there are no mages, so you don't have this loop. Of course, everything will work without it, but the loop only makes you feel like oil. But you are obstinately trying to use it, so it seems to be an end in itself: you may use as much of everything and anything to keep in stock as possible.

Hello, Vasily!

Thank you for timely joining the topic and directing me on the right way as always. Now let me explain everything in one order:

  1. A template in the Expert Advisor was inserted exactly when you have kindly provided it to me, for which I want to express my gratitude!
  2. I decided that an EA with Trailin Stop should be tested in the strategy tester, but I did not know how to do it without automatically opening at least one position. That is why I started to feel anxious when writing a "full-fledged" Expert Advisor. I put it in quotes because my Expert Advisor has no strategy as such. I simply did not want to use the random condition to open a position.
  3. None of the Expert Advisor's interlocutors, except for you, suggested that the for loop to search positions in this situation is not necessary. My fault, I could have guessed it long ago myself and asked - was a loop really necessary? As it turned out, you don't. Thanks again for the tip!
  4. To finally go to writing the trailing stop and not to abandon the process half-way through, I only need to write the code of 2 functions that determine the direction of opening of a netting Buy or Sell position.
  5. Yes, I completely agree with you that the self-study is starting to drag on. But if take into account that I follow unexplored and crooked road, I hope it is possible to make a discount.
  6. During the whole period of self-study I've got huge amount of information and now I'm trying not only to arrange it but also use it in practice. For this purpose I downloaded an Expert Advisor from CodeBase, developed it and used it for a fortnight on a demo account of a Forex dealer. The result is exactly what I expected. Soon I will start using it on a real account. This is already a plus!
  7. I do not chase the speed of self-study because I've already written earlier that the excess of information from time to time comes stupor.
  8. For the whole period of self-study little by little began to memorize English words and phrases that appear after the compilation code. I look in Google Translate less often now. This is also a positive moment in self-study.
  9. I will post everything I have written in the Expert Advisor exactly when a complete workpiece for a trailing stop is ready. I will try to finish it on Saturday. This is where the main work on writing the trailing stop code will start.

Vasily, I am extremely grateful to you for guidance and constructive criticism! I also express my gratitude to all the participants of this theme who help me in my self-study of MQL5 programming language from scratch.

Self-study continues. To be continued.

Regards, Vladimir.

 
Андрей:

Good afternoon everyone!

If I wanted to add something interesting, I think the idea of "self-training in MQL5 from scratch" is not quite right. If a person is 0 in programming, he has to learn how to program first. If the aim is to learn how to program in MQL from the scratch, a person must first learn howto program in C, at least the very basics, and then learn to write in MQL, because MQL is in fact C, but it is specialized for a certain task, a person doesn't understand how loops work, and already trying to write programs. It's like trying to learn Latin without knowing Russian...

Another thing is that C is not a very friendly language to learn programming, it is simple, but it is too concise, it is difficult for a beginner to read and understand code without having basic understanding of algorithms, data types, Boolean algebra. In C three characters in a row may mean several strings in another language.

To learn to program simply from scratch, for the base, to learn to talk to a computer in one (no matter what) language, I would recommend starting with Pascal, the easiest book to start with it (2-3 weeks at ease), then C (there after Pascal max week with diligence, master the syntax, I mean the basic language skills!) and then take up specialized languages like MQL, because MQL is C, which has a little twist and simplification, since it is designed for a single task and the compiler knows the obvious. And C in turn is a kind of RAR-compressed Pascal, but Pascal is almost English =).

Now about loops:

When I learned programming, the analogy with sums in algebra helped me, where you specify the initial value of n, the final value of n and the formula with this n to calculate.

Hello Andrey! I completely agree with you about the basis. I don't have it and never had it. But as the saying goes - Moscow wasn't built at once! Thank you for your advices and tips!

Regards, Vladimir.

 
Roman Shiredchenko:

Yeah. I agree - his codes are good too! You're getting yourself worked up over nothing. Take your time sorting out the code without rushing and that's it. It's all elementary here - select and trawl: (how much easier - just your topic of choosing the NEED position... :-))

Besides that, include files - it means that they are in your code as functions as well and that's it.

Thanks, Roman, for the codes and links! I am dealing with the codes calmly and surely do not hurry anywhere!

Sincerely, Vladimir.

 

Good day and good mood everyone!

I continue studying the MQL5 programming language . Today, as promised, I'm posting for everyone to see the code of the Expert Advisor template designed for writing a trailing stop. Due to the fact that the EA template code turned out to be quite cumbersome, so we had to reduce the comments as much as possible. The full version of the Expert Advisor with detailed comments on each line of code, in a presentation accessible to a student of the 1st grade of a programming school, will be published later in the form of a file with the working name Trailing_Stop.mq5 so as not to produce another "footcloth" on the site.

Before publishing the code, the EA was tested in the strategy tester . No problems have been identified. The EA uses a netting position accounting system. This accounting system implies that at one time there can be only one open position on the account for the same symbol (financial instrument).

At the moment, the Expert Advisor has the ability to:

  1. Check the trading account on which it is planned to install it. If the adviser is installed on a demo account, then permission to continue working will appear in the message window. If an attempt is made to install the adviser on a real account , then a warning will appear in the message window about the impossibility of continuing work, after which it will automatically be deleted from the working window of the trading terminal .
  2. Once a trading day at exactly 9:00 a.m. according to Moscow time, automatically open one position in the direction where the first tick will be directed. For example, if at 9:00 a.m. Moscow time, the first tick will be directed upwards, which means a BUY position will open, if the first tick is down, then a SELL position will open.
  3. Set stop loss size.
  4. Set lot size.
  5. Set other parameters that will be necessary for the trailing stop to work.

In addition, the EA has a pre-installed template, kindly provided by Vasily Sokolov, which will be filled with code during the self-learning process.

A WARNING!!!

The Expert Advisor is developed according to the self-study plan for a demo account and for educational purposes only! Not intended for trading on a real account and making a profit!

With best 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 description "Советник создан для демо-счёта исключительно в учебных целях!"
#property description "Не предназначен для торговли на реальном счёте и извлечения прибыли!"
#property version      "1.00"
/* Краткое описание советника Trailing_Stop. Код советника разрабатывается в соответствии с
   планом самообучения языку программирования MQL5. В советнике применена неттинговая система
   учёта позиций. Эта система учета подразумевает, что в один момент времени на счете может быть
   только одна открытая позиция по одному и тому же символу (финансовому инструменту). Алгоритм
   работы советника прост: один раз в торговый день ровно в 9 ч. 00 мин. по московскому времени
   будет открываться одна позиция в ту сторону, куда будет направлен первый тик. Например, если
   первый тик будет направлен вверх, то значит откроется позиция BUY, если первый тик будет вниз,
   то значит откроется позиция SELL. У открытой позиции сразу будет устанавливаться ордер Stop Loss
   фиксированного размера для минимизации потерь в том случае, если цена финансового инструмента
   станет двигаться в убыточном направлении. Если цена инструмента достигнет этого уровня, то
   позиция полностью закроется автоматически. Если цена финансового инструмента будет двигаться
   в прибыльном направлении, то тогда автоматически включится в работу Trailing_Stop (Трейлинг Стоп).
   Схема работы Трейлинг Стоп:
   1. С приходом новых котировок советник проверяет, прибыльна ли открытая позиция.
   2. Как только прибыль (в пунктах) станет равной либо большей той величины, которая указана во
      входном параметре советника "Уровень перестановки Stop Loss в безубыток", автоматически
      поступит команда для перемещения ордера Stop Loss на тот уровень цены, по которому открылась
      существующая позиция, т.е. в безубыток.
   3. Если цена и дальше продолжит движение с увеличением прибыльности позиции, то при превышении
      величины, указаной во входном параметре советника "Уровень перестановки Stop Loss в безубыток"
      на величину, которая указана во входном параметре "Шаг трейлинг стопа", Stop Loss вслед за
      текущей ценой автоматически переместится с уровня безубытка на величину этого шага.
   4. Если прибыльность позиции уменьшится, то модификации ордера происходить не будет. Таким
      образом, будет автоматически фиксироваться прибыль торговой позиции.
   Если в течении торгового дня открытая позиция не закроется по Stop Loss или Trailing_Stop, то в
   23 ч. 50 мин. советник принудительно закроет эту позицию.

   ВАЖНО!!! Советник создан для демо-счёта исключительно в учебных целях!
            Не предназначен для торговли на реальном счёте и извлечения прибыли!*/

//--- Создадим входные параметры советника
input ushort BreakevenLevel= 100 ; //Уровень перестановки Stop Loss в безубыток
input ushort TrailingStop= 10 ;     //Шаг трейлинг стопа
input ushort SL= 200 ;             //Стоп-лосс
input double Lot= 0.1 ;             //Лот
input long    Magic_Number= 3215 ;   //Магический номер
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
/* Функция инициализации советника OnInit с типом данных int. Если возвращаемое значение для функции
   return(-1), то это "неудачная инициализация". Если возвращаемое значение для функции return(0), то
   это "удачная инициализация". INIT_SUCCEEDED означает, что инициализация прошла успешно и дальше
   можно продолжать тестирование эксперта. Этот код означает то же самое, что и нулевое значение, т.е.
   "удачная инициализация".
*/
int OnInit ()
  {
//--- Определим тип счёта на который устанавливаем советник: демо или реальный счет
   ENUM_ACCOUNT_TRADE_MODE account_type=( ENUM_ACCOUNT_TRADE_MODE ) AccountInfoInteger ( ACCOUNT_TRADE_MODE );
//--- теперь превратим значение перечисления в понятный вид
   string trade_mode;               //создадим переменную для торгового режима
   /* Создадим оператор-переключатель switch, который cравнивает значение выражения с константами во всех
      вариантах case и передает управление оператору с соответствующим значением выражения.*/
   switch (account_type)
     {
       case ACCOUNT_TRADE_MODE_DEMO : //если ключевое слово ACCOUNT_TRADE_MODE_DEMO
         trade_mode= "Счёт DEMO" ;     //значит торговый режим счёта - демо
         break ;                     //оператор break прекращает выполнение ближайшего оператора switch
       case ACCOUNT_TRADE_MODE_REAL : //если ключевое слово ACCOUNT_TRADE_MODE_REAL
         trade_mode= "Счёт REAL" ;     //значит торговый режим счёта - реальный
         break ;                     //оператор break прекращает выполнение ближайшего оператора switch
     }
   if (account_type== ACCOUNT_TRADE_MODE_REAL ) //если торговый режим счёта - реальный
     {
       //--- выводим окно сообщений на торговом терминале и закрываем советник
       MessageBox ( "Работа на реальном счете запрещена, выходим!" , "Советник запущен на реальном счете" );
       return (- 1 ); //возвращаем для функции OnInit ненулевое значение означающее "неудачная инициализация"
     }
   if (account_type== ACCOUNT_TRADE_MODE_DEMO ) //если торговый режим счёта - демо
     {
       //--- выводим окно сообщений на торговом терминале и продолжаем работу советника
       MessageBox ( "Работа на демо-счете разрешена!" , "Советник запущен на демо-счете" );
       return ( 0 ); //возвращаем для функции OnInit нулевое значение означающее "удачная инициализация"
     }
   return ( INIT_SUCCEEDED );
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit ( const int reason)
  {
//--- сообщим код завершения работы эксперта
   Print ( __FILE__ , ": Код причины деинициализации = " ,reason);
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick ()
  {
//--- Зададим время открытия и закрытия позиции
   MqlDateTime time_current,time_open,time_open1,time_close;
   TimeToStruct ( TimeCurrent (),time_current);
   TimeToStruct (( D'1970.01.01 09:00:00' ),time_open);
   TimeToStruct (( D'1970.01.01 09:01:00' ),time_open1);
   TimeToStruct (( D'1970.01.01 23:50:00' ),time_close);
//--- Зададим условия для открытия позиций BUY и SELL   
   double price= SymbolInfoDouble ( Symbol (), SYMBOL_ASK );
   double point= SymbolInfoDouble ( Symbol (), SYMBOL_POINT );
   int digits=( int ) SymbolInfoInteger ( Symbol (), SYMBOL_DIGITS );
   price= NormalizeDouble (price,digits);
   if ( PositionSelect ( Symbol ())== false
      && PositionGetInteger ( POSITION_MAGIC )!=Magic_Number
      && time_current.hour==time_open.hour
      && time_current.min>=time_open.min
      && time_current.min<time_open1.min
      && (TickUP()==(price+point)))
     {OpenBUY();}
   else
     {
       if ( PositionSelect ( Symbol ())== false
         && PositionGetInteger ( POSITION_MAGIC )!=Magic_Number
         && time_current.hour==time_open.hour
         && time_current.min>=time_open.min
         && time_current.min<time_open1.min
         && (TickDOWN()==(price-point)))
        {OpenSELL();}
     }
   if (time_current.hour==time_close.hour && time_current.min==time_close.min)
      CloseALL();

//+------------------------------------------------------------------+
//| Шаблон трейлинг стопа предоставленный Василием Соколовым         |
//+------------------------------------------------------------------+

//-- Выбираем позиции по текущему символу. Если позиции нет и выбирать нечего, то выходим!
   if (! PositionSelect ( Symbol ()))
       return ;
//-- Стоп-лосс длинной позиции переставляем в безубыток и тралим его
   if ( PositionGetInteger ( POSITION_TYPE ) == POSITION_TYPE_BUY )
     {
      SetBreakevenForBuyPosition(); // установить безубыток для Buy позиции
      TrailingStopLossForBuyPosition(); // перетащить Stop Loss для Buy позиции
     }
//-- Стоп-лосс короткой позиции переставляем в безубыток и тралим его
   else
       if ( PositionGetInteger ( POSITION_TYPE ) == POSITION_TYPE_SELL )
        {
         SetBreakevenForSellPosition(); // установить безубыток для Sell позиции
         TrailingStopLossForSellPosition(); // перетащить Stop Loss для Sell позиции
        }
  }

//+------------------------------------------------------------------+
//| Timer function                                                   |
//+------------------------------------------------------------------+
void OnTimer ()
  {
//---

  }
//+------------------------------------------------------------------+
//| Buy Position Open function                                       |
//+------------------------------------------------------------------+

//--- Создадим функцию для открытия позиции Buy и назовём её OpenBUY
void OpenBUY()
  {
//--- Создадим запрос на сервер и получим ответ с результатом
   MqlTradeRequest request= { 0 };
   MqlTradeResult result= { 0 };
//--- Создадим переменные необходимые для работы с сервером
   double price= SymbolInfoDouble ( Symbol (), SYMBOL_ASK );
   double point= SymbolInfoDouble ( Symbol (), SYMBOL_POINT );
   int digits=( int ) SymbolInfoInteger ( Symbol (), SYMBOL_DIGITS );
   request.action= TRADE_ACTION_DEAL ;
   request.symbol= Symbol ();
   request.volume=Lot;
   request.deviation= 2 ;
   request.magic=Magic_Number;
   request.type= ORDER_TYPE_BUY ;
   request.price= NormalizeDouble (price,digits);
   /*Создадим запрос на торговый сервер request.sl, в котором укажем, где должен находиться уровень
     стоп лосс относительно цены, по которой открылась позиция "BUY". Уровень SL должен находиться
     ниже цены, поэтому пишем price-SL*point. Для нормализации уровня SL применим функцию преобразования
     данных NormalizeDouble, где обязательно умножим уровень SL на point (размер одного пункта) и укажем
     digits(количество знаков после запятой).
   */
   request.sl= NormalizeDouble (price-SL*point,digits);
   if (! OrderSend (request,result))
       PrintFormat ( "OrderSend error %d" , GetLastError ());
   PrintFormat ( "retcode=%u  deal=%I64u  order=%I64u" ,result.retcode,result.deal,result.order);
  }
//+------------------------------------------------------------------+
//| Sell Position Open function                                      |
//+------------------------------------------------------------------+

//--- Создадим функцию для открытия позиции Sell и назовём её OpenSELL
void OpenSELL()
  {
//--- Создадим запрос на сервер и получим ответ с результатом
   MqlTradeRequest request= { 0 };
   MqlTradeResult result= { 0 };
//--- Создадим переменные необходимые для работы с сервером
   double price= SymbolInfoDouble ( Symbol (), SYMBOL_ASK );
   double point= SymbolInfoDouble ( Symbol (), SYMBOL_POINT );
   int digits=( int ) SymbolInfoInteger ( Symbol (), SYMBOL_DIGITS );
   request.action= TRADE_ACTION_DEAL ;
   request.symbol= Symbol ();
   request.volume=Lot;
   request.deviation= 2 ;
   request.magic=Magic_Number;
   request.type= ORDER_TYPE_SELL ;
   request.price= NormalizeDouble (price,digits);
   /*Точно также создадим запрос на торговый сервер request.sl, в котором укажем, где должен
     находиться уровень стоп лосс относительно цены, по которой открылась позиция "SELL".
     Уровень SL теперь должен находиться выше цены, поэтому пишем price+SL*point. Снова для
     нормализации уровня SL применим функцию преобразования данных NormalizeDouble, где обязательно
     умножим уровень SL на point (размер одного пункта) и укажем digits(количество знаков после запятой).
   */
   request.sl= NormalizeDouble (price+SL*point,digits);
   if (! OrderSend (request,result))
       PrintFormat ( "OrderSend error %d" , GetLastError ());
   PrintFormat ( "retcode=%u  deal=%I64u  order=%I64u" ,result.retcode,result.deal,result.order);
  }
//+------------------------------------------------------------------+
//| All Position Close function                                      |
//+------------------------------------------------------------------+

//--- Создадим функцию для закрытия всех позиций и назовем её CloseALL
void CloseALL()
  {
//---  Создадим запрос на сервер и получим ответ с результатом
   MqlTradeRequest request;
   MqlTradeResult   result;
//--- перебираем все открытые позиции
   for ( int i= PositionsTotal ()- 1 ; i>= 0 ; i--)
     {
       //--- определяем параметры
       ulong   ticket= PositionGetTicket (i);                                             // тикет позиции
       string symbol= PositionGetString ( POSITION_SYMBOL );                               // символ
       int     digits=( int ) SymbolInfoInteger (symbol, SYMBOL_DIGITS );                     // количество знаков после запятой
       ulong   magic= PositionGetInteger ( POSITION_MAGIC );                               // MagicNumber позиции
       double volume= PositionGetDouble ( POSITION_VOLUME );                               // объем позиции
       ENUM_POSITION_TYPE type=( ENUM_POSITION_TYPE ) PositionGetInteger ( POSITION_TYPE ); // тип позиции
       //--- выводим информацию о позиции
       PrintFormat ( "#%I64u %s  %s  %.2f  %s [%I64d]" ,
                  ticket,
                  symbol,
                   EnumToString (type),
                  volume,
                   DoubleToString ( PositionGetDouble ( POSITION_PRICE_OPEN ),digits),
                  magic);
       //--- если MagicNumber совпадает
       if (magic==Magic_Number)
        {
         //--- обнуляем значения запроса на сервер и результата ответа
         ZeroMemory (request);
         ZeroMemory (result);
         //--- устанавливаем параметры операции
         request.action   = TRADE_ACTION_DEAL ;   // тип торговой операции (немедленное исполнение)
         request.position =ticket;               // тикет позиции
         request.symbol   =symbol;               // символ
         request.volume   =volume;               // объём позиции
         request.deviation= 2 ;                   // допустимое отклонение от цены
         request.magic    =Magic_Number;         // MagicNumber позиции
         if (type== POSITION_TYPE_BUY )             // если тип позиции "покупка"
           {
             //--- запрашиваем лучшее предложение цены на "продажу" по текущему символу
            request.price= SymbolInfoDouble (symbol, SYMBOL_BID );
             //--- запрашиваем тип рыночного ордера на "продажу" и закрываем позицию встречным ордером
            request.type = ORDER_TYPE_SELL ;
           }
         else // в противном случае
           {
             //--- запрашиваем лучшее предложение цены на "покупку" по текущему символу
            request.price= SymbolInfoDouble (symbol, SYMBOL_ASK );
             //--- запрашиваем тип рыночного ордера на "покупку" и закрываем позицию встречным ордером
            request.type = ORDER_TYPE_BUY ;
           }
         //--- выводим информацию о закрытии
         PrintFormat ( "Close #%I64d %s %s" ,ticket,symbol, EnumToString (type));
         //--- отправляем запрос
         if (! OrderSend (request,result))
             PrintFormat ( "OrderSend error %d" , GetLastError ());   // если отправить запрос не удалось, выводим код ошибки
         //--- информация об операции
         PrintFormat ( "retcode=%u  deal=%I64u  order=%I64u" ,result.retcode,result.deal,result.order);
         //---
        }
     }
  }
//+------------------------------------------------------------------+
//| Tick Up function                                                 |
//+------------------------------------------------------------------+
double TickUP()
  {
//---
   double price= SymbolInfoDouble ( Symbol (), SYMBOL_ASK );
   double point= SymbolInfoDouble ( Symbol (), SYMBOL_POINT );
   int digits=( int ) SymbolInfoInteger ( Symbol (), SYMBOL_DIGITS );
   double price1= NormalizeDouble (price+point,digits);
   return (price1);
  }
//+------------------------------------------------------------------+
//| Tick DOWN function                                               |
//+------------------------------------------------------------------+
double TickDOWN()
  {
//---
   double price= SymbolInfoDouble ( Symbol (), SYMBOL_ASK );
   double point= SymbolInfoDouble ( Symbol (), SYMBOL_POINT );
   int digits=( int ) SymbolInfoInteger ( Symbol (), SYMBOL_DIGITS );
   double price2= NormalizeDouble (price-point,digits);
   return (price2);
  }
  
//+------------------------------------------------------------------+
//| Шаблон трейлинг стопа предоставленный Василием Соколовым         |
//+------------------------------------------------------------------+
  
//+------------------------------------------------------------------+
//| Устанавливает sl позиции BUY в безубыток                         |
//+------------------------------------------------------------------+
void SetBreakevenForBuyPosition() // установить безубыток для Buy позиции
  {
//---
   ;
  }
//+------------------------------------------------------------------+
//| Тралит стоп-лосс позиции BUY вслед за ценой                      |
//+------------------------------------------------------------------+
void TrailingStopLossForBuyPosition() // перетащить Stop Loss для Buy позиции
  {
//---
   ;
  }
//+------------------------------------------------------------------+
//| Устанавливает sl позиции SELL в безубыток                        |
//+------------------------------------------------------------------+
void SetBreakevenForSellPosition() // установить безубыток для Sell позиции
  {
//---
   ;
  }
//+------------------------------------------------------------------+
//| Тралит стоп-лосс позиции SELL вслед за ценой                     |
//+------------------------------------------------------------------+
void TrailingStopLossForSellPosition() // перетащить Stop Loss для Sell позиции
  {
//---
   ;
  }
//+------------------------------------------------------------------+
 

Good day and good mood everyone!

I continue studying the MQL5 programming language. Yesterday I wrote the code of Stop Loss at Breakeven for Sell and Buy positions. I am pasting the code without any comments yet. I will publish the full version of the Expert Advisor with a detailed description of each code line, in a form accessible for 1st year pupils of the programming school, later in the file with the working title Trailing_Stop.mq5. Before publishing the code, we checked the performance of the Expert Advisor in the strategy tester. No problems were found.

Regards, Vladimir.

//+------------------------------------------------------------------+
//| Устанавливает sl позиции BUY в безубыток                         |
//+------------------------------------------------------------------+
void SetBreakevenForBuyPosition() // функция "Установить безубыток для позиции Buy"
  {
//---  Создадим запрос на сервер и получим ответ с результатом
   MqlTradeRequest request={0};
   MqlTradeResult result={0};
//--- Запустим цикл перебора всех открытых позиций
   for(int i=PositionsTotal()-1; i>=0; i--)
     {
      //--- параметры позиции Buy
      ulong  ticket=PositionGetTicket(i);                         // тикет позиции
      string symbol=PositionGetString(POSITION_SYMBOL);           // символ
      int    digits=(int)SymbolInfoInteger(symbol,SYMBOL_DIGITS); // количество знаков после запятой
      ulong  magic=PositionGetInteger(POSITION_MAGIC);            // MagicNumber позиции
      double volume=PositionGetDouble(POSITION_VOLUME);           // объем позиции
      double sl=PositionGetDouble(POSITION_SL);                   // Stop Loss позиции
      ENUM_POSITION_TYPE type=(ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);  // тип позиции
      //--- выводим информацию о позиции Buy
      PrintFormat("#%I64u %s  %s  %.2f  %s  sl: %s  tp: %s  [%I64d]",
                  ticket,
                  symbol,
                  EnumToString(type),
                  volume,
                  DoubleToString(PositionGetDouble(POSITION_PRICE_OPEN),digits),
                  DoubleToString(sl,digits),
                  magic);
      //--- если MagicNumber совпадает
      if(magic==Magic_Number)
        {
         double point=SymbolInfoDouble(symbol,SYMBOL_POINT);
         double price=SymbolInfoDouble(Symbol(),SYMBOL_ASK);
         double price_open=PositionGetDouble(POSITION_PRICE_OPEN);
         double price_breakeven=NormalizeDouble(price_open+BreakevenLevel*point,digits);
         //--- зададим условие переноса Stop Loss в безубыток для позиции Buy
         if(type==POSITION_TYPE_BUY && price==price_breakeven)
           {
            sl=NormalizeDouble(price_open,digits);
           }
         //--- обнуляем значения запроса и результата
         ZeroMemory(request);
         ZeroMemory(result);
         //--- устанавливаем параметры операции
         request.action=TRADE_ACTION_SLTP; // тип торговой операции
         request.position=ticket;          // тикет позиции
         request.symbol=symbol;            // символ
         request.sl=sl;                    // Stop Loss позиции
         request.magic=Magic_Number;       // MagicNumber позиции
         //--- выводим информацию о модификации
         PrintFormat("Modify #%I64d %s %s",ticket,symbol,EnumToString(type));
         //--- отправка запроса
         if(!OrderSend(request,result)) // если отправить запрос не удалось
            PrintFormat("OrderSend error %d",GetLastError()); // выводим код ошибки
         //--- информация об операции
         PrintFormat("retcode=%u  deal=%I64u  order=%I64u",result.retcode,result.deal,result.order);
        }
     }
  }
//+------------------------------------------------------------------+
//| Устанавливает sl позиции SELL в безубыток                        |
//+------------------------------------------------------------------+
void SetBreakevenForSellPosition() // функция "Установить безубыток для позиции Sell"
  {
//---  Создадим запрос на сервер и получим ответ с результатом
   MqlTradeRequest request={0};
   MqlTradeResult result={0};
//--- Запустим цикл перебора всех открытых позиций
   for(int i=PositionsTotal()-1; i>=0; i--)
     {
      //--- параметры позиции Sell
      ulong  ticket=PositionGetTicket(i);                         // тикет позиции
      string symbol=PositionGetString(POSITION_SYMBOL);           // символ
      int    digits=(int)SymbolInfoInteger(symbol,SYMBOL_DIGITS); // количество знаков после запятой
      ulong  magic=PositionGetInteger(POSITION_MAGIC);            // MagicNumber позиции
      double volume=PositionGetDouble(POSITION_VOLUME);           // объем позиции
      double sl=PositionGetDouble(POSITION_SL);                   // Stop Loss позиции
      ENUM_POSITION_TYPE type=(ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);  // тип позиции
      //--- выводим информацию о позиции Sell
      PrintFormat("#%I64u %s  %s  %.2f  %s  sl: %s  tp: %s  [%I64d]",
                  ticket,
                  symbol,
                  EnumToString(type),
                  volume,
                  DoubleToString(PositionGetDouble(POSITION_PRICE_OPEN),digits),
                  DoubleToString(sl,digits),
                  magic);
      //--- если MagicNumber совпадает
      if(magic==Magic_Number)
        {
         double point=SymbolInfoDouble(symbol,SYMBOL_POINT);
         double price=SymbolInfoDouble(Symbol(),SYMBOL_BID);
         double price_open=PositionGetDouble(POSITION_PRICE_OPEN);
         double price_breakeven=NormalizeDouble(price_open-BreakevenLevel*point,digits);
         //--- зададим условие переноса Stop Loss в безубыток для позиции Sell
         if(type==POSITION_TYPE_SELL && price==price_breakeven)
           {
            sl=NormalizeDouble(price_open,digits);
           }
         //--- обнуляем значения запроса и результата
         ZeroMemory(request);
         ZeroMemory(result);
         //--- устанавливаем параметры операции
         request.action=TRADE_ACTION_SLTP; // тип торговой операции
         request.position=ticket;          // тикет позиции
         request.symbol=symbol;            // символ
         request.sl=sl;                    // Stop Loss позиции
         request.magic=Magic_Number;       // MagicNumber позиции
         //--- выводим информацию о модификации
         PrintFormat("Modify #%I64d %s %s",ticket,symbol,EnumToString(type));
         //--- отправка запроса
         if(!OrderSend(request,result)) // если отправить запрос не удалось
            PrintFormat("OrderSend error %d",GetLastError()); // выводим код ошибки
         //--- информация об операции
         PrintFormat("retcode=%u  deal=%I64u  order=%I64u",result.retcode,result.deal,result.order);
        }
     }
  }
//+------------------------------------------------------------------+
 
MrBrooklin:

Good day and good mood everyone!

I continue studying the MQL5 programming language. Today, as promised, I am pasting the code of the template of my Expert Advisor designed for writing a trailing stop. Due to the fact that the code of the template EA is quite cumbersome, I had to cut the comments as short as possible. The full version of the Expert Advisor with detailed comments on each line of the code, in a form accessible for a 1st grade programming school student, will be published later as a file with the working name Trailing_Stop.mq5, to avoid creating another spoilage on the website.

...

Very good. The main idea is well captured. Especially I like the development process:

MrBrooklin:

Good day and good mood everyone!

I continue studying the MQL5 programming language. Yesterday I wrote the code for Stop Loss at Breakeven for Buy and Sell positions.

I.e. everything is correct. You do not have to solve the problem all at once in one place. You should gradually solve it, just like you did. First, you describe the basic logic in the OnTick function and basic functions like OpenBUY, OpenSELL, TickUP, TickDown.

Then, when this basic code is debugged, compiled and works within its capabilities, you start describing the other functions. This may be done the next day or even a week. This means that you don't have to change the main code. I think you can see why.

Now you need to hone this manner of development: continue writing functions, linking functionality through them to the existing code. The existing program should work correctly. The complexity should not increase. The functions to be added must return simple, clear results. Their names should be as simple and clear to you. If you can't do this, it may be because you need to write not one but two or even three functions to solve the problem. At first, the overall framework of the application will be hard to define. That's why you'd better ask advice of more experienced colleagues. Over time, you will learn to develop such templates on your own.

As time goes by,you will need to use more and more language constructs within functions to make them fit your needs.At this point, you will gradually and most importantly, organically extend your knowledge of language constructs, learn loops, arrays and even working with pointers.

In fact, you have already learned the hardest part of programming, although you have not yet consolidated the material you have learned. All you need to do now is to repeat it many times to consolidate it. From here there will be nothing fundamentally new, everything is the same: General template -> Description of the names of functions and their parameters-> Writing the contents of these functions -> Arrangement of these functions in the central unit. That's it. All that remains is to perfect the skill and be consistent. Various additional constructions you start using like loops and arrays are just details, sometimes cleverly done, but nothing more than details.

 
By the way, pay attention to the overall size of your programme. It's already quite substantial. How do you like it? By the way, a novice cannot write such a large code size: variables start getting confused, brackets get too large, compilation errors start creeping in like mushrooms after the rain. After compilation, a program of such size starts glitching and nobody can understand what's wrong. And everything works in your code for some reason), and it is clear in the functions what is going on and how. In a word, it's a beauty.
 

As there is no limit to perfection, I will add a few more comments on the code:

void OnTick()
  {
//--- Зададим время открытия и закрытия позиции
   MqlDateTime time_current,time_open,time_open1,time_close;
   TimeToStruct(TimeCurrent(),time_current);
   TimeToStruct((D'1970.01.01 09:00:00'),time_open);
   TimeToStruct((D'1970.01.01 09:01:00'),time_open1);
   TimeToStruct((D'1970.01.01 23:50:00'),time_close);
//--- Зададим условия для открытия позиций BUY и SELL   
   double price=SymbolInfoDouble(Symbol(),SYMBOL_ASK);
   double point=SymbolInfoDouble(Symbol(),SYMBOL_POINT);
   int digits=(int)SymbolInfoInteger(Symbol(),SYMBOL_DIGITS);
   price=NormalizeDouble(price,digits);
   if(PositionSelect(Symbol())==false
      && PositionGetInteger(POSITION_MAGIC)!=Magic_Number
      && time_current.hour==time_open.hour
      && time_current.min>=time_open.min
      && time_current.min<time_open1.min
      && (TickUP()==(price+point)))
     {OpenBUY();}
   else
     {
      if(PositionSelect(Symbol())==false
         && PositionGetInteger(POSITION_MAGIC)!=Magic_Number
         && time_current.hour==time_open.hour
         && time_current.min>=time_open.min
         && time_current.min<time_open1.min
         && (TickDOWN()==(price-point)))
        {OpenSELL();}
     }
   if(time_current.hour==time_close.hour && time_current.min==time_close.min)
      CloseALL();
}

I have highlighted two non-trivial places in yellow.

1) Note that the code is repeated in the first if and in the next else. The only difference is in the last line and end action (OpenBUY, OpenSell).

2) Conditions for getting into the else block are not obvious. They are not visible because of the abundance of ??. In fact, they only depend on the last line:

TickUP()==(price+point)

This is a sure sign that a function is missing here.

We need to write a function that returns true if the time to open the position corresponds to the given one (I will write it later)

 
Vasiliy Sokolov:

Very good. The main point is captured correctly. Especially liked the development process:

I.e. Everything is right. You don't have to solve the problem all at once in one place. You do it gradually, as it happened in your case. First, you describe the basic logic in the OnTick function and basic functions like OpenBUY, OpenSELL, TickUP, TickDown.

Then, when this basic code is debugged, compiled and works within its capabilities, you start describing the other functions. This may be done the next day or even a week. This means that you don't have to change the main code. I think you can see why.

Now you need to hone this manner of development: continue writing functions, linking functionality through them to the existing code. The existing program should work correctly. The complexity should not increase. The functions to be added must return simple, clear results. Their names should be as simple and clear to you. If you can not do this, it may be that you need to write not one but two or even three functions to solve the problem.

In order for a function to perform its intended tasks,you will eventually need to use more and more language constructs within such functions. That's when you will gradually and most importantly, organically extend your knowledge of language constructions, learn loops, arrays and even work with pointers.

Hello, Vasily! Thank you very much for your timely suggestions and support. Your commentaries on the role of functions and principles of program code construction have really helped me in learning the MQL5 programming language:

  1. https://www.mql5.com/ru/forum/352460/page28#comment_18636493
  2. https://www.mql5.com/ru/forum/352460/page28#comment_18637800
  3. https://www.mql5.com/ru/forum/352460/page29#comment_18641729
  4. https://www.mql5.com/ru/forum/352460/page52#comment_18694985

Now that the information in my head is structured, it is easier to understand the code written not only by me, but also by other programmers. I hope this topic will be a good help for those who are starting to learn the MQL5 programming language from the scratch.

Regards, Vladimir.