How I Built a Hybrid, ML-Powered EA for MT5 (And Why a "Black Box" Isn't Enough)

How I Built a Hybrid, ML-Powered EA for MT5 (And Why a "Black Box" Isn't Enough)

4 November 2025, 18:46
Mauricio Vellasquez
0
774
How I Built a Hybrid, ML-Powered EA for MQL5 (And Why a "Black Box" Isn't Enough)

As an MQL developer, I've spent years building trading robots. We all chase the same thing: a system that is both intelligent and robust. We rely on technical indicators, price action, and complex logic to find an edge. For a long time, Machine Learning felt like a "holy grail," but one that was just out of reach or too much of a "black box."

My main hesitation was this: I don't want an EA that *just* relies on a blind prediction. The market has context. A model trained on historical data might say "BUY," but as a trader, I know that signal is worthless if the spread is 100 pips, volatility is zero, or a major trend on a higher timeframe is screaming "SELL."

So, I decided to build something different: a Hybrid EA. An EA that uses a powerful Machine Learning model for its core signal but then validates that signal against a gauntlet of proven, "common-sense" technical confluence filters.

Today, I want to walk you through the exact process I used to build this, from a Python script to a fully functional MQL5 Expert Advisor.

Part 1: The ML Workflow - From Data to Model

You can't just "make" an AI. You have to train it. This entire part of the process happens outside of MetaTrader, typically in Python using libraries like TensorFlow (Keras) and Scikit-learn.

1. Data Preparation & Feature Engineering

First, I needed data. Lots of it. I exported historical data (Open, High, Low, Close, Tick_Volume) for my target symbol. The key isn't just the data, but how you frame the problem. I'm not trying to predict the *exact* next price; I'm trying to predict a simple binary outcome: "Will the next bar's Close be higher or lower than the current bar's Close?"

I structured this as a "windowed" dataset. The model would look at a sequence of 60 bars ( WINDOW_SIZE = 60 ) to predict the outcome of the 61st bar.

2. Normalization (The Crucial Step)

Neural networks don't like raw price data. A price of 2300.00 is just a "big number" and can cause the model's math to explode. We must normalize all our features, usually to a range between 0 and 1. I used a standard `MinMaxScaler`.

This is critical: you must save the *exact* parameters (min, max, scale) used to normalize the training data. We will need them inside MQL5 to prepare live market data for the model.

<!-- PSEUDO-CODE: Saving the Scaler (Python) --> scaler = MinMaxScaler(feature_range=(0, 1)) X_train_scaled = scaler.fit_transform(X_train) # --- Save the scaler parameters --- # This is the "secret key" for our EA save_scaler_to_file(scaler, "my_scaler.pkl")


3. Model Training (Python/TensorFlow)

I used a simple but powerful LSTM (Long Short-Term Memory) network. LSTMs are great at understanding sequences, which is perfect for time-series data like charts.

<!-- PSEUDO-CODE: Model Training (Python) --> # 'y_train' is 1 if next_close > close, else 0 model = Sequential([ LSTM(units=50, input_shape=(60, 5)), # 60 bars, 5 features Dropout(0.2), Dense(units=1, activation='sigmoid') # Final output: 0.0 to 1.0 ]) model.compile(optimizer='adam', loss='binary_crossentropy') model.fit(X_train_scaled, y_train, epochs=30) # Save the trained model model.save("My_Gold_Model.h5")

The `sigmoid` activation is key. It means the model's output isn't just "BUY" or "SELL," but a probability from 0.0 (100% chance of DOWN) to 1.0 (100% chance of UP). A value of 0.5 is neutral.

4. Conversion to ONNX

MetaTrader 5 can't run TensorFlow models directly. It runs models in the ONNX (Open Neural Network Exchange) format. This is a simple conversion step using a Python library.

<!-- PSEUDO-CODE: Conversion (Shell) --> # This one-liner converts our Keras model to ONNX !python -m tf2onnx.convert --keras My_Gold_Model.h5 --output My_Gold_Model.onnx

Now I have two essential files: My_Gold_Model.onnx and the scaler parameters (which I exported to a simple CSV file).


Part 2: The MQL5 Integration - Building the Hybrid EA

This is where the magic happens. We bring our trained model into MQL5.

1. Loading the Model and Scaler

I embed both the `.onnx` file and the scaler data directly into the EA's code using #resource . In OnInit() , the EA loads the model into memory and parses the scaler values into a global array.

    
<!-- PSEUDO-CODE: MQL5 OnInit() -->
#resource "\\Files\\MLModels\\My_Gold_Model.onnx" as const uchar Model_M5[]
#include <Trade/Trade.mqh>

long g_modelHandle = INVALID_HANDLE;
double g_scalerMin[5]; // open, high, low, close, volume
double g_scalerScale[5];

int OnInit()
{
    // ... load scaler values from resource into g_scalerMin/g_scalerScale ...
    
    // Load the ONNX model from the resource buffer
    g_modelHandle = OnnxCreateFromBuffer(Model_M5, ONNX_DEFAULT);
    if(g_modelHandle == INVALID_HANDLE)
    {
        Print("Failed to load ONNX model!");
        return(INIT_FAILED);
    }
    return(INIT_SUCCEEDED);
}

2. The Prediction Loop (OnTick)

On every tick (or new bar), the EA does the *exact same process* as our Python script:

  1. Gets the last 60 bars of data.
  2. Normalizes this data using our saved g_scalerMin and g_scalerScale values.
  3. Passes the 60x5 normalized matrix to the ONNX model.
  4. Gets a single float value back (our probability).

<!-- PSEUDO-CODE: MQL5 OnTick() Prediction --> void OnTick() { // 1. Get last 60 bars MqlRates rates[]; CopyRates(_Symbol, _Period, 0, 60, rates); // 2. Normalize data matrixf input_data(60, 5); for(int i=0; i<60; i++) { input_data[i][0] = (float)((rates[i].open - g_scalerMin[0]) * g_scalerScale[0]); input_data[i][1] = (float)((rates[i].high - g_scalerMin[1]) * g_scalerScale[1]); // ... and so on for low, close, volume ... } // 3. Run prediction vectorf output_data(1); if(!OnnxRun(g_modelHandle, 0, input_data, output_data)) { Print("OnnxRun failed!"); return; } // 4. Interpret result double probability_of_up = output_data[0]; // Now... what to do with this? ProcessSignal(probability_of_up); }

Part 3: The "Secret Sauce" - My Confluence Filter

This is what separates a "toy" from a professional tool. I do not trade if probability_of_up > 0.5 . That's a rookie mistake.

Instead, I use the model's output as my primary signal, which must then be confirmed by my confluence filter. This filter, inspired by my other EAs, is designed to answer one question: "Is this a safe and logical time to trade?"

Before my new EA places any trade, it checks all of this:

  • Spread Check: Is the current spread below my InpMaxSpreadPips ? If not, no trade.
  • Threshold Check: Is the probability signal strong enough? (e.g., > 0.55 or < 0.45, based on InpMinPredictionDiff ).
  • Multi-Timeframe EMA: Does the ML signal align with the EMA trend on the current, previous, AND next timeframes?
  • RSI Confirmation: Is RSI above 55 for a buy or below 45 for a sell?
  • MACD Confirmation: Is the MACD line on the correct side of the signal line?
  • Volatility Filter: Is the market moving? We check if ATR is within a minimum and maximum pip range.
  • Trend Strength: Is the ADX value above 20, confirming a trend is even present?

Only if the ML signal is strong AND the market context is logical does the trade get placed.

Pre-Release Announcement: Ratio X Gold ML (ONNX)

This hybrid philosophy is the core of my brand-new Expert Advisor, the Ratio X Gold ML (ONNX), which I've just finished developing.

It combines everything I've discussed above into one powerful, professional-grade package. It isn't just a blind predictor; it's an intelligent trading assistant that fuses next-generation ML predictions with time-tested technical analysis.

The key features include:

  • Pre-Trained ONNX Models: Hard-coded models for M1, M5, M15, M30, H1, and H4, so you can trade on any of these timeframes instantly.
  • Full Confluence Filter: The exact multi-timeframe filter I described (EMA, RSI, MACD, ATR, ADX, Spread) to ensure high-quality entries.
  • Full Risk Management Suite:
    • Fixed Lot or Risk-Percentage Autolot sizing.
    • ATR-based or Fixed Pips for Stop Loss and Take Profit.
    • Daily Profit and Loss Targets (as % of balance).
    • Trading Time Filter.
    • Breakeven and multi-function Trailing Stop logic.
    • A smart Margin Check that auto-adjusts lot size if margin is low.

How to Get Early Access

I am doing a special, quiet pre-release of this EA for my MQL5 community friends before the official launch.

If you are interested in this hybrid trading approach and want to be one of the first to use the Ratio X Gold ML, here's what to do:

1. Add me as a Friend on MQL5.

2. Keep an eye on my MQL5 wall.

I will be posting it on my wall first with a special introductory price only for those who are following me. This is my most advanced EA to date, and I'm excited to share it with a serious group of traders first.

Thanks for reading, and I hope this gives you some new ideas for your own development!