EURUSDとGBPUSDを両方持っていて、「これでリスクを分散できている」

と思っていないでしょうか。

2つの通貨ペアが強く相関していれば、

それは分散ではなく、実質的に同じ賭けの重複かもしれません。

この記事では、複数の通貨ペアの値動きの相関係数を計算し、

チャート上のパネルに一覧表示するインジケーターを作ります。

この記事で分かること
・通貨ペアの相関とは何か、なぜ知る必要があるか
・ピアソンの相関係数の計算方法
・複数シンボルのデータを取得する際の注意点
・実際に動くパネル表示インジケーターのコード全体

通貨ペアの相関とは何か・なぜ知りたいのか

まず、「相関」という考え方を整理します。

相関とは何か(一緒に動くか、逆に動くか)

相関係数は、2つの通貨ペアが、同じ方向に動く傾向が強いか(正の相関)、

逆方向に動く傾向が強いか(負の相関)を、数値で表したものです。

相関を知らずに複数ポジションを持つリスク

注意
・EURUSDの買いとGBPUSDの買いは、見た目は別の2ポジションに見える
・相関が強い場合、実質的には同じ方向への賭けを2倍にしているだけ
・損切りが同時に重なるリスクを過小評価しやすい

既刊「通貨強弱メーター」との違い

既刊の通貨強弱メーターは、USDやEUR等「単独の通貨」の強さを計算するものでした。

この記事の相関は、「2つの通貨ペアの関係」を計算する、別の概念です。

ピアソンの相関係数の計算方法

実際の計算方法を確認します。

相関係数の意味(+1〜-1の範囲)

相関係数は`+1`(完全に同じ方向に動く)から、

`-1`(完全に逆方向に動く)の範囲の値になります。

`0`に近いほど、関係が薄いことを意味します。

計算式の考え方

相関係数 = 共分散 ÷ (xの標準偏差 × yの標準偏差)

各通貨ペアの「変化率」を一定期間分集め、その変化率どうしの関係性を数値化します。

MQL4に相関を計算する標準関数は無い

MQL4には相関係数を直接返す関数が無いため、

この記事では`MathSqrt`等の基本的な数学関数を使い、

計算式をそのまま自作します。

複数シンボルのデータを取得する際の注意点

既刊の通貨強弱メーターでも扱った、実装上の落とし穴です。

iClose()は対象シンボルがMarket Watchに無いと0を返す

比較したい通貨ペアがMarket Watchに表示されていないと、

履歴が読み込まれず、`iClose()`が0を返してしまいます。

SymbolSelectで明示的に追加する

`SymbolSelect(symbol, true)`を使い、

比較対象の通貨ペアを`OnInit()`で、まとめて1回だけ追加しておく設計にします。

実際に動くコード全体(相関係数パネル)

チャートの通貨ペアを基準に、比較対象の相関係数を一覧表示するインジケーターです。

//+------------------------------------------------------------------+
//|                                CurrencyCorrelationPanel.mq4       |
//|                     Copyright 2026, FX-EA System Project Creator |
//|                        https://creator.fx-ea-system-project.com/ |
//+------------------------------------------------------------------+
#property strict
#property indicator_chart_window

input int    InpLookbackBars    = 50;    //相関を計算する期間(本数)
input string InpCompareSymbols  = "GBPUSD,USDJPY,AUDUSD,EURJPY"; //比較対象(カンマ区切り)

string CompareList[];
string PanelPrefix = "CcyCorr_";

int OnInit()
  {
   ushort sep = StringGetCharacter(",", 0);
   int count = StringSplit(InpCompareSymbols, sep, CompareList);

   for(int i = 0; i < count; i++)
      SymbolSelect(CompareList[i], true); //Market Watchに追加(iCloseの0返り対策)

   for(int i = 0; i < count + 1; i++) //+1はヘッダー行
     {
      string name = PanelPrefix + IntegerToString(i);
      ObjectCreate(0, name, OBJ_LABEL, 0, 0, 0);
      ObjectSetInteger(0, name, OBJPROP_CORNER, CORNER_RIGHT_UPPER);
      ObjectSetInteger(0, name, OBJPROP_XDISTANCE, 10);
      ObjectSetInteger(0, name, OBJPROP_YDISTANCE, 20 + i * 18);
      ObjectSetInteger(0, name, OBJPROP_FONTSIZE, 10);
     }

   return(INIT_SUCCEEDED);
  }

void OnDeinit(const int reason)
  {
   int count = ArraySize(CompareList);
   for(int i = 0; i < count + 1; i++)
      ObjectDelete(0, PanelPrefix + IntegerToString(i));
  }

void BuildReturns(string symbol, int bars, double &out[])
  {
   ArrayResize(out, bars);
   for(int i = 0; i < bars; i++)
     {
      double prevClose = iClose(symbol, 0, i + 1);
      double nowClose  = iClose(symbol, 0, i);
      out[i] = (prevClose == 0) ? 0 : (nowClose - prevClose) / prevClose;
     }
  }

double CalcCorrelation(double &x[], double &y[])
  {
   int n = ArraySize(x);
   if(n <= 1 || ArraySize(y) != n)
      return(0);

   double sumX = 0, sumY = 0;
   for(int i = 0; i < n; i++)
     {
      sumX += x[i];
      sumY += y[i];
     }
   double meanX = sumX / n;
   double meanY = sumY / n;

   double sumXY = 0, sumXX = 0, sumYY = 0;
   for(int i = 0; i < n; i++)
     {
      double dx = x[i] - meanX;
      double dy = y[i] - meanY;
      sumXY += dx * dy;
      sumXX += dx * dx;
      sumYY += dy * dy;
     }

   if(sumXX == 0 || sumYY == 0)
      return(0);

   return(sumXY / MathSqrt(sumXX * sumYY));
  }

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[])
  {
   int count = ArraySize(CompareList);

   double baseReturns[];
   BuildReturns(_Symbol, InpLookbackBars, baseReturns);

   string headerName = PanelPrefix + "0";
   ObjectSetString(0, headerName, OBJPROP_TEXT, _Symbol + " との相関係数");
   ObjectSetInteger(0, headerName, OBJPROP_COLOR, clrWhite);

   for(int i = 0; i < count; i++)
     {
      double compReturns[];
      BuildReturns(CompareList[i], InpLookbackBars, compReturns);

      double corr = CalcCorrelation(baseReturns, compReturns);
      string name = PanelPrefix + IntegerToString(i + 1);
      string text = StringFormat("%s  %.2f", CompareList[i], corr);

      color c = clrSilver;
      if(corr >= 0.7)
         c = clrLimeGreen;
      else if(corr <= -0.7)
         c = clrOrangeRed;

      ObjectSetString(0, name, OBJPROP_TEXT, text);
      ObjectSetInteger(0, name, OBJPROP_COLOR, c);
     }

   return(rates_total);
  }

MetaEditorでのコンパイル・表示手順

  1. MetaEditorで新規カスタムインジケーター「CurrencyCorrelationPanel」を作成し、上のコードを貼り付けてコンパイルする
  2. 任意の通貨ペアのチャートにドラッグ&ドロップで適用する
  3. チャート右上に、比較対象ごとの相関係数がパネル表示されることを確認する
  4. `InpCompareSymbols`を書き換え、比較対象を増減させて動作を確認する

よくあるエラーと注意点

実際に使う前に、確認しておきたい注意点をまとめます。

表示直後は値が0のままになることがある

ブローカーによっては、他通貨ペアの気配配信や履歴読み込みが、少し遅れることがあります。

数秒待ってから再度確認してください。

InpLookbackBarsの決め方

期間を短くすると直近の短期的な関係に、長くすると中長期的な関係に、それぞれ敏感になります。

相関は固定ではなく時間とともに変化する

補足
・ある時期に強かった相関が、別の時期には弱まることがある
・このパネルは「今この瞬間」の相関であり、恒久的な関係ではない
・定期的に見直す前提で使う指標です

相関インジケーターの使いどころと限界

実務上の使い方と、注意点を整理します。

分散になっていない組み合わせを発見できる

相関が高い通貨ペアを複数持っている場合、このパネルを見れば、

分散のつもりが分散になっていないことに気づけます。

相関は過去データに基づく点に注意

このインジケーターが示す相関係数は、あくまで過去`InpLookbackBars`本分の、

値動きに基づく結果であり、未来の相関を保証するものではありません。

よくある質問

通貨ペアの相関について、よく検索される疑問に回答します。

相関係数がどれくらいなら「高い」と言えますか?

一般的には`0.7`以上(または`-0.7`以下)を、強い相関とみなすことが多いですが、

これは厳密な決まりではなく、目安として使ってください。

比較対象の通貨ペアはいくつでも増やせますか?

`InpCompareSymbols`にカンマ区切りで追加すれば、

理論上はいくつでも増やせます。

ただし増やすほどパネルの表示領域も必要になります。

このロジックをEAの判断に組み込めますか?

できます。

`CalcCorrelation()`関数をそのまま使えば、

「相関が高いペアでは同時に新規エントリーしない」といったフィルターにも応用できます。

【MQL4】複数の通貨ペアの値動きの相関をパネルで一覧表示するインジケーターの作り方について解説してみた(通貨強弱メーターとの違いも整理):まとめ

複数の通貨ペアを持っているとき、それが本当に分散になっているかは、

値動きを見ているだけでは判断できません。

ピアソンの相関係数を計算し、

パネルに一覧表示することで、ポジションの重複リスクを数値で確認できるようになります。

相関は時間とともに変化するため、一度きりの確認で終わらせず、

定期的に見直す前提で活用してください。

関連記事