English Русский 中文 Español Deutsch Português
トレーダーのライフハック: インジケーターで作られたファストフード

トレーダーのライフハック: インジケーターで作られたファストフード

MetaTrader 5統合 | 15 3月 2018, 09:03
1 564 0
Vladimir Karputov
Vladimir Karputov

「もし何か本当に悪いものがあって、それが禁止されて欲しいと望めば、それは逆に許可される。」 ロシアのことわざ

シンプルさと信頼性

2005年に新しくリリースされたメタトレーダー 4では、簡単な MQL II スクリプト言語が MQL4 に置き換えられました。 今日となってはおかしな話ですが、多くのトレードは新しい C のような言語に嫌悪感を感じました。 多くの討論および報告は MetaQuotes社で指針されました。 批評家たちは、言語が非常に複雑であり、マスターすることは不可能であると主張しました。

12年後、今となってはそのような主張は奇妙に思えるが、歴史は繰り返します。 ちょうど2005年のように、一部のトレーダーは、MQL5 は MQL4 と比較して、MQL5が複雑であると言います。 これは、開発者が C++ 言語のさらに強力なツールを使用して、アルゴリズムトレードを提供する上で移行することを恐れていなかったという事実のおかげであり、長年にわたって、トレーディングロボットの開発の全体的なレベルが大幅に成長していることを意味します。 新しい言語であるMQL5 を使用すると、プログラマはすべての操作の結果を最大限チェックすることができます。 (トレードの処理に特に重要です)、オンデマンドで RAM を消費します。 古い言語であるMQL4 は、MQL5レベルになる前に、その種の機会をあまり提供していません。 その上、構文自体はあまり厳格ではありませんでした。

MQL5 の複雑さについての討論は、それほど長い期間を要することなく、忘れさられると信じています。 しかし、多くのトレーダーは、まだ "古き良き MQL4 " についてノスタルジックを感じるので、MQL5で実装されている場合、おなじみの MQL4 でどのように再現できるか試みるかもしれません。

MQL5 に新たに切り替えた場合、この記事は役に立つでしょう。 まず、インジケーターデータとシリーズへのアクセスは、通常の MQL4 スタイルで行われます。 次に、このシンプルさを MQL5 に実装します。 すべての関数は、可能な限り明確であり、ステップバイステップのデバッグに最適です。


1. MQL4 スタイルを使用して MQL5 でインディケーターを操作することは可能でしょうか。

インジケータの操作の主な差は、 MQL4 のインジケーターデータ取得文字列が、実際には、インジケーター作成コマンド (iMACD (NULL、0、12、26、9、PRICE_CLOSE) と、必要なインジケーターバッファからのデータのリクエストを組み合わせたことです。

//+------------------------------------------------------------------+
//|                                                        iMACd.mq4 |
//|                              Copyright © 2018, Vladimir Karputov |
//|                                           http://wmua.ru/slesar/ |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2018, Vladimir Karputov"
#property link      "http://wmua.ru/slesar/"
#property version   "1.00"
#property strict
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---

//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---

  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
   double macd_main_1=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_MAIN,1);
  }
//+------------------------------------------------------------------+

その結果、単一の文字列は1つのステップだけを表します。

MQL5 では、このコードに相当する手順があります。

  • インジケーターハンドルが格納される変数を宣言します。
  • インジケーターハンドルの作成と確認。
  • インジケーターの値を提供する個別の関数。
//+------------------------------------------------------------------+
//|                                                       iMACD mq5 |
//|                              Copyright © 2018, Vladimir Karputov |
//|                                           http://wmua.ru/slesar/ |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2018, Vladimir Karputov"
#property link      "http://wmua.ru/slesar/"
#property version   "1.000"

int    handle_iMACD;                         //iMACD インジケーターのハンドルを格納するための変数
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---インジケーター iMACD のハンドルを作成。
   handle_iMACD=iMACD(Symbol(),Period(),12,26,9,PRICE_CLOSE);
//ハンドルが作成されていない場合 
   if(handle_iMACD==INVALID_HANDLE)
     {
      //--- tell about the failure and output the error code 
      PrintFormat("Failed to create handle of the iMACD indicator for the symbol %s/%s, error code %d",
                  Symbol(),
                  EnumToString(Period()),
                  GetLastError());
      //--- the indicator is stopped early 
      return(INIT_FAILED);
     }
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---

  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
   double MACD_main_1=iMACDGet(MAIN_LINE,1);
  }
//+------------------------------------------------------------------+
//| Get value of buffers for the iMACD                               |
//
115/5000
//|   0 - MAIN_LINE, 1 - SIGNAL_LINE                                 |
//+------------------------------------------------------------------+
double iMACDGet(const int buffer,const int index)
  {
   double MACD[1];
//--- reset error code 
   ResetLastError();
//iMACDBuffer 配列の一部を、0のインデックスを持つインジケーターバッファの値で塗りつぶす 
   if(CopyBuffer(handle_iMACD,buffer,index,1,MACD)<0)
     {
      //---コピーが失敗した場合は、エラーコードを伝えます。 
      PrintFormat("Failed to copy data from the iMACD indicator, error code %d",GetLastError());
      //---ゼロの結果で終了-インジケーターが計算されていない 
      return(0.0);
     }
   return(MACD[0]);
  }
//+------------------------------------------------------------------+

MQL4 スタイルでコードを書き直してみましょう。

インジケーターハンドルの作成とインジケーターデータの取得は、1つの関数で実装されます。

//+------------------------------------------------------------------+
//| iMACD function in MQL4 notation                                  |
//+------------------------------------------------------------------+
double iMACD(
             string              symbol,              //シンボル名
             ENUM_TIMEFRAMES     period,              //期間
             int                 fast_ema_period,     //高速平均計算の期間
             int                 slow_ema_period,     //低速平均計算の期間
             int                 signal_period,       //差異の平均の期間
             ENUM_APPLIED_PRICE  applied_price,       //価格またはハンドルの種類
             int                 buffer,              //バッファ
             int                 shift                //シフト
             )
  {
   double result=NULL;
//---
   int handle=iMACD(symbol,period,fast_ema_period,slow_ema_period,signal_period,
                    applied_price);
   double val[1];
   int copied=CopyBuffer(handle,buffer,shift,1,val);
   if(copied>0)
      result=val[0];
   return(result);
  }

注意! この関数を書き込んだ後、すべてのティックにインジケータハンドルを作成します。 ドキュメントではこのような創造性を推奨していないと思うかもしれません。 [テクニカルインジケーター関数] セクションを見てみましょう。

インジケーター値の計算には時間が必要なため、作成後にインジケーターデータを参照することはできません。 したがって、インジケーターハンドルは、OnInit() のように作成することをお勧めします。

では、なぜこのコードが動作し、メモリを消費しないのでしょうか。 答えは同じセクションにあります。

注意. 1 つの MQL5 プログラム内で同じパラメータを持つインディケータ関数の繰り返し呼び出しは、参照カウンタの複数の増加につながるわけではありません。カウンタは1回だけ増加します。 ただし、インジケーターを関数またはクラスコンストラクターで処理し、さらにハンドルを他の関数で使用することをお勧めします。 MQL5 プログラムが deinitialized の場合、参照カウンタは減少します。

言い換えると、MQL5 は最適に設計されています: ハンドルの作成を制御し、同じパラメータを何度も同じインディケータで作成することはできません。 インジケーターのコピーであるハンドルの作成を繰り返し試行した場合は、以前に作成したインジケーターのハンドルを対応する設定で取得するだけです。 いずれにせよ、まだ OnInit() の1回の処理をすることをお勧めします。 理由は後で説明します。

注: 生成されたハンドルの有効性のチェックはありません。

iMACD インジケーターの値を受け取るコードは次のようになります。

//+------------------------------------------------------------------+
//|                                           MACD MQL4 style EA.mq5 |
//|                              Copyright © 2018, Vladimir Karputov |
//|                                           http://wmua.ru/slesar/ |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2018, Vladimir Karputov"
#property link      "http://wmua.ru/slesar/"
#property version   "1.000"

#define MODE_MAIN 0
#define MODE_SIGNAL 1
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- 

//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---

  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
   double MACD_main_1=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_MAIN,1);
  }
//+------------------------------------------------------------------+
//| iMACD function in MQL4 notation                                  |
//+------------------------------------------------------------------+
double iMACD(
             string              symbol,              //シンボル名
             ENUM_TIMEFRAMES     period,              //期間
             int                 fast_ema_period,     //高速平均計算の期間
             int                 slow_ema_period,     //低速平均計算の期間
             int                 signal_period,       //差異の平均の期間
             ENUM_APPLIED_PRICE  applied_price,       //価格またはハンドルの種類
             int                 buffer,              //バッファ
             int                 shift                //シフト
             )
  {
   double result=NULL;
//---
   int handle=iMACD(symbol,period,fast_ema_period,slow_ema_period,signal_period,
                    applied_price);
   double val[1];
   int copied=CopyBuffer(handle,buffer,shift,1,val);
   if(copied>0)
      result=val[0];
   return(result);
  }
//+------------------------------------------------------------------+

注: MQL4 スタイルのインジケーターにアクセスすることは、戻り値をチェックする選択肢を奪います。MQL4 スタイルのすべての関数は、' double ' 値のみを返すのが理由です。 可能な解決策は、セクション1.1 で提供されます。

これまでのところかなり面倒そうなので、' define ' ブロックと double iMACD() 関数を別個のIndicatorsMQL5.mqhインクルードファイルに実装して、別のフォルダに配置することができます "[データフォルダ] MQL5\Include\SimpleCall"。 この場合、このコードはかなり短くなります。 IndicatorsMQL5.mqhファイルが含まれていることに注意してください。 MACDにアクセスするときに MQL4 MODE_MAIN ではなく、MQL5 MAIN_LINE の形式でインディケータ行の名前を転送する必要があることを意味します。

//+------------------------------------------------------------------+
//|                                     MACD MQL4 style EA short.mq5 |
//|                              Copyright © 2018, Vladimir Karputov |
//|                                           http://wmua.ru/slesar/ |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2018, Vladimir Karputov"
#property link      "http://wmua.ru/slesar/"
#property version   "1.000"
#include<SimpleCallIndicatorsMQL5.mqh></SimpleCallIndicatorsMQL5.mqh>
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- 

//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---

  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
   double MACD_main_1=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MAIN_LINE,1);
   Comment("MACD, main buffer, index 1: ",DoubleToString(MACD_main_1,Digits()+1));
  }
//+------------------------------------------------------------------+

検証のためだけに "コメント " を実装しました。 ビジュアルモードで "MACD MQL4 style EA short.mq5" を起動し、インデックス #1 の足にカーソルを置く場合、テスターのタスクを確認することができます。

テスター上の "MACD MQL4 style EA short.mh5"

図1. テスター上の "MACD MQL4 style EA short.mh5"

1.1. "IndicatorsXXXX.mqh "で稼働するときのニュアンス


戻り値のエラー処理

すべてのインジケーターは、データを double として渡します。 インジケーターからデータを取得できなくなった場合に、ユーザーにメッセージを送信するときに問題です。 インジケーターハンドルが作成されていない場合 (存在しないシンボルが指定されている場合など)、または CopyBuffer の呼び出し中にコピーエラーが発生した場合に発生することがあります。

エラーの場合には "0.0 " を渡すことは、ほとんどのインジケーターの選択肢ではありません。 "0.0 " は非常に正常な値です (例えば、MACD)。 EMPTY_VALUE 定数 (DBL_MAX の値を持つ) を返すことはオプションではありませんが、フラクタルインジケータは EMPTY_VALUE 値によってバッファインデックスを埋めるため、エラーではありません。

残りの唯一のオプションは、 "not 番号 " を渡すことです ( NaN)。 これを実現するために、 NaN変数はグローバルレベルで作成されます。 この変数は、 "非数値 " によって初期化されます。

double NaN=double("nan");
//+------------------------------------------------------------------+
//| iAC function in MQL4 notation                                    |
//+------------------------------------------------------------------+
double   iAC(
             string                       symbol,              //シンボル名
             ENUM_TIMEFRAMES              timeframe,           //期間
             int                          shift                //シフト
             )
  {
   double result=NaN;
//---
   int handle=iAC(symbol,timeframe);
   if(handle==INVALID_HANDLE)
     {
      Print(__FUNCTION__,": INVALID_HANDLE error=",GetLastError());
      return(result);
     }
   double val[1];
   int copied=CopyBuffer(handle,0,shift,1,val);
   if(copied>0)
      result=val[0];
   else
      Print(__FUNCTION__,": CopyBuffer error=",GetLastError());
   return(result);
  }

このアプローチの利点は、エラーが発生した場合に NaN が返され、任意の数値との比較結果が "false" になることです。

//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//NaN 比較の
   double NaN=double("nan");
   double a=10.3;
   double b=-5;
   double otherNaN=double("nan");
   Print("NaN>10.3=",NaN>a);
   Print("NaN<-5=",NaN<b);
   Print("(NaN==0)=",NaN==0);
   Print("(NaN==NaN)=",NaN==otherNaN);
//---結果
   NaN>10.3=false
   NaN<-5=false
   (NaN==0)=false
   (NaN==NaN)=false
//---
  }

したがって、この関数を MQL4 スタイルで使用する場合は、比較の結果がtrueである場合にのみ、トレード操作 (およびその他の重要なアクション) を実行する必要があります。 この場合、 MathIsValidNumber関数を使用して戻り値をチェックします。 

MQL4 および MQL5 のインジケーターラインの識別子

インジケーターラインを記述する定数の値の一部に互換性の問題があります。 たとえば、次のように iAlligator を実行します。

  • MQL4: 1 - MODE_GATORJAW, 2 - MODE_GATORTEETH, 3 - MODE_GATORLIPS
  • MQL5: 0 - GATORJAW_LINE,   1 - GATORTEETH_LINE,   2 - GATORLIPS_LINE 

この問題は、 "IndicatorsXXXX.mqh "関数のインジケーターが数値として表示されることです。 たとえば、この数値が1の場合、ユーザーが何を意味したかは誰も言うことができません。

この点で、2つのインクルードファイルを作成することにしました。実質的に2つ: "IndicatorsMQL4.mqh" と "IndicatorsMQL5.mqh"。 その差は、 "IndicatorsMQL4.mqh " ファイルが MQL4 スタイルでのみインジケーターラインを認識し、ファイル "IndicatorsMQL5.mqh " は MQL5 スタイルでのみインジケーターラインを認識していることです。 "IndicatorsMQL4.mqh " では、インプットパラメータのインジケーターラインの変換は、iADX、iAlligator の内部で直接実行されます。#define に変換することはできません。

iBands と iEnvelopes の例で、この理由を説明しましょう:

//+------------------------------------------------------------------+
//| iBands function in MQL4 notation                                 |
//|   The buffer numbers are the following:                          |
//|      MQL4 0 - MODE_MAIN, 1 - MODE_UPPER, 2 - MODE_LOWER          |
//|      MQL5 0 - BASE_LINE, 1 - UPPER_BAND, 2 - LOWER_BAND          |
//+------------------------------------------------------------------+
double   iBands(
...
//+------------------------------------------------------------------+
//| iEnvelopes function in MQL4 notation                             |
//|   The buffer numbers are the following:                          |
//|      MQL4 0 - MODE_MAIN,  1 - MODE_UPPER, 2 - MODE_LOWER         | ???
//|      MQL5 0 - UPPER_LINE, 1 - LOWER_LINE,        -/-             |
//+------------------------------------------------------------------+
double   iEnvelopes(

MQL4 では、 MODE_UPPERバンドインジケーターは1に変換され、エンベロープインジケーターの場合は0 に変換されます。

2. 各ティックで MQL4 スタイルのインジケータを適用した場合のメモリ消費量はどのくらいでしょうか。

2つの EAのメモリ消費量を比較してみましょう。: "iMACD.mq5 "-インジケータと "MACD MQL4 style EA short.mq5" ウィンドウ内の最大バット数は、ターミナルの設定で "100 000 " に設定されています。 14のチャートの2つのプロファイルを作成します。

  • "iMACD" プロファイル— "iMACD.mq5 " EA は13のチャートに設定されており、すべてのチャートは M30 のタイムフレームです。
  • "MACD MQL4 style EA short" プロファイル- "MACD MQL4 style EA short.mq5 " は13チャートに設定されています。

"Terminal memory used.mq5" インジケーターは、14のチャートで開始されます。 その目的は、10秒ごとにTERMINAL_MEMORY_USED識別子をPrintすることです。

2つの値を比較します: ターミナルが消費する RAM の量 (タスクマネージャデータ) とPrintされたTERMINAL_MEMORY_USED識別子。 この観察は10分間実施されます。余りにも多くのメモリが消費されれば確認します。 主な条件: ターミナルを起動した後、新しいタブを開いたり、チャットを読むことはありません。

Profile Task manager TERMINAL_MEMORY_USED タスクマネージャ (10 分) TERMINAL_MEMORY_USED (10 分)
iMACD 279.7 MB 745 MB 279.7 MB 745 MB
MACD MQL4 style EA short 279.9 MB 745 MB 280.0 MB 745 MB

さて、テストを変更してみましょう: タスクの10分後、H1 にすべてのチャートの時間枠を切り替えます。

Profile Task manager TERMINAL_MEMORY_USED タスクマネージャ (10 分) TERMINAL_MEMORY_USED (10 分)
iMACD 398.0 MB 869 MB 398.3 MB 869 MB
MACD MQL4 style EA short 319.2 MB 874 MB 330.5 MB 874 MB

メモリ使用量を明確にするためのサマリーテーブル:

Profile タスクマネージャ
(M30), MB
TERMINAL_MEMORY_USED
(M30), MB
タスクマネージャ
(H1), MB
TERMINAL_MEMORY_USED
(H1), MB

start 10分 start 10分 start 10分 start 10分
iMACD 279.7 279.7 745 745 398.0 869 398.3 869
MACD MQL4 style EA short 279.9 280.0 745 745 319.2 874 330.5 874

3. MACD Sample.mq4の新ライフ

実行速度、メモリ消費量と [data folder]\MQL4\Experts\MACD Sample.mq4 EAを確認してみましょう。 (MQL5 で開発されたが、 "MACD MQL4 style EA short.mq5 " のような MQL4 スタイルで[data folder]\MQL5\Experts\Examples\MACD\MACD Sample.mq5 EAに準拠

3.1. 一度に1つの値を受け取るように "MACD Sample.mq5 " EA を変更してみましょう

標準配信の "MACD Sample.mq5 " は、 2 つのインジケーター値を一度に受け取ります。

//+------------------------------------------------------------------+
//|main 関数は、任意のポジションが処理された場合に true を返します |
//+------------------------------------------------------------------+
bool CSampleExpert::Processing(void)
  {
//---リフレッシュレート
   if(!m_symbol.RefreshRates())
      return(false);
//---更新インジケーター
   if(BarsCalculated(m_handle_macd)<2 || BarsCalculated(m_handle_ema)<2)
      return(false);
   if(CopyBuffer(m_handle_MACD,0,0,2,m_buff_MACD_main)  !=2 ||
      CopyBuffer(m_handle_macd,1,0,2,m_buff_MACD_signal)!=2 ||
      CopyBuffer(m_handle_ema,0,0,2,m_buff_EMA)         !=2)
      return(false);
//   m_indicators.Refresh();
//コーディングを簡素化し、アクセスを高速化する
//---データを内部変数に入れる
   m_MACD_current   =m_buff_MACD_main[0];
   m_MACD_previous  =m_buff_MACD_main[1];
   m_signal_current =m_buff_MACD_signal[0];
   m_signal_previous=m_buff_MACD_signal[1];
   m_ema_current    =m_buff_EMA[0];
   m_ema_previous   =m_buff_EMA[1];

その後、次元 "2 " の配列のデータが変数に割り当てられます。 なぜこのように行われているのでしょうか? 時間ごとに1つまたは2つの値によってコピーするかどうかにかかわらず、まだCopyBufferを使用します。 ただし、2つの値を一度にコピーする場合は、1つの書き込み操作を配列に保存します。

しかし、 "MACD Sample.mq4 " EA は、1回につき一つのインジケーター値を受け取ります。

//コーディングを簡素化し、アクセスデータを高速化する
   MACDCurrent=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_MAIN,0);
   MACDPrevious=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_MAIN,1);
   SignalCurrent=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_SIGNAL,0);
   SignalPrevious=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_SIGNAL,1);
   MaCurrent=iMA(NULL,0,MATrendPeriod,0,MODE_EMA,PRICE_CLOSE,0);
   MaPrevious=iMA(NULL,0,MATrendPeriod,0,MODE_EMA,PRICE_CLOSE,1);

MACD のメインライン、MACD のシグナル線と移動平均は、ぞれ2回調査されます。 したがって、 "MACD Sample.mq5 " は、同じフォームにする必要があります。 この EA のバージョン "MACD Sample One value at a time.mq5 " と呼んでみましょう。 ここでは、どのように変更されるかを扱うので、一度に1つの値を受け取ります:

//---更新インジケーター
   if(BarsCalculated(m_handle_macd)<2 || BarsCalculated(m_handle_ema)<2)
      return(false);
//(CopyBuffer (m_handle_MACD, 0, 0, 2, m_buff_MACD_main)! = 2 | |
//CopyBuffer (m_handle_MACD、1、0、2、m_buff_MACD_signal)! = 2 | |
//CopyBuffer (m_handle_ema、0、0、2、m_buff_EMA)! = 2)
//      return(false);
//   m_indicators.Refresh();
//コーディングを簡素化し、アクセスを高速化する
//---データを内部変数に入れる
   CopyBuffer(m_handle_MACD,0,0,1,m_buff_MACD_main);
   m_MACD_current=m_buff_MACD_main[0];
   CopyBuffer(m_handle_MACD,0,1,1,m_buff_MACD_main);
   m_MACD_previous=m_buff_MACD_main[0];
   CopyBuffer(m_handle_MACD,1,0,1,m_buff_MACD_signal);
   m_signal_current=m_buff_MACD_signal[0];
   CopyBuffer(m_handle_MACD,1,1,1,m_buff_MACD_signal);
   m_signal_previous=m_buff_MACD_signal[0];
   CopyBuffer(m_handle_ema,0,0,1,m_buff_EMA);
   m_ema_current=m_buff_EMA[0];
   CopyBuffer(m_handle_ema,0,1,1,m_buff_EMA);
   m_ema_previous=m_buff_EMA[0];

このコードは、記事の最後に添付された "MACD Sample One value at a time.mq5 " に保存されます。

3.2. 「MACD Sample.mq4」を MQL5 コードに変換します。

MQL4 スタイルのインジケーターにアクセスできるようにするだけでなく、ポジションやトレードでのタスクとして、 "IndicatorsMQL4.mqh" ファイルと、 CPositionInfoCSymbolInfoCAccountInfoトレーディングクラスを含める必要があります (このファイルは、インジケータラインの MQL4 名を理解する) 。 また、 "IndicatorsMQL4.mqh" のインジケーターに適切にアクセスするには、「defines」のブロック (インジケーターライン名) を EA に追加する必要があります。

#property description " and the indicators are accessed in the style of MQL4"
#defineMODE_MAIN    0
#defineMODE_SIGNAL  1 
#include<SimpleCallIndicatorsMQL4.mqh></SimpleCallIndicatorsMQL4.mqh>
//---
#include<TradePositionInfo.mqh></TradePositionInfo.mqh>
#include<TradeTrade.mqh></TradeTrade.mqh>
#include<TradeSymbolInfo.mqh></TradeSymbolInfo.mqh>  
#include<TradeAccountInfo.mqh></TradeAccountInfo.mqh>
CPositionInfo  m_position;                   //トレードポジションオブジェクト
CTrade         m_trade;                      //トレーディングオブジェクト
CSymbolInfo    m_symbol;                     //シンボル情報オブジェクト
CAccountInfo   m_account;                    //アカウント情報ラッパー
//---
input double TakeProfit    =50;

また、3桁と5桁のクオートを調整するには、特別な乗数が必要です。

input double MACDCloseLevel=2;
input int    MATrendPeriod =26;
//---
double       m_adjusted_point;               //3または5ポイント調整
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+

現在の価格を受け取るには、CSymbolInfo トレーディングクラスのm_symbolオブジェクトを使用します。

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
   if(!m_symbol.Name(Symbol())) //シンボル名を設定
      return(INIT_FAILED);
   RefreshRates();

RefreshRates () メソッドは価格を更新し、 "0.0 " に等しい価格がないことを確認します。

//+------------------------------------------------------------------+
//|シンボルのクオートデータを更新します |
//+------------------------------------------------------------------+
bool RefreshRates(void)
  {
//---リフレッシュレート
   if(!m_symbol.RefreshRates())
     {
      Print("RefreshRates error");
      return(false);
     }
// "ゼロ " の戻り値に対する保護
   if(m_symbol.Ask()==0 || m_symbol.Bid()==0)
      return(false);
//---
   return(true);
  }

m_adjusted_point乗数は、 m_symbolオブジェクトを初期化した後で、次のように、OnInit() で初期化されます。

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
   if(!m_symbol.Name(Symbol())) //シンボル名を設定
      return(INIT_FAILED);
   RefreshRates();
   //3または5桁のチューニング
   int digits_adjust=1;
   if(m_symbol.Digits()==3 || m_symbol.Digits()==5)
      digits_adjust=10;
   m_adjusted_point=m_symbol.Point()*digits_adjust;
//---
   return(INIT_SUCCEEDED);
  }

OnTick では、 "IndicatorsMQL4Style.mqh" のおかげで MQL4 スタイルのインジケーターにアクセスします。

   if(!RefreshRates())
      return;
//コーディングを簡素化し、アクセスデータを高速化する
   MACDCurrent=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MAIN_LINE,0);
   MACDPrevious=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MAIN_LINE,1);
   SignalCurrent=iMACD(NULL,0,12,26,9,PRICE_CLOSE,SIGNAL_LINE,0);
   SignalPrevious=iMACD(NULL,0,12,26,9,PRICE_CLOSE,SIGNAL_LINE,1);
   MaCurrent=iMA(NULL,0,MATrendPeriod,0,MODE_EMA,PRICE_CLOSE,0);
   MaPrevious=iMA(NULL,0,MATrendPeriod,0,MODE_EMA,PRICE_CLOSE,1);

3.2.1. ポジションの操作

コンプライアンスを最大限にするには、ポジションの有無を決定します。

   total=PositionsTotal();
   if(total<1)
     {

このアプローチは完全には正しくないが、他のシンボルのポジションの存在および/または他の識別子 (マジック番号) を考慮に入れません。

3.2.2. 買いポジション は、CTrade クラスのbuyメソッドを使用して開かれ、同じクラスのResultDealメソッドによって実行の正確性が検証されます。 ResultDeal が実行された場合、ディールチケットを返します。

      //---ロングポジションのチェック (買い) 可能性
      if(MacdCurrent<0 && MacdCurrent>SignalCurrent && MacdPrevious<SignalPrevious && 
         MathAbs(MACDCurrent) > (MACDOpenLevel * m_adjusted_point) & & MaCurrent > MaPrevious)
        {
         m_trade.Buy(Lots,m_symbol.Name(),m_symbol.Ask(),
                     0.0,
                     m_symbol.NormalizePrice(m_symbol.Ask()+TakeProfit*m_adjusted_point),
                     "MACD sample");
         if(m_trade.ResultDeal()!=0)
            Print("BUY position opened : ",m_trade.ResultPrice());
         else
            Print("Error opening BUY position : ",m_trade.ResultRetcodeDescription());
         return;
        }

トレードリクエストの価格は、CSymbolInfo トレーディングクラスのNormalizePriceメソッドを使用して正規化されていることに注意してください。 このメソッドは、量子化を考慮することができます。つまり、最小の価格変化と小数点以下桁数です。 

売りポジションを開くには、同じメソッドを使用します。

3.2.3. ポジションのバイパスブロック: 決済または変更。

ループ自体は、共通のポジションの数から0までの 1までの範囲から渡されます。 ポジションを操作できるようにするには、まず、[一般] リストでインデックスを選択する必要があります。

   for(int i=PositionsTotal()-1;i>=0;i--)
      if(m_position.SelectByIndex(i)) //プロパティへのさらなるアクセスにインデックスによるポジションを選択

PositionCloseメソッドを使用してポジションが閉じられ、変更はPositionModifyによって行われます。 この変更により、CSymbolInfo トレーディングクラスのNormalizePriceメソッドを使用することができます。

ポジションのバイパスブロック全体:

//---正しく相場に入ることは重要であるが、正しく決済することはより重要です。   
   for(int i=PositionsTotal()-1;i>=0;i--)
      if(m_position.SelectByIndex(i)) //プロパティへのさらなるアクセスにインデックスによるポジションを選択
         if(m_position.Symbol()==m_symbol.Name())
           {
            //---ロングポジションをオープン
            if(m_position.PositionType()==POSITION_TYPE_BUY)
              {
               //---閉じるかどうか
               if(MacdCurrent>0 && MacdCurrent<SignalCurrent && MacdPrevious>SignalPrevious && 
                  MACDCurrent>(MACDCloseLevel*m_adjusted_point))
                 {
                  //---ポジションと決済
                  if(!m_trade.PositionClose(m_position.Ticket()))
                     Print("PositionClose error ",m_trade.ResultRetcodeDescription());
                  return;
                 }
               //---トレーリングストップのチェック
               if(TrailingStop>0)
                 {
                  if(m_position.PriceCurrent()-m_position.PriceOpen()>m_adjusted_point*TrailingStop)
                    {
                     if(m_position.StopLoss()<m_symbol.Bid()-m_adjusted_point*TrailingStop)
                       {
                        //---ポジションの変更と決済
                        if(!m_trade.PositionModify(m_position.Ticket(),
                           m_symbol.NormalizePrice(m_position.PriceCurrent()-m_adjusted_point*TrailingStop),
                           m_position.TakeProfit()))
                           Print("PositionModify error ",m_trade.ResultRetcodeDescription());
                        return;
                       }
                    }
                 }
              }

            if(m_position.PositionType()==POSITION_TYPE_SELL)
              {
               //---閉じるかどうか
               if(MacdCurrent<0 && MacdCurrent>SignalCurrent && 
                  MacdPrevious<SignalPrevious && MathAbs(MacdCurrent)>(MACDCloseLevel*m_adjusted_point))
                 {
                  //---ポジションと決済
                  if(!m_trade.PositionClose(m_position.Ticket()))
                     Print("PositionClose error ",m_trade.ResultRetcodeDescription());
                  return;
                 }
               //---トレーリングストップのチェック
               if(TrailingStop>0)
                 {
                  if((m_position.PriceOpen()-m_position.PriceCurrent())>(m_adjusted_point*TrailingStop))
                    {
                     if((m_position.StopLoss()>(m_symbol.Ask()+m_adjusted_point*TrailingStop)) || (m_position.StopLoss()==0.0))
                       {
                        //---ポジションの変更と決済
                        if(!m_trade.PositionModify(m_position.Ticket(),
                           m_symbol.NormalizePrice(m_symbol.Ask()+m_adjusted_point*TrailingStop),
                           m_position.TakeProfit()))
                           Print("PositionModify error ",m_trade.ResultRetcodeDescription());
                        return;
                       }
                    }
                 }
              }
           }

すべての変更が行われます。 最後のファイル "MACD Sample 4 to 5 MQL4 style.mq5" は、以下に添付されています。

3.3. MACD ベースの EA を実行する速度を比較してみましょう

比較には次の EAが使用されます。

  • "MACD Sample.mq5" — EA はインジケーターへの正しいアクセスを提供
  • "MACD Sample One value at a time.mq5"- "MACD Sample.mq5 " に相当する、1時間あたりのインジケーターから一つの値を取得する
  • "MACD Sample 4 to 5 MQL4 style.mq5"-MQL4 EA は、最小の変更と MQL4 スタイルのインジケータへのアクセスを MQL5 に変換

このテストは、MetaQuotes-デモサーバー上の2018.01.16 に2017.02.01 から USDJPY M30 で実行されました。 各テストの後にターミナルがリセットされた (EAの切り替えか、ティック生成モードの切り替えか)。 PC の構成:

Windows 10 (build 16299) x64, IE 11, UAC, Intel Core i3-3120M  @ 2.50GHz, Memory: 4217 / 8077 Mb, Disk: 335 / 464 Gb, GMT+2

# EA 実際のティックに基づいた全ティック 全ティック OHLC


テスト時間 Trades Deals テスト時間 Trades Deals テスト時間 Trades Deals
 1  MACD Sample.mq5  0:01:19.485  122  244  0:00:53.750  122  244  0:00:03.735  119  238
 2  MACD Sample One value at a time.mq5  0:01:20.344  122  244  0:00:56.297  122  244  0:00:03.687  119  238
 3  MACD Sample 4 to 5 MQL4 style.mq5  0:02:37.422  122  244  0:01:52.171  122  244  0:00:06.312  119  238

すべての3つの EA は、 "全ティック・モード " で類似したチャートを示しました:

MACD のサンプル

図2. ストラテジーテスターのMACD Sample XXXX


結論: "MACD Sample 4 to 5 MQL4 style.mq5 " EA は MQL4 スタイルのインジケータにアクセスすることは、インジケータへの正しいアクセスを持つ同様の EA に比べて2倍遅くなります。

3.4. MACD ベースの EA のメモリ消費量を比較してみましょう

同じ14の図表はポイント2のように使用されます。 各ティックで MQL4 スタイルのインジケーターを適用した場合のメモリ消費量はどうなりますか。 "Terminal memory used.mq5" インジケーターは、常に最初のチャートに残されています。 10秒ごとにTERMINAL_MEMORY_USED ID を出力しますが、EAは残りの13個で1つずつ起動します。各測定の前にターミナルがリセットされます。

# EA Task manager, MB TERMINAL_MEMORY_USED, Мб
 1  MACD Sample.mq5  334.6  813
 2  MACD Sample One value at a time.mq5  335.8  813
 3  MACD Sample 4 to 5 MQL4 style.mq5  342.2  818

結論: MQL4 スタイルのインジケーターへのアクセス権を持つインジケーターと MACD ベースの EA への正しいアクセスと MACD ベースの EA は、メモリ消費量の面で同等である. ほぼ同じ量のメモリを消費します。

4. [data folder]\MQL4\Experts\Moving Average.mq4の新しいライフ

前のセクションでは、MQL4 を MQL5 に変換しました。 Movinge Average.mq4 については、移動平均を"IndicatorsMQL5 mqh"ファイルで変更することをお勧めします。

#property version   "1.00"
#include<SimpleCallIndicatorsMQL5.mqh></SimpleCallIndicatorsMQL5.mqh>

#include<TradeTrade.mqh></TradeTrade.mqh>

とCopyBufferの置換

//現在の移動平均を取得 
   double   ma[1];
   if(CopyBuffer(ExtHandle,0,0,1,ma)!=1)
     {
      Print("CopyBuffer from iMA failed, no data");
      return;
     }

インジケータにMQL4 スタイルでアクセスする:

//移動平均を取得 
   ma=iMA(NULL,0,MovingPeriod,MovingShift,MODE_SMA,PRICE_CLOSE,0);

操作の結果をチェックするだけで1つのオプションを残します。-ゼロで得られたデータを比較します。 これらを考慮すると、 "CheckForOpen " および "CheckForClose " ブロックの最後のエントリは次のように見えてきました。

//現在の移動平均を取得 
   double   ma[1];
   if(CopyBuffer(ExtHandle,0,0,1,ma)!=1)
     {
      Print("CopyBuffer from iMA failed, no data");
      return;
     }

次のようになります。

//現在の移動平均を取得 
   double   ma[1];
   ma[0]=iMA(_Symbol,_Period,MovingPeriod,MovingShift,MODE_SMA,PRICE_CLOSE,0);
//(CopyBuffer (ExtHandle, 0, 0, 1, ma)! = 1)
   if(ma[0]==0.0)
     {
      //Print("CopyBuffer from iMA failed, no data");
      Print("Get iMA in MQL4 style failed, no data");
      return;
     }

"Moving Average MQL4 style.mq5" EA で保存が予定されている変更です。 EA は以下に添付されています。 標準の "Moving Average.mq5" と "Moving Average MQL4 style.mq5" の間のパフォーマンスとメモリ消費量を測定してみましょう。 

このテストは、次のシステムで実行されました

Windows 10 (build 16299) x64, IE 11, UAC, Intel Core i3-3120M  @ 2.50GHz, Memory: 4217 / 8077 Mb, Disk: 335 / 464 Gb, GMT+2

各テストの後にターミナルがリセットされました。 このテストは、EURUSD M15 の2017.02.01 から2018.01.16 に MetaQuotes デモサーバー上で実施されました。

# EA 実際のティックに基づいた全ティック 全ティック OHLC


テスト時間 Trades Deals テスト時間 Trades Deals テスト時間 Trades Deals
 1  Moving Average.mq5  0:00:33.359  1135  2270  0:00:22.562  1114  2228  0:00:02.531  1114  2228
 2  Moving Average MQL4 style.mq5  0:00:34.984  1135  2270  0:00:23.750  1114  2228  0:00:02.578  1114  2228

結論: MQL5 コアは、MQL4 スタイルのインディケータにアクセスする際に、それぞれのティックで MACD サンプルの2つのハンドルの中から検索しなければならなかったでしょう。 ほとんどの時間はこの検索にかかりました。

移動平均 EA の場合、MQL4 スタイルのインジケーターにアクセスするとき、MQL5 core は、必要なロウソクを探すのに時間を費やすことがありません。 

移動平均ベースの EAのメモリ消費量を比較してみましょう

同じ14の図表はポイント2のように使用されます。 "Terminal memory used.mq5" インジケーターは、常に最初のチャートに残されています。 10秒ごとにTERMINAL_MEMORY_USED ID を出力しますが、EAは残りの13個で1つずつ起動します。各測定の前にターミナルがリセットされます。

# EA Task manager, MB TERMINAL_MEMORY_USED, Мб
 1  Moving Average.mq5  295.6  771
 2  Moving Average MQL4 style.mq5  283.6  760

結論: メモリ消費量はほぼ同じです。 小さな差は、ターミナルの "内部のライフ " に起因するものでしょう。: ニュースの更新など

5. iXXXX シリーズの等価

MQL4 スタイルでインディケータ値の取得を実行したので、 "時系列へのアクセスとインジケーターデータ "セクションの関数を記述してみましょう。 実装は、[data folder]\MQL5\Include\SimpleCall\Series.mqhで行います。

MQL4 のように、時系列値へのアクセスを提供するSeries.mqh の関数の一覧を示します。


MODE_OPEN、MODE_LOW、MODE_HIGH、MODE_CLOSE、MODE_VOLUME、MODE_TIME シリーズの定義済み id は、iHighest および iLowest 関数で使用できます。

iClose 関数の実装例:

//+------------------------------------------------------------------+
//| iClose function in MQL4 notation                                 |
//+------------------------------------------------------------------+
double   iClose(
                string                    symbol,              //シンボル
                ENUM_TIMEFRAMES           timeframe,           //期間
                int                       shift                //シフト
                )
  {
   double result=0.0;
//---
   double val[1];
   ResetLastError();
   int copied=CopyClose(symbol,timeframe,shift,1,val);
   if(copied>0)
      result=val[0];
   else
      Print(__FUNCTION__,": CopyClose error=",GetLastError());
//---
   return(result);
  }

shift足の終値は、最初の呼び出し形式であるCopyClose (初期ポジションと必要な要素数によるアクセス) を使用して取得されます。

int  CopyClose( 
   string           symbol_name,       //シンボル名
   ENUM_TIMEFRAMES  timeframe,         //期間
   int              start_pos,         //初期ポジション
   int              count,             //コピー番号
   double           close_array[]      //終値をコピーするための配列
   );

結論

ご覧の通り、MQL5 は、MQL4 のファンが自分の好きなスタイルでインジケーターと時系列の値を取得することができます。 このコードは短く、読みやすいと思います。 プラットフォームの開発者は、関数を呼び出すとき慎重さが必要です。 (これは完全に同意)。 この記事で説明した関数の長所と短所を簡潔に示しましょう。


Cons:
  • インジケーターにアクセスするときに返されるエラーを処理する場合の制限。
  • 複数のインジケータに同時にアクセスする場合は、テスト速度を落とします。
  • IndicatorsMQL5.mqh または IndicatorsMQL4.mqh が接続されているかどうかに応じて、インジケータラインを正しくハイライト表示する必要があります。
Pros
  • コード記述の簡潔さ-複数の代わりに1つの文字列;
  • 可視性と簡潔—コード量が少ないほど、理解しやすくなります。
しかし、インジケーターにアクセスするための古典的な MQL5 アプローチにコミットしたままです。 この記事では、可能な代替をテストしています。

MetaQuotes Ltdによってロシア語から翻訳されました。
元の記事: https://www.mql5.com/ru/articles/4318

添付されたファイル |
MQL5.zip (25.33 KB)
制御された最適化: シミュレーティットアニーリング 制御された最適化: シミュレーティットアニーリング
MetaTrader5トレーディングプラットフォームのストラテジーテスターは、パラメータと遺伝的アルゴリズムの完全な検索、つまり、2 つの最適化オプションのみを提供します。 この記事では、トレーディング戦略を最適化するための新しいメソッドを提案します (シミュレーティットアニーリング)。 このメソッドのアルゴリズム、実装、およびEAへの統合を考察します。 開発したアルゴリズムは移動平均 EA でテストします。
トレーダーのリスクを低減するには トレーダーのリスクを低減するには
金融市場における取引には広範囲のリスクがつきもので、これらは取引システムのアルゴリズムで考慮されるべきです。そのようなリスクを低減することは、取引で利益を得るために最も重要な課題です。
メタトレーダー5のカスタムニュースフィードを作成する メタトレーダー5のカスタムニュースフィードを作成する
この記事では、ニュースの種類とまたその情報元の面でより多くのオプションを提供しています。柔軟なニュースフィードを作成する汎用性を考察します。 この記事では、web API を MetaTrader5 ターミナルと統合する方法について説明します。
高速数学的計算に基づくカスタムストラテジーテスター 高速数学的計算に基づくカスタムストラテジーテスター
この記事では、カスタムストラテジーテスターと最適化パスのカスタムアナライザーを作成する方法について説明します。 これにより、数学の計算モード、いわゆるフレームの仕組みを理解することができ、計算のカスタムデータをロードしその圧縮の効果的なアルゴリズムを使用できるようになります。 この記事は、EAの中でカスタム情報を保存する方法に興味がある方にも有意義なものになります。