FX自動売買基礎と応用

MT5版の3本表示RCIを作成する【MQLプログラミングの基礎】

1.概要

この記事では、「MT5版のRCIを作成する【MQLプログラミングの基礎】」記事で作成したRCIのファイルを流用し、3本のRCIを表示するツールを作成します。
3本のRCIがパーフェクトオーダー(期間の順に整列)になった時、メインチャートに矢印サインが表示される機能も実装させます。

2.ファイルの流用

作成済みのRCI.mq5をメタエディター(MetaEditor)で開き、ソースファイル内2行目の「RCI.mq5」を「3RCI_Sign.mq5」へ変更します。
そして、ファイル名を3RCI_Sign.mq5に変更して保存します。

名前を付けて保存

3.3本のRCI表示対応

バッファ数を「3」に変更します。


#property indicator_buffers 1
#property indicator_plots   1


#property indicator_buffers 3
#property indicator_plots   3

に変更。

2本目・3本目用の表示仕様の式を追加します。


#property indicator_type1   DRAW_LINE
#property indicator_color1  clrWhite
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1

に追記して


#property indicator_type1   DRAW_LINE
#property indicator_type2   DRAW_LINE
#property indicator_type3   DRAW_LINE
#property indicator_color1  clrWhite
#property indicator_color2  clrYellow
#property indicator_color3  clrRed
#property indicator_style1  STYLE_SOLID
#property indicator_style2  STYLE_SOLID
#property indicator_style3  STYLE_SOLID
#property indicator_width1  1
#property indicator_width2  1
#property indicator_width3  1

とします。
2本目を「Yellow」、3本目を「Red」としています。

期間を指定するパラメータを3種に変更します。


input int      PERIOD=14;


input int      PERIOD0 = 10; // 短期
input int      PERIOD1 = 20; // 中期
input int      PERIOD2 = 30; // 長期

に変更。

RCI用のバッファを3つにします。


double         RCIBuffer[];


double         RCIBuffer0[], RCIBuffer1[], RCIBuffer2[];

に変更。

OnInit()関数内の各式も3つに増やします。


   SetIndexBuffer(0,RCIBuffer,INDICATOR_DATA);
   ArraySetAsSeries(RCIBuffer, true);
   string name = "RCI(" + (string)PERIOD + ")";
   PlotIndexSetString(0, PLOT_LABEL, name);


   SetIndexBuffer(0, RCIBuffer0, INDICATOR_DATA);
   SetIndexBuffer(1, RCIBuffer1, INDICATOR_DATA);
   SetIndexBuffer(2, RCIBuffer2, INDICATOR_DATA);
   ArraySetAsSeries(RCIBuffer0, true);
   ArraySetAsSeries(RCIBuffer1, true);
   ArraySetAsSeries(RCIBuffer2, true);
   string name0 = "RCI(" + (string)PERIOD0 + ")";
   string name1 = "RCI(" + (string)PERIOD1 + ")";
   string name2 = "RCI(" + (string)PERIOD2 + ")";
   PlotIndexSetString(0, PLOT_LABEL, name0);
   PlotIndexSetString(1, PLOT_LABEL, name1);
   PlotIndexSetString(2, PLOT_LABEL, name2);

に変更。

インジケーター名称用として、変数nameを定義して適用します。


   string name = name0 + ", " + name1 + ", " + name2;
   IndicatorSetString(INDICATOR_SHORTNAME, name);

OnCalculate()関数内で、3本のRCIを計算するように修正します。


   iRCI(array, RCIBuffer, PERIOD, limit);


   iRCI(array, RCIBuffer0, PERIOD0, limit);
   iRCI(array, RCIBuffer1, PERIOD1, limit);
   iRCI(array, RCIBuffer2, PERIOD2, limit);

に変更。

コンパイルしてチャートにセットすると、3本のRCIが表示できるようになります。

3RCI

4.矢印サイン表示用の関数を流用

本ツールはサブウインドウ用のインジケーターなので、メインチャートにインジケーターバッファを利用した矢印サインは表示できません。
矢印サインをオブジェクトで表示するために、MQL5リファレンスから関数ArrowCreate()をコピーして流用します。
https://www.mql5.com/ja/docs/constants/objectconstants/enum_object/obj_arrow
下記を、ソースファイル末尾に貼り付けてください。


//+------------------------------------------------------------------+
//| 矢印の作成                                                         |
//+------------------------------------------------------------------+
bool ArrowCreate(const long              chart_ID=0,           // チャート識別子
                const string            name="Arrow",         // 矢印名
                const int               sub_window=0,         // サブウィンドウ番号
                datetime                time=0,               // アンカーポイントの時刻
                double                  price=0,             // アンカーポイントの価格
                const uchar             arrow_code=252,       // 矢印コード
                const ENUM_ARROW_ANCHOR anchor=ANCHOR_BOTTOM, // アンカーポイント位置
                const color             clr=clrRed,           // 矢印の色
                const ENUM_LINE_STYLE   style=STYLE_SOLID,   // 境界線のスタイル
                const int               width=3,             // 矢印のサイズ
                const bool              back=false,           // 背景で表示する
                const bool              selection=true,       // 強調表示して移動
                const bool              hidden=true,         // オブジェクトリストに隠す
                const long              z_order=0)           // マウスクリックの優先順位
 {
//--- 設定されてない場合アンカーポイントの座標を設定する
  ChangeArrowEmptyPoint(time,price);
//--- エラー値をリセットする
  ResetLastError();
//--- 矢印を作成
  if(!ObjectCreate(chart_ID,name,OBJ_ARROW,sub_window,time,price))
    {
    Print(__FUNCTION__,
          ": failed to create an arrow! Error code = ",GetLastError());
    return(false);
    }
//--- 矢印コードを設定
  ObjectSetInteger(chart_ID,name,OBJPROP_ARROWCODE,arrow_code);
//--- アンカーの種類を設定
  ObjectSetInteger(chart_ID,name,OBJPROP_ANCHOR,anchor);
//--- 矢印の色を設定
  ObjectSetInteger(chart_ID,name,OBJPROP_COLOR,clr);
//--- 境界線のスタイルを設定
  ObjectSetInteger(chart_ID,name,OBJPROP_STYLE,style);
//--- 矢印のサイズを設定
  ObjectSetInteger(chart_ID,name,OBJPROP_WIDTH,width);
//--- 前景(false)または背景(true)に表示
  ObjectSetInteger(chart_ID,name,OBJPROP_BACK,back);
//--- マウスで矢印を移動させるモードを有効(true)か無効(false)にする
//--- ObjectCreate 関数を使用してグラフィックオブジェクトを作成する際、オブジェクトは
//--- デフォルトではハイライトされたり動かされたり出来ない。このメソッド内では、選択パラメータは
//--- デフォルトでは true でハイライトと移動を可能にする。
  ObjectSetInteger(chart_ID,name,OBJPROP_SELECTABLE,selection);
  ObjectSetInteger(chart_ID,name,OBJPROP_SELECTED,selection);
//--- オブジェクトリストのグラフィックオブジェクトを非表示(true)か表示(false)にする
  ObjectSetInteger(chart_ID,name,OBJPROP_HIDDEN,hidden);
//--- チャートのマウスクリックのイベントを受信するための優先順位を設定する
  ObjectSetInteger(chart_ID,name,OBJPROP_ZORDER,z_order);
//--- 実行成功
  return(true);
 }
//+------------------------------------------------------------------+

5.ArrowCreate()関数の修正

ChangeArrowEmptyPoint()関数は、今回利用しないので、下記の行を削除します。


//--- 設定されてない場合アンカーポイントの座標を設定する
  ChangeArrowEmptyPoint(time,price);

また、描画後に選択状態としたくないので、


                const bool              selection=true,       // 強調表示して移動

の「true」の部分を


                 const bool              selection = false,     // 強調表示して移動

上記のように、「false」へ変更します。

6.パーフェクトオーダーサイン表示用の関数DrawSign()を作成

ソースファイルの末尾に、関数DrawSign()を定義します。


//+------------------------------------------------------------------+
//| Draw sign function                                               |
//+------------------------------------------------------------------+
void DrawSign()
{

}

バッファサイズが0の初期読み込み時に動作させないよう、


   if (ArraySize(RCIBuffer0) == 0) return;

を追記。

サイン描画時に利用する接頭辞prefixを定義します。


   string prefix = MQLInfoString(MQL_PROGRAM_NAME) + "_";

本関数を実施時に、矢印サインオブジェクトを毎回全削除するよう、


   ObjectsDeleteAll(0, prefix);

を追記。

チャート上で見えている範囲のみを計算させるよう、左端と右端のバーの番号を定義します。


   int barF = (int)ChartGetInteger(0, CHART_FIRST_VISIBLE_BAR);
   int barR = barF - (int)ChartGetInteger(0, CHART_WIDTH_IN_BARS);
   if (barR < 0) barR = 0;

for文にて、表示範囲内のパーフェクトオーダー条件を判定。


   for (int i = barF; i >= barR; i--) {
      bool upNow = RCIBuffer0[i] > RCIBuffer1[i] && RCIBuffer1[i] > RCIBuffer2[i];
      bool upPre = RCIBuffer0[i + 1] > RCIBuffer1[i + 1] && RCIBuffer1[i + 1] > RCIBuffer2[i + 1];
      bool dnNow = RCIBuffer0[i] < RCIBuffer1[i] && RCIBuffer1[i] < RCIBuffer2[i];
      bool dnPre = RCIBuffer0[i + 1] < RCIBuffer1[i + 1] && RCIBuffer1[i + 1] < RCIBuffer2[i + 1];
   }

上昇のパーフェクトオーダーは「短期RCI>中期RCI>長期RCI」で判定し、下降のパーフェクトオーダーは「短期RCI<中期RCI<長期RCI」で判定します。

各変数の意味は下記の通りです。

upNow:現足の上昇パーフェクトオーダー
upPre:前足の上昇パーフェクトオーダー
dnNow:現足の下降パーフェクトオーダー
dnPre:前足の下降パーフェクトオーダー

前足で不成立の状態から、現足でパーフェクトオーダー成立になった場所に、矢印サインを表示するよう、for文内に下記の式を追加します。


      if (upNow && !upPre) {
         string name = prefix + (string)i;
         ArrowCreate(0, name, 0, iTime(NULL, 0, i), iLow(NULL, 0, i), 233, ANCHOR_TOP, clrRed, STYLE_SOLID, 2);
      }
      if (dnNow && !dnPre) {
         string name = prefix + (string)i;
         ArrowCreate(0, name, 0, iTime(NULL, 0, i), iHigh(NULL, 0, i), 234, ANCHOR_BOTTOM, clrDodgerBlue, STYLE_SOLID, 2);
      }

上昇の場合、安値側にRedの上向き矢印(コード233)を表示し、下降の場合、高値側にDodgerBlueの下向き矢印(コード234)を表示するようにしています。

計算後に再描画処理をするよう、DrawSign()関数の最後に


ChartRedraw();

を追記します。

7.DrawSign()関数の実行

OnCalculate()関数内のRCI計算後に


   DrawSign();

を追記します。

チャート画面のスクロール時に、サイン描画を再計算するよう、


//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
{
   if (id == CHARTEVENT_CHART_CHANGE) DrawSign();
}

を追加します。

本ツールをチャートから削除した時、矢印サインオブジェクトが削除されるよう、


//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
   ObjectsDeleteAll(0, MQLInfoString(MQL_PROGRAM_NAME) + "_");
}

を追加します。

これでコンパイルすると完成です。パーフェクトオーダーになった箇所に矢印サインが表示されます。

POサイン

8.ソースコード

今回、作成したソースコードは下記の通りです。


//+------------------------------------------------------------------+
//|                                                    3RCI_Sign.mq5 |
//|                                  Copyright 2024, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_separate_window
#property indicator_minimum -100
#property indicator_maximum 100
#property indicator_buffers 3
#property indicator_plots   3
//--- plot RCI
#property indicator_type1   DRAW_LINE
#property indicator_type2   DRAW_LINE
#property indicator_type3   DRAW_LINE
#property indicator_color1  clrWhite
#property indicator_color2  clrYellow
#property indicator_color3  clrRed
#property indicator_style1  STYLE_SOLID
#property indicator_style2  STYLE_SOLID
#property indicator_style3  STYLE_SOLID
#property indicator_width1  1
#property indicator_width2  1
#property indicator_width3  1
//--- input parameters
input int      PERIOD0 = 10; // 短期
input int      PERIOD1 = 20; // 中期
input int      PERIOD2 = 30; // 長期
//--- indicator buffers
double         RCIBuffer0[], RCIBuffer1[], RCIBuffer2[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   SetIndexBuffer(0, RCIBuffer0, INDICATOR_DATA);
   SetIndexBuffer(1, RCIBuffer1, INDICATOR_DATA);
   SetIndexBuffer(2, RCIBuffer2, INDICATOR_DATA);
   ArraySetAsSeries(RCIBuffer0, true);
   ArraySetAsSeries(RCIBuffer1, true);
   ArraySetAsSeries(RCIBuffer2, true);
   string name0 = "RCI(" + (string)PERIOD0 + ")";
   string name1 = "RCI(" + (string)PERIOD1 + ")";
   string name2 = "RCI(" + (string)PERIOD2 + ")";
   PlotIndexSetString(0, PLOT_LABEL, name0);
   PlotIndexSetString(1, PLOT_LABEL, name1);
   PlotIndexSetString(2, PLOT_LABEL, name2);
   string name = name0 + ", " + name1 + ", " + name2;
   IndicatorSetString(INDICATOR_SHORTNAME, name);
   
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
   ObjectsDeleteAll(0, MQLInfoString(MQL_PROGRAM_NAME) + "_");
}

//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
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[])
  {
//---
   double array[];
   ArraySetAsSeries(array, true);
   ArraySetAsSeries(close, true);
   ArrayCopy(array, close);

   int limit = rates_total - prev_calculated - 1;
   if (limit < 1) limit = 1;
   iRCI(array, RCIBuffer0, PERIOD0, limit);
   iRCI(array, RCIBuffer1, PERIOD1, limit);
   iRCI(array, RCIBuffer2, PERIOD2, limit);

   DrawSign();
   
//--- return value of prev_calculated for next call
   return(rates_total);
  }
//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
{
   if (id == CHARTEVENT_CHART_CHANGE) DrawSign();
}
//+------------------------------------------------------------------+
//| RCI function                                                     |
//+------------------------------------------------------------------+
void iRCI(double &close[], double &rci[], int period, int limit)
{
   int D[];
   ArrayResize(D, period);
   for(int i = 0; i < period; i++) D[i] = -i * 2;
   int N = period * (period * period - 1) * 2 / 3;
   int max = ArraySize(rci) - 1;
   
   int n = limit;
   double d = 0;
   for (int i = 0; i < period; i++) {
      for (int j = i + 1; j < period; j++) {
         if (n + j > max) continue;
         if (close[n + i] < close[n + j]) {
            D[i] += 2;
         } else if(close[n + i] == close[n + j]) {
            D[i]++;
            D[j]++;
         } else {
            D[j] += 2;
         }
      }
      d += D[i] * D[i];
   }
   rci[n] = (1 - (d / N)) * 100;

   for(n = limit - 1; n >= 0; n--) {
      d = 0;
      for(int i = period - 1; i >= 1; i--) {
         D[i] = D[i - 1] - 2;
         if (n + i > max || n + period > max) continue;
         if(close[n + i] < close[n]) D[i] += 2;
         else if(close[n + i] == close[n]) D[i]++;
         if(close[n + i] < close[n + period]) D[i] -= 2;
         else if(close[n + i] == close[n + period]) D[i]--;
         d += D[i] * D[i];
      }
      D[0] = 0;
      for(int j = 1; j < period; j++) {
         if (n + j > max) continue;
         if(close[n] < close[n + j]) D[0] += 2;
         else if(close[n] == close[n + j]) D[0]++;
      }
      d += D[0] * D[0];
      rci[n] = (1 - (d / N)) * 100;
   }
}
//+------------------------------------------------------------------+
//| 矢印の作成                                                         |
//+------------------------------------------------------------------+
bool ArrowCreate(const long              chart_ID=0,           // チャート識別子
                const string            name="Arrow",         // 矢印名
                const int               sub_window=0,         // サブウィンドウ番号
                datetime                time=0,               // アンカーポイントの時刻
                double                  price=0,             // アンカーポイントの価格
                const uchar             arrow_code=252,       // 矢印コード
                const ENUM_ARROW_ANCHOR anchor=ANCHOR_BOTTOM, // アンカーポイント位置
                const color             clr=clrRed,           // 矢印の色
                const ENUM_LINE_STYLE   style=STYLE_SOLID,   // 境界線のスタイル
                const int               width=3,             // 矢印のサイズ
                const bool              back=false,           // 背景で表示する
                const bool              selection=false,       // 強調表示して移動
                const bool              hidden=true,         // オブジェクトリストに隠す
                const long              z_order=0)           // マウスクリックの優先順位
 {
//--- エラー値をリセットする
  ResetLastError();
//--- 矢印を作成
  if(!ObjectCreate(chart_ID,name,OBJ_ARROW,sub_window,time,price))
    {
    Print(__FUNCTION__,
          ": failed to create an arrow! Error code = ",GetLastError());
    return(false);
    }
//--- 矢印コードを設定
  ObjectSetInteger(chart_ID,name,OBJPROP_ARROWCODE,arrow_code);
//--- アンカーの種類を設定
  ObjectSetInteger(chart_ID,name,OBJPROP_ANCHOR,anchor);
//--- 矢印の色を設定
  ObjectSetInteger(chart_ID,name,OBJPROP_COLOR,clr);
//--- 境界線のスタイルを設定
  ObjectSetInteger(chart_ID,name,OBJPROP_STYLE,style);
//--- 矢印のサイズを設定
  ObjectSetInteger(chart_ID,name,OBJPROP_WIDTH,width);
//--- 前景(false)または背景(true)に表示
  ObjectSetInteger(chart_ID,name,OBJPROP_BACK,back);
//--- マウスで矢印を移動させるモードを有効(true)か無効(false)にする
//--- ObjectCreate 関数を使用してグラフィックオブジェクトを作成する際、オブジェクトは
//--- デフォルトではハイライトされたり動かされたり出来ない。このメソッド内では、選択パラメータは
//--- デフォルトでは true でハイライトと移動を可能にする。
  ObjectSetInteger(chart_ID,name,OBJPROP_SELECTABLE,selection);
  ObjectSetInteger(chart_ID,name,OBJPROP_SELECTED,selection);
//--- オブジェクトリストのグラフィックオブジェクトを非表示(true)か表示(false)にする
  ObjectSetInteger(chart_ID,name,OBJPROP_HIDDEN,hidden);
//--- チャートのマウスクリックのイベントを受信するための優先順位を設定する
  ObjectSetInteger(chart_ID,name,OBJPROP_ZORDER,z_order);
//--- 実行成功
  return(true);
 }
//+------------------------------------------------------------------+
//| Draw sign function                                               |
//+------------------------------------------------------------------+
void DrawSign()
{
   if (ArraySize(RCIBuffer0) == 0) return;

   string prefix = MQLInfoString(MQL_PROGRAM_NAME) + "_";
   ObjectsDeleteAll(0, prefix);

   int barF = (int)ChartGetInteger(0, CHART_FIRST_VISIBLE_BAR);
   int barR = barF - (int)ChartGetInteger(0, CHART_WIDTH_IN_BARS);
   if (barR < 0) barR = 0;

   for (int i = barF; i >= barR; i--) {
      bool upNow = RCIBuffer0[i] > RCIBuffer1[i] && RCIBuffer1[i] > RCIBuffer2[i];
      bool upPre = RCIBuffer0[i + 1] > RCIBuffer1[i + 1] && RCIBuffer1[i + 1] > RCIBuffer2[i + 1];
      bool dnNow = RCIBuffer0[i] < RCIBuffer1[i] && RCIBuffer1[i] < RCIBuffer2[i];
      bool dnPre = RCIBuffer0[i + 1] < RCIBuffer1[i + 1] && RCIBuffer1[i + 1] < RCIBuffer2[i + 1];

      if (upNow && !upPre) {
         string name = prefix + (string)i;
         ArrowCreate(0, name, 0, iTime(NULL, 0, i), iLow(NULL, 0, i), 233, ANCHOR_TOP, clrRed, STYLE_SOLID, 2);
      }
      if (dnNow && !dnPre) {
         string name = prefix + (string)i;
         ArrowCreate(0, name, 0, iTime(NULL, 0, i), iHigh(NULL, 0, i), 234, ANCHOR_BOTTOM, clrDodgerBlue, STYLE_SOLID, 2);
      }
   }
   ChartRedraw();
}

//+------------------------------------------------------------------+

EA(自動売買)を学びたい方へオススメコンテンツ

EA運用の注意点

OANDAではEA(自動売買)を稼働するプラットフォームMT4/MT5の基本的な使い方について、画像や動画付きで詳しく解説しています。MT4/MT5のインストールからEAの設定方法までを詳しく解説しているので、初心者の方でもスムーズにEA運用を始めることが可能です。またOANDAの口座をお持ちであれば、独自開発したオリジナルインジケーターを無料で利用することもできます。EA運用をお考えであれば、ぜひ口座開設をご検討ください。


本ホームページに掲載されている事項は、投資判断の参考となる情報の提供を目的としたものであり、投資の勧誘を目的としたものではありません。投資方針、投資タイミング等は、ご自身の責任において判断してください。本サービスの情報に基づいて行った取引のいかなる損失についても、当社は一切の責を負いかねますのでご了承ください。また、当社は、当該情報の正確性および完全性を保証または約束するものでなく、今後、予告なしに内容を変更または廃止する場合があります。なお、当該情報の欠落・誤謬等につきましてもその責を負いかねますのでご了承ください。

この記事をシェアする

ホーム » FX自動売買基礎と応用 » MT5版の3本表示RCIを作成する【MQLプログラミングの基礎】