P
PipsGrowth
Python Trading

AI Forex Trading with MT5 & Python: ONNX Models, MCP Server, and ML Automation

Complete guide to building AI-powered forex trading systems with MT5. Learn ONNX model integration, Python ML pipelines, MCP server for Claude AI, and automated EA development with machine learning.

PG
Pips Growth Team
2026-07-10
12 min

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_eacompile_mql5run_backtestget_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

  1. Install extensions: Python, MQL5 syntax highlighting
  2. Split workspace: Open Python folder and MQL5 folder side by side
  3. 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:

  1. Write train_model.py with feature engineering and ONNX export
  2. Write AI_EA.mq5 with OnnxCreate/OnnxRun calls
  3. Run python train_model.py to generate the .onnx file
  4. Run metaeditor64.exe /compile:AI_EA.mq5
  5. Generate backtest.ini and run terminal64.exe /config:backtest.ini
  6. 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 directly
  • compile_mql5 — Claude compiles via MetaEditor
  • run_backtest — Claude runs Strategy Tester
  • run_python — Claude executes Python for analysis
  • get_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

  1. Use TimeSeriesSplit — never random cross-validation on time series data
  2. Include transaction costs — spread, slippage, commission in your backtest
  3. Confidence thresholds — only trade when model confidence > 60%
  4. Walk-forward analysis — retrain periodically on rolling windows
  5. Feature importance — drop irrelevant features to reduce overfitting
  6. Ensemble models — combine GBM, Random Forest, and LSTM for robustness
  7. Monitor drift — if live performance deviates from backtest, retrain
  8. Start with simple models — Gradient Boosting often outperforms deep learning on tabular financial data
  9. Normalize features — scale inputs to [0,1] or standardize before training
  10. 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

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.

Written by

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.

15+ Years Experience81+ Articles Published
Forex & CFD TradingTechnical AnalysisRisk ManagementBroker Reviews & Evaluation
View Full Profile
Share

Get Trading Tips

AI Forex Trading with MT5 & Python: ONNX Models, MCP Server, and ML Automation | PipsGrowth