AI Forex Trading with MT5 & Python: ONNX Models, MCP Server, and ML Automation
The intersection of AI and forex trading is no longer experimental — it's production-ready. MetaTrader 5 now supports ONNX models natively, Python integration is official, and AI assistants like Claude can write, compile, and backtest EAs autonomously.
This guide covers three approaches to AI-powered forex trading with MT5, from simplest to most advanced.
Approach 1: ONNX Models Inside MQL5 EAs
ONNX (Open Neural Network Exchange) lets you train a model in Python and run it directly inside an MT5 Expert Advisor — no external server needed.
Step 1: Train Model in Python
import numpy as np
import pandas as pd
import MetaTrader5 as mt5
from sklearn.ensemble import GradientBoostingClassifier
from sklearn.model_selection import TimeSeriesSplit
from skl2onnx import to_onnx
# Connect to MT5 and fetch data
mt5.initialize()
rates = mt5.copy_rates_from_pos("EURUSD", mt5.TIMEFRAME_H1, 0, 10000)
df = pd.DataFrame(rates)
df['time'] = pd.to_datetime(df['time'], unit='s')
# Create features
df['returns'] = df['close'].pct_change()
df['sma_10'] = df['close'].rolling(10).mean()
df['sma_50'] = df['close'].rolling(50).mean()
# RSI calculation (Wilder's method)
def compute_rsi(prices, period=14):
delta = prices.diff()
gain = delta.where(delta > 0, 0).rolling(period).mean()
loss = (-delta.where(delta < 0, 0)).rolling(period).mean()
rs = gain / loss
return 100 - (100 / (1 + rs))
df['rsi'] = compute_rsi(df['close'], 14)
df['volatility'] = df['returns'].rolling(20).std()
df['target'] = (df['close'].shift(-1) > df['close']).astype(int) # 1 = up
df = df.dropna()
# Features and target
features = ['returns', 'sma_10', 'sma_50', 'rsi', 'volatility']
X = df[features].values
y = df['target'].values
# Time-series cross-validation
tscv = TimeSeriesSplit(n_splits=5)
# Evaluate with cross-validation
scores = []
for train_idx, test_idx in tscv.split(X):
X_train, X_test = X[train_idx], X[test_idx]
y_train, y_test = y[train_idx], y[test_idx]
model = GradientBoostingClassifier(
n_estimators=100,
max_depth=4,
learning_rate=0.05,
random_state=42
)
model.fit(X_train, y_train)
scores.append(model.score(X_test, y_test))
print(f"Cross-validation accuracy: {np.mean(scores):.2%} (+/- {np.std(scores):.2%})")
# Train final model on all data
model = GradientBoostingClassifier(
n_estimators=100,
max_depth=4,
learning_rate=0.05,
random_state=42
)
model.fit(X, y)
print(f"Full training accuracy: {model.score(X, y):.2%}")
# Export to ONNX
onnx_model = to_onnx(model, X[:1].astype(np.float32),
target_opset=15,
options={'zipmap': False})
# Save to MT5 Experts folder
onnx_path = r"C:\Users\you\AppData\Roaming\MetaQuotes\Terminal\ID\MQL5\Files\price_predictor.onnx"
with open(onnx_path, "wb") as f:
f.write(onnx_model.SerializeToString())
print(f"ONNX model saved to: {onnx_path}")
Step 2: Load ONNX in MQL5 EA
//+------------------------------------------------------------------+
//| AI-Powered EA using ONNX Model |
//+------------------------------------------------------------------+
#property strict
#include <Trade\Trade.mqh>
// ONNX model handle
long onnx_handle;
// Input parameters
input double LotSize = 0.1;
input int StopLossPips = 50;
input int TakeProfitPips = 100;
input double ConfidenceThreshold = 0.6;
// Feature buffer (must match training features)
struct ModelFeatures {
double returns;
double sma_10;
double sma_50;
double rsi;
double volatility;
};
int OnInit()
{
// Load ONNX model
onnx_handle = OnnxCreate("Files\\price_predictor.onnx", ONNX_DEFAULT);
if(onnx_handle == INVALID_HANDLE)
{
Print("Failed to load ONNX model: ", GetLastError());
return INIT_FAILED;
}
// Set input/output shapes
long input_shape[] = {1, 5}; // 1 sample, 5 features
OnnxSetInputShape(onnx_handle, ONNX_DEFAULT, input_shape);
long output_shape[] = {1, 2}; // 1 sample, 2 classes (down/up)
OnnxSetOutputShape(onnx_handle, ONNX_DEFAULT, output_shape);
Print("ONNX model loaded successfully");
return INIT_SUCCEEDED;
}
void OnTick()
{
// Only trade on new bar
static datetime last_bar = 0;
datetime current_bar = iTime(_Symbol, _Period, 0);
if(current_bar == last_bar) return;
last_bar = current_bar;
// Prepare features
ModelFeatures features;
features.returns = (iClose(_Symbol, _Period, 1) - iClose(_Symbol, _Period, 2))
/ iClose(_Symbol, _Period, 2);
features.sma_10 = iMA(_Symbol, _Period, 10, 0, MODE_SMA, PRICE_CLOSE, 1);
features.sma_50 = iMA(_Symbol, _Period, 50, 0, MODE_SMA, PRICE_CLOSE, 1);
features.rsi = iRSI(_Symbol, _Period, 14, PRICE_CLOSE, 1);
double closes[];
ArraySetAsSeries(closes, true);
CopyClose(_Symbol, _Period, 0, 21, closes);
double vol = 0;
for(int i = 0; i < 20; i++)
vol += MathPow((closes[i] - closes[i+1]) / closes[i+1], 2);
features.volatility = MathSqrt(vol / 20);
// Run inference
float input_data[5];
input_data[0] = (float)features.returns;
input_data[1] = (float)features.sma_10;
input_data[2] = (float)features.sma_50;
input_data[3] = (float)features.rsi;
input_data[4] = (float)features.volatility;
float output_data[2];
if(!OnnxRun(onnx_handle, ONNX_DEFAULT,
input_data, output_data))
{
Print("ONNX inference failed: ", GetLastError());
return;
}
// output_data[0] = P(down), output_data[1] = P(up)
double prob_up = output_data[1];
double prob_down = output_data[0];
// Trading logic with confidence threshold
if(prob_up > ConfidenceThreshold)
{
double price = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
double sl = price - StopLossPips * _Point;
double tp = price + TakeProfitPips * _Point;
MqlTradeRequest request = {};
MqlTradeResult result = {};
request.action = TRADE_ACTION_DEAL;
request.symbol = _Symbol;
request.volume = LotSize;
request.type = ORDER_TYPE_BUY;
request.price = price;
request.sl = sl;
request.tp = tp;
request.magic = 888888;
request.comment = "AI Buy";
OrderSend(request, result);
PrintFormat("AI Signal: BUY (P=%.2f)", prob_up);
}
else if(prob_down > ConfidenceThreshold)
{
double price = SymbolInfoDouble(_Symbol, SYMBOL_BID);
double sl = price + StopLossPips * _Point;
double tp = price - TakeProfitPips * _Point;
MqlTradeRequest request = {};
MqlTradeResult result = {};
request.action = TRADE_ACTION_DEAL;
request.symbol = _Symbol;
request.volume = LotSize;
request.type = ORDER_TYPE_SELL;
request.price = price;
request.sl = sl;
request.tp = tp;
request.magic = 888888;
request.comment = "AI Sell";
OrderSend(request, result);
PrintFormat("AI Signal: SELL (P=%.2f)", prob_down);
}
}
void OnDeinit(const int reason)
{
if(onnx_handle != INVALID_HANDLE)
OnnxRelease(onnx_handle);
}
Approach 2: Python Flask API Bridge
For more complex ML models that don't fit in ONNX, use a Flask API:
Python Server
from flask import Flask, request, jsonify
import MetaTrader5 as mt5
import pandas as pd
import numpy as np
import joblib
import os
app = Flask(__name__)
# Load pre-trained models
models = {
'gbm': joblib.load('models/gbm_model.pkl'),
'rf': joblib.load('models/rf_model.pkl'),
'lstm': joblib.load('models/lstm_model.pkl'),
}
mt5.initialize()
@app.route('/predict', methods=['POST'])
def predict():
"""Receive market data from EA, return trading signal."""
data = request.json
symbol = data.get('symbol', 'EURUSD')
# Fetch latest data from MT5
rates = mt5.copy_rates_from_pos(symbol, mt5.TIMEFRAME_H1, 0, 100)
df = pd.DataFrame(rates)
# Create features
features = create_features(df) # Your feature engineering function
# Ensemble prediction
predictions = {}
for name, model in models.items():
pred = model.predict_proba(features[-1:].reshape(1, -1))[0]
predictions[name] = {'up': float(pred[1]), 'down': float(pred[0])}
# Consensus signal
avg_up = np.mean([p['up'] for p in predictions.values()])
avg_down = np.mean([p['down'] for p in predictions.values()])
signal = 'BUY' if avg_up > 0.6 else 'SELL' if avg_down > 0.6 else 'HOLD'
return jsonify({
'signal': signal,
'confidence': max(avg_up, avg_down),
'models': predictions,
'symbol': symbol,
})
@app.route('/health')
def health():
return jsonify({'status': 'ok', 'mt5_connected': mt5.terminal_info().trade_allowed})
if __name__ == '__main__':
app.run(host='127.0.0.1', port=5000)
MQL5 EA Client
The EA calls the Python API using MQL5's built-in WebRequest function (requires adding http://127.0.0.1 to Tools → Options → Expert Advisors → Allow WebRequest for listed URL):
//+------------------------------------------------------------------+
//| EA that calls Python Flask API for AI signals |
//+------------------------------------------------------------------+
#property strict
#include <Trade\Trade.mqh>
input string ApiUrl = "http://127.0.0.1:5000";
input double LotSize = 0.1;
input int StopLossPips = 50;
input int TakeProfitPips = 100;
input double ConfidenceThreshold = 0.6;
CTrade trade;
void OnTick()
{
// Only trade on new bar
static datetime last_bar = 0;
datetime current = iTime(_Symbol, _Period, 0);
if(current == last_bar) return;
last_bar = current;
// Call Python API via WebRequest
string url = ApiUrl + "/predict";
string post_data = StringFormat("{\"symbol\": \"%s\"}", _Symbol);
char post[];
char result[];
string result_headers;
StringToCharArray(post_data, post, 0, StringLen(post_data));
ResetLastError();
int res = WebRequest("POST", url, NULL, 5000, post, result, result_headers);
if(res == -1)
{
Print("WebRequest failed, error: ", GetLastError());
Print("Make sure ", url, " is added to Tools > Options > Expert Advisors > Allow WebRequest");
return;
}
// Parse JSON response (simple string search)
string response = CharArrayToString(result);
// Extract signal and confidence from JSON
string signal = "";
double confidence = 0.0;
if(StringFind(response, "\"signal\": \"BUY\"") >= 0)
signal = "BUY";
else if(StringFind(response, "\"signal\": \"SELL\"") >= 0)
signal = "SELL";
int conf_pos = StringFind(response, "\"confidence\":");
if(conf_pos >= 0)
{
string conf_str = StringSubstr(response, conf_pos + 14, 5);
confidence = StringToDouble(conf_str);
}
// Execute trade based on AI signal
if(signal == "BUY" && confidence > ConfidenceThreshold)
{
double price = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
double sl = price - StopLossPips * _Point;
double tp = price + TakeProfitPips * _Point;
trade.Buy(LotSize, _Symbol, price, sl, tp, "AI Buy");
PrintFormat("AI Signal: BUY (confidence=%.2f)", confidence);
}
else if(signal == "SELL" && confidence > ConfidenceThreshold)
{
double price = SymbolInfoDouble(_Symbol, SYMBOL_BID);
double sl = price + StopLossPips * _Point;
double tp = price - TakeProfitPips * _Point;
trade.Sell(LotSize, _Symbol, price, sl, tp, "AI Sell");
PrintFormat("AI Signal: SELL (confidence=%.2f)", confidence);
}
}
Approach 3: MCP Server for AI-Assisted EA Development
The most advanced approach — let AI write, compile, and backtest EAs autonomously using the MT5 MCP Server.
Installation
git clone https://github.com/tusharrayamajhi/mt5-mcp-server.git
cd mt5-mcp-server
pip install mcp MetaTrader5 pandas lxml
Configuration (config.py)
META_EDITOR_PATH = r"C:\Program Files\MetaTrader 5\MetaEditor64.exe"
TERMINAL_PATH = r"C:\Program Files\MetaTrader 5\terminal64.exe"
EXPERTS_DIR = r"C:\Users\you\AppData\Roaming\MetaQuotes\Terminal\ID\MQL5\Experts"
Register with Claude Desktop
{
"mcpServers": {
"mt5": {
"command": "python",
"args": ["C:\\path\\to\\mt5-mcp-server\\server.py"]
}
}
}
Available AI Tools (16 total)
| Category | Tools |
|---|---|
| EA Manager | write_ea, compile_mql5, read_file, list_files |
| Backtester | run_backtest, get_backtest_results |
| Market Data | get_price, get_price_data, get_symbols, run_python |
| Indicators | calculate_indicators, scan_symbols |
| Trade Manager | get_open_positions, get_trade_history |
Usage Examples
Write and backtest an EA from scratch:
"Write an EMA(10/50) crossover EA for EURUSD H1 with 1% risk per trade, 1.5x ATR stop loss, and 3x ATR take profit. Compile it and run a backtest from 2024.01.01 to 2025.01.01 with $10,000 deposit."
AI calls: write_ea → compile_mql5 → run_backtest → get_backtest_results → returns full performance report.
Scan for setups:
"Scan all EUR pairs on H4 for bullish EMA(25/100) crossovers."
AI calls scan_symbols with condition and filter.
Custom analysis:
"Calculate the Sharpe ratio of my EURUSD trades from 2025."
AI calls run_python with custom code that queries MT5 history.
Full AI Trading Pipeline
┌──────────────────────────────────────────────────┐
│ 1. Python: Train ML model on historical data │
│ - Fetch data via MetaTrader5 library │
│ - Engineer features (RSI, EMA, volatility) │
│ - Train with TimeSeriesSplit cross-validation│
│ - Export to ONNX format │
└──────────────────┬───────────────────────────────┘
↓
┌──────────────────────────────────────────────────┐
│ 2. MQL5: Load ONNX model in EA │
│ - OnnxCreate() to load model │
│ - OnnxRun() for inference on each tick │
│ - Execute trades based on predictions │
└──────────────────┬───────────────────────────────┘
↓
┌──────────────────────────────────────────────────┐
│ 3. CLI: Backtest and optimize │
│ - terminal64.exe /config:optimize.ini │
│ - Parse XML results with Python │
│ - Filter by Sharpe, drawdown, trade count │
└──────────────────┬───────────────────────────────┘
↓
┌──────────────────────────────────────────────────┐
│ 4. AI: Iterate and improve │
│ - MCP server lets Claude write/compile/test │
│ - Analyze results, adjust features │
│ - Retrain model with new data │
└──────────────────────────────────────────────────┘
IDE Integration: AI Trading Development Workflow
Building AI-powered EAs requires working across Python (for ML) and MQL5 (for the EA). Your IDE can streamline this:
VS Code / Windsurf Setup
- Install extensions: Python, MQL5 syntax highlighting
- Split workspace: Open Python folder and MQL5 folder side by side
- Tasks (
.vscode/tasks.json):
{
"version": "2.0.0",
"tasks": [
{
"label": "Train ONNX Model",
"type": "shell",
"command": "python",
"args": ["${workspaceFolder}/train_model.py"],
"group": "build"
},
{
"label": "Compile EA",
"type": "shell",
"command": "C:\\Program Files\\MetaTrader 5\\MetaEditor64.exe",
"args": ["/compile:${workspaceFolder}/AI_EA.mq5", "/log"],
"group": "build",
"dependsOn": "Train ONNX Model"
},
{
"label": "Backtest AI EA",
"type": "shell",
"command": "C:\\Program Files\\MetaTrader 5\\terminal64.exe",
"args": ["/config:${workspaceFolder}/backtest_ai.ini"],
"group": "build",
"dependsOn": "Compile EA"
}
]
}
Press Ctrl+Shift+B to: train model → compile EA → backtest.
Windsurf / Cursor: AI-Assisted Development
In AI-powered IDEs, you can describe what you want and the AI handles both Python and MQL5:
"Create a Python script that trains a Gradient Boosting model on EURUSD H1 data using RSI, EMA crossover, and ATR as features. Export it to ONNX. Then write an MQL5 EA that loads the ONNX model and trades based on its predictions with a 0.65 confidence threshold. Compile the EA and run a backtest from 2024.01.01 to 2025.01.01."
The AI will:
- Write
train_model.pywith feature engineering and ONNX export - Write
AI_EA.mq5withOnnxCreate/OnnxRuncalls - Run
python train_model.pyto generate the.onnxfile - Run
metaeditor64.exe /compile:AI_EA.mq5 - Generate
backtest.iniand runterminal64.exe /config:backtest.ini - Parse and display the backtest results
Claude Desktop with MCP Server (Fully Autonomous)
The MT5 MCP Server gives Claude direct access to MT5:
write_ea— Claude writes MQL5 code directlycompile_mql5— Claude compiles via MetaEditorrun_backtest— Claude runs Strategy Testerrun_python— Claude executes Python for analysisget_backtest_results— Claude reads and interprets results
Example prompt:
"Write an AI-powered EA that uses an ONNX model trained on EURUSD H1 data with RSI and EMA features. The EA should only trade when model confidence is above 65%. Compile it, run a backtest from 2024.01.01 to 2025.01.01 with $10,000 deposit, and tell me the Sharpe ratio and max drawdown."
Claude executes the entire pipeline autonomously and returns a performance summary.
Best Practices for AI Trading
- Use TimeSeriesSplit — never random cross-validation on time series data
- Include transaction costs — spread, slippage, commission in your backtest
- Confidence thresholds — only trade when model confidence > 60%
- Walk-forward analysis — retrain periodically on rolling windows
- Feature importance — drop irrelevant features to reduce overfitting
- Ensemble models — combine GBM, Random Forest, and LSTM for robustness
- Monitor drift — if live performance deviates from backtest, retrain
- Start with simple models — Gradient Boosting often outperforms deep learning on tabular financial data
- Normalize features — scale inputs to [0,1] or standardize before training
- Save model metadata — record training data range, features, and accuracy alongside the .onnx file
FAQ
Do I need a GPU to train the model?
No. For the models in this guide (Gradient Boosting, Random Forest), a CPU is sufficient. Training takes seconds to minutes. You only need a GPU for deep learning models (LSTM, Transformer) on large datasets.
Can I use ONNX models from TensorFlow/PyTorch?
Yes. ONNX is a universal format. Export from TensorFlow using tf2onnx, from PyTorch using torch.onnx.export(). MT5's OnnxCreate loads any ONNX model regardless of the training framework.
What's the latency of ONNX inference in MQL5?
Typically 1-5 milliseconds per prediction on a modern CPU. This is negligible compared to tick processing time. For comparison, calling a Python Flask API adds 10-50ms of network overhead.
Should I use ONNX or the Flask API approach?
Use ONNX for production EAs — it's faster, self-contained, and has no external dependencies. Use the Flask API during development and experimentation, when you need to quickly swap models without recompiling the EA.
How often should I retrain the model?
Every 1-4 weeks depending on the strategy. Monitor live performance — if the win rate drops below the backtest average by more than 10%, retrain immediately. Use walk-forward analysis to determine the optimal retraining frequency.
Can the MCP Server write and test EAs without human intervention?
Yes. Once configured, Claude can write an EA from a natural language description, compile it, run a backtest, analyze the results, and suggest improvements — all in a single conversation. However, always review the generated code before deploying to a live account.
Related Guides
- MT5 Vibe Coding: AI-Assisted EA Optimization — Full AI IDE workflow from prompt to backtest
- MT5 Optimization CLI Automation — Command-line backtesting
- MT5 Batch File Automation — Batch scripting for multiple EAs
- MT5 EA Backtesting Tutorial — Manual Strategy Tester
- Python Forex Trading Tutorial — Python + MT5 basics
- Best Forex EA 2026 — Top automated robots
- First MT5 EA Tutorial — Build your first EA
Affiliate Disclosure: This page contains affiliate links. We may earn a commission when you click on certain links or sign up with brokers featured on this site, at no additional cost to you. Our reviews and recommendations are based on thorough research and remain unbiased.Learn more
Risk Warning: Trading forex and CFDs involves significant risk of loss. Past performance is not indicative of future results. CFDs are complex instruments and come with a high risk of losing money rapidly due to leverage. Ensure you understand the risks before trading. This content is for educational purposes only and does not constitute financial advice.
Pips Growth Team
Trading Education & Research Team
The Pips Growth Team is a group of experienced traders, financial analysts, and trading educators dedicated to providing accurate, actionable forex education. Our team combines decades of hands-on market experience with deep technical knowledge to create comprehensive guides, honest broker reviews, and proven trading strategies. Every article is thoroughly researched, fact-checked, and reviewed by multiple team members to ensure the highest quality and accuracy.