プライスアクション分析ツールキットの開発(第36回):MetaTrader 5マーケットストリームへ直接アクセスするPython活用法
内容
はじめに
前回の記事では、シンプルなMQL5スクリプトを用いて、過去のバー情報をPythonに転送し、特徴量エンジニアリングをおこない、機械学習モデルを学習させ、そのシグナルをMetaTraderに戻して実行する方法を示しました。これにより、CSVエクスポートやExcelによる分析、バージョン管理の問題を排除できます。トレーダーは、分足データを統計的に導かれたエントリーポイントに変換し、動的に計算されたストップロス(SL)やテイクプロフィット(TP)を組み込んだエンドツーエンドのパイプラインを手に入れることができました。
このシステムは、アルゴリズム取引における以下の3つの主要な課題を解決します。
- データの断片化:CSVのコピー&ペーストや複雑なスプレッドシートの式を扱う必要がなく、MetaTrader 5のチャートが直接Pythonと通信します。
- 洞察の遅延:特徴量エンジニアリングとモデル推論を自動化することで、リアルタイムのシグナルが得られ、受動的な反応型取引から能動的なデータ駆動型取引に移行できます。
- 一貫性のないリスク管理: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 5とPythonサービス間でデータとシグナルがどのように流れるかのハイレベルなフローと、各コンポーネントの主要な役割です。

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、sl、tpが解析されると、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)、以下の依存関係をインストールします。MetaTrader 5側では、以下をおこないます。
(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チャートにドラッグし、入力設定でInpServerURLにhttp://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機械学習システムを利用し始める際の最初のステップは、次のコマンドを用いて履歴データをブートストラップすることです。
C:\Users\hp\Desktop\Intrusion Trader>python market_ai_engine.py bootstrap 2025-08-04 23:39:23 | INFO | Bootstrapped historical data: 86394 rows
ブートストラップが完了した後は、次のコマンドを用いてリアルタイム更新を継続できます。
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
データセットが最新の状態になったら、次はモデルの学習を実行します。
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
モデルの性能を実際の取引環境に近い形で評価するため、次のコマンドでバックテストを実行できます。
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.
モデルの学習と検証が完了したら、以下のコマンドでライブ推論サーバーを起動できます。
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ラインを描画し、必要に応じて自動で取引を実行できるようになりました。
今後は、XGBoostやLSTMといった別のアルゴリズムを試してみたり、リスク管理ロジックをさらに洗練させたり、PythonサービスをDockerでコンテナ化してデプロイ性を高めることも可能です。この基盤が整ったことで、バックテストの品質向上や自動売買戦略のさらなる高度化に向けて、自由に進化させていただけます。
MetaQuotes Ltdにより英語から翻訳されました。
元の記事: https://www.mql5.com/en/articles/19065
警告: これらの資料についてのすべての権利はMetaQuotes Ltd.が保有しています。これらの資料の全部または一部の複製や再プリントは禁じられています。
この記事はサイトのユーザーによって執筆されたものであり、著者の個人的な見解を反映しています。MetaQuotes Ltdは、提示された情報の正確性や、記載されているソリューション、戦略、または推奨事項の使用によって生じたいかなる結果についても責任を負いません。
MQL5での取引戦略の自動化(第27回):視覚的なフィードバックによるプライスアクションクラブハーモニックパターンの作成
MQL5での取引戦略の自動化(第26回):複数ポジション取引のためのピンバーナンピンシステムの構築
Parafracオシレーター:パラボリックとフラクタルインジケーターの組み合わせ
MQL5での取引戦略の自動化(第25回):最小二乗法と動的シグナル生成を備えたTrendline Trader
- 無料取引アプリ
- 8千を超えるシグナルをコピー
- 金融ニュースで金融マーケットを探索