MetaTrader 5 と Python:公式パッケージか、ローカル Socket ブリッジか

MetaTrader 5 と Python:公式パッケージか、ローカル Socket ブリッジか

MetaTrader 5 と Python を接続する実用的な方法は、主に二つあります。

  1. MetaQuotes 公式の MetaTrader5 Python パッケージで、ローカルの MetaTrader 5 ターミナルと通信する。
  2. MQL5 の Expert Advisor またはスクリプトと Python サービスの間で、Socket を使ってメッセージを交換する。

Python からターミナルの状態、口座情報、銘柄、ティック、バーへアクセスしたいなら、公式パッケージが短い経路です。Expert Advisor 側に制御を残し、Python は計算やモデルの結果だけを返すなら、Socket ブリッジが向いています。

以下の例は、ターミナル情報を読み取るか、中立的な Socket 応答を返すだけです。注文は送信しません。すべての自動化はまずデモ口座で試し、通信障害時は何もしない設計にしてください。

MetaTrader5 パッケージの現在の対応環境

2026 年 9 月 9 日時点で、PyPI の `MetaTrader5` 最新リリースは 5.0.6180 です。Windows x86-64 向け CPython wheel だけがあり、ソース配布はありません。実際には、64 ビット Windows 上でパッケージと MetaTrader 5 ターミナルを動かす構成になります。Linux や macOS で通常の pip install MetaTrader5 を実行しても、一致する公式パッケージはありません。

MetaQuotes は、このパッケージを MetaTrader 5 ターミナルとのプロセス間接続として説明しています。ブローカーから独立した市場データ API ではありません。表示される銘柄、履歴、口座状態、権限は、接続先ターミナルと、そのターミナルに設定された取引口座から得られます。

システムの Python へ直接入れず、仮想環境へインストールします。

py -m venv .venv
..venvScriptspython.exe -m pip install --upgrade pip
..venvScriptspython.exe -m pip install MetaTrader5

一致する配布がないと pip に表示された場合は、64 ビット版 CPython かどうか、使用中の Python バージョンに対応する wheel が PyPI のファイル一覧にあるかを確認してください。

認証情報をコードへ書かずに接続する

最も単純な方法は、ターミナルで現在選択されている口座を使うことです。

import MetaTrader5 as mt5

if not mt5.initialize():
    raise RuntimeError(f"initialize() failed: {mt5.last_error()}")

try:
    print("Python package:", mt5.__version__)
    print("Terminal version:", mt5.version())
finally:
    mt5.shutdown()

`initialize()` のリファレンスによれば、必要な場合はこの呼び出しがターミナルを起動します。MetaTrader が複数インストールされているなら、対象の実行ファイルを明示します。

import MetaTrader5 as mt5

terminal = r"C:Program FilesMetaTrader 5terminal64.exe"

if not mt5.initialize(terminal, timeout=60_000):
    raise RuntimeError(f"initialize() failed: {mt5.last_error()}")

try:
    print(mt5.version())
finally:
    mt5.shutdown()

口座パスワードをソースコード、Notebook、スクリーンショット、ログへ書かないでください。ターミナルに保存されたセッションだけで足りるなら、ログイン情報自体を渡す必要はありません。

直近のバーを安全に読み取る

次の例は、銘柄を Market Watch で有効にし、バーを要求し、空の結果を処理し、最後に必ずパッケージ接続を閉じます。

from datetime import datetime, timezone

import MetaTrader5 as mt5

symbol = "EURUSD"
timeframe = mt5.TIMEFRAME_M1
start_position = 1  # skip the current, still-forming bar
count = 100

if not mt5.initialize():
    raise RuntimeError(f"initialize() failed: {mt5.last_error()}")

try:
    if not mt5.symbol_select(symbol, True):
        raise RuntimeError(
            f"symbol_select({symbol!r}) failed: {mt5.last_error()}"
        )

    rates = mt5.copy_rates_from_pos(
        symbol,
        timeframe,
        start_position,
        count,
    )

    if rates is None or len(rates) == 0:
        raise RuntimeError(f"no bars returned: {mt5.last_error()}")

    for row in rates[:5]:
        opened = datetime.fromtimestamp(int(row["time"]), tz=timezone.utc)
        print(opened.isoformat(), row["open"], row["high"], row["low"], row["close"])
finally:
    mt5.shutdown()

ブローカーによっては EURUSD.a のように銘柄名が異なるため、固定名を前提にせずターミナルで確認します。`copy_rates_from_pos()`では位置 0 が形成中の現在バーです。確定バーだけを計算に使うなら位置 1 から取得します。取得できる履歴は、ターミナルの Max. bars in chart 設定にも制限されます。MetaQuotes は `copy_rates_from()` の注意事項でバーとティックの時刻を UTC と説明しているため、Python 側でもタイムゾーン付き UTC を使います。

最初のテストでは注文を送らない

パッケージには order_check()order_send() がありますが、チェックの成功は約定を保証しません。執行規則、注文の充填方式、銘柄名、取引時間、取引数量の刻み、権限、戻り値は、ターミナル、ブローカー、口座、銘柄によって異なります。

次の順で接続を組み立てます。

  1. パッケージとターミナルのバージョンを確認する。
  2. ターミナル情報と銘柄情報を読み取る。
  3. 少量のバーを取得し、時刻を検証する。
  4. 認証情報や不要な口座識別子を残さず、エラーを記録する。
  5. その後で、明示的にレビューした注文要求をデモ口座で試す。

注文処理では、last_error() と返された取引結果の両方を確認します。`order_check()`は検証の一段階であり、約定の約束ではありません。要求と結果の構造は、`order_send()` のリファレンスで確認してください。

Socket ブリッジが適切な境界になる場合

Socket ブリッジでは、MetaTrader に接するループを MQL5 に残し、Python を別サービスとして扱います。次のような場合に有用です。

  • 既存の Expert Advisor がタイミングと注文状態を管理している。
  • MQL5 では実装しにくい計算を Python が担当する。
  • バージョン付きの独自メッセージ仕様が必要。
  • Python が停止しても MQL5 側が安全に動作を続けなければならない。

MetaTrader のネットワーク関数ドキュメントでは、接続先アドレスを Tools > Options > Expert Advisors へ手動で追加する必要があります。Socket 関数を呼べるのは Expert Advisor とスクリプトで、インジケーターからは呼べません。`SocketConnect()` には有限の接続タイムアウトが必要です。さらに `SocketTimeouts()` で送受信のタイムアウトを設定してください。既定値の 0 では無期限に待つことがあります。

同一マシン内のブリッジなら、Python は 0.0.0.0 ではなく 127.0.0.1 に bind します。通常の TCP はメッセージを認証も暗号化もしません。別のマシンで Python サービスを動かす必要がある場合は、認証のない取引制御ポートを公開せず、認証と TLS を備えた保護されたネットワーク設計を使ってください。

次は、メッセージ境界を試すための、接続ごとに1件だけ処理する小さなサーバーです。

import json
import socket

HOST = "127.0.0.1"
PORT = 9090
MAX_MESSAGE = 64 * 1024

with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as server:
    server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    server.bind((HOST, PORT))
    server.listen(5)
    print(f"Listening on {HOST}:{PORT}")

    while True:
        conn, address = server.accept()
        with conn:
            conn.settimeout(5)
            with conn.makefile("rwb") as stream:
                try:
                    line = stream.readline(MAX_MESSAGE + 1)
                except OSError:
                    continue

                if not line or len(line) > MAX_MESSAGE or not line.endswith(b"n"):
                    reply = {"status": "error", "action": "none"}
                else:
                    try:
                        request = json.loads(line.decode("utf-8"))
                        if not isinstance(request, dict):
                            raise ValueError("request must be a JSON object")
                        request_id = request.get("request_id")
                        if (
                            not isinstance(request_id, str)
                            or not request_id.strip()
                            or len(request_id) > 128
                        ):
                            raise ValueError("invalid request_id")
                        reply = {
                            "status": "ok",
                            "request_id": request_id,
                            "action": "none",
                        }
                    except (UnicodeDecodeError, json.JSONDecodeError, ValueError):
                        reply = {"status": "error", "action": "none"}

                try:
                    stream.write(json.dumps(reply).encode("utf-8") + b"n")
                    stream.flush()
                except OSError:
                    continue

これはフレーミングを確認する例であり、本番用の取引サービスではありません。実際のプロトコルには、バージョン、要求 ID、時刻、厳密なフィールド検証、メッセージサイズ上限、冪等性の規則が必要です。MQL5 側では `SocketConnect()``SocketTimeouts()` を使い、古い応答や不正な応答を拒否し、タイムアウトまたは切断時は何もしない状態へ戻します。

どちらを選ぶか

対応する Windows 上で Python を動かし、MetaTrader ターミナルがローカルにあり、Python からターミナルデータや口座状態へ直接アクセスしたいなら、公式パッケージを使います。

Expert Advisor に制御を残したい、Python を限定された計算サービスにしたい、またはパッケージの手軽さより独自のメッセージ契約を重視するなら、Socket ブリッジを使います。

どちらの場合も、まず読み取り専用で始め、パッケージとターミナルの正確なバージョンを記録し、ブローカー固有の銘柄名で試し、認証情報をコードへ書かず、通信障害時には即興の代替処理ではなく「取引しない」結果を返してください。

コピー用のテンプレートではなく、実際のプロジェクトでの使い方を確認する例として、MicroQuant の MT5 クライアント を参照できます。公式パッケージによるターミナルの初期化と OHLC バーの取得を示すもので、Socket 方式の例ではありません。同じファイルには実注文を送る経路も含まれるため、十分に監査し、デモ口座だけで試してください。

一次資料

2026 年 9 月 9 日確認:

Leave a Reply