MQL5言語をゼロから独学で学ぶ - ページ 71

 
MrBrooklin:

イゴール MQL5言語を学びたいという気持ちは失われていませんし、逆に強くなる一方です。どうして私はこんなに頭が悪くて、このループ演算子で簡単なことが理解できないのだろうと、ただただ悩んでいます。ループ演算子がない場合は完全に動作しますが、ループがある場合は完全に混乱します。と にかく真相を突き止める。しかし、隔離期間が終わってから自習の時間がかなり減り、仕事で語学の勉強ができる瞬間がめったにない。主に夕方から深夜にかけて語学の勉強をしています。

Trailing Stopのコードを書くためには、2つのタスクを解決する必要があります。

  1. すべてのシンボルのすべてのオープンポジションを検索し、存在しない場合は、9:00:00から9:01:00までの間に買いポジションをオープンし、23:50:00に強制的にクローズするコードを書く必要があります forループ演算子がなければ、前に書いたように、すべて完璧に動作します。今度は、ループを使って同じ結果を得たいのです。
  2. 09:00:00 から 09:01:00 までの時間枠に現れる最初のティックでポジションの開く方向を 決定する関数を2つ記述する。最初のティックが上向きなら買いポジションを、下向きなら売りポジションをそれに応じてオープンする必要があります。戦略ではなく、ランダム 条件を使わないというのは、私の「やりたいこと」 なんです。
Sincerely, Vladimir.
.

ウラジミール、なんだか変なことに巻き込まれてるなぁ。あなたはテンプレートを渡されました。https://www.mql5.com/ru/forum/352460/page58#comment_18726492 あなたはそれを無視し、あなたの知恵で先に進むことにしました。この方法は難しく、何年もかかるかもしれません。途中、C、C++、Rust、C#、ポリモーフィズム、継承、ポインタの再参照、動的な型変換を勉強する。チェックしたり、ドライブしたり。目的地へは最短距離で行かなければならない。トレーリングが必要な場合は、トレーリングと書いてください。CやC++を勉強しなくてもできる。これは全部、気が向いたら選択科目として。

forループの状況を説明します。強力な構造であるがゆえに、適材適所に適用する必要があるのです。網と補助アルゴリズムがありますね。だからポジションの列挙がない、魔導師がいない、だからこのループがないんでしょう。当然、これがなくても全ては動くのですが、このループでは油しか出ません。でも、頑なに使おうとする。それは、できるだけたくさん使うこと、できるだけたくさん持つこと、それ自体が目的になっているような気がします。

 
Vasiliy Sokolov:

ウラジミール、ちょっとマンネリ化してきましたね。あなたはテンプレートを渡されました。https://www.mql5.com/ru/forum/352460/page58#comment_18726492 あなたはそれを無視し、自分の意思で進めることにしました。この道は険しく、何年もかかるかもしれません。途中、C、C++、Rust、C#、ポリモーフィズム、継承、ポインタの再参照、動的な型変換を勉強する。チェックしたり、ドライブしたり。目的地へは最短距離で行かなければならない。トレーリングが必要な場合は、トレーリングと書いてください。CやC++を勉強しなくてもできる。これは全部、気が向いたら選択科目として。

forループの状況を説明します。強力な構造であるがゆえに、適材適所に適用する必要があるのです。網と補助アルゴリズムがありますね。だからポジションの列挙がない、魔導師がいない、だからこのループがないんでしょう。もちろん、これがなくてもすべてうまくいくのですが、ループがあると油断してしまうだけなんです。でも、頑なに使おうとするから、それ自体が目的になってしまう。何でもかんでも、ストックしておくために、できるだけ使うかもしれません。

こんにちは、Vasily!

いつもながらタイムリーに話題に加わって、正しい道を示してくれてありがとうございます。では、順番に説明していきますね。

  1. Expert Advisorのテンプレートが、御社のご好意で提供されたとおりに挿入され、感謝申し上げます。
  2. Trailin Stopを搭載したEAをストラテジーテスターで テストすべきと判断しましたが、少なくとも1つのポジションを自動的に開くことなく行うにはどうしたらよいかわかりませんでした。だからこそ、「本格的なExpert Advisor」を書くときに不安を感じるようになったのです。私のExpert Advisorにはそのようなストラテジーがないので、引用符で囲みました。単にランダムな 条件でポジションを建てるのが嫌だっただけです。
  3. Expert Advisorの対談者は、あなた以外、誰もこの状況でポジションを検索するfor ループは必要ないとの意見を述べませんでした。私が悪いのですが、もっと前に自分で推測して、「ループは本当に必要な のか」と問うことができたはずです。結果的には、そうじゃなかったんですね。また、情報をありがとうございました
  4. 最終的にトレーリングストップの記述に入り、途中で処理を放棄しない ためには、ネットの買いまたは売りポジションの開始方向を決定する2つの関数のコードを書くだけでよいのです。
  5. そうですね、自習が長引くようになったというのは全く同感です。しかし、未踏の曲りくねった道を行くことを考慮すれば、値引きは可能であろう。
  6. 自習期間中、膨大な量の情報を得たので、今はそれを整理するだけでなく、実践に役立てようと思っています。そのために、CodeBaseからExpert Advisorをダウンロードして開発し、2週間ほどFXディーラーのデモ口座で使ってみました。期待通りの仕上がりです。近々、実際のアカウントで使い始める予定です。これはもう、プラスアルファですね
  7. 自習のスピードを追わないのは、先に書いたように、時折、情報の過剰が呆気なくやってくるからである。
  8. 独学の期間中、コンパイルコードの後に出てくる英単語やフレーズを少しずつ覚え始めた。Google翻訳を見る回数が減りました。これも自習のプラスになる瞬間です。
  9. トレーリングストップ用の完全なワークが出来上がったら、Expert Advisorに書き込んだ内容を全て正確に掲載します。土曜日に完成させようと 思っています。ここからトレーリングストップのコードを書くための主な作業が始まります。

Vasilyさん、ご指導と建設的なご批判をいただき、大変感謝していますまた、MQL5のプログラミング 言語をゼロから独学で学ぶにあたり、本テーマに参加された皆様に感謝いたします。

自習は続ける。続きはこちら

ウラジミールさん、ありがとうございます。

 
Андрей:

皆さん、こんにちは。

面白いことを付け加えるとすれば、「MQL5を ゼロから独学で」というのはちょっと違うんじゃないかと思います。 プログラミングが0点の人は、まずプログラミングを学ばないといけないんですよ。MQLで ゼロからプログラミングを学ぶことを目的とする場合、人はまずCでプログラミング する方法を、少なくとも非常に基本的なことから学ばなければなりません。ロシア語を知らずにラテン語を学ぼうとするようなものだ...。

もうひとつは、C言語がプログラミングを学ぶのにあまり適していないということです。C言語はシンプルですが、簡潔すぎるため、アルゴリズム、データ型、ブール代数の基本的な理解がないと、初心者がコードを読んで理解するのは困難です。 C言語で3文字並んでいても、他の言語では複数の文字列を意味することもあるのです。

ゼロから単にプログラミングを学ぶために、ベースのために、1つの(関係ない)言語でコンピュータに話をすることを学ぶために、私はパスカル、それからC(勤勉とパスカル最大週の後にそこに、構文をマスターする最も簡単な本で始まることをお勧めします、私は基本的な言語スキルを意味します!)。)、そしてMQLのような専門的な言語を取り上げる。MQLはC言語であり、単一のタスクのために設計され、コンパイラは当たり前のことを知っているので、少しひねって単純化したものだからだ。そして、CはRAR圧縮されたPascalのようなものですが、Pascalはほとんど英語です =)。

さて、ループについてです。

プログラミングを学んだとき、代数学の和とのアナロジーが役に立ちました。nの初期値、nの最終値、このnを使った計算式を指定するのです。

アンドレイさん、こんにちは!基礎の部分については、まったく同意見です。持っていないし、持ったこともない。しかし、「モスクワは一度ではつくれない」ということわざがある。アドバイスやヒントをありがとうございました。

ウラジミールさん、ありがとうございます。

 
Roman Shiredchenko:

そうですね、彼のコードも良いですね。無駄に興奮してるな。焦らずじっくりとコードを整理していく、それだけです。ここでは 全て初歩的なことです- 選択とトロール:(どれだけ簡単か - NEEDの位置を選ぶというあなたのトピックだけ...:-)。

それ以外に、インクルードファイル - それは、あなたのコードに関数としても含まれていることを意味し、それだけです。

Romanさん、コードとリンクありがとうございます。私は冷静にコードに対処し、きっとどこにも急がないでしょう!

敬具 ウラジミール

 

みなさん、良い一日と良い気分!

MQL5プログラミング言語の勉強を続けています。今日、約束通り、トレーリングストップを書くために設計されたExpertAdvisorテンプレートのコードをみんなに見てもらうために投稿しています。 EAテンプレートコードは非常に面倒であることが判明したため、コメントをできるだけ減らす必要がありました。プログラミング学校の1年生がアクセスできるプレゼンテーションで、コードの各行に詳細なコメントが記載されたExpert Advisorの完全版は、 Trailing_Stop.mq5という作業名のファイルの形式で後で公開されます。サイト上で別の「フットクロス」を作成しないようにします。

コードを公開する前に、EAは戦略テスターでテストされました。問題は確認されていません。 EAはネッティングポジション会計システムを使用しています。この会計システムは、同じシンボル(金融商品)のアカウントに一度に1つのオープンポジションしか存在できないことを意味します。

現時点では、エキスパートアドバイザーには次の機能があります。

  1. インストールする予定の取引口座を確認してください。アドバイザーがデモアカウントにインストールされている場合は、作業を続行するための許可がメッセージウィンドウに表示されます。アドバイザーを実際のアカウントにインストールしようとすると、メッセージウィンドウに作業を続行できないという警告が表示され、その後、トレーディング端末の作業ウィンドウから自動的に削除されます。
  2. ちょうど午前9時の取引日の1回。モスクワ時間に従って、最初の目盛りが向けられる方向に自動的に1つの位置を開きます。たとえば、午前9時の場合モスクワ時間では、最初の目盛りが上向きになります。つまり、買いポジションが開き、最初の目盛りが下がると、売りポジションが開きます。
  3. ストップロスサイズを設定します。
  4. ロットサイズを設定します。
  5. トレーリングストップが機能するために必要となる他のパラメータを設定します。

さらに、EAには、Vasily Sokolovから提供されたテンプレートがプリインストールされており、自己学習プロセス中にコードが入力されます。

警告!!!

Expert Advisorは、デモアカウントおよび教育目的のみの自習プランに従って開発されています。実際のアカウントで取引して利益を上げることを目的としていません!

よろしく、ウラジミール。

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

皆さん、ご機嫌いかがでしょうか?

プログラミング言語「MQL5」の勉強を続けています。昨日、売りと買いのポジションのStop Loss at Breakevenのコードを書きました。まだ何もコメントがない状態で、コードを貼り付けています。このExpert Advisorの完全版と各コードの詳細な説明を、プログラミングスクールの1年生が理解できる形で、Trailing_Stop.mq5という ファイル名で後日公開する予定です。コードを公開する前に、ストラテジーテスターで Expert Advisorのパフォーマンスを確認しました。問題は見つかりませんでした。

ウラジミールさん、ありがとうございます。

//+------------------------------------------------------------------+
//| Устанавливает 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:

皆さん、ご機嫌いかがでしょうか?

プログラミング言語「MQL5」の勉強を続けています。今日は、約束通り、トレーリングストップを書くためにデザインしたExpert Advisorのテンプレートの コードを貼り付けます。テンプレートEAのコードはかなり煩雑なため、コメントはできるだけ短くする必要がありました。エキスパートアドバイザーの完全版は、コードの各行に詳細なコメントを付け、プログラミングスクールの1年生がアクセスできる形式にして、後日、作業名をTrailing_Stop.mq5 とするファイルとして公開し、ウェブサイト上で別の汚点を作らないようにします。

...

非常に良い。主旨をよく捉えている。特に、開発プロセスが気に入っています。

MrBrooklin:

皆さん、ご機嫌いかがでしょうか?

プログラミング言語「MQL5」の勉強を続けています。昨日、買いポジションと売りポジションのブレイクイーブンでのストップロスの コードを書きました。

すなわち、すべてが正しいのです。一箇所で一気に解決する必要はありません。あなたのように徐々に解決していけばいいのです。まず、OnTick関数とOpenBUY、OpenSELL、TickUP、TickDownといった基本的な関数の基本ロジックについて説明していますね。

そして、この基本的なコードがデバッグされ、コンパイルされ、その能力の範囲内で動作するようになったら、他の機能の記述に入ります。これは翌日、あるいは1週間後に行うこともあります。つまり、メインコードを変更する必要がないのです。その理由は、おわかりいただけたと思います。

あとは、関数を書き続け、関数を介して既存のコードに機能をリンクさせる、このような開発方法を磨いていく必要があります。既存のプログラムは正常に動作するはずです。複雑さを増してはいけない。追加する機能は、シンプルで明確な結果を返すものでなければならない。その名前は、あなたにとってできるだけシンプルで明確なものであるべきです。これができない場合、問題を解決するために1つではなく、2つ、あるいは3つの関数を書く必要があるからかもしれません。最初は、アプリケーションの全体的な枠組みを定義するのは難しいでしょう。だから、経験豊富な仲間にアドバイスをもらった方がいいんです。時間が経てば、そのようなテンプレートを自分で開発できるようになります。

時間が経つにつれて、関数内でより多くの言語構造を 使用して、自分のニーズに合うようにする必要があります。この時点で、徐々に、そして最も重要なことですが、言語構成に関する知識を有機的に拡大し、ループ、配列、さらにはポインタの扱い方を学びます。

実は、学んだ内容を定着させることはできていないものの、プログラミングの最も難しい部分をすでに学んでいるのです。あとは、何度も繰り返して定着させるだけです。ここからは根本的に新しいことはなく、一般的なテンプレート→関数名とそのパラメータの記述→その関数の内容の記述→その関数のセントラルユニットへの配置という流れになるかと思います。それだけです。あとは技術を完成させ、安定させるだけです。ループや配列のような追加的な構造は、細部に過ぎず、時には巧妙にできていますが、細部に過ぎないのです。

 
ちなみに、プログラム全体のサイズにも気を配ってください。もうかなり充実していますね。いかがでしょうか。ちなみに、初心者がこのような大きなコードサイズを書くことはできません。変数が混乱し始め、ブラケットが大きくなりすぎ、コンパイルエラーが雨後のキノコのように忍び込み始めます。コンパイル後、このサイズのプログラムは不具合を起こし、誰も何が悪いのかわからない。そして、あなたのコードではなぜかすべてがうまくいくのです)、何がどのように起こっているのか、関数の中で明確にされているのです。一言で言えば、「美しい」です。
 

完璧を求めるとキリがないので、コードに少しコメントを加えておきます。

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

自明でない2箇所を黄色で強調しました。

1) 最初のifと次のelseでコードが繰り返されていることに注意してください。違いは最後の行とエンドアクション(OpenBUY、OpenSell)だけです。

2)elseブロックに入る条件が明らかでない。が多いため、目に見えない。実際には、最後の行にしか依存しない。

TickUP()==(price+point)

これは、ここに機能が欠けていることを意味しています。

ポジションを開く 時間が与えられたものと一致する場合に真を返す関数を書く必要があります(後で書きます)。

 
Vasiliy Sokolov:

非常に良い。要点を的確に捉えている。特に気に入ったのは、開発プロセスです。

すなわち、すべてが正しいのです。一箇所で一気に解決する必要はありません。徐々にやっていくんですね、今までのように。まず、OnTick関数とOpenBUY、OpenSELL、TickUP、TickDownといった基本的な関数の基本ロジックについて説明していますね。

そして、この基本的なコードがデバッグされ、コンパイルされ、その能力の範囲内で動作するようになったら、他の機能の記述に入ります。これは翌日でも、1週間後でも構いません。つまり、メインコードを変更する必要がないのです。その理由は、おわかりいただけたと思います。

あとは、関数を書き続け、関数を介して既存のコードに機能をリンクさせる、このような開発方法を磨いていく必要があります。既存のプログラムは正常に動作するはずです。複雑さを増してはいけない。追加する機能は、シンプルで明確な結果を返すものでなければならない。その名前は、あなたにとってできるだけシンプルで明確なものであるべきです。これができない場合、問題を解決するためには、1つではなく、2つ、あるいは3つの関数を書く必要があるのかもしれません。

関数がその役割を果たすためには、その関数の中でより多くの言語構成要素を使用することが最終的に必要に なります。その時に、徐々に、そして最も重要なことですが、言語の構文に関する知識を有機的に広げ、ループや配列、さらにはポインタの扱い方を学ぶことができます。

こんにちは、Vasily!タイムリーな提案とサポートに大変感謝しています。関数の役割やプログラムコード構築の原則など、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

頭の中の情報が構造化されたことで、自分だけでなく、他のプログラマーが書いたコードも理解しやすくなったのです。このトピックが、これからプログラミング言語MQL5をゼロから学び始める方にとって、良い参考になれば幸いです。

ウラジミールさん、ありがとうございます。

理由: