【MQL5】 MT5のEA作成の勉強 その2 自動作成したinit()はどんな処理? 1/2

【MQL5】 MT5のEA作成の勉強 その2 自動作成したinit()はどんな処理? 1/2

まえがき

 前回の投稿で、MT5EA自動作成機能を使って、EAを作成しました。本投稿では自動作成したEAのコードを読み解いてゆきたいと思います。前回の投稿は以下です。
【MQL5】 MT5のEA作成の勉強 その1 EAの1番簡単な作り方 + 処理順の確認
 ただ、処理の内容のほとんどがMQL5の付属ファイルで補われていることが分かったため、そちらのソースは私が作成したものでない都合上、掲載を控えています。ですので、この投稿で処理の中身を理解するのは難しいと思います。この投稿を参考に、実際にMQL5を操作してみて、中の処理を確認してみてください。実行環境は引き 続き「OANDA Japan」のMQL5を使用します。

OnInit()について -全体-

 前回の投稿でも少し触れましたが、Oninit()EA初回起動時に実行される処理です。前回の投稿の手順で作製したソースでは、Oninit()は以下のようになっていました。

int OnInit()
  {
//--- Initializing expert
   if(!ExtExpert.Init(Symbol(),Period(),Expert_EveryTick,Expert_MagicNumber))
     {
      //--- failed
      printf(__FUNCTION__+": error initializing expert");
      ExtExpert.Deinit();
      return(INIT_FAILED);
     }
//--- Creating signal
   CExpertSignal *signal=new CExpertSignal;
   if(signal==NULL)
     {
      //--- failed
      printf(__FUNCTION__+": error creating signal");
      ExtExpert.Deinit();
      return(INIT_FAILED);
     }
//---
   ExtExpert.InitSignal(signal);
   signal.ThresholdOpen(Signal_ThresholdOpen);
   signal.ThresholdClose(Signal_ThresholdClose);
   signal.PriceLevel(Signal_PriceLevel);
   signal.StopLevel(Signal_StopLevel);
   signal.TakeLevel(Signal_TakeLevel);
   signal.Expiration(Signal_Expiration);
//--- Creating filter CSignalSAR
   CSignalSAR *filter0=new CSignalSAR;
   if(filter0==NULL)
     {
      //--- failed
      printf(__FUNCTION__+": error creating filter0");
      ExtExpert.Deinit();
      return(INIT_FAILED);
     }
   signal.AddFilter(filter0);
//--- Set filter parameters
   filter0.Step(Signal_SAR_Step);
   filter0.Maximum(Signal_SAR_Maximum);
   filter0.Weight(Signal_SAR_Weight);
//--- Creation of trailing object
   CTrailingNone *trailing=new CTrailingNone;
   if(trailing==NULL)
     {
      //--- failed
      printf(__FUNCTION__+": error creating trailing");
      ExtExpert.Deinit();
      return(INIT_FAILED);
     }
//--- Add trailing to expert (will be deleted automatically))
   if(!ExtExpert.InitTrailing(trailing))
     {
      //--- failed
      printf(__FUNCTION__+": error initializing trailing");
      ExtExpert.Deinit();
      return(INIT_FAILED);
     }
//--- Set trailing parameters
//--- Creation of money object
   CMoneyFixedLot *money=new CMoneyFixedLot;
   if(money==NULL)
     {
      //--- failed
      printf(__FUNCTION__+": error creating money");
      ExtExpert.Deinit();
      return(INIT_FAILED);
     }
//--- Add money to expert (will be deleted automatically))
   if(!ExtExpert.InitMoney(money))
     {
      //--- failed
      printf(__FUNCTION__+": error initializing money");
      ExtExpert.Deinit();
      return(INIT_FAILED);
     }
//--- Set money parameters
   money.Percent(Money_FixLot_Percent);
   money.Lots(Money_FixLot_Lots);
//--- Check all trading objects parameters
   if(!ExtExpert.ValidationSettings())
     {
      //--- failed
      ExtExpert.Deinit();
      return(INIT_FAILED);
     }
//--- Tuning of all necessary indicators
   if(!ExtExpert.InitIndicators())
     {
      //--- failed
      printf(__FUNCTION__+": error initializing indicators");
      ExtExpert.Deinit();
      return(INIT_FAILED);
     }
//--- ok
   return(INIT_SUCCEEDED);
  }

・・・長いですね。他にもいくつか関数がありますが、全て一行で終わっているので、ここを理解できれば殆ど理解できると信じて頑張ります。

OnInit()について -Initializing expert-

 まずは、3行目~10行目の「Initializing expert」の部分です。直訳すると、「エキスパートの初期化」となります。

//--- Initializing expert
   if(!ExtExpert.Init(Symbol(),Period(),Expert_EveryTick,Expert_MagicNumber))
     {
      //--- failed
      printf(__FUNCTION__+": error initializing expert");
      ExtExpert.Deinit();
      return(INIT_FAILED);
     }

初めに私が思ったのは、「ExtExpertってなんやねん」ということでした。そこで、定義を追いかけてみると、Oninit()のすぐ上で、グローバル変数として定義されていました。

//+------------------------------------------------------------------+
//| Global expert object                                             |
//+------------------------------------------------------------------+
CExpert ExtExpert;
//+------------------------------------------------------------------+
//| Initialization function of the expert                            |
//+------------------------------------------------------------------+
int OnInit()

 さて、ここで次なる疑問です。「CExpertってなんやねん」ということです。今度は定義を追いかけても引っかからなかったので、さらに上のincludeファイルを確認しました。ちなみに、includeファイルとは、Pythonにおけるライブラリの様に、役に立つ変数・メソッドを詰め合わせた外部ファイルと思って頂けば大丈夫です。そうしたところ、ソースの一番上付近にそれらしい記述を発見しました。

//+------------------------------------------------------------------+
//| Include                                                          |
//+------------------------------------------------------------------+
#include <Expert\Expert.mqh>
//--- available signals
#include <Expert\Signal\SignalSAR.mqh>
//--- available trailing
#include <Expert\Trailing\TrailingNone.mqh>
//--- available money management
#include <Expert\Money\MoneyFixedLot.mqh>
//+----------------------------------------------

 いろいろありますが、とりあえず、「Expert.mqh」の中身を確認してみました。すると、 CExpert を定義しているブロックを無事に発見することができました。このソースは私が作ったものではないので、一部抜粋とします。詳細は以下の公式リファレンスをご覧ください。
https://www.mql5.com/ja/docs/standardlibrary/expertclasses/expertbaseclasses/cexpert

 元のソースで、「ExtExpert.○○」という表記がいきなり出てきた場合、このファイルに書いてあるメソッドを呼び出していると思ってよいようです。
 前置きが長くなりましたが、この部分で行われていることは、

CExpert.mqlファイルの CExpert クラスのinit()メソッドに引数を渡して起動し、 CExpert クラスの 実体を作る。

ということのようです。失敗したらエラーを出して処理を終了するようになっています。ちなみ、引数はの意味はざっくり以下のようになっています。

引数名意味
Symbol()現在選択されている価格ペアに対して処理を行います。
Period()現在選択されている時間足に対して処理を行います。
Expert_EveryTickソースの上部でFalseと定義。Trueの場合、価格が更新されるごとに初期化が実行される?
Expert_MagicNumberソースの上部で任意の番号を定義。EAによる注文を判別するために使用するマジックナンバー(番号)です。複数のEAを同時に使用する場合、これが被らないようにする必要があります。

OnInit()について -Creating signal-

 次は11行目~27行目の 「 Creating signal 」の部分です。 直訳すると「シグナル作製」です。

//--- Creating signal
   CExpertSignal *signal=new CExpertSignal;
   if(signal==NULL)
     {
      //--- failed
      printf(__FUNCTION__+": error creating signal");
      ExtExpert.Deinit();
      return(INIT_FAILED);
     }
//---
   ExtExpert.InitSignal(signal);
   signal.ThresholdOpen(Signal_ThresholdOpen);
   signal.ThresholdClose(Signal_ThresholdClose);
   signal.PriceLevel(Signal_PriceLevel);
   signal.StopLevel(Signal_StopLevel);
   signal.TakeLevel(Signal_TakeLevel);
   signal.Expiration(Signal_Expiration);

 まず、「CExpertSignal」ですが、これは先の「CExpert」と同じく、Expert.mqlに定義された変数です。ただし、問題は「*signalってなんやねん」ということです。
 調べてみると、MQL5のベースとなっているC言語では「型*変数」の表記で、「この変数はポインタです」という定義になるそうです。ポインタという概念はC言語特有のものでオブジェクト指向になれた私にはやや理解しにくいものでしたが、要するに、通常の変数が直接値を格納するのに対して、ポインタは値が格納された「メモリ上のアドレス」を格納するということのようです。ちょっと怪しい理解ですが、結果的に値を取りだせるという点においては同じように扱っても大丈夫なように思えます。
 次に、作成した 「*signal 」ポインタを引数として、ExtExpert.InitSignalを起動しています。さらにその下では、signalの様々な変数に値を格納しています。これらの処理ですが、ざっくり言うと、

ExtExpert に含まれる変数m_signalの値を設定したのち、CExpertSignalに含まれる取引指標用の変数を設定している

ようです。ちなみに、下半分でsignal.○○の引数になっている変数は、ソースの上部で定義されたものです。この値を書き換えることで、損切価格などを変更できるようです。

小まとめ

 思いの外長ったらしくなってしまったので一旦ここで切りたいと思います。
次回、Oninit()の28行目以降の処理を見ていこうと思います。