English Deutsch
preview
プライスアクション分析ツールキットの開発(第36回):MetaTrader 5マーケットストリームへ直接アクセスするPython活用法

プライスアクション分析ツールキットの開発(第36回):MetaTrader 5マーケットストリームへ直接アクセスするPython活用法

MetaTrader 5トレーディングシステム |
91 0
Christian Benjamin
Christian Benjamin

内容


はじめに

前回の記事では、シンプルなMQL5スクリプトを用いて、過去のバー情報をPythonに転送し、特徴量エンジニアリングをおこない、機械学習モデルを学習させ、そのシグナルをMetaTraderに戻して実行する方法を示しました。これにより、CSVエクスポートやExcelによる分析、バージョン管理の問題を排除できます。トレーダーは、分足データを統計的に導かれたエントリーポイントに変換し、動的に計算されたストップロス(SL)やテイクプロフィット(TP)を組み込んだエンドツーエンドのパイプラインを手に入れることができました。

このシステムは、アルゴリズム取引における以下の3つの主要な課題を解決します。

  1. データの断片化:CSVのコピー&ペーストや複雑なスプレッドシートの式を扱う必要がなく、MetaTrader 5のチャートが直接Pythonと通信します。
  2. 洞察の遅延:特徴量エンジニアリングとモデル推論を自動化することで、リアルタイムのシグナルが得られ、受動的な反応型取引から能動的なデータ駆動型取引に移行できます。
  3. 一貫性のないリスク管理:ATRベースのSL/TPをバックテストとライブ取引の両方に組み込むことで、すべての取引がボラティリティ調整済みのルールに従い、エッジを維持できます。

ただし、エキスパートアドバイザー(EA)にデータをPythonに送らせる方法では、遅延や複雑性が生じることがあります。今回のリリースでは、PythonがMetaTrader 5クライアントとして動作できる機能を活用し、MetaTrader 5ライブラリを用いてデータを直接取得、更新できるようになりました。このアプローチにより、EAタイマーへの依存がなくなり、Pythonが随時データを取り込み、Parquetに効率的に書き込み、重い計算を非同期で実行できるようになります。

この基盤をもとに、Python–MQL5ハイブリッドツールはさらに強力な機能を提供します。

  • Python側:MetaTrader 5ネイティブライブラリを使用したリアルタイムデータの取り込み、スパイクzスコア、MACD差分、ATRバンド、Prophetトレンド差分などの高度な特徴量エンジニアリング、時系列対応の勾配ブースティングパイプライン(ローリングウィンドウでの再トレーニング)を実装し、軽量なFlask APIを通じて提供します。
  • MQL5側:リトライロジックを備えた堅牢なRESTポーリングEA、チャート上でのシグナル、信頼度、接続状況のダッシュボード、エントリーとエグジットの矢印マーカー、および厳格なリスク管理ルール下での自動注文実行(オプション)を提供します。

前回の記事が概念実証レベルであったのに対し、このプロダクショングレードのフレームワークはセットアップ時間を大幅に短縮し、フィードバックループを短縮し、データに基づく精度の高い取引を可能にします。それでは、さっそく始めましょう。



システムアーキテクチャの概要

以下は、MetaTrader 5Pythonサービス間でデータとシグナルがどのように流れるかのハイレベルなフローと、各コンポーネントの主要な役割です。


MetaTrader 5ターミナル

MetaTrader 5ターミナルは、主要な市場インターフェースおよびチャートプラットフォームとして機能します。選択した銘柄のライブおよび過去の価格バーをホストし、EAの実行環境を提供します。組み込みのWebRequest()関数を通じて、EAは定期的に最新のバー情報を取得し、シグナル、SL/TPライン、エントリー・エグジットの矢印をチャート上に直接表示します。MetaTrader 5ターミナルは、注文執行(有効化されている場合)、ローカルオブジェクト管理(パネル、矢印、ラベル)、およびシステム出力のユーザー向け可視化を担当します。

Pythonデータフィード

EAにバー情報のプッシュを依存させる代わりに、Pythonデータフィードコンポーネントは公式のMetaTrader 5 Pythonライブラリを使用して、過去およびリアルタイムの分足OHLCデータを随時取得します。圧縮されたParquetデータストアを起動して過去の価格変動を保持し、新しいバーが到着するたびに追記します。この構成により、MQL5のタイマー間隔に依存せず、Pythonサービスは常にバックテストやライブ推論に必要な完全な価格履歴に即座にランダムアクセスできる状態を維持します。

特徴量エンジニアリング

生のバーがメモリまたはディスク上で利用可能になると、特徴量エンジニアリング層が機械学習の統計的に意味のある入力に変換します。具体的には、正規化されたスパイクzスコア、MACDヒストグラム差分、14期間RSI値、ボラティリティ用の14期間ATR、動的EMAベースのエンベロープバンドを計算します。さらに、FacebookのProphetライブラリを活用して、分単位のトレンドデルタを推定し、平均回帰バイアスとトレンドバイアスを捕捉します。この自動化パイプラインにより、ライブデータと過去データが同一の処理を受け、モデルの忠実性が保持されます。

MLモデル

システムの中核には、標準スケーリングを組み込んだscikit-learnパイプライン内の勾配ブースティング分類器があります。モデルは過去のバーのローリングウィンドウを用いて学習し、TimeSeriesSplitで未来情報の漏れを防ぎ、RandomizedSearchCVでハイパーパラメータを最適化します。ラベルは価格を10分先まで見て、構成可能な閾値に基づき買い、売り、待機のクラスに分類して生成します。学習済み推定器はmodel.pklにシリアライズされ、バックテストおよびライブ実行の両方で低レイテンシのロードと推論を可能にします。

Flask API

Flask APIは、PythonのデータサイエンスエコシステムとMQL5 EAの橋渡しをおこないます。単一の「/analyze」エンドポイントを公開し、最近の終値とタイムスタンプを含むJSONペイロードを受け取り、特徴量パイプラインとロード済みモデルを適用してクラス確率を計算し、signal、sl、tp、conf(信頼度)を含む簡潔なJSONレスポンスを返します。この軽量RESTインターフェースはコンテナ化や任意のサーバへのデプロイが可能で、Python側の計算資源をMetaTraderの実行環境から分離し、スケーラビリティを容易にします。

MQL5 EA

クライアント側のMQL5 EAは、ユーザーインタラクションと取引実行に専念します。定期的にFlask APIをポーリングし、受信したJSONを解析、各シグナルを[エクスパート]タブおよびローカルCSVファイルにログ記録し、チャート上のダッシュボードに現在のシグナル、信頼度、接続状況、タイムスタンプを更新します。有効な買い、売り、またはクローズシグナルが到着すると、EAは矢印とSL/TPラインを描画し、EnableTradingがtrueの場合はCTradeクラスを通じて注文を発注またはクローズします。すべてのデータサイエンス処理をPythonにオフロードすることで、EAは軽量で応答性が高く、保守も容易になります。


Pythonバックエンドの詳細な調査

バックエンドの基盤には、公式のMetaTrader 5 Pythonパッケージを活用した堅牢なデータ取り込みパイプラインがあります。初回実行時には、過去数日の分足OHLCデータを取得して圧縮されたParquetファイルに書き込むことで、サービスを「ブートストラップ」します。Parquetの列型フォーマットとZstandard圧縮により、時系列スライスの読み取りが非常に高速になり、ディスク使用量も最小限に抑えられます。その後は、単純な増分更新により新規に形成されたバーのみを追記するため、重複ダウンロードを避けつつ、ライブ推論およびバックテストが常に最新かつ単一の情報源に基づいて実行されることを保証します。

import datetime as dt
import pandas as pd
import MetaTrader5 as mt5
from pathlib import Path

PARQUET_FILE = "hist.parquet.zst"
DAYS_TO_PULL = 60
UTC = dt.timezone.utc

def bootstrap():
    """Fetch last DAYS_TO_PULL days of M1 bars and write to Parquet."""
    now = dt.datetime.utcnow()
    start = now - dt.timedelta(days=DAYS_TO_PULL)
    mt5.initialize()
    mt5.symbol_select("Boom 300 Index", True)
    bars = mt5.copy_rates_range("Boom 300 Index", mt5.TIMEFRAME_M1,
                                start.replace(tzinfo=UTC),
                                now.replace(tzinfo=UTC))
    df = pd.DataFrame(bars)
    df['time'] = pd.to_datetime(df['time'], unit='s')
    df.set_index('time').to_parquet(PARQUET_FILE, compression='zstd')

def append_new_bars():
    """Append only the newest bars since last timestamp."""
    df = pd.read_parquet(PARQUET_FILE)
    last = df.index[-1]
    now = dt.datetime.utcnow()
    new = mt5.copy_rates_range("Boom 300 Index", mt5.TIMEFRAME_M1,
                               last.replace(tzinfo=UTC) + dt.timedelta(minutes=1),
                               now.replace(tzinfo=UTC))
    if new:
        new_df = pd.DataFrame(new)
        new_df['time'] = pd.to_datetime(new_df['time'], unit='s')
        merged = pd.concat([df, new_df.set_index('time')])
        merged[~merged.index.duplicated()].to_parquet(PARQUET_FILE,
                                                      compression='zstd')

生のバーが揃った後、パイプラインはモメンタム、ボラティリティ、急激な値動きを捉える特徴量群を計算します。価格の1次差分を20バーのローリング標準偏差で割り、正規化されたz-spikeスコアとして急激な価格上昇を検出します。MACDヒストグラム差分と14期間RSIはそれぞれトレンドと買われ過ぎ・売られすぎ状態を定量化し、14期間ATRは現在のボラティリティを測定します。さらに、20期間EMAを基準にエンベロープバンド(EMA×0.997およびEMA×1.003)を定義し、市場の変化に適応させます。最後に、FacebookのProphetライブラリが終値の全系列を入力として分単位のトレンドデルタを予測し、時間依存の季節性やドリフトを捉えます。

import numpy as np
import pandas as pd
import ta
from prophet import Prophet

def engineer(df: pd.DataFrame) -> pd.DataFrame:
    df = df.copy()
    # z-spike (20-bar rolling std)
    df['r'] = df['close'].diff()
    df['z_spike'] = df['r'] / (df['r'].rolling(20).std() + 1e-9)

    # MACD histogram diff, RSI, ATR
    df['macd'] = ta.trend.macd_diff(df['close'])
    df['rsi']  = ta.momentum.rsi(df['close'], window=14)
    df['atr']  = ta.volatility.average_true_range(df['high'],
                                                  df['low'],
                                                  df['close'],
                                                  window=14)

    # EMA envelopes
    ema = df['close'].ewm(span=20).mean()
    df['env_low'] = ema * 0.997
    df['env_up']  = ema * 1.003

    # Prophet trend delta (minute-level)
    if len(df) > 200:
        m = Prophet(daily_seasonality=False, weekly_seasonality=False)
        m.fit(pd.DataFrame({'ds': df.index, 'y': df['close']}))
        df['delta'] = m.predict(m.make_future_dataframe(periods=0,
                                                        freq='min'))['yhat'] - df['close']
    else:
        df['delta'] = 0.0

    return df.dropna()

予測タスクは三クラス分類として定義されます。10分後の価格が閾値以上に上昇すれば「BUY」、閾値以上に下落すれば「SELL」、それ以外は「WAIT」とラベル付けします。ラベルが割り当てられると、特徴量とラベルをローリングタイムウィンドウに分割して学習に使用します。scikit-learnパイプラインでまず各特徴量を標準化し、その後GradientBoostingClassifierを適合させます。ハイパーパラメータ(学習率、決定木の数、最大深さ)はTimeSeriesSplitを用いた交差検証とRandomizedSearchCVで最適化され、未来情報の漏洩を防ぎます。最良モデルはmodel.pklにシリアライズされ、バックテストおよびライブ推論で低レイテンシに即時利用できます。

import numpy as np
import joblib
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.ensemble import GradientBoostingClassifier
from sklearn.model_selection import TimeSeriesSplit, RandomizedSearchCV

LOOKAHEAD_MIN   = 10
LABEL_THRESHOLD = 0.0015
FEATS = ['z_spike','macd','rsi','atr','env_low','env_up','delta']

def label_and_train(df: pd.DataFrame):
    # Look-ahead return
    chg = (df['close'].shift(-LOOKAHEAD_MIN) - df['close']) / df['close']
    df['label'] = np.where(chg > LABEL_THRESHOLD, 1,
                   np.where(chg < -LABEL_THRESHOLD, 2, 0))

    X = df[FEATS].dropna()
    y = df.loc[X.index, 'label']

    pipe = Pipeline([
        ('scaler', StandardScaler()),
        ('gb', GradientBoostingClassifier(random_state=42))
    ])
    param_dist = {
        'gb__learning_rate': [0.01, 0.05, 0.1],
        'gb__n_estimators': [300, 500, 700],
        'gb__max_depth': [2, 3, 4]
    }
    cv = TimeSeriesSplit(n_splits=5)
    rs = RandomizedSearchCV(pipe, param_dist, n_iter=12,
                            cv=cv, scoring='roc_auc_ovr',
                            n_jobs=-1, random_state=42)
    rs.fit(X, y)
    joblib.dump(rs.best_estimator_, 'model.pkl')
PythonとMetaTraderの橋渡しとして、Flaskの「/analyze」エンドポイントを公開しています。クライアントは、銘柄名、終値配列、対応するUNIXタイムスタンプを含むJSONペイロードを送信します。エンドポイントではそのペイロードに対して特徴量パイプラインを再適用し、事前学習済みモデルをロードしてクラス確率を計算し、最も信頼度の高いシグナルを判定します。またATR特徴量から動的にSLおよびTPレベルを算出します。レスポンスはコンパクトなJSONオブジェクトとして返されます。
from flask import Flask, request, jsonify
import joblib
import pandas as pd

app = Flask(__name__)
model = joblib.load('model.pkl')

@app.route('/analyze', methods=['POST'])
def analyze():
    payload = request.get_json(force=True)
    closes = payload['prices']
    times  = pd.to_datetime(payload['timestamps'], unit='s')
    df = pd.DataFrame({'close': closes}, index=times)
    # duplicate open/high/low for completeness
    df[['open','high','low']] = df[['close']]

    feat = engineer(df).iloc[-1:]
    probs = model.predict_proba(feat[FEATS])[0]
    p_buy, p_sell = probs[1], probs[2]
    signal = ('BUY' if p_buy > 0.55 else
              'SELL' if p_sell > 0.55 else 'WAIT')
    atr = feat['atr']
    entry = feat['close']
    sl = entry - atr if signal=='BUY' else entry + atr
    tp = entry + 2*atr if signal=='BUY' else entry - 2*atr

    return jsonify(signal=signal,
                   sl=round(sl,5),
                   tp=round(tp,5),
                   conf=round(max(p_buy,p_sell),2))

if __name__ == '__main__':
    app.run(port=5000)


MQL5 EAクライアントアーキテクチャの探究

EAのコアループは、タイマーイベント(OnTimer)または新バー検知に存在し、WebRequest()を使用してHTTPメッセージの送受信をおこないます。まず、CopyRatesで最新のN本のバーを取得し、MqlRates配列をUTF-8 JSONペイロードに変換して、銘柄名と終値シーケンスを含め、必要なHTTPヘッダーを設定します。WebRequest()が失敗した場合(戻り値が0以下)は、EAはGetLastError()でエラーコードを取得し、リトライカウンタを増加させ、エラーをログに記録します。その後、リトライ回数が上限に達するか次のタイマー発火まで追加のリクエストを延期します。HTTPステータスが200以上の場合は、リトライカウントをリセットしlastStatusを更新します。このパターンにより、チャートスレッドをブロックせず、一時的なネットワーク障害が発生してもEAがクラッシュしない、堅牢で非同期なシグナリングが実現します。

// In OnTimer() or OnNewBar():
MqlRates rates[];
// Copy the last N bars into `rates`
if(CopyRates(_Symbol, _Period, 0, InpBufferBars, rates) != InpBufferBars)
    return;
ArraySetAsSeries(rates, true);

// Build payload
string payload = "{";
payload += StringFormat("\"symbol\":\"%s\",", _Symbol);
payload += "\"prices\":[";
for(int i=0; i<InpBufferBars; i++)
  {
    payload += DoubleToString(rates[i].close, _digits);
    if(i < InpBufferBars-1) payload += ",";
  }
payload += "]}";

// Send request
string headers = "Content-Type: application/json\r\nAccept: application/json\r\n\r\n";
char  req[], resp[];
int   len = StringToCharArray(payload, req, 0, WHOLE_ARRAY, CP_UTF8);
ArrayResize(req, len);
ArrayResize(resp, 8192);

int status = WebRequest("POST", InpServerURL, headers, "", InpTimeoutMs,
                        req, len, resp, headers);
if(status <= 0)
{
  int err = GetLastError();
  PrintFormat("WebRequest error %d (attempt %d/%d)", err, retryCount+1, MaxRetry);
  ResetLastError();
  retryCount = (retryCount+1) % MaxRetry;
  lastStatus = StringFormat("Err%d", err);
  return;
}
retryCount = 0;
lastStatus = StringFormat("HTTP %d", status);

有効なJSON レスポンスからsignal、sltpが解析されると、EAはチャート上のダッシュボードを更新し、新しい矢印やラインを描画します。ダッシュボードは単一のOBJ_RECTANGLE_LABELで構成され、銘柄、現在のシグナル、HTTPステータス、タイムスタンプの4つのテキストラベルを表示します。取引の場合、既存のプレフィックス付きオブジェクトを削除した後、BUY(緑上向き)、SELL(赤下向き)、CLOSE(オレンジ)の各シグナルに応じて矢印(OBJ_ARROW)を作成します。水平線(OBJ_HLINE)はSLとTPをそれぞれ赤と緑で表示します。各オブジェクトにチャート固有の接頭辞を付与し、シグナル変更や非初期化時にクリーンアップすることで、チャートは常に整理され、視認性が維持されます。

// Panel (rectangle + labels)
void DrawPanel()
{
  const string pid = "SigPanel";
  if(ObjectFind(0, pid) < 0)
    ObjectCreate(0, pid, OBJ_RECTANGLE_LABEL, 0, 0, 0);

  ObjectSetInteger(0, pid, OBJPROP_CORNER, CORNER_LEFT_UPPER);
  ObjectSetInteger(0, pid, OBJPROP_XDISTANCE, PanelX);
  ObjectSetInteger(0, pid, OBJPROP_YDISTANCE, PanelY);
  ObjectSetInteger(0, pid, OBJPROP_XSIZE, PanelW);
  ObjectSetInteger(0, pid, OBJPROP_YSIZE, PanelH);
  ObjectSetInteger(0, pid, OBJPROP_BACK, true);
  ObjectSetInteger(0, pid, OBJPROP_BGCOLOR, PanelBG);
  ObjectSetInteger(0, pid, OBJPROP_COLOR, PanelBorder);

  string lines[4] = {
    StringFormat("Symbol : %s", _Symbol),
    StringFormat("Signal : %s", lastSignal),
    StringFormat("Status : %s", lastStatus),
    StringFormat("Time   : %s", TimeToString(TimeLocal(), TIME_MINUTES))
  };

  for(int i=0; i<4; i++)
  {
    string lbl = pid + "_L" + IntegerToString(i);
    if(ObjectFind(0, lbl) < 0)
      ObjectCreate(0, lbl, OBJ_LABEL, 0, 0, 0);
    ObjectSetInteger(0, lbl, OBJPROP_CORNER, CORNER_LEFT_UPPER);
    ObjectSetInteger(0, lbl, OBJPROP_XDISTANCE, PanelX + 6);
    ObjectSetInteger(0, lbl, OBJPROP_YDISTANCE, PanelY + 4 + i*(TxtSize+2));
    ObjectSetString(0, lbl, OBJPROP_TEXT, lines[i]);
    ObjectSetInteger(0, lbl, OBJPROP_FONTSIZE, TxtSize);
    ObjectSetInteger(0, lbl, OBJPROP_COLOR, TxtColor);
  }
}

// Arrows & SL/TP lines
void ActOnSignal(ESignal code, double sl, double tp)
{
  // remove old arrows/lines
  for(int i=ObjectsTotal(0)-1; i>=0; i--)
    if(StringFind(ObjectName(0,i), objPrefix) == 0)
      ObjectDelete(0, ObjectName(0,i));

  // arrow
  int    arrCode = (code==SIG_BUY ? 233 : code==SIG_SELL ? 234 : 158);
  color  clr     = (code==SIG_BUY ? clrLime : code==SIG_SELL ? clrRed : clrOrange);
  string name    = objPrefix + "Arr_" + TimeToString(TimeCurrent(), TIME_SECONDS);
  ObjectCreate(0, name, OBJ_ARROW, 0, TimeCurrent(), SymbolInfoDouble(_Symbol, SYMBOL_BID));
  ObjectSetInteger(0, name, OBJPROP_ARROWCODE, arrCode);
  ObjectSetInteger(0, name, OBJPROP_COLOR, clr);

  // SL line
  if(sl > 0)
  {
    string sln = objPrefix + "SL_" + name;
    ObjectCreate(0, sln, OBJ_HLINE, 0, 0, sl);
    ObjectSetInteger(0, sln, OBJPROP_COLOR, clrRed);
  }

  // TP line
  if(tp > 0)
  {
    string tpn = objPrefix + "TP_" + name;
    ObjectCreate(0, tpn, OBJ_HLINE, 0, 0, tp);
    ObjectSetInteger(0, tpn, OBJPROP_COLOR, clrLime);
  }
}

実際の注文執行はEnableTradingフラグに依存しており、視覚表示のみとライブ実行を簡単に切り替えることができます。注文をおこなう前に、EAはPositionSelect(_Symbol)を使用して重複ポジションを回避します。BUYシグナルの場合はCTrade.Buy()でFixedLots、SL、TPを指定し、SELLではCTrade.Sell()、CLOSEではCTrade.PositionClose()を実行します。決済時にはスリッページ許容値(SlippagePoints)を考慮します。この最小限かつ状態管理されたロジックにより、同一方向に重複してエントリーすることを防ぎ、すべての注文が事前定義されたリスクパラメータを遵守することを保証します。

void ExecuteTrade(ESignal code, double sl, double tp)
{
  if(!EnableTrading) return;

  bool hasPosition = PositionSelect(_Symbol);
  if(code == SIG_BUY && !hasPosition)
    trade.Buy(FixedLots, _Symbol, 0, sl, tp);
  else if(code == SIG_SELL && !hasPosition)
    trade.Sell(FixedLots, _Symbol, 0, sl, tp);
  else if(code == SIG_CLOSE && hasPosition)
    trade.PositionClose(_Symbol, SlippagePoints);
}

インストールと設定

ライブシグナルを生成する前に、Python環境とMetaTrader 5プラットフォームの両方を準備する必要があります。まず、MetaTrader 5ターミナルが稼働する同一マシンにPython3.8以降をインストールします。仮想環境を作成して有効化し(Windowsではvenv\Scripts\activate、macOS/Linuxではsource venv/bin/activate)、以下の依存関係をインストールします。
pip install MetaTrader 5 pandas numpy ta prophet scikit-learn flask loguru joblib
次に、Windowsファイアウォールでpython.exeおよびterminal64.exeのアウトバウンドHTTP リクエストを許可します。HTTPSで本番運用する場合は、SSL証明書をTrusted Root証明書ストアにインストールし、MetaTrader 5が安全な接続を受け入れるようにします。

MetaTrader 5側では、以下をおこないます。

[ツール]→[オプション]→[エキスパートアドバイザ]で[DLLの使用を許可する]を有効にし、ローカルAPIホスト

(http://127.0.0.1:5000)を[WebRequestを許可するURL]に追加します。この許可リスト設定は必須で、設定しない場合、MetaTrader 5はPOSTペイロードを無視します。

プロジェクトフォルダにPythonサービススクリプト(例:market_ai_engine.py)を配置し、スクリプト上部で取引銘柄(MAIN_SYMBOL)、MetaTrader 5のログイン情報(LOGIN_ID、PASSWORD、SERVER)、ファイルパス(PARQUET_FILE、MODEL_FILE)を設定します。Flaskサーバーの非デフォルトポートを使用する場合は、起動時に--portで指定します。
EAを展開するには、コンパイル済みのEA.ex5(または.mq5ソース)をMetaTrader 5のMQL5/Expertsフォルダに配置します。

MetaTrader 5を再起動またはナビゲータを更新すると、EAがリストに表示されます。EAをPythonで設定したのと同じ銘柄のM1チャートにドラッグし、入力設定でInpServerURLhttp://127.0.0.1:5000/analyzeを指定、InpBufferBars(例:60)、InpPollInterval(例:60秒)、InpTimeoutMs(例:5000ms)を設定します。最初はEnableTradingをオフにして、実際の注文を執行せずにシグナルを確認するだけにします。

Pythonバックエンドは以下の順序で起動します。

1. python market_ai_engine.py bootstrap

2. python market_ai_engine.py collect 

3. python market_ai_engine.py train

4. python market_ai_engine.py serve --port 5000

Flaskサーバーが稼働し、MetaTrader自動売買が有効になると、EAはライブシグナルをポーリングし、チャート上に矢印とSL/TPラインを描画します。十分に信頼できるシグナルが得られた段階で、事前定義したリスクルールに基づいて注文を出すことができます。

トラブルシューティング

EAがデータを表示しない、または常に「WAIT」を返す場合は、MetaTrader 5のEA設定でAPI URLが許可リストに追加されていることを確認してください。HTTP/HTTPS混在環境では、ローカルテスト時はHTTP (127.0.0.1)を使用し、本番運用時に信頼済み証明書を用いてHTTPSに切り替えます。サーバーとMetaTrader 5ターミナルの時計が同期していること(UTCまたは同一タイムゾーン)を確認し、バー取得のズレを防ぎます。最後に、自動売買がオンになっていること、他のEAやグローバル権限がブロックしていないことを確認してください。


評価とパフォーマンスの結果

ハイブリッド型のPython–MQL5機械学習システムを利用し始める際の最初のステップは、次のコマンドを用いて履歴データをブートストラップすることです。

python market_ai_engine.py bootstrap
この処理により、MetaTrader 5のネイティブPythonライブラリを使用して、直近60日分のM1(1分足)バーがダウンロードされ、ローカル環境に初期化されます。データは圧縮Parquetファイル(hist.parquet.zst)として保存され、高速なディスクアクセスと効率的なストレージを実現します。このブートストラップは一度行えば十分で、履歴データを完全にリセットしたい場合のみ再実行が必要です。
C:\Users\hp\Desktop\Intrusion Trader>python market_ai_engine.py bootstrap
2025-08-04 23:39:23 | INFO | Bootstrapped historical data: 86394 rows

ブートストラップが完了した後は、次のコマンドを用いてリアルタイム更新を継続できます。

python market_ai_engine.py collect
このコレクタは、データセットを随時最新状態へ更新します。バックグラウンドで常時動かしておくことも可能ですが、毎回ブートストラップをおこなわずに連続的なデータ更新を維持したい場合にのみ必須となります。
C:\Users\hp\Desktop\Intrusion Trader>python market_ai_engine.py collect
2025-08-04 23:41:01 | INFO | Appended 2 new bars
2025-08-04 23:42:01 | INFO | Appended 1 new bars
2025-08-04 23:43:01 | INFO | Appended 1 new bars

データセットが最新の状態になったら、次はモデルの学習を実行します。 

python market_ai_engine.py train
これは、完全な機械学習パイプラインをトリガーします。この処理では、Parquetファイルの読み込み、スパイク検出・MACD差分・RSI・ATRバンド・EMAエンベロープ・Prophetを用いたトレンド推定といった特徴量エンジニアリング、さらにGradientBoostingClassifierRandomizedSearchCVによる最適モデルの学習がおこなわれます。完成したモデルはmodel.pklとして保存され、即時の推論に利用できる状態になります。
C:\Users\hp\Desktop\Intrusion Trader>python market_ai_engine.py train
23:48:44 - cmdstanpy - INFO - Chain [1] start processing
23:51:24 - cmdstanpy - INFO - Chain [1] done processing
2025-08-05 02:59:08 | INFO | Model training complete

モデルの性能を実際の取引環境に近い形で評価するため、次のコマンドでバックテストを実行できます。

python market_ai_engine.py backtest --days 30
これにより、過去30日分のデータを用いたシグナル生成と取引結果のシミュレーションがおこなわれます。シグナル精度、勝率、総損益などの指標が計算され、CSVとして出力されます。これにより、戦略が期待どおりのパフォーマンスを発揮するかどうかを評価できます。
C:\Users\hp\Desktop\Intrusion Trader>python market_ai_engine.py backtest --days 30
06:57:33 - cmdstanpy - INFO - Chain [1] start processing
06:58:30 - cmdstanpy - INFO - Chain [1] done processing
2025-08-05 06:59:20 | INFO | Backtest results saved to backtest_results_30d.csv

バックテスト結果

下記は、30日間のバックテストから抽出した主要指標です。

累積資本の経時変化グラフ

主要な指標の概要は次のとおりです。

*   **Average Entry Price:** 3099.85
*   **Average Exit Price:** 3096.53
*   **Average PNL (Profit and Loss):** 3.32
*   **Total PNL:** 195.69
*   **Average Cumulative Equity:** 96.34
*   **First Trade Time:** 2025-07-11 14:18:00
*   **Last Trade Time:** 2025-07-27 02:00:00

勝率

win_rate
72.88135528564453
The win rate is 72.88%. This means that approximately 73% of the trades resulted in a profit.

モデルの学習と検証が完了したら、以下のコマンドでライブ推論サーバーを起動できます。

python market_ai_engine.py serve --port 5000
このコマンドは、MQL5 EAからのリクエストを待機する軽量なFlask APIを起動します。EAが「/analyze」エンドポイントへポーリングをおこなうと、サーバーは直近のバーを即座に取得し、特徴量エンジニアリングを適用したうえでモデル推論を実行し、SL、TP、信頼度を含む予測結果をJSON形式で返します。このサーバーは、チャートとAIエンジンを接続するリアルタイムの橋渡しとして機能します。
2025-08-05 12:41:53 | INFO | analyze: signal=%s, sl=%.5f, tp=%.5f
127.0.0.1 - - [05/Aug/2025 12:41:53] "POST /analyze HTTP/1.1" 200 -

MetaTrader側では、EAがPythonサーバーへ適切にポーリングできるよう設定する必要があります。EAの入力パラメータ内でサーバーURL(例:http://127.0.0.1:5000/analyze)を指定し、さらにEAをモデルの学習に使用した銘柄および時間足(通常はM1)と同じチャートに適用します。EAが稼働すると、一定間隔でシグナルを取得し、チャート上に矢印として描画するとともに、必要に応じて厳格なリスク管理ルールに基づく自動売買を実行します。

2025.08.05 12:41:53.532 trained model (1) (Boom 300 Index,M1)   >>> JSON: {"symbol":"Boom 300 Index","prices":[2701.855,2703.124,
2704.408,2705.493,2705.963,2696.806,2698.278,2699.877,2701.464,2702.788,2691.762,2693.046,2694.263,2695.587,2696.863,2698.
179,2699.775,2701.328,2702.888,2698.471,2699.887,2695.534,2696.952,2698.426,2699.756,2699.552,2700.954,2702.131,2703.571,
2699.549,2700.868,2702.567,2703.798,2705.067,2706.874,2698.084,2699.538,2700.856,2702.227,2703.692,2705.102,2706.188,2707.609,2709.001,
2710.335,2711.716,2712.919,2712.028,2713.529,2715.052,2716.578,2717.
2025.08.05 12:41:53.943 trained model (1) (Boom 300 Index,M1)   <<< HTTP 200 hdr:
2025.08.05 12:41:53.943 trained model (1) (Boom 300 Index,M1)   {"conf":0.43,"signal":"WAIT","sl":2725.04317,"tp":2720.18266}
2025.08.05 12:41:53.943 trained model (1) (Boom 300 Index,M1)   [2025.08.05 12:41:53] Signal → WAIT | SL=2725.04317 | TP=2720.18266 | Conf=0.43


結論

本記事では、Pythonのデータサイエンス基盤を活用するMQL5 EAを構築してきました。この記事を通じて、次のような機能を手にしていただけたはずです。
  • データパイプライン:EAがMetaTrader 5から1分足バーを取得し、Parquet形式で書き出せるようになりました。
  • 特徴量エンジニアリング:スパイクzスコア、MACD、RSI、ATR、エンベロープバンド、さらにProphetによるトレンドデルタまで計算できるようになりました。
  • モデル構築とサービング:時間依存性を考慮した勾配ブースティングモデルを学習し、Flaskを通じて予測を提供できる環境を整えました。
  • チャート上のアクション:MQL5側ではこれらのシグナルを受け取り、矢印やSL/TPラインを描画し、必要に応じて自動で取引を実行できるようになりました。
また、FlaskでのJSONパースにおける追加データの扱いや、EA側でHTTP呼び出しを適切に制御する方法など、実運用で直面しがちな課題への対処も体験していただけたと思います。処理の役割を明確に分離することで、全体の保守性と拡張性が大きく向上することも確認できました。
今後は、XGBoostやLSTMといった別のアルゴリズムを試してみたり、リスク管理ロジックをさらに洗練させたり、PythonサービスをDockerでコンテナ化してデプロイ性を高めることも可能です。この基盤が整ったことで、バックテストの品質向上や自動売買戦略のさらなる高度化に向けて、自由に進化させていただけます。






ChartProjector
Analytical Comment
Analytics Master
Analytics Forecaster 
Volatility Navigator
Mean Reversion Signal Reaper
Signal Pulse 
Metrics Board 
External Flow
VWAP
Heikin Ashi   FibVWAP  
RSI DIVERGENCE
Parabolic Stop and Reverse (PSAR) 
Quarters Drawerスクリプト
Intrusion Detector
TrendLoom Tool  Quarters Board 
ZigZag Analyzer  Correlation Pathfinder  Market Structure Flip Detector Tool
Correlation Dashboard   Currency Strength Meter 
PAQ Analysis Tool 
Dual EMA Fractal Breaker
Pin bar, Engulfing and RSI divergence
Liquidity Sweep Opening Range Breakout Tool Boom and Crash Interceptor CCI Zer-Line EA
Candlestick Recognition Candlestick Detection (TA-Lib) Candle Range Tool MetaTrader 5 Data Ingestor モデルの学習とデプロイ Pythonライブラリの使用

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

添付されたファイル |
MQL5での取引戦略の自動化(第27回):視覚的なフィードバックによるプライスアクションクラブハーモニックパターンの作成 MQL5での取引戦略の自動化(第27回):視覚的なフィードバックによるプライスアクションクラブハーモニックパターンの作成
本記事では、MQL5で弱気、強気両方のクラブ(Crab)ハーモニックパターンを、ピボットポイントとフィボナッチ比率を用いて識別し、正確なエントリー、ストップロス、テイクプロフィットレベルを使用して取引を自動化するクラブパターンシステムを開発します。また、XABCDパターン構造やエントリーレベルを表示するために、三角形やトレンドラインなどのチャートオブジェクトを使った視覚的な表示機能を追加します。
MQL5での取引戦略の自動化(第26回):複数ポジション取引のためのピンバーナンピンシステムの構築 MQL5での取引戦略の自動化(第26回):複数ポジション取引のためのピンバーナンピンシステムの構築
本記事では、ピンバーを検出して取引を開始し、複数ポジションを管理するためのナンピン(難平、Averaging)戦略を用いたピンバーシステムをMQL5で開発します。さらに、トレーリングストップやブレークイーブン調整で強化し、リアルタイムでポジションと利益を監視できるダッシュボードも組み込みます。
Parafracオシレーター:パラボリックとフラクタルインジケーターの組み合わせ Parafracオシレーター:パラボリックとフラクタルインジケーターの組み合わせ
パラボリックSARとフラクタルインジケーターを組み合わせて、新しいオシレーターベースのインジケーターを作成する方法について説明します。両ツールの独自の強みを統合することにより、トレーダーはより洗練された効果的な取引戦略の開発を目指すことができます。
MQL5での取引戦略の自動化(第25回):最小二乗法と動的シグナル生成を備えたTrendline Trader MQL5での取引戦略の自動化(第25回):最小二乗法と動的シグナル生成を備えたTrendline Trader
本記事では、最小二乗法を用いてサポートおよびレジスタンスのトレンドラインを検出し、価格がこれらのラインに触れた際に動的な売買シグナルを生成するTrendline Traderプログラムを開発します。また、生成されたシグナルに基づきポジションをオープンする仕組みも構築します。