MT5 Python API 完全ガイド|導入から注文送信まで

この記事の結論

MT5 Python APIは、PythonスクリプトからMetaTrader 5ターミナルへ接続し、価格データ取得、口座確認、ポジション確認、注文前検証、注文送信を行うための仕組みです。
初心者は、initialize()last_error()copy_rates_from()positions_get()order_check()order_send()shutdown() の順に理解すると全体像をつかみやすくなります。
分析専用の処理と注文を送る処理は分離してください。注文送信を実装する場合は、デモ口座で動作を確認し、銘柄仕様、ロット、証拠金、スプレッド、約定方式を事前に検証する必要があります。

1. MT5 Python APIとは

【結論】MT5 Python APIは、PythonからMetaTrader 5ターミナルへ接続して、相場データや取引情報を扱うためのAPIです。Pythonの分析処理とMT5の取引環境を接続できます。

MT5 Python APIを使うと、ローソク足、ティック、口座情報、注文、ポジション、取引履歴をPython側で扱えます。取得したデータは、集計、可視化、統計分析、機械学習用データの作成に利用できます。

Pythonスクリプトは、単独で取引サーバーへ直接接続するのではありません。基本構造は、PythonスクリプトからMetaTrader 5ターミナルへ接続し、ターミナルを経由して必要な情報を扱う流れです。

MT5 Python APIでできること

  • MT5ターミナルへの接続と切断
  • 口座情報とターミナル情報の取得
  • 銘柄情報、Bid、Askの取得
  • ローソク足とティックデータの取得
  • 現在の注文とポジションの確認
  • 注文前の証拠金確認
  • 注文リクエストの送信
  • 注文履歴と約定履歴の取得

2. 導入前に理解しておくこと

【結論】最初に、MT5 Python APIはMQL5プログラムと同じものではないと理解してください。Python APIは外部スクリプトからターミナルを操作する仕組みであり、EAのイベント関数をそのまま使う仕組みではありません。

MQL5のEAは、一般的に OnInit()OnTick()OnDeinit() などのイベント関数で動作します。一方、Pythonスクリプトでは、自分で接続、データ取得、判定、待機、終了処理の順序を組み立てます。

方法メリットデメリット向いている場面
Pythonスクリプト分析ライブラリを使いやすい常時監視や再接続を自分で設計する必要があるデータ分析、検証ツール、外部処理連携
MQL5 EAティックや取引イベントに合わせて動かしやすいPythonの分析資産を直接使いにくい場合があるMT5内で完結する自動売買、低遅延の監視
PythonとMQL5の役割分担分析と執行の責務を分離しやすい連携方式と障害時処理の設計が必要になる分析処理が複雑なシステム

初心者は、最初に分析専用スクリプトを作成してください。注文送信を後から追加すると、接続不良と注文条件不良を切り分けやすくなります。

3. インストールと接続

【結論】Python側では MetaTrader5 パッケージを導入し、initialize() でMT5ターミナルへ接続します。接続に失敗した場合は、last_error() の内容を確認してください。

パッケージは次のコマンドで導入できます。

pip install MetaTrader5

更新する場合は次のコマンドを使います。

pip install --upgrade MetaTrader5

最小構成の接続確認コードは次のとおりです。

import MetaTrader5 as mt5


def main() -> None:
    if not mt5.initialize():
        raise RuntimeError(f"initialize() failed: {mt5.last_error()}")

    try:
        print("terminal:", mt5.terminal_info())
        print("version:", mt5.version())
        print("account:", mt5.account_info())
    finally:
        mt5.shutdown()


if __name__ == "__main__":
    main()

initialize() は、引数なしで接続先ターミナルを探索できます。複数のMT5ターミナルを使い分ける環境では、対象となる実行ファイルのパスを明示すると接続先を管理しやすくなります。

if not mt5.initialize(r"C:\Path\To\terminal64.exe"):
    raise RuntimeError(f"initialize() failed: {mt5.last_error()}")

口座番号、パスワード、サーバー名をコードへ直接書くと、漏えいリスクが高くなります。認証情報が必要な場合は、環境変数や権限を制限した設定ファイルで管理してください。

4. よく使う関数の全体像

【結論】MT5 Python APIは、接続、情報取得、価格データ取得、取引管理、履歴取得の5グループに分けると理解しやすくなります。最初から全関数を覚える必要はありません。

分類主な関数役割
接続initialize()login()shutdown()ターミナルへの接続、口座ログイン、切断
エラーと環境last_error()terminal_info()account_info()エラー、ターミナル、口座の状態確認
銘柄symbols_get()symbol_info()symbol_info_tick()symbol_select()銘柄一覧、仕様、Bid、Ask、表示状態の確認
価格データcopy_rates_from()copy_rates_range()copy_ticks_from()ローソク足とティックの取得
注文とポジションorders_get()positions_get()order_check()order_send()注文、ポジション、注文前検証、注文送信
履歴history_orders_get()history_deals_get()注文履歴と約定履歴の取得
MT5 Python API execution flow from initialize() and rate retrieval to order_check(), order_send(), last_error(), and shutdown().

分析専用スクリプトでは、接続、銘柄確認、価格データ取得、切断までで十分な場合があります。注文を送る処理は別モジュールへ分けると、意図しない実行を防ぎやすくなります。

5. ローソク足データを取得する方法

【結論】ローソク足データは copy_rates_from() で取得できます。返り値が None でないことと、必要な件数が取得できたことを確認してください。

copy_rates_from() は、銘柄、時間足、開始日時、件数を指定してバーを取得します。取得結果には、時刻、始値、高値、安値、終値、ティックボリューム、スプレッド、実ボリュームが含まれます。

from datetime import datetime, timezone

import MetaTrader5 as mt5
import pandas as pd


def get_rates(symbol: str, count: int = 300) -> pd.DataFrame:
    start = datetime(2025, 1, 1, tzinfo=timezone.utc)
    rates = mt5.copy_rates_from(symbol, mt5.TIMEFRAME_H1, start, count)

    if rates is None:
        raise RuntimeError(f"copy_rates_from() failed: {mt5.last_error()}")

    if len(rates) < count:
        print(f"warning: requested={count}, received={len(rates)}")

    frame = pd.DataFrame(rates)
    frame["time"] = pd.to_datetime(frame["time"], unit="s", utc=True)
    return frame


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

try:
    print(get_rates("EURUSD").tail())
finally:
    mt5.shutdown()

MT5側のバーとティックの時刻はUTCとして扱います。Pythonの datetime を作るときも、UTCを明示すると時差による取得範囲のずれを避けやすくなります。

必要な履歴件数が取得できない場合は、MT5ターミナルに読み込まれている履歴範囲も確認してください。取得件数不足を無視すると、移動平均や特徴量の計算結果が不安定になります。

6. 銘柄情報と現在価格を確認する方法

【結論】注文や分析の前に、symbol_info()symbol_info_tick() で銘柄仕様と現在価格を確認します。銘柄が非表示の場合は、symbol_select() でMarket Watchへ追加できる場合があります。

import MetaTrader5 as mt5


def get_symbol_snapshot(symbol: str):
    info = mt5.symbol_info(symbol)
    if info is None:
        raise RuntimeError(f"symbol_info() failed: {symbol}, {mt5.last_error()}")

    if not info.visible and not mt5.symbol_select(symbol, True):
        raise RuntimeError(f"symbol_select() failed: {symbol}, {mt5.last_error()}")

    tick = mt5.symbol_info_tick(symbol)
    if tick is None:
        raise RuntimeError(f"symbol_info_tick() failed: {symbol}, {mt5.last_error()}")

    return info, tick

ブローカーによって銘柄名が異なる場合があります。たとえば、接尾辞付きの銘柄名が使われる環境では、固定文字列の EURUSD がそのまま使えないことがあります。

7. ポジションと注文を確認する方法

【結論】保有ポジションは positions_get()、未決済注文は orders_get() で確認します。None は取得エラーの可能性があり、空の結果とは分けて扱う必要があります。

import MetaTrader5 as mt5


def show_positions(symbol: str) -> None:
    positions = mt5.positions_get(symbol=symbol)

    if positions is None:
        raise RuntimeError(f"positions_get() failed: {mt5.last_error()}")

    if not positions:
        print(f"no open positions: {symbol}")
        return

    for position in positions:
        print(
            position.ticket,
            position.symbol,
            position.volume,
            position.price_open,
            position.profit,
        )

MT5では、netting口座とhedging口座でポジションの持ち方が異なります。netting口座では、同一銘柄のポジションが集約されます。hedging口座では、同一銘柄で複数のポジションを持てるため、決済対象のチケットを明確に管理してください。

8. 注文前チェックと注文送信

【結論】注文処理では、order_send() の前に order_check() を実行してください。order_check() が成功しても約定は保証されないため、送信結果の retcode も必ず確認します。

注文処理では、少なくとも次の条件を確認します。

  • 自動売買が許可されているか
  • 銘柄が取引可能か
  • 銘柄名が環境に合っているか
  • 最小ロット、最大ロット、ロットステップに合っているか
  • 証拠金が不足していないか
  • スプレッドが許容範囲か
  • 損切りと利確がストップレベルに抵触しないか
  • 約定方式と type_filling が銘柄仕様に合っているか
  • 既存ポジションと口座タイプを考慮しているか

次のコードは、注文リクエストを作成して order_check() まで実行する検証用サンプルです。order_send() は呼び出さないため、このコードだけでは注文は送信されません。

import MetaTrader5 as mt5


def validate_buy_request(symbol: str, volume: float):
    info = mt5.symbol_info(symbol)
    if info is None:
        raise RuntimeError(f"symbol_info() failed: {symbol}, {mt5.last_error()}")

    if not info.visible and not mt5.symbol_select(symbol, True):
        raise RuntimeError(f"symbol_select() failed: {symbol}, {mt5.last_error()}")

    tick = mt5.symbol_info_tick(symbol)
    if tick is None:
        raise RuntimeError(f"symbol_info_tick() failed: {symbol}, {mt5.last_error()}")

    if volume < info.volume_min or volume > info.volume_max:
        raise ValueError("volume is outside symbol limits")

    steps = round((volume - info.volume_min) / info.volume_step)
    normalized_volume = info.volume_min + steps * info.volume_step
    if abs(normalized_volume - volume) > 1e-9:
        raise ValueError("volume does not match volume_step")

    request = {
        "action": mt5.TRADE_ACTION_DEAL,
        "symbol": symbol,
        "volume": volume,
        "type": mt5.ORDER_TYPE_BUY,
        "price": tick.ask,
        "deviation": 10,
        "magic": 20250601,
        "comment": "python validation sample",
        "type_time": mt5.ORDER_TIME_GTC,
        "type_filling": mt5.ORDER_FILLING_RETURN,
    }

    check = mt5.order_check(request)
    if check is None:
        raise RuntimeError(f"order_check() failed: {mt5.last_error()}")

    return request, check

実際に送信する処理では、注文前チェックを通過したリクエストだけを order_send() へ渡し、戻り値と retcode を記録します。

def send_checked_request(request: dict):
    check = mt5.order_check(request)
    if check is None:
        raise RuntimeError(f"order_check() failed: {mt5.last_error()}")

    if check.retcode != 0:
        raise RuntimeError(f"order_check() rejected: {check}")

    result = mt5.order_send(request)
    if result is None:
        raise RuntimeError(f"order_send() failed: {mt5.last_error()}")

    if result.retcode != mt5.TRADE_RETCODE_DONE:
        raise RuntimeError(f"order_send() rejected: {result}")

    return result

この送信関数は検証用の最小例です。実運用では、銘柄ごとの約定方式、スプレッド上限、損切り、利確、取引時間、既存ポジション、ログ保存、再送条件を追加してください。type_filling は銘柄仕様に合わせて調整する必要があります。

9. エラー処理の考え方

【結論】MT5 Python APIでは、関数の失敗と注文の不成立を分けて確認します。関数が NoneFalse を返した場合は last_error() を確認し、注文送信後は結果オブジェクトの retcode を確認してください。

よくある切り分け手順は次のとおりです。

  1. initialize() が成功しているか確認する
  2. terminal_info()account_info() を表示する
  3. symbol_info() で銘柄名を確認する
  4. symbol_select() で銘柄を表示する
  5. symbol_info_tick() が値を返すか確認する
  6. order_check() の戻り値を確認する
  7. order_send() の戻り値と retcode を確認する
  8. 失敗時の入力値とエラー内容をログへ保存する

last_error() はライブラリ関数の失敗確認に使います。order_send() が結果オブジェクトを返した後は、retcode による取引結果の確認が必要です。

10. 安全な設計パターン

【結論】安全性を高めるには、分析、判定、リスク確認、注文前チェック、注文送信、ポジション管理、ログ出力を分離します。1つの関数へ処理を詰め込むと、障害時の切り分けが難しくなります。

推奨する構造は次のとおりです。

モジュール役割主な確認事項
接続管理MT5への接続、再接続、切断接続先、タイムアウト、終了処理
データ取得バー、ティック、銘柄仕様の取得UTC、欠損、取得件数
シグナル判定分析結果から候補を作る確定足、過剰最適化
リスク確認ロット、損切り幅、許容損失の確認最小ロット、最大ロット、ロットステップ
注文前チェックリクエストの検証証拠金、スプレッド、ストップレベル
注文送信検証済みリクエストだけを送るretcode、再送条件、ログ
ポジション管理保有状態と決済対象の管理netting口座、hedging口座、チケット

分析専用モードと注文許可モードを設定で分離すると、検証時の誤送信を防ぎやすくなります。実運用では、注文許可を初期状態で無効にする設計が扱いやすくなります。

11. バックテストとフォワードテスト

【結論】Pythonで作成した売買ロジックは、データ上の検証だけでなく、デモ口座を使ったフォワードテストが必要です。バックテスト結果は将来の利益を保証しません。

バックテストで確認する項目

  • 総損益
  • 最大ドローダウン
  • 勝率
  • 損益比
  • 取引回数
  • 連敗数
  • スプレッド条件
  • 期間依存性
  • パラメータ依存性
  • データ欠損と時刻ずれ

フォワードテストで確認する項目

  • バックテストとの乖離
  • スプレッド拡大時の挙動
  • 約定遅延とスリッページ
  • 注文拒否時の処理
  • 取引頻度
  • ドローダウン
  • ブローカー条件の差
  • デモ口座とリアル口座の約定条件差
  • VPSや常時実行環境での安定性
  • 切断後の再接続と二重注文防止

レバレッジが高いほど、同じ価格変動でも損益とドローダウンが大きくなりやすくなります。ロット計算と停止条件は、売買シグナルとは別に検証してください。

12. よくある失敗

【結論】初心者が遭遇しやすい問題は、接続先、銘柄名、時刻、取得件数、ロット、約定方式、口座タイプの見落としです。エラーを一括で扱わず、処理段階ごとに確認してください。

MT5へ接続できない

initialize() の戻り値と last_error() を確認します。複数ターミナルがある場合は、対象となる実行ファイルのパスを明示します。

ローソク足が取得できない

銘柄名、時間足、UTC、ターミナルに読み込まれている履歴範囲を確認します。None と取得件数不足を分けて処理します。

注文前チェックで拒否される

ロット、証拠金、ストップレベル、取引時間、銘柄の約定方式を確認します。ブローカー仕様により利用できる条件は異なります。

注文送信後に想定どおり約定しない

order_send() の呼び出し成功だけで判断せず、結果の retcode、約定価格、コメントを保存します。スプレッド、スリッページ、約定遅延により結果は変わる場合があります。

ポジション決済の対象がずれる

netting口座とhedging口座の違いを確認し、必要に応じてポジションチケットを指定します。銘柄だけで管理すると、複数ポジション環境で対象を誤る可能性があります。

13. 実運用での注意点

【結論】MT5 Python APIを使った自動売買では、接続が成功することと、安定して運用できることは別問題です。実運用前にデモ口座でフォワードテストを行い、停止条件と復旧条件を決めてください。

実運用では、次のリスクを考慮します。

  • スプレッド拡大で成績が悪化する場合がある
  • 約定遅延やスリッページが発生する場合がある
  • ブローカーの銘柄仕様により挙動が変わる場合がある
  • デモ口座とリアル口座で約定条件が異なる場合がある
  • 切断と再接続により二重注文が起きる可能性がある
  • パラメータ依存が強いロジックはフォワードテストで崩れやすい
  • 過剰最適化により再現性が低下する場合がある

注文ID、ポジションチケット、リクエスト内容、レスポンス、エラー、時刻をログへ保存してください。停止後に状態を復元できる設計にすると、障害時の確認がしやすくなります。

14. まとめ

【結論】MT5 Python APIの学習は、接続、データ取得、状態確認、注文前チェック、注文送信、終了処理の順に進めると理解しやすくなります。最初は分析専用スクリプトを作り、注文処理はデモ口座で段階的に追加してください。

重要なポイントは、last_error()retcode を使い分けること、UTCを意識すること、order_check() を注文送信前に実行すること、口座タイプとブローカー仕様の差を考慮することです。

関連する関数仕様:

FAQ

MT5 Python APIとは何ですか?

MT5 Python APIは、PythonスクリプトからMetaTrader 5ターミナルへ接続し、価格データ、口座情報、注文、ポジション、履歴を扱うための仕組みです。

MT5 Python APIを使うには何をインストールしますか?

Python環境へ MetaTrader5 パッケージを導入します。データを表形式で扱う場合は、用途に応じて pandas も利用できます。

initialize() が失敗したときは何を確認しますか?

last_error() の内容、MT5ターミナルの状態、接続対象の実行ファイル、口座設定を確認します。複数ターミナルがある環境では、対象パスを明示すると切り分けやすくなります。

ローソク足データはどの関数で取得しますか?

開始日時と件数を指定する場合は copy_rates_from() を使えます。取得結果が None でないことと、必要件数がそろっていることを確認してください。

MT5 Python APIの時刻は何に注意しますか?

バーとティックの時刻はUTCとして扱います。Python側でもタイムゾーン付きの datetime を使うと、取得範囲のずれを避けやすくなります。

order_check() が成功すれば注文は必ず約定しますか?

いいえ。order_check() は注文前の検証に使いますが、約定を保証するものではありません。注文送信後は order_send() の結果と retcode を確認してください。

netting口座とhedging口座の違いは何ですか?

netting口座では同一銘柄のポジションが集約されます。hedging口座では同一銘柄で複数ポジションを持てるため、決済対象のチケット管理が重要です。

MT5 Python APIで自動売買を始める前に何を確認しますか?

最初に分析専用モードで動作を確認し、次にデモ口座でフォワードテストを行います。スプレッド、約定差、ロット制限、証拠金、再接続、二重注文防止を確認してください。