【MQL5】 MT5のEA作成の勉強 その22 他の時間軸の移動平均線インジケータの作り方(1 / 3)※失敗例

【MQL5】 MT5のEA作成の勉強 その22 他の時間軸の移動平均線インジケータの作り方(1 / 3)※失敗例

まえがき

 MT5のチャートに別の時間軸の移動平均線を表示することで、下記の投稿で扱ったマルチタイムフレーム分析(MTF分析)を使ったEAロジックの妥当性を検証しやすくなります。(MTF分析を行ったEAのテスター表示は時間軸ごとに別のチャートで表示されてしまいます。詳しくは下記投稿をご覧ください。)
【MQL5】 MT5のEA作成の勉強 その20 ENUM_TIMEFRAMESでマルチタイムフレーム分析 (MTF分析)

※ この投稿は失敗例です。

(MetaEditerのインジケータ作成機能で雛形を作るところまでは大丈夫ですが)
ただ、同じところではまる人が多いと思うので、一応投稿しました。成功例は近日中に意地でも投稿する所存です!
2021/09/26成功例は以下を参照してください。
【MQL5】 MT5のEA作成の勉強 その23 他の時間軸の移動平均線インジケータの作り方(2 / 3)※原因

MetaEditerのインジケータ作成機能で雛形を作るところまでは大丈夫ですが)
ただ、同じところではまる人が多いと思うので、一応投稿しました。成功例は近日中に意地でも投稿する所存です!
【2021/09/26】成功例できました!

※ 成功例は以下を参照してください。

【MQL5】 MT5のEA作成の勉強 その23 他の時間軸の移動平均線インジケータの作り方(2 / 3)※原因
【MQL5】 MT5のEA作成の勉強 その24 他の時間軸の移動平均線インジケータの作り方(3 / 3)※結論

インジケータを作るために必要な項目

 インジケータを作るためには、ざっくりと以下の項目をコードに入力する必要があります。時刻を参照したり、トレードサインを出すようなインジケータでは他のイベントハンドラ(後述)が必要になるケースもありますが、今回目指す移動平均線ではこれだけで十分です。各項目の詳細は以前の投稿に書いています。

【MQL5】 MT5のEA作成の勉強 その15 サインツールの作り方・売買サインの可視化方法

  • コメント
  • 入力変数
  • グローバル変数
  • プロパティ
  • Oninit()処理
  • OnCalculate()処理

MetaEditerのインジケータ作成機能で雛形を作る。

 まずは、MetaEditerの新規作成から、インジケータの雛型を作ります。途中までは以前、EAの自動作成について触れた以下の記事と同じ手順です。
【MQL5】 MT5のEA作成の勉強 その1 EAの1番簡単な作り方 + 処理順の確認

インジケータ作成手順1

1.「新規作成」ボタンをクリック。

インジケータ作成手順2

2. 「カスタムインディケータ」を選択。

インジケータ作成手順3

3. ファイル名と、入力変数を定義。(下の3つは手作業で入力する必要があるので、名前だけ入力しています。詳しくは後述します。)

インジケータ作成手順4

4. イベントハンドラを選択(今回は1つ以上のタイムシリーズを使う「OnCalculate」のみ)
※イベントハンドラに関しては以下の記事で解説しています。
【MQL5】 MT5のEA作成の勉強 その2 自動作成したinit()はどんな処理? 1/2

【MQL5】 MT5のEA作成の勉強 その4 自動作成したEAはどんな処理?

【MQL5】 MT5のEA作成の勉強 その5 Ontick() / Processing() はどんな処理? 1/2

インジケータ作成手順5

5. サブウィンドウに表示のチェックを外す。
表示したいインジケータを追加。
「完了」ボタンをクリック。

これで、インジケータの雛型の完成です。

インジケータの雛型を書き換える

 作成した インジケータの雛型を書き換えてゆきます。まずは、イベントハンドラ以外の部分を以下のように書き換えます。

  • コメント    → 変更なし
  • 入力変数    → 変数の型を変更
  • グローバル変数 → 移動平均線の値を取得するハンドル変数(後述)を追加
  • プロパティ   → 変更なし

 入力変数の書き換えについて、雛形作成の手順3で初期値が空白だった3つの変数は、雛形に以下のように書き込まれています。

input int      MA_Type;
input int      LongTimeFrame;
input int      VeryLongTimeFrame;

これを、以下のように直します。

input ENUM_MA_METHOD       MA_Type            = MODE_SMA; //--- 移動平均線のタイプ
input ENUM_TIMEFRAMES      LongTimeFrame     = PERIOD_H1; //--- 長期移動平均線の時間軸
input ENUM_TIMEFRAMES      VeryLongTimeFrame = PERIOD_H4; //--- 超長期移動平均線の時間軸

なぜこんなまどろっこしい方法を取るかというと、これらの入力変数の型がMetaEditerの自動作成で選択できる入力変数の型に含まれていないためです。ENUM_MA_METHODの様にインジケータ固有の変数は割と多いので、 MetaEditerの自動作成 だけでは対応できない場合は往々にしてあります。

 グローバル変数には以下の変数を追加します。ハンドル変数については以下をご覧ください。
【MQL5】 MT5のEA作成の勉強 その16 EA / インジケータにテクニカル指標導入

int         CurrentHandle;
int         LongHandle;
int         VeryLongHandle;

Oninit()関数を書き換える

 次にOninit()関数を書き換えます。Oninit()関数はインジケータの初回起動時に一度だけ呼び出される関数です。主に後述するOncalculate関数で使用する変数の割り当てを行います。雛形にはSetIndexBuffer処理が書き込まれていると思いますが、これはそのままで大丈夫です。この処理の意味は以下で学習しました。
【MQL5】 MT5のEA作成の勉強 その16 EA / インジケータにテクニカル指標導入

 この下に、以下のコードを追加して、先ほどグローバル変数に追加したハンドル変数に移動平均線のハンドルを格納してゆきます。

//--- 現在の時間軸に対する移動平均線
   if((CurrentHandle=iMA(NULL,0,MA_Period,MA_Shift,MA_Type,PRICE_CLOSE))==INVALID_HANDLE)
   {
   Print("Error initialize iMA handle (Current)");
   return(INIT_FAILED);
   }
//--- 長期の時間軸に対する移動平均線
   if((LongHandle=iMA(NULL,LongTimeFrame,MA_Period,MA_Shift,MA_Type,PRICE_CLOSE))==INVALID_HANDLE)
   {
   Print("Error initialize iMA handle (Long)");
   return(INIT_FAILED);
   }
//--- 超長期の時間軸に対する移動平均線
   if((VeryLongHandle=iMA(NULL,VeryLongTimeFrame,MA_Period,MA_Shift,MA_Type,PRICE_CLOSE))==INVALID_HANDLE)
   {
   Print("Error initialize iMA handle (VeryLong)");
   return(INIT_FAILED);
   }

Oncalculate()関数を書き換える

 次に Oncalculate()関数を書き換えます。 Oncalculate()関数は価格の更新ごとに実行される関数で、これを連続的に行うことで、各バーにインジケータの値を割り当てて行きます。 ここでは、CopyBuffer関数を使って、移動平均線の値を表示用のバッファに割り当てて行きます。この時、割り当てるバッファサイズ(バーの数)はMQL5の仕様で動的に割り当てる必要があります。以下のコードを Oncalculate()関数に追加します。

   int barCount;
   if(prev_calculated>rates_total || prev_calculated<=0)
      barCount  = rates_total-MA_Period;
   else
      barCount = rates_total-prev_calculated;
  
//--- インジケータの値を取得
   if(CopyBuffer(CurrentHandle, 0, 0, barCount+1, CurrentBuffer)==0)
      return(0);  
   if(CopyBuffer(LongHandle, 0, 0, barCount+1, LongBuffer)==0)
      return(0); 
   if(CopyBuffer(VeryLongHandle, 0, 0, barCount+1, VeryLongBuffer)==0)
      return(0);  

実行結果

インジケータの実行結果は以下のようになりました。ちなみに、使用した時間軸は15min1hour4hourです。上位足の移動平均線はカクカクした動きになっています。

実行結果
実行結果

手作業で入力した入力変数も、リストから選択できるようになっています。

MT5の入力変数の設定画面
MT5の入力変数の設定画面

使用する時間軸を6hour24hourにしてみます。より一層カクカクした線になりました。

ちなみに、同じ時間軸の移動平均線の平均期間を伸ばした場合と比べると以下のような感じです。

って、あれっ!??

 すこし見にくいですが、中央付近の緑の価格バーにほぼ重なっている黄色い線が平均期間7本、時間軸15minの移動平均線です。なだらかなオレンジの線は平均期間28本、なだらかな赤の線は平均期間112本、時間軸はいずれも15minの移動平均線です。そして、めちゃくちゃな動きをしているオレンジの線は平均期間7本、時間軸1hour、赤の線は平均期間7本、時間軸4hourの移動平均線です。
 普通に考えれば、同じ色の線はほぼ重なっているはずです。ですが、実際にはありえない動きをしています。丸2日以上かけて調べ、検討したのですが、結局原因は不明です。強いて言うなら、CopyBufferの時の要素数が違う( 時間軸1hourのチャートは時間軸15minのチャートの 1/4の本数しかない)のが悪さをしているかと思います。完全に無根拠ですが。
 というか、テストでうまく行って、本番でうまく行かない意味が分かりません。EAでも同じ現象が起こるのだとしたら相当タチが悪いと言わざるを得ません。

まとめ

 何かヒントになる情報はないかと、公式コミュニティで、「multi time」を検索してみると5件ほどヒットしました。中には私がやろうとしていることの上位互換のような記事もありましたが、まあそれはこれ勉強なのでということで。しかし、全てに共通して、iMAを初めとするMQL5既定のインジケータは使用されておらず、計算は自力で実装されていました。今後、これらを拝読し、何とかうまく行くものを作っていきたいと思います。