【MT5/MQL5】インジケータ取得処理をクラスでラッピング(移動平均線)

この記事は約14分で読めます。

今回作成するプログラムの概要

今回は、前回のボリンジャーバンドに続き、移動平均線のインジケータ値を取得する処理をクラスでラッピングするプログラムを作ろうと思います。

移動平均線のインジケータをクラスでラッピング

サンプルコード

早速、サンプルコードを紹介します。今回は「移動平均線のクラスファイル(CIndMA.mqh)」と、「インジケータ表示用ファイル(IndicatorMA.mq5)」の2ファイルあります。2ファイルともインジケータフォルダの同じ階層に配置してください。

移動平均線のクラスファイル(CIndMA.mqh)

//+------------------------------------------------------------------+
//|                                                       CIndMA.mqh |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"


//+------------------------------------------------------------------+
//|
//| [インジケータラッピングクラス]
//| 移動平均線
//|
//+------------------------------------------------------------------+
class CIndMA
  {
private:

public:

   //|---------------------------------------------------------------+
   //| メンバ変数
   //|---------------------------------------------------------------+
   int               m_ind_handle;
   string            m_symbol;
   ENUM_TIMEFRAMES   m_timeframe;

   //|---------------------------------------------------------------+
   //| コンストラクタ、デストラクタ
   //|---------------------------------------------------------------+
                     CIndMA() {};
                    ~CIndMA() {};

   //|---------------------------------------------------------------+
   //| メンバ関数
   //|---------------------------------------------------------------+

   //| インジケータ生成関数
   void              createIndicator(string, ENUM_TIMEFRAMES, int, int, ENUM_MA_METHOD, ENUM_APPLIED_PRICE);

   //| インジケータ値取得関数
   double            getValue(int, int);

   //| 移動平均線取得関数
   double            MA(int iArgBar) { return this.getValue(0,iArgBar); };


  };

//+------------------------------------------------------------------+
//|
//| [メンバ関数]
//| インジケータ生成関数
//|
//+------------------------------------------------------------------+
void   CIndBands::createIndicator(
   string              sArgSymbol,                // 銘柄名
   ENUM_TIMEFRAMES     enArgTimeframe,            // 期間
   int                 iArgPeriod,                // 平均期間
   int                 iArgShift,                 // Barシフト
   ENUM_MA_METHOD,     enArgMAMethod,             // 平滑化の種類
   ENUM_APPLIED_PRICE  enArgAppliedPrice)         // 価格の種類
  {

   this.m_symbol      = sArgSymbol;
   this.m_timeframe   = enArgTimeframe;
   this.m_ind_handle  = iMA(
                          sArgSymbol,
                          enArgTimeframe,
                          iArgPeriod,
                          iArgShift,
                          enArgMAMethod,
                          enArgAppliedPrice);

  }

//+------------------------------------------------------------------+
//|
//| [メンバ関数]
//| インジケータ値取得関数
//|
//+------------------------------------------------------------------+
double CIndBands::getValue(int iArgBufIndex,          // インデックス番号
                           int iArgBar)               // Bar位置
  {
   int iRet;

   double buf[];
   iRet=CopyBuffer(this.m_ind_handle,iArgBufIndex,iArgBar,1,buf);
   return buf[0];
  }
Expand

インジケータ表示用ファイル(IndicatorMA.mq5)

//+------------------------------------------------------------------+
//|                                                  IndicatorMA.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_chart_window

#include "CIndMA.mqh"

#property indicator_buffers  1
#property indicator_plots    1

#property indicator_type1    DRAW_LINE
#property indicator_style1   STYLE_SOLID
#property indicator_color1   clrBlue
#property indicator_width1   1
double    bufMA[];

//+------------------------------------------------------------------+
//| インジケータ取得用クラス(ポインタ)
//+------------------------------------------------------------------+
CIndMA *cIndMA;

//+------------------------------------------------------------------+
//| 【初期化関数】
//|  ・チャートの初期表示時、または時間足変更等のチャート初期化が必要な
//|    タイミングで呼び出される。
//+------------------------------------------------------------------+
int OnInit()
  {

// 移動平均線
   ArraySetAsSeries(bufMA,    true);
   ArrayInitialize(bufMA,     0);
   SetIndexBuffer(1,          bufMA,             INDICATOR_DATA);
   PlotIndexSetDouble(1,      PLOT_EMPTY_VALUE,  0.0);

// 移動平均線取得インスタンス生成
   cIndMA = new CIndMA();
   cIndMA.createIndicator(Symbol(),PERIOD_CURRENT,20,0,2.0,PRICE_CLOSE);

   return(INIT_SUCCEEDED);

  }

//+------------------------------------------------------------------+
//| 【計算イベント関数】
//|  ・ローソク足に変化が発生する毎に呼び出される。
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
  {

//+------------------------------------------------------------------+
//| 1. 新規チャートのインジケータ値がまだ計算されていない場合
//|   → 過去チャートのインジケータ値を計算する。
//+------------------------------------------------------------------+
   if(prev_calculated == 0)
     {
      for(int i=rates_total-20; i>=0; i--)
        {
         setBufferValue(i,false);
        }
     }

//+------------------------------------------------------------------+
//| 2. 過去チャートのインジケータ値は計算済で、
//|    計算済Bar数が前回呼び出し時と異なる場合 (Liveで新規Barが発生した)
//|    → 新規Barのインジケータ値を計算する。
//+------------------------------------------------------------------+
   else
     {
      if(prev_calculated < rates_total)
        {
         setBufferValue(0,true);
        }
     }

//+------------------------------------------------------------------+
//| 3. 同Bar内でのティック変更によって呼び出された場合
//|    → インジケータ値は計算しない
//+------------------------------------------------------------------+

// NOP

//+------------------------------------------------------------------+
//| 今回の処理でインジケータ値を計算したBar数を返却する。
//|   → このreturn値は、次回OnCalculate関数が呼び出された際、
//|     引数のprev_calculatedに設定される。
//+------------------------------------------------------------------+

   return(rates_total);

  }

//+------------------------------------------------------------------+
//| 【インデックスバッファ設定関数】
//|  ・指定されたBar位置のインジケータ値を計算する。
//+------------------------------------------------------------------+
void setBufferValue(int iCurrentBar, bool bIsLiveNewBar)
  {

   bufMA[iCurrentBar] = cIndMA.MA(iCurrentBar);

  }

//+------------------------------------------------------------------+
Expand

コード解説

移動平均線のクラスファイル(CIndMA.mqh)

57~76行目

インジケータ生成関数に渡された引数のうち、必要なものはメンバ変数に保持しておき、iMA()関数を呼び出します。iMA()関数呼び出しによって得られた指標ハンドルも、メンバ変数に保持しておきます。

84~92行目

メンバ変数に保持している指標ハンドルを利用して、引数で指定された「インデックス番号」「Bar位置」のインジケータ値を取得してリターンします。

45~46行目

上記で定義したgetValue()関数を使用して、移動平均線の指標値を取得します。この関数は定義しなくても大丈夫ですが、getValue()関数を使う場合、インジケータのインデックス番号を指定する必要があるので、指標データ用の個別のアクセス関数を準備しておいたほうが便利です。

インジケータ表示用ファイル(IndicatorMA.mq5)

11行目

移動平均線のクラスファイルを取り込んでいます。インジケータファイルと同階層なので、””で括っていますが、クラスファイルをIncludeフォルダに配置した場合は、<>で括ってください。詳しくは、MQL5の公式サイトのこちらを参照してください。

25,42,43行目
クラスファイルのポインタを作成し、インスタンス生成、及びインジケータ初期化を実施しています。

65~103行目

新規ローソク足発生時のみ計算する処理になっていますが、解説はこちらの記事を参照してください。

114行目

インジケータバッファを設定しています。インジケータ値設定処理は、この1行だけになります。クラスファイルに、それぞれの指標用のメンバ関数を準備しているので、Bar位置だけ引数に渡してあげれば簡単に指標値を取得する事ができます。

MQL5の公式サイトにiMAを利用したサンプルプログラムが載っていますが、そのコードと比較しても、だいぶすっきりとしています。

実行結果

IndicatorMAインジケータの実行結果は以下のようになります。移動平均線がチャートに表示されます。

まとめ

今回は、移動平均線のインジケータ値を取得する処理をクラスでラッピングしてみました。

サンプルプログラムでは、クラスファイル(CIndMA.mqh)をインジケータと同じ場所(Indicatorフォルダ)に配置しましたが、Includeフォルダに配置すれば、EAからでもクラスファイルにアクセスできるようになります。

インジケータとして表示するだけであれば、普通にプリインストールされている移動平均線を利用すれば良いですが、EAに組み込んだり、クラスに拡張メンバ関数を作成する際に便利です。また、クラス化することによって、コーディング時にメンバ関数の自動補完機能が有効になるので、コーディングの効率も向上します。

今後も引き続き、他のインジケータもクラス化していければと思います。

コメント

タイトルとURLをコピーしました