Autoapprendimento del linguaggio MQL5 da zero - pagina 71

 
MrBrooklin:

Igor, il desiderio di imparare il linguaggio MQL5 non è perso, al contrario, aumenta solo. Sono combattuto, perché sono così stupido e non riesco a capire le cose semplici con questo operatore di loop. La cosa principale è che senza l'operatore di loop il codice funziona perfettamente, ma con il loop è un casino completo. Andrò in fondo a questa storia in ogni caso. Tuttavia ho molto meno tempo per lo studio autonomo da quando il periodo di quarantena è finito e ho rari momenti per studiare la lingua al lavoro. Per lo più studio la lingua la sera e la notte tardi.

Ho bisogno di risolvere 2 compiti per arrivare finalmente a scrivere il codice Trailing Stop:

  1. Ho bisogno di scrivere un codice con l'uso dell'operatore for loop per cercare tutte le posizioni aperte per tutti i simboli, e se non ce ne sono, allora aprire una posizione Buy tra le 09:00:00 e le 09:01:00, e chiuderla forzatamente alle 23:50:00, se durante la giornata di trading non è scattato uno stop loss. Senza l'operatore for loop, come ho scritto prima, tutto funziona perfettamente. Ora voglio ottenere lo stesso risultato, ma con l'uso di loop.
  2. Scrivi 2 funzioni che determinano la direzione di apertura della posizione dal primo tick che appare nel time frame dalle 09:00:00 alle 09:01:00. Se il primo tick è al rialzo, si dovrebbe aprire una posizione Buy; se il primo tick è al ribasso, si dovrebbe aprire una posizione Sell. Non è una strategia, è solo il mio "desiderio" di non usare la condizione casuale.
Sinceramente, Vladimir.

Vladimir, ti stai addentrando in cose strane. Ti è stato dato un modello: https://www.mql5.com/ru/forum/352460/page58#comment_18726492 L'hai ignorato e hai deciso di andare avanti con il tuo ingegno. Questa via è difficile e può richiedere anni. Sulla tua strada, studia C, C++, Rust, C#, polimorfismo, ereditarietà, dereferenziazione dei puntatori, conversione dinamica dei tipi: Controlla o guida. Dovete prendere la via più breve per raggiungere l'obiettivo. Se volete il trailing, scrivete trailing. Non c'è bisogno di studiare C e C++ per farlo. Tutto questo come elettivo, se vuoi.

La situazione con il ciclo for è illustrativa. È una costruzione potente che deve essere applicata al posto giusto. Avete una rete e un algoritmo ausiliario. Ecco perché non c'è un'enumerazione di posizioni, non ci sono maghi, quindi non si ha questo ciclo. Naturalmente, tutto funzionerà anche senza, ma il ciclo ti fa sentire solo il petrolio. Ma si cerca ostinatamente di usarlo, sembra essere un fine in sé: usare il più e il più possibile, avere il più possibile.

 
Vasiliy Sokolov:

Vladimir, stai entrando in una sorta di routine. Ti è stato dato un modello: https://www.mql5.com/ru/forum/352460/page58#comment_18726492 L'hai ignorato e hai deciso di andare avanti con la tua mente. Questa strada è difficile e può richiedere anni. Sulla tua strada, studia C, C++, Rust, C#, polimorfismo, ereditarietà, dereferenziazione dei puntatori, conversione dinamica dei tipi: Controlla o guida. Dovete prendere la via più breve per raggiungere l'obiettivo. Se volete il trailing, scrivete trailing. Non c'è bisogno di studiare C e C++ per farlo. Tutto questo come elettivo, se vuoi.

La situazione con il ciclo for è illustrativa. È una costruzione potente che deve essere applicata al posto giusto. Avete una rete e un algoritmo ausiliario. Ecco perché non c'è un'enumerazione di posizioni, non ci sono maghi, quindi non si ha questo ciclo. Certo, tutto funzionerà anche senza, ma il loop ti fa sentire solo il petrolio. Ma tu cerchi ostinatamente di usarlo, quindi sembra essere un fine in sé: puoi usare il più possibile di tutto e di qualsiasi cosa da tenere in magazzino.

Ciao, Vasily!

Grazie per esserti unito tempestivamente all'argomento e per avermi indirizzato come sempre sulla strada giusta. Ora lasciatemi spiegare tutto in un ordine:

  1. Un modello nell'Expert Advisor è stato inserito esattamente quando me l'hai gentilmente fornito, per cui voglio esprimere la mia gratitudine!
  2. Ho deciso che un EA con Trailin Stop dovrebbe essere testato nello strategy tester, ma non sapevo come farlo senza aprire automaticamente almeno una posizione. Ecco perché ho iniziato a sentirmi ansioso quando ho scritto un Expert Advisor "completo". L'ho messo tra virgolette perché il mio Expert Advisor non ha una strategia come tale. Semplicemente non volevo usare la condizione casuale per aprire una posizione.
  3. Nessuno degli interlocutori di Expert Advisor, tranne te, ha suggerito che il ciclo for per cercare posizioni in questa situazione non è necessario. Colpa mia, avrei potuto indovinarlo io stesso molto tempo fa e chiedere - era davvero necessario un loop? Come si è scoperto, non è così. Grazie ancora per il suggerimento!
  4. Per andare finalmente a scrivere il trailing stop e non abbandonare il processo a metà strada, ho solo bisogno di scrivere il codice di 2 funzioni che determinano la direzione di apertura di una posizione netting Buy o Sell.
  5. Sì, sono completamente d'accordo con te che l'auto-apprendimento sta iniziando a trascinarsi. Ma se si tiene conto che seguo una strada inesplorata e tortuosa, spero che sia possibile fare uno sconto.
  6. Durante l'intero periodo di autoapprendimento ho ottenuto un'enorme quantità di informazioni e ora sto cercando non solo di organizzarle ma anche di usarle nella pratica. A questo scopo ho scaricato un Expert Advisor da CodeBase, l'ho sviluppato e l'ho usato per due settimane su un conto demo di un commerciante di Forex. Il risultato è esattamente quello che mi aspettavo. Presto inizierò ad usarlo su un conto reale. Questo è già un vantaggio!
  7. Non inseguo la velocità dell'autoapprendimento perché ho già scritto prima che l'eccesso di informazioni di tanto in tanto porta allo stupore.
  8. Per tutto il periodo di studio autonomo a poco a poco ha cominciato a memorizzare parole e frasi inglesi che appaiono dopo il codice di compilazione. Ora guardo meno spesso in Google Translate. Questo è anche un momento positivo nell'auto-apprendimento.
  9. Posterò tutto quello che ho scritto nell'Expert Advisor esattamente quando un pezzo completo per un trailing stop sarà pronto. Cercherò di finirlo sabato. Qui è dove inizierà il lavoro principale sulla scrittura del codice di trailing stop.

Vasily, ti sono estremamente grato per la guida e la critica costruttiva! Esprimo anche la mia gratitudine a tutti i partecipanti di questo tema che mi hanno aiutato nel mio auto-studio del linguaggio di programmazione MQL5 da zero.

L'autoapprendimento continua. Da continuare.

Saluti, Vladimir.

 
Андрей:

Buon pomeriggio a tutti!

Se volessi aggiungere qualcosa di interessante, penso che l'idea di "autoformazione in MQL5 da zero" non sia del tutto corretta. Se una persona è uno 0 nella programmazione, deve prima imparare a programmare. Se l'obiettivo è quello di imparare a programmare in MQL da zero, una persona deve prima impararea programmare in C, almeno le basi, e poi imparare a scrivere in MQL, perché MQL è in realtà C, ma è specializzato per un certo compito, una persona non capisce come funzionano i loop, e già cerca di scrivere programmi. È come cercare di imparare il latino senza conoscere il russo...

Un'altra cosa è che il C non è un linguaggio molto amichevole per imparare la programmazione, è semplice, ma è troppo conciso, è difficile per un principiante leggere e capire il codice senza avere una comprensione di base di algoritmi, tipi di dati, algebra booleana. In C tre caratteri in una riga possono significare diverse stringhe in un altro linguaggio.

Per imparare a programmare semplicemente da zero, per la base, per imparare a parlare con un computer in un (non importa quale) linguaggio, consiglierei di iniziare con Pascal, il libro più facile per iniziare con esso (2-3 settimane a proprio agio), poi C (lì dopo Pascal max settimana con diligenza, padroneggiare la sintassi, intendo le competenze linguistiche di base!) e poi prendere linguaggi specializzati come MQL, perché MQL è C, che ha una piccola torsione e semplificazione, dato che è progettato per un singolo compito e il compilatore conosce l'ovvio. E C a sua volta è una specie di Pascal compresso RAR, ma Pascal è quasi inglese =).

Ora, per quanto riguarda i loop:

Quando ho imparato la programmazione, mi ha aiutato l'analogia con le somme in algebra, dove si specifica il valore iniziale di n, il valore finale di n e la formula con questo n da calcolare.

Ciao Andrey, sono completamente d'accordo con te sulla base. Non ce l'ho e non l'ho mai avuto. Ma come dice il proverbio - Mosca non è stata costruita in una volta sola! Grazie per i vostri consigli e suggerimenti!

Saluti, Vladimir.

 
Roman Shiredchenko:

Sì, sono d'accordo - anche i suoi codici sono buoni! Ti stai agitando per niente. Prendete il vostro tempo per sistemare il codice senza fretta e questo è tutto. È tutto elementare qui - seleziona e traina: (quanto più facile - solo il tuo argomento di scegliere la posizione NEED... :-))

Oltre a questo, includere i file - significa che sono nel vostro codice anche come funzioni e questo è tutto.

Grazie, Roman, per i codici e i link! Sto affrontando i codici con calma e sicuramente non ho fretta da nessuna parte!

Sinceramente, Vladimir.

 

Buona giornata e buon umore a tutti!

Continuo a studiare il linguaggio di programmazione MQL5 . Oggi, come promesso, pubblico per far vedere a tutti il codice del template Expert Advisor pensato per scrivere un trailing stop. A causa del fatto che il codice del modello EA si è rivelato piuttosto ingombrante, abbiamo dovuto ridurre il più possibile i commenti. La versione completa dell'Expert Advisor con commenti dettagliati su ogni riga di codice, in una presentazione accessibile ad uno studente del 1° grado di una scuola di programmazione, sarà pubblicata successivamente sotto forma di file con nome di lavoro Trailing_Stop.mq5 così per non produrre un altro "footcloth" sul sito.

Prima di pubblicare il codice, l'EA è stato testato nel tester di strategia . Non sono stati individuati problemi. L'EA utilizza un sistema di contabilità della posizione di compensazione. Questo sistema contabile implica che contemporaneamente può esserci una sola posizione aperta sul conto per lo stesso simbolo (strumento finanziario).

Al momento, l'Expert Advisor ha la capacità di:

  1. Controlla il conto di trading su cui è prevista l'installazione. Se il consulente è installato su un account demo, nella finestra del messaggio verrà visualizzata l'autorizzazione per continuare a lavorare. Se si tenta di installare il consulente su un conto reale , nella finestra del messaggio verrà visualizzato un avviso sull'impossibilità di continuare il lavoro, dopodiché verrà automaticamente eliminato dalla finestra di lavoro del terminale di trading .
  2. Una volta al giorno di negoziazione esattamente alle 9:00 secondo l'ora di Mosca, apri automaticamente una posizione nella direzione in cui verrà diretto il primo segno di spunta. Ad esempio, se alle 9:00 Ora di Mosca, il primo tick sarà diretto verso l'alto, il che significa che si aprirà una posizione ACQUISTA, se il primo tick è in basso, si aprirà una posizione VENDITA.
  3. Imposta la dimensione dello stop loss.
  4. Imposta la dimensione del lotto.
  5. Impostare altri parametri che saranno necessari per il funzionamento del trailing stop.

Inoltre, l'EA ha un modello preinstallato, gentilmente fornito da Vasily Sokolov, che verrà riempito con il codice durante il processo di autoapprendimento.

UN AVVERTIMENTO!!!

L'Expert Advisor è sviluppato secondo il piano di autoapprendimento per un conto demo e solo per scopi didattici! Non progettato per fare trading su un conto reale e realizzare un profitto!

Con i migliori saluti, 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 позиции
  {
//---
   ;
  }
//+------------------------------------------------------------------+
 

Buona giornata e buon umore a tutti!

Continuo a studiare il linguaggio di programmazione MQL5. Ieri ho scritto il codice di Stop Loss a Breakeven per le posizioni Sell e Buy. Sto incollando il codice senza ancora alcun commento. Pubblicherò la versione completa dell'Expert Advisor con una descrizione dettagliata di ogni linea di codice, in una forma accessibile agli alunni del primo anno della scuola di programmazione, più tardi nel file con il titolo di lavoro Trailing_Stop.mq5. Prima di pubblicare il codice, abbiamo controllato le prestazioni dell'Expert Advisor nel tester delle strategie. Non sono stati trovati problemi.

Saluti, 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:

Buona giornata e buon umore a tutti!

Continuo a studiare il linguaggio di programmazione MQL5. Oggi, come promesso, sto incollando il codice del modello del mio Expert Advisor progettato per scrivere un trailing stop. A causa del fatto che il codice del template EA è abbastanza ingombrante, ho dovuto ridurre i commenti il più possibile. La versione completa dell'Expert Advisor con commenti dettagliati su ogni linea di codice, in una forma accessibile per uno studente di scuola di programmazione di 1° grado, sarà pubblicata più tardi come un file con il nome di lavoro Trailing_Stop.mq5, al fine di non produrre un altro spoilage.

...

Molto bene. L'idea principale è ben catturata. Soprattutto mi piace il processo di sviluppo:

MrBrooklin:

Buona giornata e buon umore a tutti!

Continuo a studiare il linguaggio di programmazione MQL5. Ieri ho scritto il codice per lo Stop Loss a Breakeven per le posizioni Buy e Sell.

Cioè tutto è corretto. Non è necessario risolvere il problema tutto in una volta in un solo posto. Dovresti risolverlo gradualmente, proprio come hai fatto tu. In primo luogo, si descrive la logica di base nella funzione OnTick e le funzioni di base come OpenBUY, OpenSELL, TickUP, TickDown.

Poi, quando questo codice di base è debuggato, compilato e funziona entro le sue capacità, si inizia a descrivere le altre funzioni. Questo può essere fatto il giorno dopo o anche una settimana. Questo significa che non è necessario cambiare il codice principale. Penso che possiate capire perché.

Ora dovete affinare questo modo di sviluppare: continuate a scrivere funzioni, collegando la funzionalità attraverso di esse al codice esistente. Il programma esistente dovrebbe funzionare correttamente. La complessità non dovrebbe aumentare. Le funzioni da aggiungere devono restituire risultati semplici e chiari. I loro nomi dovrebbero essere altrettanto semplici e chiari per voi. Se non ci riuscite, potrebbe essere perché avete bisogno di scrivere non una ma due o anche tre funzioni per risolvere il problema. All'inizio, il quadro generale dell'applicazione sarà difficile da definire. Ecco perché è meglio chiedere consiglio a colleghi più esperti. Con il tempo, imparerete a sviluppare tali modelli per conto vostro.

Con il passare del tempo,avrete bisogno di usare sempre più costrutti linguistici all'interno delle funzioni per renderle adatte alle vostre esigenze.A questo punto, gradualmente e soprattutto, estenderete organicamente la vostra conoscenza dei costrutti del linguaggio, imparerete i loop, le matrici e persino a lavorare con i puntatori.

In effetti, avete già imparato la parte più difficile della programmazione, anche se non avete ancora consolidato il materiale che avete imparato. Tutto quello che dovete fare ora è ripeterlo molte volte per consolidarlo. Da qui non ci sarà nulla di fondamentalmente nuovo, tutto è lo stesso: Modello generale -> Descrizione dei nomi delle funzioni e dei loro parametri-> Scrittura del contenuto di queste funzioni -> Disposizione di queste funzioni nell'unità centrale. Questo è tutto. Non resta che perfezionare l'abilità ed essere coerenti. Varie costruzioni aggiuntive che si iniziano ad usare come i loop e gli array sono solo dettagli, a volte fatti in modo intelligente, ma niente di più che dettagli.

 
A proposito, fate attenzione alla dimensione complessiva del vostro programma. È già abbastanza consistente. Come ti piace? A proposito, un principiante non può scrivere un codice così grande: le variabili iniziano a confondersi, le parentesi diventano troppo grandi, gli errori di compilazione iniziano a insinuarsi come funghi dopo la pioggia. Dopo la compilazione, un programma di tali dimensioni inizia a fare glitch e nessuno riesce a capire cosa c'è di sbagliato. E tutto funziona nel tuo codice per qualche motivo), ed è chiaro nelle funzioni cosa sta succedendo e come. In una parola, è una bellezza.
 

Poiché non c'è limite alla perfezione, aggiungerò qualche altro commento sul codice:

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();
}

Ho evidenziato in giallo due posti non banali.

1) Notate che il codice è ripetuto nel primo if e nel successivo else. L'unica differenza è nell'ultima riga e nell'azione finale (OpenBUY, OpenSell).

2) Le condizioni per entrare nel blocco else non sono ovvie. Non sono visibili a causa dell'abbondanza di ?? Infatti, dipendono solo dall'ultima linea:

TickUP()==(price+point)

Questo è un segno sicuro che qui manca una funzione.

Dobbiamo scrivere una funzione che restituisca vero se il tempo di apertura della posizione corrisponde a quello dato (la scriverò più tardi)

 
Vasiliy Sokolov:

Molto bene. Il punto principale è catturato correttamente. Mi è piaciuto soprattutto il processo di sviluppo:

Cioè tutto è giusto. Non è necessario risolvere il problema tutto in una volta in un solo posto. Lo fai gradualmente, come è successo nel tuo caso. In primo luogo, si descrive la logica di base nella funzione OnTick e le funzioni di base come OpenBUY, OpenSELL, TickUP, TickDown.

Poi, quando questo codice di base è debuggato, compilato e funziona entro le sue capacità, si inizia a descrivere le altre funzioni. Questo può essere fatto il giorno dopo o anche una settimana. Questo significa che non è necessario cambiare il codice principale. Credo che possiate capire perché.

Ora dovete affinare questo modo di sviluppare: continuate a scrivere funzioni, collegando la funzionalità attraverso di esse al codice esistente. Il programma esistente dovrebbe funzionare correttamente. La complessità non dovrebbe aumentare. Le funzioni da aggiungere devono restituire risultati semplici e chiari. I loro nomi dovrebbero essere altrettanto semplici e chiari per voi. Se non potete farlo, può essere che abbiate bisogno di scrivere non una ma due o anche tre funzioni per risolvere il problema.

Per far sì che una funzione esegua i compiti previsti,alla fine avrete bisogno di usare sempre più costrutti linguistici all'interno di tali funzioni. È allora che gradualmente e soprattutto, organicamente, estenderete la vostra conoscenza delle costruzioni del linguaggio, imparerete i loop, gli array e persino il lavoro con i puntatori.

Ciao, Vasily! Grazie mille per i vostri suggerimenti tempestivi e il vostro supporto. I vostri commenti sul ruolo delle funzioni e sui principi di costruzione del codice del programma mi hanno aiutato molto nell'apprendimento del linguaggio di programmazione MQL5:

  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

Ora che le informazioni nella mia testa sono strutturate, è più facile capire il codice scritto non solo da me, ma anche da altri programmatori. Spero che questo argomento sia un buon aiuto per coloro che stanno iniziando ad imparare il linguaggio di programmazione MQL5 da zero.

Saluti, Vladimir.

Motivazione: