ホーム » FX自動売買基礎と応用 » MT5で複数通貨のランキングツールを作成する【MQLプログラミングの基礎】

MT5で複数通貨のランキングツールを作成する【MQLプログラミングの基礎】

1.ファイルの新規作成

この記事では、複数通貨ペアの値動き情報を利用して通貨の強さ(買われている度合い)のランク付けをし、ランキングの順に通貨名を表示するツールを作成します。

※この記事はMQL5の内容です。

今回は、主要の8通貨(USD、EUR、JPY、GBP、AUD、CHF、CAD、NZD)のランキングを集計します。

MetaEditorの「新規作成」アイコンをクリックしてMQLウィザードを開始します。

MQLウィザード新規作成

「カスタムインディケータ」を選択して「次へ」をクリック。

一般プロパティ

ファイル名を「CurrencyRank.mq5」とし、「次へ」をクリック。

イベントハンドラ

イベントハンドラは一番上のOnCalculateのみを選択して「次へ」をクリック。

描画プロパティ

「カスタムインディケータの描画プロパティ」では、特に何も追加せず「完了」をクリックすれば、ファイルのベースが作成されます。

今回のファイルでは、インジケーターバッファを利用しないので、「#property indicator_chart_window」の行の下へ、下記を追加します。


#property indicator_buffers 0
#property indicator_plots   0

2.通貨ペア名称の定義

8通貨の情報を計算するため、28の通貨ペアを配列として定義します。
#property indicator_plots 0」の下へ、下記を追記します。


string symbol[28];

同様に、通貨名称を定義する配列を上記の下へ追記します。


string currency[8];

OnInit関数内へ、下記を追記して通貨ペア名と通貨名を入力します。


   symbol[0] = "EURUSD";
   symbol[1] = "USDJPY";
   symbol[2] = "GBPUSD";
   symbol[3] = "AUDUSD";
   symbol[4] = "EURJPY";
   symbol[5] = "GBPJPY";
   symbol[6] = "AUDJPY";
   symbol[7] = "EURGBP";
   symbol[8] = "EURAUD";
   symbol[9] = "GBPAUD";
   symbol[10] = "USDCHF";
   symbol[11] = "USDCAD";
   symbol[12] = "NZDUSD";
   symbol[13] = "EURCHF";
   symbol[14] = "EURCAD";
   symbol[15] = "EURNZD";
   symbol[16] = "CHFJPY";
   symbol[17] = "CADJPY";
   symbol[18] = "NZDJPY";
   symbol[19] = "GBPCHF";
   symbol[20] = "GBPCAD";
   symbol[21] = "GBPNZD";
   symbol[22] = "AUDCHF";
   symbol[23] = "AUDCAD";
   symbol[24] = "AUDNZD";
   symbol[25] = "CADCHF";
   symbol[26] = "NZDCHF";
   symbol[27] = "NZDCAD";
   
   currency[0] = "USD";
   currency[1] = "EUR";
   currency[2] = "JPY";
   currency[3] = "GBP";
   currency[4] = "AUD";
   currency[5] = "CHF";
   currency[6] = "CAD";
   currency[7] = "NZD";

通貨ペア名称6文字の後ろの7文字目以降に文字がある場合に対応するため、下記を追記します(表示しているチャートの通貨ペア名称の7文字目以降を配列symbol[]の末尾へ追加する)。


   for (int i = 0; i < 28; i++) {
      symbol[i] += StringSubstr(_Symbol, 6);
   }

あとで通貨名を表示する際、見やすいよう、各通貨に色を登録します。
string currency[8];」の下へ、下記を追記します。


color clrCu[8];

OnInit関数内へ、下記を追記して各通貨の色を入力します。


   clrCu[0] = clrRed;
   clrCu[1] = clrYellow;
   clrCu[2] = clrWhite;
   clrCu[3] = clrDodgerBlue;
   clrCu[4] = clrLimeGreen;
   clrCu[5] = clrMagenta;
   clrCu[6] = clrOrange;
   clrCu[7] = clrAqua;

3.通貨毎のポイントを集計

最新のローソク足が陽線か陰線かで、通貨の強さポイントを集計します。

例えばUSDJPY(米ドル/円)の場合、陽線であればUSDにプラス1ポイント、陰線であればJPYにプラス1ポイント、十字線の場合は、USDとJPY共にプラス0.5ポイントとします。

まずは、各通貨ペアの最新足の方向を判定するためのfor文をOnCalculate関数内へ追記します。


   for (int i = 0; i < 28; i++) {
      double op = iOpen(symbol[i], NULL, 0);
      double cl = iClose(symbol[i], NULL, 0);
      int direction = 0; // 十字線
      if (cl > op) { // 陽線
         direction = 1;
      } else if (cl < op) { // 陰線
         direction = -1;
      }
      // あとでここへ、ポイント集計の式を入れる・・・➀
   }

変数directionは陽線の場合1、陰性の場合-1、十字線の場合0になります。
ポイントを集計する配列point[]をfor文の前に追記します。


   double point[8];
   ArrayInitialize(point, 0);

通貨毎にポイントを集計するために、for文内の最後(➀の場所)に下記を追記します。


      for (int j = 0; j < 8; j++) {
         // 通貨ペア名の1~3文字目と通貨名が一致
         if (StringSubstr(symbol[i], 0, 3) == currency[j]) { 
            if (direction == 1) point[j] += 1; // 陽線なので+1
            else if (direction == 0) point[j] += 0.5; // 十字線なので+0.5
         // 通貨ペア名の4~5文字目と通貨名が一致
         } else if (StringSubstr(symbol[i], 3, 3) == currency[j]) { 
            if (direction == -1) point[j] += 1; // 陰線なので+1
            else if (direction == 0) point[j] += 0.5; // 十字線なので+0.5
         }
      }

4.集計結果の仮確認

Comment関数 を利用して、集計内容を簡易表示します。
OnCalculate関数内のfor文の後に、下記を追記します。


   string text;
   for (int i = 0; i < 8; i++) {
      text += currency[i] + " : " + DoubleToString(point[i], 1) + "\n";
   }
   Comment(text);

コンパイルしてチャートにセットすると、下記のような表示になります。

ポイント集計

0~7の数字が表示されていれば、正常に集計されていると考えられます。
エラーが発生したり、数値が異常な場合は、ここまでのプログラムを再確認してください。
確認できたら、「string text;」から「Comment(text);」までの行は削除してください。

5.ランキング判定

集計したポイントの多い順からランク付けします。
ランキングを行う回路として下記をOnCalculate関数内のfor文の後に追記します。


   int rank[8];
   ArrayInitialize(rank, 0);
   for (int i = 0; i < 8; i++) {
      for (int j = i + 1; j < 8; j++) {
         if (point[i] < point[j]) rank[i]++;
         else rank[j]++;
      }
   }

他と比較してポイントが低い場合、rank[]の数を加算しています。
従って、rank[]の数が小さいほど、強さが上位になります。

6.ランク順に通貨名を表示

ラベルオブジェクトを利用してチャート上へ通貨名を並べて表示します。
MetaEditorメニューの「ヘルプ」から「MQL5リファレンス」を開いて、「目次」タブを選択し、「標準的な定数、列挙と構造体」→「オブジェクト定数」→「オブジェクト型」にある「OBJ_LABEL」を選択してください。

ラベルオブジェクト関数

OBJ_LABEL内の「//| ラベルを作成する」以下にある「LabelCreate」関数をコピーして、今回のプログラムの最下部へ貼り付けます。

――――― コピーして貼り付けするコード(ここから) ―――――


//+------------------------------------------------------------------+ 
//| ラベルを作成する                                                      | 
//+------------------------------------------------------------------+ 
bool LabelCreate(const long              chart_ID=0,               // チャート識別子 
                const string            name="Label",             // ラベル名 
                const int               sub_window=0,             // サブウィンドウ番号 
                const int               x=0,                     // X 座標 
                const int               y=0,                     // Y 座標 
                const ENUM_BASE_CORNER  corner=CORNER_LEFT_UPPER, // アンカーに使用されるチャートのコーナー 
                const string            text="Label",             // テキスト 
                const string            font="Arial",             // フォント 
                const int               font_size=10,             // フォントサイズ 
                const color             clr=clrRed,               // 色 
                const double            angle=0.0,               // テキストの傾斜 
                const ENUM_ANCHOR_POINT anchor=ANCHOR_LEFT_UPPER, // アンカーの種類 
                const bool              back=false,               // 背景で表示する 
                const bool              selection=false,         // 強調表示して移動 
                const bool              hidden=true,             // オブジェクトリストに隠す 
                const long              z_order=0)               // マウスクリックの優先順位 
 { 
//--- エラー値をリセットする 
  ResetLastError(); 
//--- ラベルを作成する 
  if(!ObjectCreate(chart_ID,name,OBJ_LABEL,sub_window,0,0)) 
    { 
    Print(__FUNCTION__, 
          ": failed to create text label! Error code = ",GetLastError()); 
    return(false); 
    } 
//--- ラベル座標を設定する 
  ObjectSetInteger(chart_ID,name,OBJPROP_XDISTANCE,x); 
  ObjectSetInteger(chart_ID,name,OBJPROP_YDISTANCE,y); 
//--- ポイント座標が相対的に定義されているチャートのコーナーを設定 
  ObjectSetInteger(chart_ID,name,OBJPROP_CORNER,corner); 
//--- テキストを設定する 
  ObjectSetString(chart_ID,name,OBJPROP_TEXT,text); 
//--- テキストフォントを設定する 
  ObjectSetString(chart_ID,name,OBJPROP_FONT,font); 
//--- フォントサイズを設定する 
  ObjectSetInteger(chart_ID,name,OBJPROP_FONTSIZE,font_size); 
//--- テキストの傾斜を設定する 
  ObjectSetDouble(chart_ID,name,OBJPROP_ANGLE,angle); 
//--- アンカーの種類を設定 
  ObjectSetInteger(chart_ID,name,OBJPROP_ANCHOR,anchor); 
//--- 色を設定 
  ObjectSetInteger(chart_ID,name,OBJPROP_COLOR,clr); 
//--- 前景(false)または背景(true)に表示 
  ObjectSetInteger(chart_ID,name,OBJPROP_BACK,back); 
//--- マウスでラベルを移動させるモードを有効(true)か無効(false)にする 
  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); 
 } 
//+------------------------------------------------------------------+

――――― コピーして貼り付けするコード(ここまで) ―――――

ランクが変化したときに、最新の並びが反映されるよう、下記のif文内に


  if(!ObjectCreate(chart_ID,name,OBJ_LABEL,sub_window,0,0)) 
     { 
     Print(__FUNCTION__, 
           ": failed to create text label! Error code = ",GetLastError()); 
     return(false); 
     }

Y座標を指定する行を追加します。


  if(!ObjectCreate(chart_ID,name,OBJ_LABEL,sub_window,0,0)) 
     { 
     ObjectSetInteger(chart_ID,name,OBJPROP_YDISTANCE,y);
     Print(__FUNCTION__, 
           ": failed to create text label! Error code = ",GetLastError()); 
     return(false); 
     }

オブジェクトの名称の頭に共通の文字列を付けて管理するために、接頭辞を定義します。
ファイル上部のプロパティ「#property indicator_plots 0」の下に、下記を追記します。


#define PREFIX "CurrencyRank_"

インジケーターの削除や再読み込み時に、トレンドラインオブジェクトを一括消去するため、OnDeinit関数を追加します。
下記をOnInit関数の下などへ追加してください(他の関数の中でなければ、どこへ追加しても構いません)。


void OnDeinit(const int reason)
{
   ObjectsDeleteAll(0, PREFIX);
   Comment("");
}

上記には、Comment関数で仮表示した文字を消すため、「Comment(“”);」も入れています。
LabelCreate関数を利用して文字を表示するため、ランキング判定したfor文の下へ、下記を追記します。


   for (int i = 0; i < 8; i++) {
      LabelCreate(0, PREFIX + (string)i, 0, 20, 20 + 24 * rank[i], CORNER_LEFT_UPPER, currency[i], "Arial Black", 16, clrCu[i], 0, ANCHOR_LEFT_UPPER);
   }
   ChartRedraw();

チャートの左上基準で、X座標20、Y座標20の位置から下へ24の間隔で、フォント「Arial Black」、サイズ16の通貨名が並べられます。
上記までの作業で完成となります。

コンパイルすると、表示されているチャートの時間足の最新ローソク足方向で判定した通貨の強さの順に、通貨名が表示されます。

ランキング表示

6.ソースコード

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


//+------------------------------------------------------------------+
//|                                                 CurrencyRank.mq5 |
//|                                  Copyright 2025, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2025, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_chart_window
#property indicator_buffers 0
#property indicator_plots   0
#define PREFIX "CurrencyRank_"

string symbol[28];
string currency[8];
color clrCu[8];
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
   symbol[0] = "EURUSD";
   symbol[1] = "USDJPY";
   symbol[2] = "GBPUSD";
   symbol[3] = "AUDUSD";
   symbol[4] = "EURJPY";
   symbol[5] = "GBPJPY";
   symbol[6] = "AUDJPY";
   symbol[7] = "EURGBP";
   symbol[8] = "EURAUD";
   symbol[9] = "GBPAUD";
   symbol[10] = "USDCHF";
   symbol[11] = "USDCAD";
   symbol[12] = "NZDUSD";
   symbol[13] = "EURCHF";
   symbol[14] = "EURCAD";
   symbol[15] = "EURNZD";
   symbol[16] = "CHFJPY";
   symbol[17] = "CADJPY";
   symbol[18] = "NZDJPY";
   symbol[19] = "GBPCHF";
   symbol[20] = "GBPCAD";
   symbol[21] = "GBPNZD";
   symbol[22] = "AUDCHF";
   symbol[23] = "AUDCAD";
   symbol[24] = "AUDNZD";
   symbol[25] = "CADCHF";
   symbol[26] = "NZDCHF";
   symbol[27] = "NZDCAD";
   
   currency[0] = "USD";
   currency[1] = "EUR";
   currency[2] = "JPY";
   currency[3] = "GBP";
   currency[4] = "AUD";
   currency[5] = "CHF";
   currency[6] = "CAD";
   currency[7] = "NZD";
   
   for (int i = 0; i < 28; i++) {
      symbol[i] += StringSubstr(_Symbol, 6);
   }
   
   clrCu[0] = clrRed;
   clrCu[1] = clrYellow;
   clrCu[2] = clrWhite;
   clrCu[3] = clrDodgerBlue;
   clrCu[4] = clrLimeGreen;
   clrCu[5] = clrMagenta;
   clrCu[6] = clrOrange;
   clrCu[7] = clrAqua;
//---
   return(INIT_SUCCEEDED);
  }

void OnDeinit(const int reason)
{
   ObjectsDeleteAll(0, PREFIX);
   Comment("");
}

//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int32_t rates_total,
                const int32_t 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 int32_t &spread[])
  {
//---
   double point[8];
   ArrayInitialize(point, 0);
   for (int i = 0; i < 28; i++) {
      double op = iOpen(symbol[i], NULL, 0);
      double cl = iClose(symbol[i], NULL, 0);
      int direction = 0; // 十字線
      if (cl > op) { // 陽線
         direction = 1;
      } else if (cl < op) { // 陰線
         direction = -1;
      }
      for (int j = 0; j < 8; j++) {
         // 通貨ペア名の1~3文字目と通貨名が一致
         if (StringSubstr(symbol[i], 0, 3) == currency[j]) { 
            if (direction == 1) point[j] += 1; // 陽線なので+1
            else if (direction == 0) point[j] += 0.5; // 十字線なので+0.5
         // 通貨ペア名の4~5文字目と通貨名が一致
         } else if (StringSubstr(symbol[i], 3, 3) == currency[j]) { 
            if (direction == -1) point[j] += 1; // 陰線なので+1
            else if (direction == 0) point[j] += 0.5; // 十字線なので+0.5
         }
      }
   }
   
   int rank[8];
   ArrayInitialize(rank, 0);
   for (int i = 0; i < 8; i++) {
      for (int j = i + 1; j < 8; j++) {
         if (point[i] < point[j]) rank[i]++;
         else rank[j]++;
      }
   }

   for (int i = 0; i < 8; i++) {
      LabelCreate(0, PREFIX + (string)i, 0, 20, 20 + 24 * rank[i], CORNER_LEFT_UPPER, currency[i], "Arial Black", 16, clrCu[i], 0, ANCHOR_LEFT_UPPER);
   }
   ChartRedraw();
//--- return value of prev_calculated for next call
   return(rates_total);
  }

//+------------------------------------------------------------------+ 
//| ラベルを作成する                                                      | 
//+------------------------------------------------------------------+ 
bool LabelCreate(const long              chart_ID=0,               // チャート識別子 
                const string            name="Label",             // ラベル名 
                const int               sub_window=0,             // サブウィンドウ番号 
                const int               x=0,                     // X 座標 
                const int               y=0,                     // Y 座標 
                const ENUM_BASE_CORNER  corner=CORNER_LEFT_UPPER, // アンカーに使用されるチャートのコーナー 
                const string            text="Label",             // テキスト 
                const string            font="Arial",             // フォント 
                const int               font_size=10,             // フォントサイズ  
                const color             clr=clrRed,               // 色 
                const double            angle=0.0,               // テキストの傾斜  
                const ENUM_ANCHOR_POINT anchor=ANCHOR_LEFT_UPPER, // アンカーの種類 
                const bool              back=false,               // 背景で表示する 
                const bool              selection=false,         // 強調表示して移動 
                const bool              hidden=true,             // オブジェクトリストに隠す 
                const long              z_order=0)               // マウスクリックの優先順位 
 { 
//--- エラー値をリセットする 
  ResetLastError(); 
//--- ラベルを作成する 
  if(!ObjectCreate(chart_ID,name,OBJ_LABEL,sub_window,0,0)) 
     {
     ObjectSetInteger(chart_ID,name,OBJPROP_YDISTANCE,y); 
     Print(__FUNCTION__, 
           ": failed to create text label! Error code = ",GetLastError()); 
     return(false); 
     } 
//--- ラベル座標を設定する 
  ObjectSetInteger(chart_ID,name,OBJPROP_XDISTANCE,x); 
   ObjectSetInteger(chart_ID,name,OBJPROP_YDISTANCE,y); 
//--- ポイント座標が相対的に定義されているチャートのコーナーを設定 
  ObjectSetInteger(chart_ID,name,OBJPROP_CORNER,corner); 
//--- テキストを設定する 
  ObjectSetString(chart_ID,name,OBJPROP_TEXT,text); 
//--- テキストフォントを設定する 
  ObjectSetString(chart_ID,name,OBJPROP_FONT,font); 
//--- フォントサイズを設定する 
  ObjectSetInteger(chart_ID,name,OBJPROP_FONTSIZE,font_size); 
//--- テキストの傾斜を設定する 
  ObjectSetDouble(chart_ID,name,OBJPROP_ANGLE,angle); 
//--- アンカーの種類を設定 
  ObjectSetInteger(chart_ID,name,OBJPROP_ANCHOR,anchor); 
//--- 色を設定 
  ObjectSetInteger(chart_ID,name,OBJPROP_COLOR,clr); 
//--- 前景(false)または背景(true)に表示 
  ObjectSetInteger(chart_ID,name,OBJPROP_BACK,back); 
//--- マウスでラベルを移動させるモードを有効(true)か無効(false)にする 
  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); 
  } 
//+------------------------------------------------------------------+

本記事の監修者・HT FX

2013年にFXを開始し、その後専業トレーダーへ。2014年からMT4/MT5のカスタムインジケーターの開発に取り組む。ブログでは100本を超えるインジケーターを無料公開。投資スタイルは自作の秒足インジケーターを利用したスキャルピング。

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

EA運用の注意点

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


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

この記事をシェアする