English Deutsch
preview
プライスアクション分析ツールキットの開発(第20回):External Flow (IV) — Correlation Pathfinder

プライスアクション分析ツールキットの開発(第20回):External Flow (IV) — Correlation Pathfinder

MetaTrader 5 |
37 0
Christian Benjamin
Christian Benjamin

内容


はじめに

FX(外国為替)取引では、さまざまな要因を正確に理解することが求められます。その中でも特に重要な要素のひとつが通貨の相関関係です。通貨の相関とは、2つの通貨ペアがどのような関係で価格変動するかを示すものです。同じ方向に動くのか、反対方向に動くのか、あるいは無関係に動くのかという「関係性」を時間の経過とともに明らかにします。通貨は常にペアで取引されるため、すべての通貨ペアは他のペアと相互に関連したネットワークを形成しています。

こうした関係性を理解することで、取引戦略を洗練させたり、リスクを抑えることが可能になります。たとえば、EUR/USDとGBP/USDが強い正の相関にある時に両方を買うと、同じ市場要因へのリスクが2倍になります。逆にこの相関性を理解していれば、ポートフォリオの分散やヘッジ戦略をより効果的に構築できます。

この記事では、通貨相関の分析を取引ツールキットに組み込む方法を解説します。実用的な洞察と、すぐに実践できる戦略を通じて、取引パフォーマンスを向上させる手助けとなる内容です。以下の2つの図は、EUR/USDとGBP/USDの市場構造を同じ日付で比較したものです。どちらのペアも4月2日に上昇トレンドとなり、4月3日に下落に転じており、正の相関を示しています。このような相関を利用して、片方のペアを使ってもう一方の反転を確認することが可能になります。たとえば、EUR/USDが買われすぎの状態で、同時にGBP/USDが売られている場合、EUR/USDに反転のシグナルが出ていると判断できます。Correlation Pathfinderツールは、通貨ペア間の関係性を明確に可視化するため、より正確な市場の全体像を把握したいトレーダーにとって、極めて重要なツールです。

GBP/USD

GPBUSD

図1:GBP/USD


EUR/USD

EURUSD

図2:EUR/USD



システムの概要

通貨の相関関係は、-1から+1の範囲の相関係数として表されます。+1に近い値は2つの通貨ペアが同じ方向に動く傾向が強いことを意味し、-1に近い値は反対方向に動くことを示します。0付近の値は両者に明確な関係性がないこと、または両者の相関が非常に弱いことを表します。

この相関の理解は、効果的なリスク管理において非常に重要です。たとえば、EUR/USDとGBP/USDが強く正の相関にあるときに両方を買うと、市場へのエクスポージャーが実質的に2倍となり、リスクも倍増します。逆に、相関の度合いを把握していれば、ポートフォリオの分散や、予想外の値動きへのヘッジ戦略に活用できます(先ほど述べたとおりです)。

このシステムは、2つの連携コンポーネントから構成されています。1番目のコンポーネントはMQL5エキスパートアドバイザー(EA)です。まず、EAがEUR/USDとGBP/USDの過去価格データを継続的に取得し、それをJSON形式に変換し、Pythonサーバーへ送信します。2番目のコンポーネントは、Pythonベースの分析エンジンです。Python側では、次に、Pandasを使って相関係数(全体的および移動的)を計算し、Matplotlibを用いて一定幅の移動相関グラフを生成します。さらに、このサーバーは、通貨ペアが同じ方向に動いているのか、あるいは乖離しているのかを明確に解説し、その分析結果が取引戦略にどのような意味を持つかについてコメントを自動で生成します。

これらのデータの流れと分析処理を理解するには、以下のフローチャートを参照することで、全体像が把握しやすくなります。

フローチャート

図3:フロー図

この図は、MetaTrader 5によるデータ取得からPythonサーバー上での分析およびコメント生成までの一連のワークフローを、視覚的にわかりやすく示しています。AからHまでラベル付けされた各ノードはプロセスの各段階を表しており、データの収集、JSON形式へのパッケージ化、サーバーへの送信、Pandasによる解析、Matplotlibによる視覚化、そして解釈を含むコメントの生成といった流れが、順を追って示されています。


技術的詳細

MQL5 EA

データ取得

EAは、MetaTrader 5に内蔵されているCopyRates関数を用いて、過去の価格データを取得します。この関数は、MqlRatesという構造体形式の価格データ配列を取得し、各データには時刻、始値、高値、安値、終値などの情報が含まれます。このEAでは、ユーザーが時間足(たとえば15分足はPERIOD_M15)と、出力するバー数(データ数)をパラメータBarsToExportによって自由に設定できるようになっています。これにより、このEAはさまざまな取引戦略に合わせて柔軟にカスタマイズできます。短期のスナップショット(瞬間的な値動き)を取得したい場合でも、より広範囲な過去のトレンドを把握したい場合でも、目的に応じたデータ収集が可能です。

MqlRates rates1[];
if(CopyRates(Symbol1, TimeFrame, 0, BarsToExport, rates1) <= 0)
{
   Print("Failed to copy rates for ", Symbol1);
   return "";
}
ArraySetAsSeries(rates1, true);

価格データが各通貨ペア(たとえばEUR/USDやGBP/USD)に対して取得されると、EAはまずデータ配列を時系列として設定します。このステップは非常に重要で、配列内の最新のバーがインデックス0に配置されるよう並べ替えをおこないます。これは、MQL5の他の多くの関数がこの形式を前提として動作するためです。このようにして過去データを適切に準備することで、必要なバー数が正確に取得されるとともに、時系列の順序が保たれ、その後の分析処理が正確におこなえるようになります。

JSONペイロードの構築

価格データの収集が完了すると、EAは次にそれを整然と構造化されたフォーマットにまとめ、JSONペイロードとして構築します。この処理は、BuildJSONPayload関数でおこなわれます。関数はまず、2つの通貨ペアの名前を含むJSONオブジェクトを作成するところから始まります。次に、各通貨ペアに対して、それぞれのバー(ローソク足)データの配列を作成します。配列内の各オブジェクトは1本のバーを表しており、「時刻」と「終値」という2つの主要な情報が含まれます。時刻はTimeToString関数を用いてTIME_DATEおよびTIME_SECONDSのパラメータで統一された形式に変換され、終値はDoubleToString関数によって小数点以下5桁にフォーマットされます。

string json = "{";
json += "\"symbol1\":\"" + Symbol1 + "\",";
json += "\"symbol2\":\"" + Symbol2 + "\",";
json += "\"data1\":[";
for(int i = 0; i < ArraySize(rates1); i++)
{
   string timeStr = TimeToString(rates1[i].time, TIME_DATE | TIME_SECONDS);
   json += "{\"time\":\"" + timeStr + "\",\"close\":" + DoubleToString(rates1[i].close, 5) + "}";
   if(i < ArraySize(rates1) - 1)
      json += ",";
}
json += "],";
// The same pattern repeats for Symbol2's data array.
json += "}";
return json;

このモジュール化されたアプローチにより、ペイロードにはPythonサーバー側での解析に必要なすべての情報が確実に含まれるようになります。JSON形式の構造を採用することで、データの一貫性が保たれ、サーバー側でのデータの解析も混乱なくおこなえるようになります。たとえば、配列をdata1とdata2として明確にラベル付けすることで、サーバースクリプトはどのデータセットがどの通貨ペアに対応しているかを即座に判断できます。このような明確な区別は、後で相関係数を計算する際にデータを結合するために非常に重要です。この関数は、各通貨ペアの履歴データ配列をループで処理し、それぞれのレコードを正しいJSONフォーマットで連結していきます。そして最後にJSONオブジェクトを閉じることで、ペイロードの構築を完了します。

WebRequestとの統合

JSONペイロードの構築が完了すると、EAはMetaTraderのWebRequest関数を使ってサーバーにデータを送信します。この関数は、取引プラットフォームから直接HTTPリクエストを実行できる重要なツールであり、MQL5のEAとPythonサーバー側の解析エンジンとの間の通信を担います。送信前に、EAはJSON文字列をStringToCharArray関数を用いてuchar型の動的配列に変換します。これはWebRequest関数がリクエストボディとしてこの形式を要求するためであり、ネットワーク経由で正しくデータを送信するために不可欠な変換処理となります。

string requestHeaders = "Content-Type: application/json\r\n";
uchar result[];
string responseHeaders;
int webRequestResult = WebRequest("POST", pythonUrl, requestHeaders, timeout, requestData, result, responseHeaders);
if(webRequestResult == -1)
{
   Print("Error in WebRequest. Error code = ", GetLastError());
   return;
}

string response = CharArrayToString(result);
Print("Server response: ", response);

EAは次に、HTTPヘッダーを設定します。データがJSON形式であることを示すため、「Content-Type: application/json\r\n」というヘッダーを指定します。また、pythonUrl(サーバーのエンドポイント)やtimeout(応答を待機する最大時間)といった入力パラメータはユーザーが設定できるようになっており、使用環境に応じてネットワーク条件を柔軟に調整できます。これらの設定を用いて、WebRequest関数によりHTTP POSTリクエストがPythonサーバーに送信されます。リクエストが失敗した場合、EAはエラーコードを出力し、接続トラブルの原因特定やデバッグに役立ちます。一方、リクエストが成功した場合は、戻ってきたuchar配列のレスポンスを文字列に変換し、サーバーからの応答内容を出力します。この応答には、相関係数の計算結果や、Python側の解析エンジンが生成したコメントなどの有用な情報が含まれていることが期待されます。

Python解析サーバー

サーバー環境

このシステムは、Flaskベースのサーバー上に構築されており、HTTPのPOSTリクエストを待ち受けるように設計されています。サーバーを起動すると、Flaskのデフォルト設定で初期化され、ログレベルはDEBUGに設定されます。これにより、すべての受信リクエストおよび処理ステップが詳細にログとして記録されます。サーバーは、JSONデータを受け取り、それを処理・解析したうえで、JSON形式の結果を返すようになっています。Flaskを使用することで、サーバーは軽量かつ効率的に動作し、GUIを必要としない、いわゆるヘッドレス環境でも安定稼働できるため、自動売買向けの用途に非常に適しています。

import matplotlib
matplotlib.use("Agg")  # Use non-interactive backend to avoid GUI overhead
import matplotlib.pyplot as plt
from flask import Flask, request, jsonify
import logging

app = Flask(__name__)
logging.basicConfig(level=logging.DEBUG)

if __name__ == "__main__":
    app.run(host="127.0.0.1", port=5000)

データの解析と分析

サーバーがPOSTリクエストを受け取ると、まず最初に受信したJSONペイロードの解析を試みます。標準のJSONパーサーでの読み込みに失敗した場合は、リクエストの生データを直接デコードし、最後の中括弧(})以降に余分な文字列があればトリミングしたうえでJSONを読み込みます。JSONデータの読み込みが成功すると、それぞれの通貨ペア用に2つのPandas DataFramesに変換されます。ペイロード内の「time」フィールドは、文字列からdatetimeオブジェクトに変換され、正確なマージ処理と時系列分析が可能になります。その後、共通の「Time」列をもとに2つのDataFramesをマージし、2種類の相関指標を計算します。まず、終値に基づく全体的な相関係数を計算し、次に、50本のローリングウィンドウを用いた移動相関係数を計算します。この移動相関によって、通貨ペア間の相関関係が時間の経過とともにどのように変化しているかを把握できます。これは市場のダイナミクスを理解し、相関が強まっている時期や、弱まっている時期を特定する上で非常に重要です。

import pandas as pd
import json

@app.route('/analyze', methods=['POST'])
def analyze():
    # Parse JSON payload
    data = request.get_json(silent=True)
    if not data:
        raw_data = request.data.decode('utf-8').strip()
        app.logger.debug("Raw request data: %s", raw_data)
        try:
            end_index = raw_data.rfind("}")
            trimmed_data = raw_data[:end_index+1] if end_index != -1 else raw_data
            data = json.loads(trimmed_data)
        except Exception as e:
            app.logger.error("Failed to parse JSON: %s", str(e))
            return jsonify({"error": "Invalid JSON received"}), 400

    # Convert incoming JSON arrays to DataFrames
    data1 = pd.DataFrame(data["data1"])
    data2 = pd.DataFrame(data["data2"])
    
    # Convert time strings to datetime objects
    data1['Time'] = pd.to_datetime(data1['time'])
    data2['Time'] = pd.to_datetime(data2['time'])
    
    # Merge DataFrames on 'Time'
    merged = pd.merge(data1, data2, on="Time", 
                      suffixes=('_' + data["symbol1"], '_' + data["symbol2"]))
    
    # Calculate overall correlation between the close prices
    correlation = merged[f'close_{data["symbol1"]}'].corr(merged[f'close_{data["symbol2"]}'])
    
    # Calculate rolling correlation with a 50-bar window
    merged['RollingCorrelation'] = merged[f'close_{data["symbol1"]}'].rolling(window=50).corr(merged[f'close_{data["symbol2"]}'])
    
    # [Graph generation and commentary code follows here, see next sections]

グラフの生成と保存

視覚的な表現のために、サーバーはMatplotlibを用いてグラフを作成しますが、Aggバックエンドを使用しています。このバックエンドはグラフィカルユーザーインターフェイス(GUI)を必要とせず、ヘッドレス環境でも問題なくプロットを生成できるため、GUIに関連するオーバーヘッドを回避できます。グラフは幅7.5インチ、解像度100 DPIの固定サイズで作成されます。この設定により、出力される画像の横幅は固定で750ピクセルとなり、レポートごとに一貫性が保たれるとともに、視覚的にデータを即座に把握しやすくなります。作成した移動相関のプロットは、Pythonスクリプトと同じディレクトリにPNGファイルとして保存されます。画像をサーバーのJSONレスポンスに含める代わりにローカル保存することで、簡単に取り出して共有できる利便性が確保されています。

import matplotlib.pyplot as plt

# Generate a rolling correlation plot
plt.figure(figsize=(7.5, 6), dpi=100)  # 7.5 inches * 100 dpi = 750 pixels width
plt.plot(merged['Time'], merged['RollingCorrelation'], label="Rolling Correlation (50 bars)")
plt.xlabel("Time")
plt.ylabel("Correlation")
plt.title(f"{data['symbol1']} and {data['symbol2']} Rolling Correlation")
plt.legend()
plt.grid(True)
plt.tight_layout()

# Save the graph as a PNG file in the same folder
plot_filename = "rolling_correlation.png"
plt.savefig(plot_filename)
plt.close()

解説コメント

単なる数値やグラフの提供にとどまらず、サーバーは解析結果をより深く理解できるように解説コメントを生成します。このコメントは専用の関数によって作成され、全体的な相関値および最近の移動相関値の両方を検証します。たとえば、全体の相関が非常に高く(+1に近い場合)、コメントでは、この2つの通貨ペアが一般的に同じ方向に動いていることを説明します。これは、複数ペアを取引する際の分散効果が限定的である可能性を示唆しています。一方で、相関が低い、またはマイナスに転じた場合は、通貨ペア間で乖離が発生している可能性を指摘し、ヘッジやエクスポージャーの調整に活用できるチャンスを示唆しています。

def generate_commentary(corr, rolling_series):
    """Generate a commentary based on overall and recent correlation values."""
    commentary = ""
    if corr >= 0.8:
        commentary += ("The currency pairs have a very strong positive correlation, meaning "
                       "they typically move together. This may support the use of hedging strategies.\n")
    elif corr >= 0.5:
        commentary += ("The pairs display a moderately strong positive correlation with some deviations, "
                       "indicating they often move in the same direction.\n")
    elif corr >= 0.0:
        commentary += ("The overall correlation is weakly positive, suggesting occasional movement together "
                       "but limited consistency, which may offer diversification opportunities.\n")
    elif corr >= -0.5:
        commentary += ("The pairs exhibit a weak to moderate negative correlation; they tend to move in opposite "
                       "directions, which can be useful for diversification.\n")
    else:
        commentary += ("The pairs have a strong negative correlation, implying they generally move in opposite "
                       "directions, a factor exploitable in hedging strategies.\n")
    
    if not rolling_series.empty:
        recent_trend = rolling_series.iloc[-1]
        commentary += f"Recently, the rolling correlation is at {recent_trend:.2f}. "
        if recent_trend > 0.8:
            commentary += ("This high correlation suggests near mirror-like movement. "
                           "Relative strength approaches may need reconsideration for diversification.")
        elif recent_trend < 0.3:
            commentary += ("A significant drop in correlation indicates potential decoupling. "
                           "This may signal opportunities in pair divergence trades.")
        else:
            commentary += ("The correlation remains moderate, meaning the pairs show some synchronization but also "
                           "retain independent movement.")
    return commentary

この解説コメントは、最近の相関トレンドに関する洞察も提供し、トレーダーに対してこれらの統計的シグナルがリスク管理や戦略にどのような影響を与えるかに関する実践的な指針を提供します。定量的な分析と定性的な洞察を組み合わせることで、システムはトレーダーが市場の動きをより深く理解し、より賢明な意思決定をおこなう手助けをします。


結果

結果の説明に入る前に、Pythonサーバーの起動方法について説明しておく必要があります。まず、python.orgからPythonをダウンロード・インストールし、python -m venv venvコマンドで仮想環境を作成し、これを有効化します。次に、pip install Flask pandas matplotlibコマンドを実行して必要なパッケージをインストールします。Flaskサーバーのコードと必要なエンドポイントを含むPythonスクリプト(例:server.py)を作成します。最後に、スクリプトのあるディレクトリへ移動し、python server.pyを実行してサーバーを起動します。詳細は、以前の私のExternal Flowに関する記事をご参照ください。

以下は、EUR/USDとGBP/USDの通貨ペアを対象に実施したテスト結果の概要です。最良の結果を得るために、EAで指定した通貨ペアと同じペアを使ってシステムをテストすることを推奨します。初期のコマンドプロンプトのログには、システムが正常に初期化されたことが示されており、MQL5 EAからMetaTrader 5経由でPythonサーバーに送信されたデータ(4月2日から4月9日までの期間の始値、終値、時間など)が明確に表示されています。ログの"POST /analyze HTTP/1.1" 200という記録は、接続が成功し、Pythonサーバーが期待どおりに処理を実行したことを確認しています。

DEBUG:plotter:Raw request data: {"symbol1":"EURUSD","symbol2":"GBPUSD","data1":[{"time":"2025.04.09 07:00:00"
,"close":1.10766},{"time":"2025.04.09 06:45:00","close":1.10735},{"time":"2025.04.09 06:30:00","close":1.10602}
,{"time":"2025.04.09 06:15:00","close":1.10538},{"time":"2025.04.09 06:00:00","close":1.10486},
{"time":"2025.04.09 05:45:00","close":1.10615},{"time":"2025.04.09 05:30:00","close":1.10454},
{"time":"2025.04.09 05:15:00","close":1.10402},{"time":"2025.04.09 05:00:00","close":1.10447},
{"time":"2025.04.09 04:45:00","close":1.10685},{"time":"2025.04.09 04:30:00","close":1.10582},
{"time":"2025.04.09 04:15:00","close":1.10617},{"time":"2025.04.09 04:00:00","close":1.10384},
{"time":"2025.04.09 03:45:00","close":1.10196},{"time":"2025.04.09 03:30:00","close":1.10184},
{"time":"2025.04.09 03:15:00","close":1.10339},{"time":"2025.04.09 03:00:00","close":1.10219},
{"time":"2025.04.09 02:45:00","close":1.10197},{"time":"2025.04.09 02:30:00","close":1.10130},
{"time":"2025.04.09 02:15:00","close":1.10233},{"time":"2025.04.09 02:00:00","close":1.10233},
{"time":"2025.04.09 01:45:00","close":1.10200},{"time":"2025.04.09 01:30:00","close":1.10289},
{"time":"2025.04.09 01:15:00","close":1.10382},{"time":"2025.04.09 01:00:00","close":1.10186},
{"time":"2025.04.09 00:45:00","close":1.10148},{"time":"2025.04.09 00:30:00","close":1.09985},
{"time":"2025.04.09 00:15:00","close":1.09894},{"time":"2025.04.09 00:00:00","close":1.09747},
{"time":"2025.04.08 23:45:00","close":1.09776},{"time":"2025.04.08 23:30:00","close":1.09789},
{"time":"2025.04.08 23:15:00","close":1.09793},{"time":"2025.04.08 23:00:00","close":1.09740},
{"time":"2025.04.08 22:45:00","close":1.09681},{"time":"2025.04.08 22:30:00","close":1.09718},
{"time":"2025.04.08 22:15:00","close":1.09669},{"time":"2025.04.08 22:00:00","close":1.09673},
{"time":"2025.04.08 21:45:00","close":1.09586},{"time":"2025.04.08 21:30:00","close":1.09565},
{"time":"2025.04.08 21:15:00","close":1.09507},{"time":"2025.04.08 21:00:00","close":1.09493},
{"time":"2025.04.08 20:45:00","close":1.09529},{"time":"2025.04.08 20:30:00","close":1.09442},
{"time":"2025.04.08 20:15:00","close":1.09417},{"time":"2025.04.08 20:00:00","close":1.09533},
{"time":"2025.04.08 19:45:00","close":1.09541},{"time":"2025.04.08 19:30:00","close":1.09587},
{"time":"2025.04.08 19:15:00","close":1.09684},{"time":"2025.04.08 19:00:00","close":1.09724},
{"time":"2025.04.08 18:45:00","close":1.09521},{"time":"2025.04.08 18:30:00","close":1.09551},
{"time":"2025.04.08 18:15:00","close":1.09561},{"time":"2025.04.08 18:00:00","close":1.09474},
{"time":"2025.04.08 17:45:00","close":1.09337},{"time":"2025.04.08 17:30:00","close":1.09334},
{"time":"2025.04.08 17:15:00","close":1.09421},{"time":"2025.04.08 17:00:00","close":1.09429},
{"time":"2025.04.08 16:45:00","close":1.09296},{"time":"2025.04.08 16:30:00","close":1.09210},
{"time":"2025.04.08 16:15:00","close":1.09123},{"time":"2025.04.08 16:00:00","close":1.09073},
{"time":"2025.04.08 15:45:00","close":1.09116},{"time":"2025.04.08 15:30:00","close":1.09083},
{"time":"2025.04.08 15:15:00","close":1.09119},{"time":"2025.04.08 15:00:00","close":1.08986},
{"time":"2025.04.08 14:45:00","close":1.09102},{"time":"2025.04.08 14:30:00","close":1.08954},
{"time":"2025.04.08 14:15:00","close":1.09051},{"time":"2025.04.08 14:00:00","close":1.09213},
{"time":"2025.04.08 13:45:00","close":1.09357},{"time":"2025.04.08 13:30:00","close":1.09300},
{"time":"2025.04.08 13:15:00","close":1.09548},{"time":"2025.04.08 13:00:00","close":1.09452},
{"time":"2025.04.08 12:45:00","close":1.09485},{"time":"2025.04.08 12:30:00","close":1.09585},
{"time":"2025.04.08 12:15:00","close":1.09477},{"time":"2025.04.08 12:00:00","close":1.09512},
{"time":"2025.04.08 11:45:00","close":1.09342},{"time":"2025.04.08 11:30:00","close":1.09311},
{"time":"2025.04.07 09:45:00","close":1.09627},{"time":"2025.04.07 09:30:00","close":1.09545},
{"time":"2025.04.07 09:15:00","close":1.09597},{"time":"2025.04.07 09:00:00","close":1.09729},
{"time":"2025.04.07 08:45:00","close":1.09918},{"time":"2025.04.07 08:30:00","close":1.09866},
{"time":"2025.04.07 08:15:00","close":1.09705},{"time":"2025.04.07 08:00:00","close":1.10051},
{"time":"2025.04.07 07:45:00","close":1.10006},{"time":"2025.04.07 07:30:00","close":1.10232},
{"time":"2025.04.07 07:15:00","close":1.10273},{"time":"2025.04.07 07:00:00","close":1.10397},
{"time":"2025.04.07 06:45:00","close":1.10029},{"time":"2025.04.07 06:30:00","close":1.10083},
{"time":"2025.04.07 06:15:00","close":1.10012},{"time":"2025.04.07 06:00:00","close":1.10084},
{"time":"2025.04.07 05:45:00","close":1.10183},{"time":"2025.04.07 05:30:00","close":1.09905},
{"time":"2025.04.07 05:15:00","close":1.09941},{"time":"2025.04.07 05:00:00","close":1.09826},
{"time":"2025.04.07 04:45:00","close":1.09848},{"time":"2025.04.07 04:30:00","close":1.09830},
{"time":"2025.04.07 04:15:00","close":1.09739},{"time":"2025.04.07 04:00:00","close":1.09608},
{"time":"2025.04.07 03:45:00","close":1.09503},{"time":"2025.04.07 03:30:00","close":1.09456},
{"time":"2025.04.07 03:15:00","close":1.09373},{"time":"2025.04.07 03:00:00","close":1.09343},
{"time":"2025.04.07 02:45:00","close":1.09353},{"time":"2025.04.07 02:30:00","close":1.09248},
{"time":"2025.04.07 02:15:00","close":1.09360},{"time":"2025.04.07 02:00:00","close":1.09550},
{"time":"2025.04.07 01:45:00","close":1.09673},{"time":"2025.04.07 01:30:00","close":1.09740},
{"time":"2025.04.07 01:15:00","close":1.09688},{"time":"2025.04.07 01:00:00","close":1.09649},
{"time":"2025.04.07 00:45:00","close":1.09667},{"time":"2025.04.07 00:30:00","close":1.09526},
{"time":"2025.04.07 00:15:00","close":1.09555},{"time":"2025.04.07 00:00:00","close":1.09517},
{"time":"2025.04.06 23:45:00","close":1.09825},{"time":"2025.04.06 23:30:00","close":1.09981},
{"time":"2025.04.06 23:15:00","close":1.09872},{"time":"2025.04.06 23:00:00","close":1.09981},
{"time":"2025.04.06 22:45:00","close":1.09822},{"time":"2025.04.06 22:30:00","close":1.09803},
{"time":"2025.04.06 22:15:00","close":1.09826},{"time":"2025.04.06 22:00:00","close":1.09529},
{"time":"2025.04.06 21:45:00","close":1.09147},{"time":"2025.04.06 21:30:00","close":1.09046},
{"time":"2025.04.06 21:15:00","close":1.08910},{"time":"2025.04.06 21:00:00","close":1.08818},
{"time":"2025.04.04 20:45:00","close":1.09623},{"time":"2025.04.04 20:30:00","close":1.09435},
{"time":"2025.04.04 20:15:00","close":1.09339},{"time":"2025.04.04 20:00:00","close":1.09502},
{"time":"2025.04.04 19:45:00","close":1.09436},{"time":"2025.04.04 19:30:00","close":1.09631},
{"time":"2025.04.04 19:15:00","close":1.09425},{"time":"2025.04.04 19:00:00","close":1.09358},
{"time":"2025.04.04 18:45:00","close":1.09447},{"time":"2025.04.04 18:30:00","close":1.09611},
{"time":"2025.04.04 18:15:00","close":1.09604},{"time":"2025.04.04 18:00:00","close":1.09531},
{"time":"2025.04.04 17:45:00","close":1.09472},{"time":"2025.04.04 17:30:00","close":1.09408},
{"time":"2025.04.04 17:15:00","close":1.09311},{"time":"2025.04.04 17:00:00","close":1.09407},
{"time":"2025.04.04 16:45:00","close":1.09714},{"time":"2025.04.04 16:30:00","close":1.09690},
{"time":"2025.04.04 16:15:00","close":1.09845},{"time":"2025.04.04 16:00:00","close":1.09892},
{"time":"2025.04.04 15:45:00","close":1.10139},{"time":"2025.04.04 15:30:00","close":1.09998},
{"time":"2025.04.04 15:15:00","close":1.09837},{"time":"2025.04.04 15:00:00","close":1.09970},
{"time":"2025.04.04 14:45:00","close":1.09862},{"time":"2025.04.04 14:30:00","close":1.09706},
{"time":"2025.04.04 14:15:00","close":1.09991},{"time":"2025.04.04 14:00:00","close":1.10068},
{"time":"2025.04.04 13:45:00","close":1.10057},{"time":"2025.04.04 13:30:00","close":1.10252},
{"time":"2025.04.04 13:15:00","close":1.10288},{"time":"2025.04.04 13:00:00","close":1.10358},
{"time":"2025.04.04 12:45:00","close":1.10200},{"time":"2025.04.04 12:30:00","close":1.10289},
{"time":"2025.04.04 12:15:00","close":1.10794},{"time":"2025.04.04 12:00:00","close":1.10443},
{"time":"2025.04.04 11:45:00","close":1.10601},{"time":"2025.04.04 11:30:00","close":1.10697},
{"time":"2025.04.04 11:15:00","close":1.10502},{"time":"2025.04.04 11:00:00","close":1.10517},
{"time":"2025.04.04 10:45:00","close":1.10305},{"time":"2025.04.04 10:30:00","close":1.10340},
{"time":"2025.04.04 10:15:00","close":1.10447},{"time":"2025.04.04 10:00:00","close":1.09869},
{"time":"2025.04.04 09:45:00","close":1.09844},{"time":"2025.04.04 09:30:00","close":1.09757},
{"time":"2025.04.04 09:15:00","close":1.09820},{"time":"2025.04.04 09:00:00","close":1.09786},
{"time":"2025.04.04 08:45:00","close":1.09962},{"time":"2025.04.04 08:30:00","close":1.10002},
{"time":"2025.04.04 08:15:00","close":1.10062},{"time":"2025.04.04 08:00:00","close":1.10034},
{"time":"2025.04.04 07:45:00","close":1.10042},{"time":"2025.04.04 07:30:00","close":1.10223},
{"time":"2025.04.04 07:15:00","close":1.10490},{"time":"2025.04.04 07:00:00","close":1.10641},
{"time":"2025.04.04 06:45:00","close":1.10506},{"time":"2025.04.04 06:30:00","close":1.10638},
{"time":"2025.04.04 06:15:00","close":1.10649},{"time":"2025.04.04 06:00:00","close":1.10747},
{"time":"2025.04.04 05:45:00","close":1.10843},{"time":"2025.04.04 05:30:00","close":1.10809},
{"time":"2025.04.04 05:15:00","close":1.11057},{"time":"2025.04.04 05:00:00","close":1.10984},
{"time":"2025.04.04 04:45:00","close":1.10874},{"time":"2025.04.04 04:30:00","close":1.10896},
{"time":"2025.04.04 04:15:00","close":1.10906},{"time":"2025.04.04 04:00:00","close":1.10876},
{"time":"2025.04.04 03:45:00","close":1.10937},{"time":"2025.04.04 03:30:00","close":1.10918},
{"time":"2025.04.04 03:15:00","close":1.10766},{"time":"2025.04.04 03:00:00","close":1.10695},
{"time":"2025.04.04 02:45:00","close":1.10632},{"time":"2025.04.04 02:30:00","close":1.10668},
{"time":"2025.04.04 02:15:00","close":1.10625},{"time":"2025.04.04 02:00:00","close":1.10773},
{"time":"2025.04.04 01:45:00","close":1.10677},{"time":"2025.04.04 01:30:00","close":1.10625},
{"time":"2025.04.04 01:15:00","close":1.10610},{"time":"2025.04.04 01:00:00","close":1.10589},
{"time":"2025.04.04 00:45:00","close":1.10606},{"time":"2025.04.04 00:30:00","close":1.10603},
{"time":"2025.04.04 00:15:00","close":1.10403},{"time":"2025.04.04 00:00:00","close":1.10432},
{"time":"2025.04.03 23:45:00","close":1.10452},{"time":"2025.04.03 23:30:00","close":1.10467},
{"time":"2025.04.03 23:15:00","close":1.10446},{"time":"2025.04.03 23:00:00","close":1.10524},
{"time":"2025.04.03 22:45:00","close":1.10642},{"time":"2025.04.03 22:30:00","close":1.10631},
{"time":"2025.04.03 22:15:00","close":1.10582},{"time":"2025.04.03 22:00:00","close":1.10577},
{"time":"2025.04.03 21:45:00","close":1.10515},{"time":"2025.04.03 21:30:00","close":1.10497},
{"time":"2025.04.03 21:15:00","close":1.10505},{"time":"2025.04.03 21:00:00","close":1.10488},
{"time":"2025.04.03 20:45:00","close":1.10514},{"time":"2025.04.03 20:30:00","close":1.10448},
{"time":"2025.04.03 20:15:00","close":1.10312},{"time":"2025.04.03 20:00:00","close":1.10253},
{"time":"2025.04.03 19:45:00","close":1.10275},{"time":"2025.04.03 19:30:00","close":1.10164},
{"time":"2025.04.03 19:15:00","close":1.10192},{"time":"2025.04.03 19:00:00","close":1.10320},
{"time":"2025.04.03 18:45:00","close":1.10373},{"time":"2025.04.03 18:30:00","close":1.10362},
{"time":"2025.04.03 18:15:00","close":1.10322},{"time":"2025.04.03 18:00:00","close":1.10236},
{"time":"2025.04.03 17:45:00","close":1.10245},{"time":"2025.04.03 17:30:00","close":1.10222},
{"time":"2025.04.03 17:15:00","close":1.10273},{"time":"2025.04.03 17:00:00","close":1.10267},
{"time":"2025.04.03 16:45:00","close":1.10386},{"time":"2025.04.03 16:30:00","close":1.10404},
{"time":"2025.04.03 16:15:00","close":1.10367},{"time":"2025.04.03 16:00:00","close":1.10491},
{"time":"2025.04.03 15:45:00","close":1.10506},{"time":"2025.04.03 15:30:00","close":1.10452},
{"time":"2025.04.03 15:15:00","close":1.10613},{"time":"2025.04.03 15:00:00","close":1.10922},
{"time":"2025.04.03 14:45:00","close":1.11182},{"time":"2025.04.03 14:30:00","close":1.11197},
{"time":"2025.04.03 14:15:00","close":1.10950},{"time":"2025.04.03 14:00:00","close":1.10981},
{"time":"2025.04.03 13:45:00","close":1.10784},{"time":"2025.04.03 13:30:00","close":1.10911},
{"time":"2025.04.03 13:15:00","close":1.10943},{"time":"2025.04.03 13:00:00","close":1.11064},
{"time":"2025.04.03 12:45:00","close":1.10816},{"time":"2025.04.03 12:30:00","close":1.10910},
{"time":"2025.04.03 12:15:00","close":1.10858},{"time":"2025.04.03 12:00:00","close":1.10867},
{"time":"2025.04.03 11:45:00","close":1.10876},{"time":"2025.04.03 11:30:00","close":1.10839},
{"time":"2025.04.03 11:15:00","close":1.10570},{"time":"2025.04.03 11:00:00","close":1.10596},
{"time":"2025.04.03 10:45:00","close":1.10521},{"time":"2025.04.03 10:30:00","close":1.10696},
{"time":"2025.04.03 10:15:00","close":1.10859},{"time":"2025.04.03 10:00:00","close":1.11052},
{"time":"2025.04.03 09:45:00","close":1.10305},{"time":"2025.04.03 09:30:00","close":1.10280},
{"time":"2025.04.03 09:15:00","close":1.10336},{"time":"2025.04.03 09:00:00","close":1.10304},
{"time":"2025.04.03 08:45:00","close":1.10093},{"time":"2025.04.03 08:30:00","close":1.10092},
{"time":"2025.04.03 08:15:00","close":1.09885},{"time":"2025.04.03 08:00:00","close":1.09803},
{"time":"2025.04.03 07:45:00","close":1.09707},{"time":"2025.04.03 07:30:00","close":1.09658},
{"time":"2025.04.03 07:15:00","close":1.09497},{"time":"2025.04.03 07:00:00","close":1.09733},
{"time":"2025.04.03 06:45:00","close":1.09896},{"time":"2025.04.03 06:30:00","close":1.09775},
{"time":"2025.04.03 06:15:00","close":1.09488},{"time":"2025.04.03 06:00:00","close":1.09457},
{"time":"2025.04.03 05:45:00","close":1.09444},{"time":"2025.04.03 05:30:00","close":1.09515},
{"time":"2025.04.03 05:15:00","close":1.09431},{"time":"2025.04.03 05:00:00","close":1.09171},
{"time":"2025.04.03 04:45:00","close":1.09069},{"time":"2025.04.03 04:30:00","close":1.09104},
{"time":"2025.04.03 04:15:00","close":1.09109},{"time":"2025.04.03 04:00:00","close":1.09110},
{"time":"2025.04.03 03:45:00","close":1.09148},{"time":"2025.04.03 03:30:00","close":1.09118},
{"time":"2025.04.03 03:15:00","close":1.09196},{"time":"2025.04.03 03:00:00","close":1.09115},
{"time":"2025.04.03 02:45:00","close":1.09122},{"time":"2025.04.03 02:30:00","close":1.09207},
{"time":"2025.04.03 02:15:00","close":1.09220},{"time":"2025.04.03 02:00:00","close":1.09134},
{"time":"2025.04.03 01:45:00","close":1.09132},{"time":"2025.04.03 01:30:00","close":1.09137},
{"time":"2025.04.03 01:15:00","close":1.09078},{"time":"2025.04.03 01:00:00","close":1.08970},
{"time":"2025.04.03 00:45:00","close":1.08906},{"time":"2025.04.03 00:30:00","close":1.08995},
{"time":"2025.04.03 00:15:00","close":1.08831},{"time":"2025.04.03 00:00:00","close":1.08905},
{"time":"2025.04.02 23:45:00","close":1.09044},{"time":"2025.04.02 23:30:00","close":1.09068},
{"time":"2025.04.02 23:15:00","close":1.08874},{"time":"2025.04.02 23:00:00","close":1.08552},
{"time":"2025.04.02 22:45:00","close":1.08389},{"time":"2025.04.02 22:30:00","close":1.08277},
{"time":"2025.04.02 22:15:00","close":1.08221},{"time":"2025.04.02 22:00:00","close":1.08161},
{"time":"2025.04.02 21:45:00","close":1.08274},{"time":"2025.04.02 21:30:00","close":1.08286},
{"time":"2025.04.02 21:15:00","close":1.08156},{"time":"2025.04.02 21:00:00","close":1.08350},
{"time":"2025.04.02 20:45:00","close":1.08507},{"time":"2025.04.02 20:30:00","close":1.08184},
INFO:werkzeug:127.0.0.1 - - [09/Apr/2025 09:04:18] "POST /analyze HTTP/1.1" 200 -

以下はMetaTrader 5の[エキスパート]タブに表示されたログで、Pythonサーバーによる相関分析の解説コメントも含まれています。ログには、過去数日から現在までに受信したデータが詳細に記録されており、EUR/USDとGBP/USDの2つの通貨ペアが互いにどのように連動して動いてきたかが示されています。コメントでは、記録された期間を通じて両ペアが一般的に強い正の相関を維持していることが相関プロットから読み取れると説明されています。 

2025.04.09 00:57:33.296 Correlation Pathfinder (GBPUSD,M15)     Server response: 
{"commentary":"The overall correlation is weakly positive, suggesting occasional movement together but 
limited consistency, which may offer diversification opportunities.\nRecently, the rolling correlation is at 
0.82. This high correlation suggests near mirror-like movement. Relative strength approaches may need 
reconsideration for diversification.","correlation":0.3697032305325312,"message":"Plot saved as rolling_
correlation.png"}
これは、両通貨ペアが概ね同じ方向に動く傾向があることを示していますが、時折わずかな乖離も見られました。これらの乖離は一時的な市場の分散を示唆しており、ポートフォリオの分散投資やヘッジの潜在的な機会を浮き彫りにしています。全体として、ログはデータの正常な送信と正確な処理を確認しており、通貨ペア間の変化する関係に基づいた取引戦略の改善に役立つ洞察を提供しています。
2025.04.09 00:
57 :33.296 Correlation Pathfinder (EURUSD,M15)     Server response: 
{"commentary":"The overall correlation is weakly positive, suggesting occasional movement together but 
limited consistency, which may offer diversification opportunities.\nRecently, the rolling correlation is at
 0.83. This high correlation suggests near mirror-like movement. Relative strength approaches may need 
reconsideration for diversification.","correlation":0.33874205977082567,"message":"Plot saved as 
rolling_correlation.png"}

以下は相関プロットの分析結果です。4月2日から4月9日にかけて、EUR/USDとGBP/USDの移動相関はおおむね0.8から1.0の高い水準を維持し、両ペアが概ね連動して動いていることを示しています。一時的に相関が約0.3まで急落する場面もありましたが、これは短期間の市場イベントや通貨固有のニュースによる一時的な乖離を示唆しています。その後、相関は速やかに1.0に近い水準まで回復し、基盤となる市場の力がこれらのペアを再び連動させていることを確認できます。トレーダーは、このような一時的な相関の低下を乖離シグナルとして活用し、正常な相関水準に戻るまで監視することができます。

相関関係

図4:移動相関


結論

この図は、MetaTrader 5によるデータ取得からPythonサーバー上での分析およびコメント生成までの一連のワークフローを、視覚的にわかりやすく示しています。AからHまでラベル付けされた各ノードはプロセスの各段階を表しており、データの収集、JSON形式へのパッケージ化、サーバーへの送信、Pandasによる解析、Matplotlibによる視覚化、そして解釈を含むコメントの生成といった流れが、順を追って示されています。

日付 ツール名  詳細 バージョン  アップデート  備考
01/10/24 ChartProjector 前日のプライスアクションをゴースト効果でオーバーレイするスクリプト 1.0 初回リリース ツール番号1
18/11/24 Analytical Comment 前日の情報を表形式で提供し、市場の将来の方向性を予測する 1.0 初回リリース ツール番号2
27/11/24 Analytics Master 2時間ごとに市場指標を定期的に更新  1.01 v.2 ツール番号3
02/12/24 Analytics Forecaster  Telegram統合により、2時間ごとに市場指標を定期的に更新 1.1 v.3 ツール番号4
09/12/24 Volatility Navigator ボリンジャーバンド、RSI、ATR指標を使用して市場の状況を分析するEA 1.0 初回リリース ツール番号5
19/12/24 Mean Reversion Signal Reaper  平均回帰戦略を用いて市場を分析し、シグナルを提供する  1.0  初回リリース  ツール番号6 
9/01/25  Signal Pulse  多時間枠分析ツール 1.0  初回リリース  ツール番号7 
17/01/25  Metrics Board  分析用のボタン付きパネル  1.0  初回リリース ツール番号8 
21/01/25 External Flow 外部ライブラリによる分析 1.0  初回リリース ツール番号9 
27/01/25 VWAP 出来高加重平均価格   1.3  初回リリース  ツール番号10 
02/02/25  Heikin Ashi  トレンドの平滑化と反転シグナルの識別  1.0  初回リリース  ツール番号11
04/02/25  FibVWAP  Python分析によるシグナル生成  1.0  初回リリース  ツール番号12
14/02/25  RSI DIVERGENCE  プライスアクションとRSIのダイバージェンス  1.0  初回リリース  ツール番号13 
17/02/25  Parabolic Stop and Reverse (PSAR)  PSAR戦略の自動化 1.0 初回リリース  ツール番号14
20/02/25  Quarters Drawerスクリプト チャートにクォーターレベルを描く  1.0  初回リリース  ツール番号15 
27/02/25  Intrusion Detector 価格がクォーターレベルに達したときに検出して警告する 1.0   初回リリース ツール番号16 
27/02/25  TrendLoom Tool  多時間枠分析パネル 1.0 初回リリース ツール番号17
11/03/25  Quarters Board  クォーターレベルを有効または無効にするボタン付きのパネル  1.0  初回リリース ツール番号18
26/03/25  ZigZag Analyzer  ジグザグインジケーターを使ったトレンドラインの描画  1.0  初回リリース  ツール番号19 
10/04/25  Correlation Pathfinder Pythonライブラリを使用して通貨の相関関係をプロットする 1.0 初回リリース  ツール番号20 

MetaQuotes Ltdにより英語から翻訳されました。
元の記事: https://www.mql5.com/en/articles/17742

添付されたファイル |
plotter.py (4.46 KB)
既存のMQL5取引戦略へのAIモデルの統合 既存のMQL5取引戦略へのAIモデルの統合
このトピックでは、強化学習モデル(LSTMなど)や機械学習ベースの予測モデルのような訓練済みAIモデルを、既存のMQL5取引戦略に組み込むことに焦点を当てています。
オープニングレンジブレイクアウト日中取引戦略の解読 オープニングレンジブレイクアウト日中取引戦略の解読
オープニングレンジブレイクアウト(ORB)戦略は、市場が開いた直後に形成される初期の取引レンジが、買い手と売り手が価値に合意する重要な価格レベルを反映しているという考えに基づいて構築されています。特定のレンジを上抜けまたは下抜けするブレイクアウトを特定することで、市場の方向性が明確になるにつれて発生することが多いモメンタムを利用し、トレーダーは利益を狙うことができます。本記事では、Concretum Groupの論文から応用した3つのORB戦略を紹介します。
初心者からエキスパートへ:ローソク足のプログラミング 初心者からエキスパートへ:ローソク足のプログラミング
この記事では、MQL5プログラミングの第一歩を、完全な初心者でも理解できるように解説します。よく知られているローソク足パターンを、実際に機能するカスタムインジケーターへと変換する方法を紹介します。ローソク足パターンは、実際の価格変動を反映し、市場の転換を示唆するため、非常に有用です。チャートを目視で確認してパターンを探す手法ではミスや非効率が生じやすいため、この記事では、パターンを自動的に識別・ラベル付けしてくれるインジケーターを作成する方法を説明します。その過程で、インデックス(索引)、時系列、ATR(市場の変動性に応じた精度向上のため)などの重要な概念についても解説し、今後のプロジェクトで再利用可能なカスタムローソク足パターンライブラリの開発にも触れていきます。
ダイナミックマルチペアEAの形成(第2回):ポートフォリオの分散化と最適化 ダイナミックマルチペアEAの形成(第2回):ポートフォリオの分散化と最適化
ポートフォリオの分散化と最適化とは、複数の資産に戦略的に投資を分散しながら、リスク調整後のパフォーマンス指標に基づいてリターンを最大化する理想的な資産配分を選定する手法です。