🐍 Tutorial Prático

Como Exportar Modelo Python (PyTorch + Sklearn) para ONNX e Usar no MT5

Por Dan Machado · 11 min de leitura

Tutorial passo-a-passo, sem firula: você sai daqui com dois modelos ONNX funcionais (um Sklearn Random Forest, um PyTorch LSTM), prontos pra serem consumidos no Expert Advisor MT5. Pré-requisito: Python 3.10+ e MT5 instalado. Se você ainda não tem o panorama geral, comece pelo guia pillar ONNX no MT5.

Setup do ambiente Python

▸ bash · install
# Bibliotecas essenciais
pip install MetaTrader5 numpy pandas scikit-learn

# Exportadores ONNX
pip install onnx onnxruntime onnxmltools skl2onnx

# Para PyTorch (CPU)
pip install torch torchvision

# Validação
pip install matplotlib

O pacote MetaTrader5 permite que o Python leia candles direto do terminal MT5 aberto — sem export CSV nem gambiarra.

Parte 1 — Random Forest (Sklearn) → ONNX

Caso de uso: classificar a direção do próximo candle (sobe/desce) baseado em features técnicas dos últimos N candles. Random Forest é leve, treina rápido e funciona bem como baseline.

1

Coletar dados do MT5

Conecta no terminal aberto e puxa histórico do ativo desejado.

▸ python · 1_coletar_dados.py
import MetaTrader5 as mt5
import pandas as pd
from datetime import datetime, timedelta

mt5.initialize()

simbolo = "EURUSD"
timeframe = mt5.TIMEFRAME_H1
n_barras = 20000

rates = mt5.copy_rates_from_pos(simbolo, timeframe, 0, n_barras)
df = pd.DataFrame(rates)
df['time'] = pd.to_datetime(df['time'], unit='s')

df.to_csv("dados_eurusd_h1.csv", index=False)
print(f"✓ {len(df)} candles salvos")
mt5.shutdown()
2

Gerar features e target

Features: retornos dos últimos 10 candles. Target: 1 se próximo candle subiu, 0 caso contrário.

▸ python · 2_features.py
import pandas as pd
import numpy as np

df = pd.read_csv("dados_eurusd_h1.csv")

# Retorno percentual
df['ret'] = df['close'].pct_change()

# Features: últimos 10 retornos
for i in range(1, 11):
    df[f'ret_lag_{i}'] = df['ret'].shift(i)

# Target: 1 se próximo candle subiu
df['target'] = (df['ret'].shift(-1) > 0).astype(int)

df = df.dropna()

feature_cols = [f'ret_lag_{i}' for i in range(1, 11)]
X = df[feature_cols].values.astype(np.float32)
y = df['target'].values

print(f"X shape: {X.shape} | y balance: {y.mean():.3f}")
np.save("X.npy", X)
np.save("y.npy", y)
3

Treinar Random Forest

Split temporal (sem shuffle — ordem importa em séries temporais).

▸ python · 3_treinar.py
import numpy as np
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score, classification_report

X = np.load("X.npy")
y = np.load("y.npy")

# Split temporal 80/20
split = int(len(X) * 0.8)
X_train, X_test = X[:split], X[split:]
y_train, y_test = y[:split], y[split:]

model = RandomForestClassifier(
    n_estimators=200,
    max_depth=8,
    min_samples_leaf=20,
    random_state=42,
    n_jobs=-1
)

model.fit(X_train, y_train)
pred = model.predict(X_test)

print(f"Accuracy: {accuracy_score(y_test, pred):.3f}")
print(classification_report(y_test, pred))

import joblib
joblib.dump(model, "modelo_rf.pkl")

⚠️ Realidade do accuracy

Se sua accuracy passar de 55% num split temporal honesto, é ótimo. Se passar de 65%, desconfie de data leakage. Acima de 80% em série temporal financeira é quase sempre bug, não talento.

4

Exportar para ONNX

Usa skl2onnx com tipo de entrada definido.

▸ python · 4_exportar_onnx.py
import joblib
import numpy as np
from skl2onnx import convert_sklearn
from skl2onnx.common.data_types import FloatTensorType

model = joblib.load("modelo_rf.pkl")

# Define o shape da entrada: 10 features
initial_type = [('input', FloatTensorType([None, 10]))]

onnx_model = convert_sklearn(
    model,
    initial_types=initial_type,
    target_opset=15
)

with open("modelo_rf.onnx", "wb") as f:
    f.write(onnx_model.SerializeToString())

print("✓ modelo_rf.onnx criado")

# Validação rápida com onnxruntime
import onnxruntime as ort
sess = ort.InferenceSession("modelo_rf.onnx")

X_teste = np.load("X.npy")[-5:].astype(np.float32)
pred_onnx = sess.run(None, {'input': X_teste})
print(f"Predições ONNX (últimas 5): {pred_onnx[0]}")

Parte 2 — LSTM (PyTorch) → ONNX

Mesmo problema, modelo mais sofisticado. LSTM aprende dependências temporais que Random Forest ignora.

▸ python · 5_lstm_pytorch.py
import numpy as np
import torch
import torch.nn as nn

X = np.load("X.npy")  # (N, 10)
y = np.load("y.npy")

# Reshape para sequência: (batch, seq_len=10, features=1)
X_seq = X.reshape(-1, 10, 1)

split = int(len(X) * 0.8)
X_train = torch.tensor(X_seq[:split], dtype=torch.float32)
y_train = torch.tensor(y[:split], dtype=torch.long)
X_test  = torch.tensor(X_seq[split:], dtype=torch.float32)
y_test  = torch.tensor(y[split:], dtype=torch.long)

class LSTMTrader(nn.Module):
    def __init__(self, input_size=1, hidden_size=32, num_layers=2):
        super().__init__()
        self.lstm = nn.LSTM(input_size, hidden_size, num_layers,
                            batch_first=True, dropout=0.2)
        self.fc = nn.Linear(hidden_size, 2)
    
    def forward(self, x):
        out, _ = self.lstm(x)
        out = self.fc(out[:, -1, :])  # último timestep
        return out

model = LSTMTrader()
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)
criterion = nn.CrossEntropyLoss()

# Training loop simples
for epoch in range(20):
    optimizer.zero_grad()
    out = model(X_train)
    loss = criterion(out, y_train)
    loss.backward()
    optimizer.step()
    if epoch % 5 == 0:
        with torch.no_grad():
            acc = (model(X_test).argmax(1) == y_test).float().mean()
        print(f"Epoch {epoch} | loss {loss.item():.4f} | val acc {acc:.3f}")

# === EXPORT PARA ONNX ===
model.eval()
dummy_input = torch.randn(1, 10, 1)

torch.onnx.export(
    model,
    dummy_input,
    "modelo_lstm.onnx",
    input_names=['input'],
    output_names=['output'],
    dynamic_axes={
        'input':  {0: 'batch'},
        'output': {0: 'batch'}
    },
    opset_version=15
)

print("✓ modelo_lstm.onnx exportado")

Parte 3 — Consumir no Expert Advisor MT5

Os arquivos .onnx vão para a pasta MQL5\Files da instalação MT5. No EA, carrega via OnnxCreate:

▸ MQL5 · UseRFModel.mq5 (trecho)
// Carrega arquivo da pasta Files
long handle = OnnxCreate("modelo_rf.onnx", ONNX_DEFAULT);
if(handle == INVALID_HANDLE)
{
    Print("Erro: ", GetLastError());
    return INIT_FAILED;
}

// Define shape: batch=1, features=10
const long input_shape[]  = {1, 10};
const long output_shape[] = {1};
OnnxSetInputShape(handle, 0, input_shape);
OnnxSetOutputShape(handle, 0, output_shape);

// Prepara features dos últimos 10 candles
matrix input(1, 10);
for(int i = 0; i < 10; i++)
{
    double close_atual = iClose(_Symbol, PERIOD_CURRENT, i + 1);
    double close_ant   = iClose(_Symbol, PERIOD_CURRENT, i + 2);
    input[0][i] = (float)((close_atual - close_ant) / close_ant);
}

// Roda inferência
vector output(1);
OnnxRun(handle, ONNX_DEFAULT, input, output);

int direcao = (int)output[0];  // 0 = baixa, 1 = alta
Print("Predição: ", direcao == 1 ? "BUY" : "SELL");

Validação no Strategy Tester

Antes de ligar em conta real, sempre — sempre — backteste no Strategy Tester do MT5:

  1. Coloca o EA na pasta MQL5\Experts e o .onnx em MQL5\Files
  2. F7 no MetaEditor para compilar
  3. Ctrl+R no MT5 → Strategy Tester
  4. Configura ativo, timeframe e período (mínimo 6 meses)
  5. Modo “Every tick based on real ticks”
  6. Analisa profit factor, drawdown máximo, sharpe

✓ Checklist antes de operar real

1. Profit factor > 1.5 em pelo menos 6 meses backtest
2. Drawdown máximo < 20%
3. 200+ trades na amostra
4. Demo trading por 30 dias mínimo com resultado similar ao backtest
5. Risk por trade ≤ 2% do balance
6. Stop loss sempre definido

Troubleshooting comum

  • “Operator not supported” ao exportar: ajuste opset_version (tente 13, 14, 15, 17)
  • OnnxRun retorna false: verifique shapes — input do MQL5 precisa bater exatamente com o que foi declarado no export
  • Predições nan ou constantes: feature scaling. Normalize as features no Python e replique a mesma normalização no MQL5
  • Modelo gigante: simplifique. LSTM com hidden 32 é mais que suficiente para baseline

🚀 Teste seu modelo ONNX em demo Deriv MT5 ($10.000 virtuais):

Abrir Demo Deriv MT5

Próximos passos

DM

Dan Machado

Founder IA Trader Pro · Python + MQL5

⚠️ Disclaimer: Conteúdo educacional, não é recomendação de investimento. Modelos de IA não garantem lucro. Trading de derivativos envolve risco elevado. Sempre teste em demo antes de operar com capital real. Artigo contém link de afiliado Deriv. Disclaimer completo.