Auto-apprentissage du langage MQL5 à partir de zéro - page 72

 
Vasiliy Sokolov:

Comme il n'y a pas de limite à la perfection, je vais ajouter quelques commentaires supplémentaires sur le code :

J'ai souligné en jaune deux endroits non triviaux.

1) Notez que le code est répété dans le premier if et dans le else suivant. La seule différence réside dans la dernière ligne et l'action finale (OpenBUY, OpenSell).

2) Les conditions pour entrer dans l'autre bloc ne sont pas évidentes. Ils ne sont pas visibles en raison de l'abondance de ? En fait, ils ne dépendent que de la dernière ligne :

C'est un signe certain qu'une fonction manque ici.

Nous devons écrire une fonction qui retourne vrai si le temps d'ouverture de la position correspond à celui spécifié (je l'écrirai plus tard).

Oui, Vasily, tu as raison, nous aurions vraiment dû écrire la fonction.

Salutations, Vladimir.

 
Vasiliy Sokolov:
À propos, faites attention à la taille totale de votre programme. Il est déjà assez grand. Comment l'aimez-vous ? D'ailleurs, un novice ne peut pas écrire un code d'une telle taille : les variables sont mélangées, les parenthèses sont trop grandes, les erreurs de compilation se glissent comme des champignons après la pluie. Après la compilation, un programme d'une telle taille commence à avoir des ratés et personne ne peut comprendre ce qui ne va pas. Et tout fonctionne dans votre code pour une raison quelconque), et il est clair dans les fonctions ce qui se passe et comment. En un mot, c'est une beauté.

Merci Vasily ! Une grande partie de votre travail ici, puisque le modèle de trailing stop a été fourni par vous. Il ne me reste plus qu'à remplir les fonctions avec du code. Je travaille actuellement sur le trailing stop. Une partie a déjà été réalisée, mais il y a encore des choses que je dois comprendre pour pouvoir présenter la version finale de l'EA au public.

Salutations, Vladimir.

 

J'ai ajouté quelques fonctions. Je me suis retrouvé avec un code comme celui-ci :

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//--- Зададим условия для открытия позиций 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);
   //-- Если открытой позиции нет и время для открытия позволяет,
   //-- открывает BUY или SELL в зависимости от положения тика
   if(IsMainPositionOpen() == false && IsTimeForOpen())
   {
      if(TickUP()==(price+point))
         OpenBUY();
      if(TickDOWN()==(price-point))
         OpenSELL();
   }
   //-- Если наступило время закрытия позиции, закрываем все
   if(IsTimeForClose())
      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 позиции
        }
  }
  
//+------------------------------------------------------------------+
//| Возвращает истину, если позиция торгового эксперта уже открыта.  |
//| Возвращает ложь в противном случае.                              |
//+------------------------------------------------------------------+  
bool IsMainPositionOpen()
{
   //-- Если позиций нет - то и у эксперта позиции нет, возвращаем ложь.
   if(PositionSelect(Symbol()) == false)
      return false;
   //-- Позиция есть и ее мэджик совпадает с мэджиком эксперта - возвращаем истину
   if(PositionGetInteger(POSITION_MAGIC) == Magic_Number)
      return true;
   //-- Позиция есть но ее мэджик не совподает с мэджиком эксперта -
   //-- это чья-то другая позиция, позвращаем ложь
   else
      return false;
}
//+------------------------------------------------------------------+
//| Возвращает истину, если текущее время попадает в диапазон        |
//| разрешенного времени для открытия позиции. В противном случае    |
//| возвращает ложь.                                                 |
//+------------------------------------------------------------------+  
bool IsTimeForOpen()
  {
   MqlDateTime time_current,time_open,time_open1;
   TimeToStruct(TimeCurrent(),time_current);
   TimeToStruct((D'1970.01.01 09:00:00'),time_open);
   TimeToStruct((D'1970.01.01 09:01:00'),time_open1);
   if(time_current.hour == time_open.hour &&
      time_current.min >= time_open.min &&
      time_current.min < time_open1.min
      )
      return true;
   else
      return false;
   }
//+------------------------------------------------------------------+
//| Возвращает истину, если текущее время попадает в диапазон        |
//| времени для закрытия позиции. В противном случае возвращает ложь.|                                                 |
//+------------------------------------------------------------------+     
bool IsTimeForClose()
{
   MqlDateTime time_current,time_open,time_open1,time_close;
   TimeToStruct(TimeCurrent(),time_current);
   TimeToStruct((D'1970.01.01 23:50:00'), time_close);
   if(time_current.hour==time_close.hour && 
      time_current.min==time_close.min)
      return true;
   else
      return false;
}
Je ne comprends toujours pas le travail de la magie. Sur le filet, cela n'a aucun sens. Dans tous les cas, vous pouvez facilement supprimer cette vérification, car elle n'est effectuée que dans une seule fonction.
Dossiers :
MrBrooklin.mq5  38 kb
 

Le bloc OnInit est également trop réfléchi et n'est toujours pas écrit correctement. Tout d'abord, vous devez essayer d'écrire des identifiants, et non des chiffres. Retourne INIT_SUCCEEDED au lieu de -1. Deuxièmement, l'interrupteur est excessif ici. Il convient d'utiliser soit "if", soit "switch". Il faut d'abord écrire l'un et ensuite l'autre - juste de l'huile.

Troisièmement, nous devons surveiller tous les types de comptes. Nous avons Demo et puis nous avons Real. Et puis il y a le concours. Mais même s'il n'y avait pas de troisième compte, il devrait y avoir un talon qui reprendrait toutes les autres variantes:

int OnInit()
  {
//--- Определим тип счёта на который устанавливаем советник: демо или реальный счет
   ENUM_ACCOUNT_TRADE_MODE account_type=(ENUM_ACCOUNT_TRADE_MODE)AccountInfoInteger(ACCOUNT_TRADE_MODE);
//--- теперь превратим значение перечисления в понятный вид
   string trade_mode;               //создадим переменную для торгового режима
   ACCOUNT_TRADE_MODE_CONTEST
   if(account_type==ACCOUNT_TRADE_MODE_REAL) //если торговый режим счёта - реальный
     {
      //--- выводим окно сообщений на торговом терминале и закрываем советник
      MessageBox("Работа на реальном счете запрещена, выходим!","Советник запущен на реальном счете");
      return(INIT_FAILED); //возвращаем для функции OnInit ненулевое значение означающее "неудачная инициализация"
     }
   if(account_type==ACCOUNT_TRADE_MODE_DEMO) //если торговый режим счёта - демо
     {
      //--- выводим окно сообщений на торговом терминале и продолжаем работу советника
      MessageBox("Работа на демо-счете разрешена!","Советник запущен на демо-счете");
      trade_mode="Счёт REAL";
      return(INIT_SUCCEEDED); //возвращаем для функции OnInit нулевое значение означающее "удачная инициализация"
     }
//-- Заглушка на случай непредвиденных вариантов. Всегда должна быть даже если варианта явно два.
   else
   {
      MessageBox("Неизвестный тип счета. Работа невозможна!");
      return(INIT_FAILED); //возвращаем для функции OnInit нулевое значение означающее "удачная инициализация"
   }
  }
 

Et la cerise sur le gâteau : les commentaires. Lorsque nous écrivons des fonctions, il y a beaucoup d'espace, notre main est attirée pour mettre des commentaires dans les bons morceaux de code :

//+------------------------------------------------------------------+
//| Возвращает истину, если позиция торгового эксперта уже открыта.  |
//| Возвращает ложь в противном случае.                              |
//+------------------------------------------------------------------+  
bool IsMainPositionOpen()
{
   //-- Если позиций нет - то и у эксперта позиции нет, возвращаем ложь.
   if(PositionSelect(Symbol()) == false)
      return false;
   //-- Позиция есть и ее мэджик совпадает с мэджиком эксперта - возвращаем истину
   if(PositionGetInteger(POSITION_MAGIC) == Magic_Number)
      return true;
   //-- Позиция есть но ее мэджик не совподает с мэджиком эксперта -
   //-- это чья-то другая позиция, позвращаем ложь
   else
      return false;
}

Lorsque le même code est écrit "en même temps" dans le corps d'une fonction principale, il devient aussi court que possible et sans commentaires :

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

Écrivez donc plus de fonctions, elles vous encouragent à écrire les bons commentaires, et bien qu'elles rendent le code plus verbeux, elles le rendent aussi plus clair.

Le troisième point : vous êtes en train d'écrire :

//+------------------------------------------------------------------+
/ | Expert initialization function                                   |
//+------------------------------------------------------------------+
/* Функция инициализации советника OnInit с типом данных int. Если возвращаемое значение для функции
   return(-1), то это "неудачная инициализация". Если возвращаемое значение для функции return(0), то
   это "удачная инициализация". INIT_SUCCEEDED означает, что инициализация прошла успешно и дальше
   можно продолжать тестирование эксперта. Этот код означает то же самое, что и нулевое значение, т.е.
   "удачная инициализация".
*/
int OnInit()
  {
  ...
  }

Pourquoi ajouter un autre type de commentaire ? Remplacez simplement ce qui se trouve dans le bloc par votre commentaire :

//+------------------------------------------------------------------------------------------------------+
//| Функция инициализации советника OnInit с типом данных int. Если возвращаемое значение для функции    |
//| return(-1), то это "неудачная инициализация". Если возвращаемое значение для функции return(0), то   |
//| это "удачная инициализация". INIT_SUCCEEDED означает, что инициализация прошла успешно и дальше      |
//| можно продолжать тестирование эксперта. Этот код означает то же самое, что и нулевое значение, т.е.  |
//| "удачная инициализация".                                                                             |
//+------------------------------------------------------------------------------------------------------+
int OnInit()
  {
  ...
  }

N'oubliez pas que les commentaires sont pour vous, et non pas vous pour les commentaires. Supprimez les anciennes et ajoutez les vôtres à la place. Respectez le format - dans l'en-tête de la fonction, indiquez brièvement mais clairement dans les commentaires ce que fait la fonction et quelles valeurs elle renvoie dans quels cas.

 

D'ailleurs, lorsque les conditions de temps de fermeture de la position ont été séparées dans une fonction distincte, il est apparu qu'elle n'était pas écrite correctement :

//+------------------------------------------------------------------+
//| Возвращает истину, если текущее время попадает в диапазон        |
//| времени для закрытия позиции. В противном случае возвращает ложь.|                                                 |
//+------------------------------------------------------------------+     
bool IsTimeForClose()
{
   MqlDateTime time_current,time_open,time_open1,time_close;
   TimeToStruct(TimeCurrent(),time_current);
   TimeToStruct((D'1970.01.01 23:50:00'), time_close);
   if(time_current.hour==time_close.hour && 
      time_current.min==time_close.min)
      return true;
   else
      return false;
}

J'ai pris le contenu interne de votre code. Il est clair que la position ne sera fermée que dans une minute. В 23:50. Ce code fonctionnera, mais si quelque chose ne va pas à 23:50, la position restera suspendue à 23:51. C'est pourquoi tu dois au moins l'écrire :

time_current.min>=time_close.min)

Et même cette option n'est pas idéale. Une solution plus puissante consiste à utiliser des modes de négociation. Cependant, il s'agit du niveau d'excellence suivant. Pour l'instant, ce modèle fera l'affaire.

 
MrBrooklin:

Bonjour Vasily ! Merci beaucoup pour vos conseils et votre soutien opportuns. Vos messages sur le rôle des fonctions et les principes de construction du code de programme m'ont vraiment aidé à apprendre le langage de programmation 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

Maintenant que les informations dans ma tête sont structurées, il est plus facile de comprendre le code écrit non seulement par moi, mais aussi par d'autres programmeurs. J'espère que ce sujet sera une bonne aide pour ceux qui commencent à apprendre le langage de programmation MQL5 depuis le début.

Salutations, Vladimir.

Bon travail, Vladimir. Les bons codeurs ont généralement de bons algorithmiciens, et ils ont de bons fixeurs d'objectifs... Tout commence par les bons buts, et les bons objectifs. Vous pouvez construire une maison d'un coup et ensuite trouver de l'eau. Vous pouvez d'abord trouver de l'eau et construire la maison en tenant compte de l'eau. Les objectifs / le but, et la fixation des objectifs est de l'opportunité.... Vous allez directement à l'algorithme .... Mais en général, c'est très bien !

 
Vasiliy Sokolov:

D'ailleurs, lorsque les conditions de temps de fermeture de la position ont été séparées dans une fonction distincte, il est apparu qu'elle n'était pas écrite correctement :

J'ai pris le contenu interne de votre code. Il est clair que la position ne sera fermée que dans une minute. В 23:50. Ce code fonctionnera, mais si quelque chose ne va pas à 23:50, la position restera suspendue à 23:51. C'est pourquoi tu dois au moins l'écrire :

Et même cette option n'est pas idéale. Une solution plus puissante consiste à utiliser des modes de négociation. Cependant, il s'agit du niveau d'excellence suivant. Tant que cette conception peut le supporter.

Vasily, vous êtes un merveilleux professeur !

Aucun abécédaire ou manuel ne peut fournir une telle explication. Tout ce que vous avez suggéré, je vais certainement le mettre en œuvre dans la version finale de l'EA.

Salutations, Vladimir.

 

Je m'éloigne un instant du sujet et je vais vous raconter une histoire de vie d'un enseignant. Dans notre institut, alors que nous étions déjà spécialisés, nous avions un professeur formidable. À l'époque, nous étudiions l'algèbre de la logique. De nombreux élèves n'ont pas compris pendant longtemps comment 1+1 pouvait être égal à 1? Si 1x1, il serait évidemment égal à 1. Et voilà, vous l'avez ! !! Ce professeur a utilisé des exemples simples pour nous expliquer ce qu'est le OU logique et ce qu'est le ET logique, ce dont je me souviendrai toute ma vie.

Imaginez, dit le professeur, que vous devez arriver à l'institut le matin pour les cours. Vous pouvez prendre un trolleybus OU un tramway pour vous rendre à l'institut. Vous êtes arrivé à l'arrêt de bus, mais il n'y a ni trolleybus (conditionfausse ou identique à 0), ni tramway (condition fausse ou identique à 0). Naturellement, vous ne pourrez pas accéder à l'institut (condition fausse ou égale à 0). Vérifiez 0+0=0. Merveilleux ! Si vous arrivez à l'arrêt de bus et qu'il y a un trolleybus (condition vraie ou identique à 1), OU un tram (condition vraie ou identique à 1), OU un trolleybus et un tram ensemble, alors vous arriverez certainement à l'institut et la condition vraie ou identique à 1 se vérifiera ! Contrôle : 1+0=1, 0+1=1 et 1+1=1. Tout s'adapte !

En utilisant les mêmes exemples avec le trolleybus et le tram, il nous a expliqué ce qu'est le ET logique.

Voilà le pouvoir du talent d'un enseignant ! Je m'en souviendrai pour le reste de ma vie !

Sincèrement, Vladimir.

 
Valeriy Yastremskiy:

Bon travail. Les bons codeurs ont généralement de bons algorithmiciens, et ils ont des fixeurs d'objectifs, et ils ont des fixeurs d'objectifs... Tout commence par les bons buts, et les bons objectifs. Vous pouvez construire une maison d'un coup et ensuite trouver de l'eau. Vous pouvez d'abord trouver de l'eau et construire la maison en tenant compte de l'eau. Les objectifs / le but, et la fixation des objectifs est de l'opportunité.... Vous allez directement à l'algorithme .... Mais en général, c'est très bien !

Merci, Valery, pour votre participation au sujet et votre dialogue constructif.

Salutations, Vladimir.

Raison: