ONNX offers a practical path for bringing a compatible trained model closer to MetaTrader 5 execution. Instead of calling a remote Python service or external inference API, an Expert Advisor can load and evaluate an ONNX model in the terminal. This can reduce network dependence, simplify latency measurement, and make the live decision path easier to operate.
However, native inference does not turn a model into a complete trading system. The model is only one component. Inputs must match training exactly, outputs must be validated, and deterministic code must still control position sizing, exposure, spread filters, stop-loss logic, order transmission, and audit logging.
This article is an educational software-architecture guide for MQL5 developers. It does not provide financial or investment advice. Machine-learning outputs are uncertain, historical tests do not guarantee future results, and every model and Expert Advisor should be tested in controlled environments before any live use.
What Is ONNX?
ONNX, short for Open Neural Network Exchange, is a model format intended to make trained machine-learning models portable between compatible tools and runtimes. A model may be trained in one environment and then exported into an ONNX file for inference in another environment.
For MetaTrader 5 developers, the appeal is straightforward: a compact compatible model can be evaluated directly inside an MQL5 Expert Advisor without requiring a network call for every inference decision.
A simplified workflow is:
TRAINING ENVIRONMENT → EXPORTED ONNX MODEL → MQL5 FEATURE PIPELINE → ONNX INFERENCE → DETERMINISTIC RISK GATE → MT5 ORDER POLICY → AUDIT LOG
ONNX is a format and runtime path. It is not a guarantee that a model is valid, profitable, compatible, robust, or appropriate for live trading.
Why Use Native Inference in MT5?
Running inference inside an EA can be useful when the model is compact, inference is well-defined, and you want to reduce dependencies on external services. It is especially suitable for classifiers, regressors, anomaly detectors, or regime filters that inform an established deterministic strategy.
| Potential Benefit | Why It Matters | Important Limitation |
|---|---|---|
| Reduced network dependence | No remote inference request is required for each decision. | Terminal, model, history, and feature-pipeline failures still need handling. |
| Simpler latency measurement | You can measure feature creation and local inference inside one execution environment. | Low inference latency does not make a strategy suitable for very short-horizon trading. |
| Fewer moving parts | Eliminates a remote service, API credentials, network retries, and message transport for inference. | Model versioning, feature parity, and EA deployment discipline remain essential. |
| Local decision path | The EA can combine current symbol properties, spread, position state, and model output quickly. | Model output still must pass deterministic risk and execution checks. |
| Operational simplicity | A compact model can be packaged with a controlled EA deployment. | Changing the model still requires controlled validation and release management. |
Native inference is not automatically superior to a Python bridge. A complex model may be easier to research, monitor, retrain, or serve externally. Choose the architecture based on measured requirements rather than assuming local inference is always best.
The Design Rule: Model Output Is Not Order Authority
The key safety rule remains:
The model may recommend. Only deterministic MQL5 code may authorize, size, and transmit an order.
An ONNX model can return a classification, regression value, probability-like score, ranking, or regime label. It should not directly control lot size, remove a stop-loss, bypass exposure limits, or send an order because a threshold was crossed.
A safer local architecture is:
MARKET SNAPSHOT → FEATURE VALIDATION → ONNX INFERENCE → OUTPUT VALIDATION → STRATEGY FILTER → RISK GATE → ORDER POLICY → MT5 EXECUTION → AUDIT LOG
Every arrow represents a boundary where invalid, stale, or uncertain data can be rejected. The default action when a dependency fails should be NO_TRADE.
The Real Challenge: Feature Parity
The most common failure is not model loading. It is feature mismatch. A model is only meaningful when live inputs are generated exactly as they were during training.
Feature parity means that the MQL5 EA reproduces the complete training-time input pipeline:
- Same symbol interpretation and price source.
- Same timeframe.
- Same bar alignment and decision timestamp.
- Same use of completed bars versus current forming bars.
- Same lookback window and bar ordering.
- Same feature names and feature order.
- Same formulas and numeric precision policy.
- Same missing-value treatment.
- Same outlier handling or clipping rules.
- Same scaling, normalization, and transformation steps.
- Same tensor shape and data type.
A model trained on standardized returns can produce meaningless outputs if a live EA sends raw prices. A model trained with oldest-to-newest bar ordering can fail if the EA sends newest-to-oldest values. A model trained on completed candles can behave unpredictably if the EA includes an unfinished current candle.
Feature parity is not an implementation detail. It is the contract between training and execution.
Bar Alignment Must Match Training
Time-series models are especially sensitive to bar alignment. You must define exactly which bar is the “current” decision point and which bars are included in the model input.
For example, suppose the model uses the previous 64 completed M15 bars to make a decision at the close of a newly completed bar. The EA must use the same 64 completed bars, in the same chronological order, and must not accidentally include the newly forming bar.
Document:
- The decision event: new tick, new bar, bar close, timer interval, or another explicit trigger.
- The index of the most recent completed bar used in the feature vector.
- The total lookback length.
- Whether bars are ordered oldest-to-newest or newest-to-oldest.
- Whether features use open, high, low, close, tick volume, real volume, spread, or another field.
- How missing bars, weekend gaps, holidays, and unavailable history are handled.
Do not rely on informal assumptions about array direction in MQL5. Make bar order explicit, test it, and store it in the feature-schema specification.
Feature Order Must Be Fixed
Neural networks and many machine-learning models do not know feature names at inference time. They receive an ordered tensor. If the order changes, the model may silently interpret the wrong value as the wrong feature.
For example, a model trained with:
[return_1, return_5, atr_normalized, spread_normalized, trend_strength]
must receive that exact order in MQL5. Sending:
[spread_normalized, return_1, return_5, atr_normalized, trend_strength]
may not produce an error, but it invalidates the inference.
Create a versioned feature manifest that includes:
- Feature schema ID and version.
- Feature name.
- Position index.
- Source data and timeframe.
- Formula or transformation description.
- Expected data type.
- Allowed range or validation rule.
- Missing-value policy.
- Scaling or normalization method.
Do not maintain the training feature list in a notebook and retype it manually in MQL5 from memory. Generate, export, or otherwise control the manifest as a versioned artifact.
Normalization Must Be an Artifact
Scaling and normalization are frequent sources of live-model failure. If a model was trained on normalized values, live inference must use the same transformation with the same parameters.
Common transformations include:
- Standardization: subtract a training mean and divide by a training standard deviation.
- Min-max scaling using fixed training minimum and maximum values.
- Logarithmic transformation.
- Return or percentage-change transformation.
- Volatility normalization.
- Winsorization or clipping at defined thresholds.
- Robust scaling using training median and interquartile range.
Save normalization parameters as versioned artifacts rather than recalculating them from a changing live sample. Recalculating a training mean, standard deviation, or min-max range on live data silently changes the model input distribution and can make outputs incomparable with training results.
For example, if training used:
z = (x - training_mean) ÷ training_standard_deviation
then the EA must use the stored training mean and training standard deviation for that feature version. It should not substitute a rolling live mean unless the model was explicitly trained and validated with that exact rolling transformation.
Missing Values Need a Defined Policy
Missing data should never be silently converted into a random default. Define the policy during training and reproduce it in live inference.
Possible policies include:
- Reject the feature vector and return no trade.
- Use a fixed sentinel value only if the model was trained with that convention.
- Use forward fill only if it was part of training preprocessing.
- Use a defined imputation method with versioned parameters.
- Require a minimum bar count and wait until enough valid history exists.
For trading decisions, rejecting an incomplete vector is often safer than attempting to infer what missing data should mean. The model should not be asked to operate outside the assumptions used during development.
Tensor Shape and Data Type Must Match
An ONNX model expects specific input names, dimensions, tensor shapes, and data types. MQL5 inference code must configure these correctly.
Examples of model input shapes might include:
- A flat feature vector: [1, feature_count] .
- A sequence model input: [1, lookback_bars, feature_count] .
- A multi-input model with separate price, calendar, and account-state tensors.
Do not assume that a model with 64 bars and 10 features accepts a flat array of 640 values without checking its declared input shape. The shape communicates structure, and a mismatch can produce errors or incorrect interpretation.
Before deployment, document:
- ONNX input and output names.
- Input count and output count.
- Expected tensor dimensions.
- Expected data type, such as float or double-compatible representation.
- Batch dimension behavior.
- Sequence length and feature count.
- Output shape and semantic meaning of each output element.
Validate dimensions at initialization and before inference. A malformed tensor should disable new entries and produce an auditable error, not fall through to a default signal.
Understand Model Output Before Using It
A model output is only useful if its semantics are documented. A single numeric output might represent a predicted return, a class score, a probability-like value, a normalized target, a ranking score, or an uncalibrated logit.
Before connecting output to a strategy filter, define:
- What each output element means.
- What target was used during training.
- Whether the output is raw or transformed.
- Whether a classification output needs softmax, sigmoid, thresholding, or another post-processing step.
- How thresholds were selected and validated out of sample.
- How output uncertainty or low-confidence cases are handled.
- What output values should result in no trade.
Do not assume that a value near 0.80 means an 80% chance of profit. If a confidence or probability-like score is used, it must be calibrated and evaluated across relevant market regimes. Even then, it should not override deterministic risk limits.
Model Compatibility and Export Discipline
Not every training model exports cleanly into a runtime environment, and not every exported graph behaves exactly as expected. Model compatibility depends on operations used, ONNX opset version, input types, and runtime support.
Before committing to an architecture, verify that:
- The training framework can export the model successfully.
- The ONNX graph uses operations supported by the intended MQL5 runtime.
- The exported model has stable named inputs and outputs.
- Dynamic dimensions are handled deliberately rather than assumed.
- The model file is packaged, versioned, and integrity-checked.
- The model can be loaded in the target terminal environment.
- Fixed validation vectors produce acceptable output parity between training and MQL5 environments.
Keep the exported model immutable after validation. If the model is retrained or re-exported, treat it as a new release with a new version, fresh parity tests, and a controlled deployment process.
Suggested Artifact Package
A deployable model should not be only an .onnx file. Package the decision-critical artifacts together and version them as one release.
/model_release_regime_v4 model.onnx manifest.json normalization.json feature_schema.json output_contract.json validation_vectors.json validation_expected_outputs.json release_notes.md checksums.sha256
The package should answer: what model is this, what features does it expect, how are they normalized, what does the output mean, and how was parity validated?
Example Feature Manifest
{
"feature_schema_id": "regime_features_v3",
"timeframe": "M15",
"lookback_bars": 64,
"bar_policy": "completed_bars_only_oldest_to_newest",
"features": [
{
"index": 0,
"name": "return_1",
"transform": "close[t] / close[t-1] - 1",
"normalization": "zscore:return_1_mean:return_1_std",
"missing_policy": "reject"
},
{
"index": 1,
"name": "atr_normalized",
"transform": "ATR(14) / close[t]",
"normalization": "zscore:atr_mean:atr_std",
"missing_policy": "reject"
},
{
"index": 2,
"name": "spread_normalized",
"transform": "(ask - bid) / point",
"normalization": "zscore:spread_mean:spread_std",
"missing_policy": "reject"
}
]
} The exact fields are flexible, but the key point is that feature definitions are explicit, versioned, and testable.
Validate Python and MQL5 Output Parity
Before testing an order path, compare inference outputs on a fixed validation set in both the training environment and MQL5. This is the most important deployment test.
Use the same timestamped feature vectors in both environments. Store the expected input tensors and training-environment outputs as release artifacts. Then run those exact vectors through the MQL5 implementation.
The validation test is:
Run the same timestamped feature vectors through Python and MQL5, then compare every output before testing an order path.
What to Compare
- Feature values before normalization.
- Normalization parameters and normalized values.
- Tensor shape and element order.
- Model input name and output name.
- Raw output vector from the training environment.
- Raw output vector from MQL5 inference.
- Post-processing result, such as class label or threshold decision.
- Final no-trade, long, short, or filter decision.
Small numeric differences can occur because of runtime implementation, floating-point behavior, or hardware differences. Whether a difference is acceptable depends on the model and strategy. A small absolute difference may be harmless for a wide regression band but critical if it crosses a trade threshold.
Directional, class-label, threshold, or action changes require investigation. Do not deploy a model simply because values look approximately similar.
Build a Fixed Validation Set
Your validation set should include more than normal market examples. Use cases that exercise edge conditions in the feature pipeline and model output.
Include:
- Typical trending conditions.
- Typical ranging conditions.
- High-volatility periods.
- Low-volatility periods.
- Wider-than-normal spread examples.
- Boundary values near decision thresholds.
- Feature values near expected minimum and maximum ranges.
- Examples with valid but unusual price behavior.
- Known reject cases, such as insufficient history or invalid values.
Save the timestamp, symbol, timeframe, raw bars, expected feature vector, expected normalized vector, expected model output, and expected final strategy decision. This gives you a repeatable regression suite whenever the EA, feature code, or model package changes.
Initialization Must Fail Safely
Model initialization is a controlled deployment step. If the model cannot load, dimensions are invalid, or artifacts do not match expected versions, the EA should disable new entries and log the error.
At initialization, validate:
- The model file exists and is readable.
- The model checksum matches the approved release manifest.
- The model version matches the expected feature schema and normalization artifact.
- Required input and output names are present.
- Tensor shapes can be configured as expected.
- The symbol and timeframe configuration matches the model release.
- A smoke-test vector produces a finite output.
- The EA has enough history to create the required lookback.
If any check fails, set an explicit internal state such as MODEL_DISABLED or NEW_ENTRIES_DISABLED. Existing positions should be managed only by pre-defined deterministic protective rules. Do not let a missing model cause the EA to trade using an untested fallback signal.
Inference-Time Validation
A model that loaded correctly at startup can still receive invalid data later. Validate the live feature vector every time before inference.
Check:
- Enough completed bars are available.
- Bar timestamps are continuous enough for your strategy’s policy.
- All required prices and indicator values are present.
- No feature is NaN, infinity, or outside defined hard bounds.
- Spread and market conditions satisfy your strategy policy.
- Feature order and tensor dimensions match the loaded model manifest.
- The decision timestamp aligns with the completed-bar rule.
- The model output is finite, the expected shape, and within any defined sanity bounds.
If validation fails, skip inference or discard the output. Record a reason code. The safe fallback is no new trade.
Handle Non-Finite and Unexpected Outputs
Model outputs should never be trusted without validation. A model can return NaN, infinity, an unexpected shape, an unreasonably large value, or a value that does not fit the output contract.
Create explicit checks such as:
- Is every output finite?
- Does output shape match the expected output contract?
- Is every output within a plausible hard range?
- Does a classification vector sum or normalize as expected, if applicable?
- Does the selected class or threshold map to an allowed strategy action?
- Has the output distribution become abnormal compared with monitored baseline behavior?
If an output fails validation, disable new entries for the current cycle and log the model version, feature vector hash, output, and failure code. Repeated output failures should activate a circuit breaker until the system is inspected.
Use a Deterministic Strategy Filter
The ONNX output should usually be one input to a deterministic strategy filter, not the entire strategy. For example, a model might classify the market as trend, range, high volatility, or unclear. The EA can then allow only the corresponding deterministic setup type.
Other bounded uses include:
- Rejecting a deterministic setup when anomaly score is too high.
- Ranking multiple already-valid setups without changing per-trade risk.
- Allowing a trend-pullback strategy only when a regime classifier confirms trend conditions.
- Filtering trades when predicted volatility exceeds a tested threshold.
- Estimating expected holding horizon for management logic that remains deterministic.
The model should not become a reason to abandon basic mechanics. A high model score does not make an invalid stop-loss valid, a wide spread acceptable, or correlated exposure safe.
Risk Controls Still Belong Outside the Model
Local inference does not eliminate trading risk. After a model produces a valid output, the EA must still apply deterministic checks before any order is authorized.
Required risk controls generally include:
- Approved symbol, timeframe, and trading-session checks.
- Current spread and liquidity filters.
- Scheduled-news or event blackout policy.
- Logical stop-loss validation and broker stops-level checks.
- Position size calculated from fixed account risk and actual stop distance.
- Minimum and maximum volume, step, and margin validation.
- Maximum risk per trade and maximum total open risk.
- Daily loss, drawdown, trade-count, and consecutive-loss limits.
- Correlation, currency exposure, and duplicate-position limits.
- Freshness and price-drift checks between model decision and order policy.
- Kill-switch and manual-disable controls.
ONNX can reduce network dependence. It cannot replace position limits, spread filters, stop logic, or broker-aware execution policy.
MQL5 Implementation Structure
Keep ONNX integration isolated from risk and execution code. A modular project structure makes it easier to test, version, and replace the model without changing account-protection behavior.
/OnnxTradingEA /Core MarketSnapshot.mqh FeatureManifest.mqh FeatureBuilder.mqh Normalization.mqh OnnxRuntimeAdapter.mqh OutputValidator.mqh StrategyFilter.mqh RiskGate.mqh OrderPolicy.mqh ExecutionAdapter.mqh AuditLogger.mqh KillSwitch.mqh /Models ModelRegistry.mqh ValidationVectors.mqh /Config ModelReleaseConfig.mqh OnnxTradingEA.mq5
The main EA should coordinate modules. It should not mix indicator calculations, tensor management, position sizing, and order transmission in one large function.
Conceptual MQL5 Flow
OnInit():
release = ModelRegistry.LoadReleaseManifest()
if !release.IsCompatibleWithEA():
DisableNewEntries("MODEL_RELEASE_INCOMPATIBLE")
return INIT_FAILED
if !OnnxAdapter.Load(release.model_path):
DisableNewEntries("MODEL_LOAD_FAILED")
return INIT_FAILED
if !OnnxAdapter.ConfigureInputOutputShapes(release):
DisableNewEntries("MODEL_DIMENSION_CONFIGURATION_FAILED")
return INIT_FAILED
if !RunStartupParitySmokeTest(release):
DisableNewEntries("STARTUP_PARITY_TEST_FAILED")
return INIT_FAILED
Audit.LogModelInitialized(release)
return INIT_SUCCEEDED
OnTimer():
if KillSwitch.IsActive() || NewEntriesDisabled():
return
snapshot = MarketSnapshotBuilder.Create()
if !Snapshot.IsReliable():
Audit.LogNoTrade("UNRELIABLE_MARKET_STATE")
return
features = FeatureBuilder.Create(snapshot, release.feature_manifest)
if !FeatureValidator.IsValid(features):
Audit.LogNoTrade("INVALID_FEATURE_VECTOR")
return
tensor = Normalizer.BuildTensor(features, release.normalization)
if !TensorValidator.IsValid(tensor, release.input_contract):
Audit.LogNoTrade("INVALID_INPUT_TENSOR")
return
output = OnnxAdapter.Run(tensor)
if !OutputValidator.IsValid(output, release.output_contract):
Audit.LogModelFailure("INVALID_MODEL_OUTPUT")
return
proposal = StrategyFilter.BuildProposal(snapshot, output, release)
decision = RiskGate.Evaluate(snapshot, proposal)
Audit.LogDecision(snapshot, features, output, proposal, decision)
if !decision.approved:
return
request = OrderPolicy.BuildRequest(decision.trade_intent)
result = ExecutionAdapter.SendAndReconcile(request)
Audit.LogExecution(decision, request, result) Each failure exits safely. There is no automatic substitute trade when data, model state, or output is invalid.
Use New-Bar Logic Deliberately
For many bar-based models, inference should run once per completed decision bar rather than on every tick. New-bar logic reduces unnecessary inference, avoids repeated decisions from the same information, and makes feature alignment easier to reproduce.
A typical approach is:
- Detect when a new bar begins on the decision timeframe.
- Treat the just-closed bar as the newest completed bar.
- Build features from the defined historical window.
- Run one model inference for that decision point.
- Record the bar timestamp, feature hash, output, and resulting decision.
- Use cooldown and duplicate-trade controls so one bar cannot create multiple orders.
If you need intrabar inference, define it separately and test it separately. Do not reuse a close-based model with tick-by-tick live features unless that behavior was part of training and validation.
Latency: Measure It, but Keep Perspective
Local ONNX inference can reduce one category of delay: remote request and response. It does not eliminate chart data access, feature calculation, terminal scheduling, risk checks, order transmission, broker execution, or market movement while the order is processed.
Measure:
- Time to retrieve bars and symbol data.
- Feature calculation time.
- Normalization and tensor-construction time.
- ONNX inference time.
- Output-validation and risk-gate time.
- Order-policy construction time.
- Broker request and response time.
Use the measurements to decide whether the architecture fits the strategy horizon. A compact model may be appropriate for M15, H1, or H4 decisions even if it is not suitable for short-horizon execution. Do not confuse fast local inference with a license to pursue latency-sensitive strategies without complete measurement.
Model and EA Versioning
Every output and trade decision should be tied to the exact release that produced it. Version more than the ONNX file.
Record:
- ONNX model version, file hash, and export date.
- Training-data reference and evaluation version where applicable.
- Feature-schema version and manifest hash.
- Normalization artifact version and hash.
- Output contract and threshold-policy version.
- Strategy filter version.
- Risk policy, position-sizing policy, and order-policy version.
- EA build number and source-control commit.
- Broker symbol mapping and configuration version.
If a model is updated, treat it as a new strategy release. Do not replace the ONNX file under the same version name and assume results remain comparable.
Audit Logging for Local Inference
Local inference makes it easier to log a complete decision path. Use that advantage. Each cycle should have a correlation ID that links the market snapshot to features, model output, risk decision, and execution result.
Log:
- Decision timestamp in UTC and broker server time.
- Symbol, timeframe, and completed-bar timestamp.
- Model release ID, file hash, and feature-schema version.
- Feature vector or secure feature-vector reference and hash.
- Normalization artifact version and normalized tensor hash.
- Raw model output and post-processed output.
- Strategy proposal, including no-trade decisions.
- Risk-gate approvals or denials with all reason codes.
- Calculated volume, stop distance, and total exposure checks.
- Final MT5 request, broker response, tickets, fill, slippage, and position lifecycle.
Logging no-trade decisions matters. It helps distinguish “the model did not signal” from “the risk gate rejected” and “the model was disabled due to an error.”
Testing the ONNX Pipeline
Test the entire pipeline, not only the model. A model can be correct in Python while the live system is wrong because of bar direction, normalization mismatch, tensor shape, broker symbol properties, or risk-policy differences.
| Test Layer | What to Verify |
|---|---|
| Artifact validation | Model file, checksum, manifest, normalization parameters, output contract, and release compatibility. |
| Feature unit tests | Bar alignment, feature formulas, ordering, missing-data policy, scaling, clipping, and hard bounds. |
| Parity tests | Fixed timestamped feature vectors and outputs agree between training environment and MQL5 within defined tolerance. |
| Output contract tests | Finite values, expected shape, valid label mapping, threshold behavior, and no-trade handling. |
| Risk-gate tests | Spread, news, stop distance, volume, margin, daily loss, correlation, cooldown, and kill-switch denial paths. |
| Execution tests | Broker filling mode, symbol constraints, invalid stops, rejected requests, duplicate prevention, and reconciliation. |
| Forward demo tests | Live history availability, terminal behavior, actual latency, logging, reconnect handling, and broker-specific execution. |
Build a regression suite from validation vectors. Run it whenever you update the EA, indicators, feature manifest, model package, terminal environment, or broker configuration.
Use Shadow Mode Before an Order Path
Shadow mode runs the real live feature pipeline and ONNX inference but blocks all new orders. It records what the model would have proposed and what the deterministic risk gate would have allowed.
Shadow mode is useful for detecting:
- Feature mismatch between historical research and live terminal data.
- Unexpected missing bars or timestamp alignment problems.
- Model outputs that differ from expected distributions.
- Frequent no-trade results caused by live spread or session conditions.
- Risk-gate denials caused by invalid stop distance, sizing, or exposure.
- Latency or CPU cost that does not fit the intended schedule.
Do not interpret shadow-mode outcomes as proof of profitability. Use it to validate operational behavior and feature parity before enabling any demo order flow.
Common ONNX Deployment Failures
Sending Raw Prices to a Model Trained on Returns
Raw prices and normalized returns have different scales and meanings. The model may return a number, but it will not be using the input distribution it learned.
Recomputing Training Normalization on Live Data
Live recalculation changes the transformation. Use versioned training parameters unless a rolling method was specifically part of training and validation.
Using the Current Forming Bar by Accident
A close-based model can become unstable if live code includes a changing current candle. Use completed-bar rules and explicit bar indexing.
Changing Feature Order
The model may not report an error when features are reordered. Maintain a versioned manifest and validate tensor order.
Ignoring Shape Errors
Sequence dimensions, batch dimensions, and feature count all matter. Validate model input and output contracts at initialization and inference time.
Trading on Non-Finite Output
NaN, infinity, malformed output, or impossible values should disable new entries and generate a logged fault.
Skipping Parity Tests
Testing only the Python model does not prove the MQL5 implementation is equivalent. Compare fixed vectors and every output before testing orders.
Letting the Model Override Risk Controls
Local inference does not justify larger volume, wider stops, or ignored spread filters. Keep risk and execution policy deterministic.
Adding Too Many Inputs Without Evidence
More indicators and features can increase complexity, overfitting risk, and feature-parity failure points. If the broader strategy needs simplification, use the same principle as avoiding overloaded indicator stacks: add only inputs that improve out-of-sample decisions.
When ONNX Is a Good Fit
ONNX local inference is often a good fit when:
- The model is compact and compatible with the MQL5 runtime.
- The feature pipeline is stable, documented, and reproducible.
- The strategy operates on a timeframe where local feature and inference timing is practical.
- The model serves a bounded role, such as regime classification or setup filtering.
- You can create and maintain parity tests and versioned artifacts.
- The EA already has independent deterministic risk and execution controls.
It may be a poor fit when the model requires complex unsupported operations, frequent retraining and large external data dependencies, heavy natural-language context, or behavior that cannot be reliably reproduced inside the terminal.
Implementation Checklist
Use this checklist when deploying an ONNX model inside an MQL5 Expert Advisor:
- Use the model as a bounded inference component, not as direct order authority.
- Define the exact decision time, timeframe, bar alignment, and completed-bar policy.
- Freeze feature names, order, formulas, missing-value policy, and tensor shape in a versioned manifest.
- Export normalization parameters as versioned artifacts and do not silently recalculate them live.
- Document model input names, output names, dimensions, data types, and output meaning.
- Package the ONNX file with manifest, normalization, output contract, validation vectors, checksums, and release notes.
- Compare the same timestamped vectors in Python and MQL5 before testing any order path.
- Investigate any directional, class, threshold, or action mismatch between environments.
- Handle model-load failure, missing history, malformed tensors, and non-finite output by disabling new entries.
- Run inference only at defined decision points and use cooldown or duplicate controls.
- Keep position sizing, spread filters, stops, exposure limits, and order authorization deterministic.
- Log model release, feature hash, output, risk decision, and execution lifecycle for every cycle.
- Use shadow mode and forward demo testing before allowing any live order path.
- Version every model, artifact, EA build, policy, and configuration change.
Final Thoughts
Running ONNX directly inside an MQL5 Expert Advisor can reduce network dependence and bring a compatible compact model closer to the execution environment. But local inference is only reliable when feature parity is treated as a strict engineering contract.
Match bar alignment, feature order, missing-value handling, normalization, tensor shape, and output interpretation exactly. Validate the same fixed feature vectors in Python and MQL5 before an order path is tested. Then place the model behind deterministic risk gates, broker-aware execution controls, audit logs, and fail-closed behavior. The model may improve a bounded decision; it should never replace tested trading mechanics.
Risk disclaimer: Automated trading, artificial intelligence, machine learning, ONNX models, Expert Advisors, foreign exchange, CFDs, commodities, indices, stocks, cryptocurrencies, and other leveraged products involve substantial risk and may not be suitable for all investors. This article is for educational and software-architecture purposes only and does not constitute financial, investment, legal, tax, cybersecurity, or regulatory advice. Model outputs can be incorrect, delayed, incomplete, or inconsistent. Past performance, backtests, forward tests, and demo results do not guarantee future results. Test all systems carefully, verify broker-specific behavior, and use robust independent risk controls before considering live deployment.


