Die Sprache MQL5 von Grund auf selbst erlernen - Seite 72

 
Vasiliy Sokolov:

Da es keine Grenzen der Perfektion gibt, werde ich noch ein paar Kommentare zum Code hinzufügen:

Ich habe zwei nicht-triviale Stellen gelb hervorgehoben.

1) Beachten Sie, dass der Code im ersten if und im nächsten else wiederholt wird. Der einzige Unterschied besteht in der letzten Zeile und der Endaktion (OpenBUY, OpenSell).

2) Die Bedingungen, um in den else-Block zu gelangen, sind nicht offensichtlich. Sie sind nicht sichtbar, weil die vielen ? Tatsächlich hängen sie nur von der letzten Zeile ab:

Dies ist ein sicheres Zeichen dafür, dass hier eine Funktion fehlt.

Wir müssen eine Funktion schreiben, die true zurückgibt, wenn der Zeitpunkt der Positionseröffnung mit dem angegebenen Zeitpunkt übereinstimmt (ich werde sie später schreiben).

Ja, Vasily, du hast recht, wir hätten die Funktion wirklich schreiben sollen.

Mit freundlichen Grüßen, Vladimir.

 
Vasiliy Sokolov:
Übrigens: Achten Sie auf den Gesamtumfang Ihres Programms. Sie ist bereits recht groß. Wie gefällt Ihnen das? Übrigens kann ein Anfänger keinen so großen Code schreiben: Variablen geraten durcheinander, Klammern werden zu groß, Kompilierungsfehler schleichen sich ein wie Pilze nach dem Regen. Nach der Kompilierung fängt ein Programm dieser Größe an zu stottern und niemand kann verstehen, was los ist. Und aus irgendeinem Grund funktioniert alles in Ihrem Code), und es ist in den Funktionen klar, was vor sich geht und wie. Mit einem Wort, es ist eine Schönheit.

Vielen Dank, Wassili! Hier steckt viel von Ihrer Arbeit drin, denn die Vorlage für den Trailing-Stop wurde von Ihnen erstellt. Ich muss nur noch die Funktionen mit Code füllen. Ich arbeite derzeit an einem Trailing-Stop. Einiges davon ist bereits erledigt, aber es gibt noch einige Dinge, die ich ausarbeiten muss, bevor ich die endgültige EA-Version zur öffentlichen Prüfung vorlege.

Mit freundlichen Grüßen, Vladimir.

 

Ich habe ein paar Funktionen hinzugefügt. Am Ende hatte ich einen Code wie diesen:

//+------------------------------------------------------------------+
//| 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;
}
Ich verstehe immer noch nicht, wie die Magie funktioniert. Beim Netting macht es keinen Sinn. In jedem Fall können Sie diese Prüfung leicht entfernen, da sie nur in einer Funktion durchgeführt wird.
Dateien:
MrBrooklin.mq5  38 kb
 

Der OnInit-Block ist ebenfalls überdacht und noch nicht ganz korrekt geschrieben. Zunächst einmal sollten Sie versuchen, Bezeichner zu schreiben, keine Zahlen. Gibt INIT_SUCCEEDED anstelle von -1 zurück. Zweitens ist der Wechsel hier übertrieben. Dieser Code sollte entweder if oder switch enthalten. Zuerst muss man das eine schreiben und dann das andere - einfach Öl.

Drittens müssen wir alle Kontotypen überwachen. Wir haben Demo und dann haben wir Real. Und dann ist da noch der Wettbewerb. Aber selbst wenn es kein drittes Konto gäbe, müsste es einen Stummel geben, der alle anderen Varianten erfasst:

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 нулевое значение означающее "удачная инициализация"
   }
  }
 

Und das Tüpfelchen auf dem i: Kommentare. Wenn wir Funktionen schreiben, gibt es viel Platz, unsere Hand ist gezeichnet, um Kommentare in die richtigen Codestücke zu setzen:

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

Wenn derselbe Code "gleichzeitig" im Körper einer Hauptfunktion geschrieben wird, wird er so kurz wie möglich und ohne Kommentare:

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

Schreiben Sie also mehr Funktionen, sie ermutigen Sie dazu, die richtigen Kommentare zu schreiben, und obwohl sie den Code ausführlicher machen, machen sie ihn auch klarer.

Der dritte Punkt: Sie schreiben hier:

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

Warum eine weitere Art von Kommentar hinzufügen? Ersetzen Sie einfach den Inhalt des Blocks durch Ihren Kommentar:

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

Denken Sie daran: Kommentare sind für Sie, nicht Sie für Kommentare. Löschen Sie die alten und fügen Sie stattdessen Ihre eigenen hinzu. Halten Sie sich an das Format - geben Sie im Funktionskopf in den Kommentaren kurz, aber deutlich an, was die Funktion tut und welche Werte sie in welchen Fällen zurückgibt.

 

Übrigens, als die Bedingungen für den Positionsschluss in eine eigene Funktion ausgelagert wurden, stellte sich heraus, dass sie nicht korrekt geschrieben war:

//+------------------------------------------------------------------+
//| Возвращает истину, если текущее время попадает в диапазон        |
//| времени для закрытия позиции. В противном случае возвращает ложь.|                                                 |
//+------------------------------------------------------------------+     
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;
}

Ich habe den internen Inhalt aus Ihrem Code übernommen. Es ist klar, dass die Position nur innerhalb einer Minute geschlossen wird. В 23:50. Dieser Code wird funktionieren, aber wenn um 23:50 Uhr etwas schief geht, bleibt die Position um 23:51 Uhr hängen. Deshalb müssen Sie es zumindest schreiben:

time_current.min>=time_close.min)

Und selbst diese Option ist nicht ideal. Eine leistungsfähigere Lösung ist die Verwendung von Handelsmodi. Dies ist jedoch die nächste Stufe der Exzellenz. Bislang ist dieser Entwurf gut geeignet.

 
MrBrooklin:

Hallo Wassili! Vielen Dank für Ihre rechtzeitige Beratung und Unterstützung. Ihre Mitteilungen über die Rolle der Funktionen und den Aufbau eines Programmcodes haben mir beim Erlernen der Programmiersprache MQL5 sehr geholfen:

  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

Jetzt, da die Informationen in meinem Kopf strukturiert sind, ist es einfacher, den Code zu verstehen, der nicht nur von mir, sondern auch von anderen Programmierern geschrieben wurde. Ich hoffe, dass dieses Thema eine gute Hilfe für diejenigen sein wird, die die MQL5-Programmiersprache von Grund auf erlernen wollen.

Mit freundlichen Grüßen, Vladimir.

Gute Arbeit, Vladimir. Gute Programmierer haben in der Regel gute Algorithmiker, und sie haben gute Zielsetzer... Alles beginnt mit den richtigen Zielen und der richtigen Zielsetzung. Du kannst sofort ein Haus bauen und dann Wasser finden. Sie können zuerst Wasser finden und das Haus mit Blick auf das Wasser bauen. Ziele / Zweck, und Zielsetzung ist von Gelegenheit.... Sie gehen direkt zum Algorithmusm.... Aber im Allgemeinen ist es sehr gut!

 
Vasiliy Sokolov:

Übrigens, als die Bedingungen für den Positionsschluss in eine eigene Funktion ausgelagert wurden, stellte sich heraus, dass sie nicht korrekt geschrieben war:

Ich habe den internen Inhalt aus Ihrem Code übernommen. Es ist klar, dass die Position nur innerhalb einer Minute geschlossen wird. В 23:50. Dieser Code wird funktionieren, aber wenn um 23:50 Uhr etwas schief geht, bleibt die Position um 23:51 Uhr hängen. Deshalb müssen wir es zumindest schreiben:

Und selbst diese Option ist nicht ideal. Eine leistungsfähigere Lösung ist die Verwendung von Handelsmodi. Dies ist jedoch die nächste Stufe der Exzellenz. Solange das Design dies zulässt.

Wassili, du bist ein großartiger Lehrer!

Keine Fibel und kein Lehrbuch kann eine solche Erklärung liefern. Alles, was Sie vorgeschlagen haben, werde ich sicherlich in der endgültigen Version des EA umsetzen.

Mit freundlichen Grüßen, Vladimir.

 

Ich weiche für einen Moment vom Thema ab und erzähle Ihnen eine Lebensgeschichte über einen Lehrer. An unserem Institut hatten wir, als wir uns bereits spezialisiert hatten, einen wunderbaren Lehrer. Zu dieser Zeit studierten wir die Algebra der Logik. Viele Schüler konnten lange Zeit nicht verstehen, wie 1+1 gleich 1 sein kann. Wenn 1x1, würde es natürlich 1 sein. Und da haben Sie es!!! Dieser Lehrer hat uns anhand einfacher Beispiele erklärt, was das logische ODER und was das logische UND ist, und daran werde ich mich für den Rest meines Lebens erinnern.

Stellen Sie sich vor, sagt der Lehrer, dass Sie morgens zum Unterricht in das Institut kommen müssen. Sie können das Institut mit dem Trolley-Bus ODER mit der Straßenbahn erreichen. Sie sind zur Haltestelle gekommen, aber es ist weder ein Obus (Bedingungfalsch oder gleich 0) noch eine Straßenbahn (Bedingung falsch oder gleich 0) da. Natürlich werden Sie nicht in der Lage sein, das Institut zu erreichen (Bedingung false oder gleich 0). Prüfen Sie 0+0=0. Wunderbar! Wenn Sie an der Haltestelle ankommen und dort ein Trolleybus (Bedingung wahr oder gleich 1), ODER eine Straßenbahn (Bedingung wahr oder gleich 1), ODER sowohl ein Trolleybus als auch eine Straßenbahn zusammen sind, dann kommen Sie auf jeden Fall am Institut an und die Bedingung wahr oder gleich 1 ist erfüllt! Kontrolle: 1+0=1, 0+1=1 und 1+1=1. Alles passt!

Anhand der gleichen Beispiele mit dem Trolleybus und der Straßenbahn erklärte er uns, was logisches UND ist.

Das ist die Kraft des Talents eines Lehrers! Ich werde mich für den Rest meines Lebens daran erinnern!

Mit freundlichen Grüßen, Vladimir.

 
Valeriy Yastremskiy:

Gute Arbeit. Gute Programmierer haben normalerweise gute Algorithmiker, und sie haben Zielsetzer, und sie haben Zielsetzer... Alles beginnt mit den richtigen Zielen und den richtigen Zielsetzungen. Du kannst sofort ein Haus bauen und dann Wasser finden. Sie können zuerst Wasser finden und das Haus mit Blick auf das Wasser bauen. Ziele / Zweck, und Zielsetzung ist von Gelegenheit.... Sie gehen direkt zum Algorithmusm.... Aber im Allgemeinen ist es sehr gut!

Vielen Dank, Valery, für Ihre Beteiligung an diesem Thema und den konstruktiven Dialog.

Mit freundlichen Grüßen, Vladimir.