LightGBM is the most widely used gradient-boosted-tree library for tabular trading data. It trains fast, predicts fast, and works very well with engineered features. To run it inside MQL5, convert to ONNX with onnxmltools, which has explicit LightGBM support.
Important up front: gradient-boosted trees don't benefit from GPU inference. The CPU is faster for this kind of model (decision-tree traversal is a branchy, memory-bound operation; GPUs hate that). Set ONNX_USE_CPU_ONLY on the MQL5 side and forget about CUDA for this one.
What's in this article
Install
install
pip install lightgbm==4.3.0
pip install onnxmltools==1.12.0
pip install onnx==1.16.0
pip install "numpy<2.0"
Train a LightGBM model
Standard binary-classification pattern for trade entry signals:
train.py
import lightgbm as lgb
import numpy as np
# X: shape (n_samples, n_features); y: binary 0/1
train_data = lgb.Dataset(X_train, label=y_train)
params = {
"objective": "binary",
"learning_rate": 0.05,
"num_leaves": 31,
"max_depth": 6,
"verbose": -1,
}
booster = lgb.train(params, train_data, num_boost_round=200)
booster.save_model("signal.txt")
Convert to ONNX
convert.py
import lightgbm as lgb
from onnxmltools import convert_lightgbm
from onnxmltools.convert.common.data_types import FloatTensorType
booster = lgb.Booster(model_file="signal.txt")
n_features = booster.num_feature()
initial_types = [("input", FloatTensorType([None, n_features]))]
onnx_model = convert_lightgbm(
booster,
initial_types=initial_types,
target_opset=17,
)
with open("signal.onnx", "wb") as f:
f.write(onnx_model.SerializeToString())
That produces signal.onnx. Drop into MQL5\Files\.
Use it in MQL5 (CPU-only)
load and run
#resource "models\signal.onnx" as uchar SignalModel[]
long hSig = INVALID_HANDLE;
int OnInit()
{
// CPU only — trees don't benefit from GPU
hSig = OnnxCreateFromBuffer(SignalModel, ONNX_USE_CPU_ONLY);
if(hSig == INVALID_HANDLE) return(INIT_FAILED);
const long in_shape[] = {1, 12}; // 12 features
const long out_shape[] = {1, 1};
OnnxSetInputShape(hSig, 0, in_shape);
OnnxSetOutputShape(hSig, 0, out_shape);
return(INIT_SUCCEEDED);
}
double Predict(const double &features[])
{
matrixf input(1, 12);
vectorf output(1);
for(int i = 0; i < 12; i++) input[0][i] = (float)features[i];
OnnxRun(hSig, ONNX_NO_CONVERSION, input, output);
return output[0]; // probability 0..1
}
Common gotchas
- Categorical features. LightGBM supports them natively; ONNX doesn't have a perfect equivalent. Convert categoricals to numeric (one-hot or target encoding) at training time so the converter has nothing exotic to translate.
- Missing-value handling. LightGBM treats NaN as a feature; the ONNX export does too, but only if you don't manually impute. If you imputed during training, do the same imputation in MQL5 before calling
OnnxRun. - Output shape. Binary classification produces a 1D probability vector; multi-class produces a 2D matrix. Check with Netron before writing the MQL5 code.
- Multi-class label encoding. The labels in the ONNX output match the order LightGBM saw during training. Save the label-to-index mapping separately.