Die Sprache MQL5 von Grund auf selbst erlernen - Seite 71

 
MrBrooklin:

Igor, der Wunsch, die Sprache MQL5 zu erlernen, ist nicht verloren, im Gegenteil, er wird nur noch stärker. Ich bin nur hin- und hergerissen, warum ich so dumm bin und einfache Dinge mit diesem Schleifenoperator nicht verstehe. Die Hauptsache ist, dass der Code ohne den Schleifenoperator perfekt funktioniert, aber mit der Schleife ist es ein völliges Durcheinander. Ich werde der Sache trotzdem auf den Grund gehen. Allerdings habe ich viel weniger Zeit für das Selbststudium, seit die Quarantänezeit vorbei ist und ich bei der Arbeit nur noch selten Zeit habe, die Sprache zu lernen. Meistens lerne ich die Sprache am Abend und spät in der Nacht.

Ich muss 2 Aufgaben lösen, um endlich den Trailing-Stop-Code schreiben zu können:

  1. Ich muss einen Code schreiben, der mit Hilfe des for-Schleifenoperators alle offenen Positionen für alle Symbole durchsucht, und wenn es keine gibt, dann eine Kaufposition im Intervall von 09:00:00 bis 09:01:00 eröffnet und um 23:50:00 zwangsweise schließt, wenn während des Handelstages kein Stop-Loss ausgelöst wurde. Ohne den for-Schleifenoperator, wie ich zuvor geschrieben habe, funktioniert alles perfekt. Jetzt möchte ich das gleiche Ergebnis erzielen, aber mit einer Schleife.
  2. Schreiben Sie 2 Funktionen, die die Richtung der Positionseröffnung durch den ersten Tick bestimmen, der im Zeitrahmen von 09:00:00 bis 09:01:00 erscheint. Wenn der erste Tick nach oben zeigt, sollte eine Kaufposition eröffnet werden; wenn der erste Tick nach unten zeigt, sollte die Verkaufsposition entsprechend eröffnet werden. Es ist keine Strategie, es ist nur mein "Wunsch", die Zufallsbedingung nicht zu verwenden.
Mit freundlichen Grüßen, Vladimir.

Vladimir, du gerätst in eine seltsame Situation. Sie haben eine Vorlage erhalten: https://www.mql5.com/ru/forum/352460/page58#comment_18726492 Sie haben sie ignoriert und beschlossen, mit Ihrem Verstand weiterzumachen. Dieser Weg ist schwierig und kann Jahre dauern. Unterwegs lernen Sie C, C++, Rust, C#, Polymorphismus, Vererbung, Dereferenzierung von Zeigern, dynamische Typkonvertierung: Prüfen oder fahren. Sie müssen den kürzesten Weg zum Ziel nehmen. Wenn Sie einen Nachsatz wollen, schreiben Sie einen Nachsatz. Sie müssen dafür nicht C und C++ studieren. Das alles als Wahlfach, wenn Sie Lust dazu haben.

Die Situation mit der for-Schleife ist anschaulich. Es handelt sich um eine leistungsfähige Konstruktion, die an der richtigen Stelle eingesetzt werden muss. Sie haben Netting und einen Hilfsalgorithmus. Deshalb gibt es keine Aufzählung von Positionen, es gibt keine Magier, also gibt es diese Schleife nicht. Natürlich funktioniert alles auch ohne, aber die Schleife sorgt nur dafür, dass man sich wie Öl fühlt. Aber man versucht hartnäckig, es zu nutzen, es scheint ein Selbstzweck zu sein: so viel und so viel wie möglich zu nutzen, so viel wie möglich zu haben.

 
Vasiliy Sokolov:

Vladimir, du gerätst ein wenig in einen Trott. Sie haben eine Vorlage erhalten: https://www.mql5.com/ru/forum/352460/page58#comment_18726492. Sie haben sie ignoriert und beschlossen, mit Ihren Gedanken weiterzumachen. Dieser Weg ist schwierig und kann Jahre dauern. Unterwegs lernen Sie C, C++, Rust, C#, Polymorphismus, Vererbung, Dereferenzierung von Zeigern, dynamische Typkonvertierung: Prüfen oder fahren. Sie müssen den kürzesten Weg zum Ziel nehmen. Wenn Sie einen Nachsatz wünschen, schreiben Sie einen Nachsatz. Sie müssen dafür nicht C und C++ studieren. Das alles als Wahlfach, wenn Sie Lust dazu haben.

Die Situation mit der for-Schleife ist anschaulich. Es handelt sich um eine leistungsfähige Konstruktion, die an der richtigen Stelle eingesetzt werden muss. Sie haben Netting und einen Hilfsalgorithmus. Deshalb gibt es keine Aufzählung von Positionen, es gibt keine Magier, also gibt es diese Schleife nicht. Natürlich funktioniert alles auch ohne, aber die Schleife sorgt nur dafür, dass man sich wie Öl fühlt. Aber Sie versuchen hartnäckig, es zu verwenden, so dass es ein Selbstzweck zu sein scheint: Sie können so viel wie möglich von allem, was Sie auf Lager haben, verwenden.

Hallo, Wassili!

Vielen Dank, dass Sie sich rechtzeitig in das Thema eingearbeitet haben und mich wie immer auf den richtigen Weg geführt haben. Lassen Sie mich nun alles in einer Reihenfolge erklären:

  1. Eine Vorlage im Expert Advisor wurde genau dann eingefügt, als Sie sie mir freundlicherweise zur Verfügung gestellt haben, wofür ich mich ausdrücklich bedanken möchte!
  2. Ich beschloss, dass ein EA mit Trailin Stop im Strategietester getestet werden sollte, aber ich wusste nicht, wie ich es machen sollte, ohne automatisch mindestens eine Position zu eröffnen. Aus diesem Grund begann ich beim Schreiben eines "vollwertigen" Expert Advisors Angst zu haben. Ich setze es in Anführungszeichen, weil mein Expert Advisor keine Strategie als solche hat. Ich wollte einfach nicht die Zufallsbedingung verwenden, um eine Position zu eröffnen.
  3. Keiner der Gesprächspartner des Expert Advisors, außer Ihnen, hat vorgeschlagen, dass die for-Schleife für die Suche nach Positionen in dieser Situation nicht notwendig ist. Mein Fehler, ich hätte es längst selbst erraten und fragen können - war eine Schleife wirklich notwendig? Wie sich herausstellte, ist das nicht der Fall. Nochmals vielen Dank für den Tipp!
  4. Um endlich zum Schreiben des Trailing-Stops überzugehen und den Prozess nicht auf halbem Wege abzubrechen, muss ich nur noch den Code von 2 Funktionen schreiben, die die Eröffnungsrichtung einer Netting-Buy- oder Sell-Position bestimmen.
  5. Ja, ich stimme Ihnen völlig zu, dass sich das Selbststudium in die Länge zieht. Aber wenn man bedenkt, dass ich einen unerforschten und krummen Weg gehe, hoffe ich, dass es möglich ist, einen Rabatt zu machen.
  6. Während der gesamten Zeit des Selbststudiums habe ich eine riesige Menge an Informationen erhalten, und jetzt versuche ich, sie nicht nur zu ordnen, sondern auch in der Praxis anzuwenden. Zu diesem Zweck habe ich einen Expert Advisor von CodeBase heruntergeladen, entwickelt und vierzehn Tage lang auf einem Demokonto eines Devisenhändlers eingesetzt. Das Ergebnis ist genau das, was ich erwartet habe. Demnächst werde ich es auf einem echten Konto einsetzen. Dies ist bereits ein Pluspunkt!
  7. Ich verfolge nicht die Geschwindigkeit des Selbststudiums, denn ich habe schon früher geschrieben, dass das Übermaß an Informationen von Zeit zu Zeit zu einer Verdummung führt.
  8. Während der gesamten Zeit des Selbststudiums lernte ich nach und nach englische Wörter und Sätze auswendig, die nach dem Kompilationscode erscheinen. Ich schaue jetzt weniger oft in Google Translate nach. Dies ist auch ein positiver Moment des Selbststudiums.
  9. Ich werde alles, was ich im Expert Advisor geschrieben habe, genau dann posten, wenn ein komplettes Werkstück für einen Trailing Stop fertig ist. Ich werde versuchen, sie am Samstag fertig zu stellen. An dieser Stelle beginnt die Hauptarbeit beim Schreiben des Trailing-Stop-Codes.

Vasily, ich bin Ihnen sehr dankbar für Ihre Beratung und konstruktive Kritik! Mein Dank gilt auch allen Teilnehmern dieses Themas, die mir bei meinem Selbststudium der Programmiersprache MQL5 von Grund auf geholfen haben.

Das Selbststudium geht weiter. Fortsetzung folgt.

Mit freundlichen Grüßen, Vladimir.

 
Андрей:

Guten Tag zusammen!

Wenn ich noch etwas Interessantes hinzufügen wollte, so halte ich die Idee des "Selbsttrainings in MQL5 von Grund auf" für nicht ganz richtig. Wenn eine Person 0 in der Programmierung ist, muss sie zuerst lernen, wie man programmiert. Wenn das Ziel ist zu lernen, wie man in MQL von Grund auf zu programmieren, muss eine Person zuerst lernen, wie manin C zu programmieren, zumindest die Grundlagen, und dann lernen, in MQL zu schreiben, weil MQL ist in der Tat C, aber es ist für eine bestimmte Aufgabe spezialisiert, eine Person nicht verstehen, wie Schleifen arbeiten, und bereits versuchen, Programme zu schreiben. Das ist, als würde man versuchen, Latein zu lernen, ohne Russisch zu können...

Ein weiterer Punkt ist, dass C keine sehr freundliche Sprache ist, um das Programmieren zu lernen, sie ist zwar einfach, aber zu prägnant, es ist schwierig für einen Anfänger, den Code zu lesen und zu verstehen, ohne ein Grundverständnis von Algorithmen, Datentypen und Boolescher Algebra zu haben. In C können drei Zeichen in einer Reihe mehrere Strings in einer anderen Sprache bedeuten.

Um einfach von Grund auf programmieren zu lernen, für die Basis, um zu lernen, mit einem Computer in einer (egal welcher) Sprache zu sprechen, würde ich empfehlen, mit Pascal zu beginnen, das einfachste Buch, um damit zu beginnen (2-3 Wochen mit Leichtigkeit), dann C (dort nach Pascal max Woche mit Fleiß, beherrschen die Syntax, ich meine die grundlegenden Sprachkenntnisse!) und dann auf spezialisierte Sprachen wie MQL zurückgreifen, denn MQL ist C, das eine kleine Wendung und Vereinfachung aufweist, da es für eine einzige Aufgabe konzipiert ist und der Compiler das Offensichtliche kennt. Und C wiederum ist eine Art RAR-komprimiertes Pascal, aber Pascal ist fast Englisch =).

Nun zu den Schleifen:

Als ich das Programmieren lernte, half mir die Analogie zu den Summen in der Algebra, wo man den Anfangswert von n, den Endwert von n und die Formel mit diesem n angibt, um zu rechnen.

Hallo Andrey, ich stimme mit dir völlig überein, was die Grundlage betrifft. Ich habe es nicht und hatte es nie. Aber wie man so schön sagt: Moskau wurde nicht auf einmal gebaut! Ich danke Ihnen für Ihre Ratschläge und Tipps!

Mit freundlichen Grüßen, Vladimir.

 
Roman Shiredchenko:

Ja, ich stimme zu - seine Codes sind auch gut! Du regst dich wegen nichts auf. Nehmen Sie sich die Zeit, den Code zu sortieren, ohne zu hetzen, und das war's. Hier ist eine elementare Sache hier - wählen Sie und trawl: (wie viel einfacher - nur Ihr Thema der Auswahl der NEED Position... :-))

Abgesehen davon bedeuten Include-Dateien, dass sie auch als Funktionen in Ihrem Code enthalten sind, und das war's.

Danke, Roman, für die Codes und Links! Ich gehe mit den Codes ruhig um und habe es sicher nicht eilig!

Mit freundlichen Grüßen, Vladimir.

 

Guten Tag und gute Laune allerseits!

Ich studiere weiterhin die Programmiersprache MQL5 . Wie versprochen poste ich heute, damit alle den Code der Expert Advisor- Vorlage sehen können, die zum Schreiben eines Trailing-Stops entwickelt wurde. Da sich der EA-Template-Code als ziemlich umständlich herausstellte, mussten wir die Kommentare so weit wie möglich reduzieren. Die Vollversion des Expert Advisors mit detaillierten Kommentaren zu jeder Codezeile, in einer Präsentation, die einem Schüler der 1. Klasse einer Programmierschule zugänglich ist, wird später in Form einer Datei mit dem Arbeitsnamen Trailing_Stop.mq5 veröffentlicht um auf der Baustelle kein weiteres "Fußtuch" zu produzieren.

Vor der Veröffentlichung des Codes wurde der EA im Strategietester getestet. Es wurden keine Probleme festgestellt. Der EA verwendet ein Netting-Positionsabrechnungssystem. Dieses Abrechnungssystem impliziert, dass es auf dem Konto zu einem Zeitpunkt nur eine offene Position für dasselbe Symbol (Finanzinstrument) geben kann.

Im Moment hat der EA folgende Möglichkeiten:

  1. Überprüfen Sie das Handelskonto, auf dem es installiert werden soll. Wenn der Berater auf einem Demokonto installiert ist, wird im Nachrichtenfenster die Erlaubnis zum Weiterarbeiten angezeigt. Wenn versucht wird, den Berater auf einem echten Konto zu installieren, wird im Meldungsfenster eine Warnung angezeigt, dass die Arbeit nicht fortgesetzt werden kann, und danach automatisch aus dem Arbeitsfenster des Handelsterminals gelöscht.
  2. Einmal börsentäglich um genau 9:00 Uhr Öffnen Sie nach Moskauer Zeit automatisch eine Position in die Richtung, in die der erste Tick gelenkt wird. Wenn zum Beispiel um 9:00 Uhr Moskauer Zeit, der erste Tick wird nach oben gerichtet, was bedeutet, dass eine KAUF-Position eröffnet wird, wenn der erste Tick unten ist, wird eine VERKAUFS-Position eröffnet.
  3. Legen Sie die Stop-Loss-Größe fest.
  4. Losgröße festlegen.
  5. Legen Sie andere Parameter fest, die für das Funktionieren des Trailing Stops erforderlich sind.

Darüber hinaus verfügt der EA über eine vorinstallierte Vorlage, die freundlicherweise von Vasily Sokolov zur Verfügung gestellt wurde und die während des Selbstlernprozesses mit Code gefüllt wird.

EINE WARNUNG!!!

Der Expert Advisor wird nach dem Selbststudienplan für ein Demokonto und nur für Bildungszwecke entwickelt! Nicht für den Handel mit einem echten Konto und die Erzielung von Gewinn gedacht!

Mit freundlichen Grüßen, Wladimir.

 //+------------------------------------------------------------------+
//|                                                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 позиции
  {
//---
   ;
  }
//+------------------------------------------------------------------+
 

Guten Tag und gute Laune an alle!

Ich lerne weiter die Programmiersprache MQL5. Gestern habe ich den Code für Stop Loss at Breakeven für Sell- und Buy-Positionen geschrieben. Ich füge den Code noch unkommentiert ein. Ich werde die Vollversion des Expert Advisors mit einer detaillierten Beschreibung jeder einzelnen Codezeile in einer für Schüler des 1. Schuljahres der Programmierschule zugänglichen Form später in der Datei mit dem Arbeitstitel Trailing_Stop.mq5 veröffentlichen. Vor der Veröffentlichung des Codes haben wir die Leistung des Expert Advisors im Strategietester überprüft. Es wurden keine Probleme festgestellt.

Mit freundlichen Grüßen, 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:

Guten Tag und gute Laune an alle!

Ich lerne weiter die Programmiersprache MQL5. Heute, wie versprochen, füge ich den Code der Vorlage meines Expert Advisors ein, der für das Schreiben eines Trailing Stops entwickelt wurde. Da der Code der EA-Vorlage recht umständlich ist, musste ich die Kommentare so kurz wie möglich halten. Die vollständige Version des Expert Advisors mit detaillierten Kommentaren zu jeder Zeile des Codes, in einer Form, die einem Schüler der 1. Klasse zugänglich ist, wird später als Datei mit dem Arbeitsnamen Trailing_Stop.mq5 veröffentlicht, um eine weitere Verunreinigung der Website zu vermeiden.

...

Sehr gut. Der Grundgedanke wird gut erfasst. Besonders gut gefällt mir der Entwicklungsprozess:

MrBrooklin:

Guten Tag und gute Laune an alle!

Ich lerne weiter die Programmiersprache MQL5. Gestern habe ich den Code für Stop Loss at Breakeven für Kauf- und Verkaufspositionen geschrieben.

D.h. alles ist korrekt. Sie müssen das Problem nicht auf einmal an einem Ort lösen. Sie sollten es nach und nach lösen, so wie Sie es getan haben. Zunächst beschreiben Sie die grundlegende Logik in der OnTick-Funktion und grundlegende Funktionen wie OpenBUY, OpenSELL, TickUP, TickDown.

Wenn dieser grundlegende Code fehlerfrei ist, kompiliert wurde und im Rahmen seiner Möglichkeiten funktioniert, beginnen Sie mit der Beschreibung der anderen Funktionen. Dies kann am nächsten Tag oder sogar eine Woche später geschehen. Das bedeutet, dass Sie den Hauptcode nicht ändern müssen. Ich denke, Sie können verstehen, warum.

Nun müssen Sie diese Art der Entwicklung verfeinern: Schreiben Sie weiterhin Funktionen und verknüpfen Sie diese mit dem bestehenden Code. Das vorhandene Programm sollte korrekt funktionieren. Die Komplexität sollte nicht zunehmen. Die hinzuzufügenden Funktionen müssen einfache und klare Ergebnisse liefern. Ihre Namen sollten für Sie einfach und klar sein. Wenn Sie das nicht können, liegt es vielleicht daran, dass Sie nicht nur eine, sondern zwei oder sogar drei Funktionen schreiben müssen, um das Problem zu lösen. Der Gesamtrahmen der Anwendung ist anfangs schwer zu definieren. Deshalb ist es besser, wenn Sie sich von erfahrenen Kollegen beraten lassen. Mit der Zeit werden Sie lernen, solche Vorlagen selbst zu entwickeln.

Im Laufe der Zeitwerden Sie immer mehr Sprachkonstrukte innerhalb von Funktionenverwenden müssen, um sie an Ihre Bedürfnisse anzupassen.An diesem Punkt werden Sie schrittweise und vor allem organisch Ihr Wissen über Sprachkonstrukte erweitern, Schleifen, Arrays und sogar die Arbeit mit Zeigern lernen.

Den schwierigsten Teil des Programmierens haben Sie bereits gelernt, auch wenn Sie das Gelernte noch nicht gefestigt haben. Alles, was Sie jetzt noch tun müssen, ist, es viele Male zu wiederholen, um es zu festigen. Von hier aus gibt es nichts grundlegend Neues, alles ist gleich: Allgemeine Vorlage -> Beschreibung der Namen der Funktionen und ihrer Parameter-> Schreiben der Inhalte dieser Funktionen -> Anordnung dieser Funktionen in der zentralen Einheit. Das war's. Alles, was bleibt, ist, die Fähigkeit zu perfektionieren und beständig zu sein. Verschiedene zusätzliche Konstruktionen, die Sie verwenden, wie Schleifen und Arrays, sind nur Details, manchmal clever gemacht, aber nichts weiter als Details.

 
Übrigens: Achten Sie auf den Gesamtumfang Ihres Programms. Sie ist bereits recht umfangreich. 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.
 

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

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

Ich habe zwei nicht-triviale Stellen gelb markiert.

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:

TickUP()==(price+point)

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 übereinstimmt (ich werde sie später schreiben)

 
Vasiliy Sokolov:

Sehr gut. Der wichtigste Punkt ist richtig erfasst. Besonders gefallen hat mir der Entwicklungsprozess:

Das heißt, alles ist richtig. Sie müssen das Problem nicht auf einmal an einem Ort lösen. Sie tun es schrittweise, so wie es in Ihrem Fall geschehen ist. Zunächst beschreiben Sie die grundlegende Logik in der OnTick-Funktion und grundlegende Funktionen wie OpenBUY, OpenSELL, TickUP, TickDown.

Wenn dieser grundlegende Code fehlerfrei ist, kompiliert wurde und im Rahmen seiner Möglichkeiten funktioniert, beginnen Sie mit der Beschreibung der anderen Funktionen. Dies kann am nächsten Tag oder sogar eine Woche später geschehen. Das bedeutet, dass Sie den Hauptcode nicht ändern müssen. Ich denke, Sie können verstehen, warum.

Nun müssen Sie diese Art der Entwicklung verfeinern: Schreiben Sie weiterhin Funktionen und verknüpfen Sie diese mit dem bestehenden Code. Das vorhandene Programm sollte korrekt funktionieren. Die Komplexität sollte nicht zunehmen. Die hinzuzufügenden Funktionen müssen einfache und klare Ergebnisse liefern. Ihre Namen sollten für Sie einfach und klar sein. Wenn Sie das nicht können, müssen Sie vielleicht nicht eine, sondern zwei oder sogar drei Funktionen schreiben, um das Problem zu lösen.

Damit eine Funktion die ihr zugedachten Aufgaben erfüllen kann,müssen Sie mit der Zeit immer mehr Sprachkonstrukte in solchen Funktionen verwenden. Dabei werden Sie schrittweise und vor allem organisch Ihre Kenntnisse über Sprachkonstruktionen erweitern, Schleifen, Arrays und sogar die Arbeit mit Zeigern lernen.

Hallo, Wassili! Vielen Dank für Ihre rechtzeitigen Vorschläge und Ihre Unterstützung. Ihre Kommentare über die Rolle der Funktionen und die Prinzipien der Programmcodekonstruktion 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.

Grund der Beschwerde: