preview
The MQL5 Standard Library Explorer (Part 16): Building a Regime-Adaptive Expert Advisor

The MQL5 Standard Library Explorer (Part 16): Building a Regime-Adaptive Expert Advisor

MetaTrader 5Examples |
265 0
Clemence Benjamin
Clemence Benjamin

In Part 15 of the MQL5 Standard Library Explorer, we used dataanalysis.mqh to transform market bars into normalized features and train a decision forest that distinguishes bearish, neutral, and bullish forward price moves. Classification alone does not define a trading system. In this installment, we place that model behind a controlled decision layer and build an Expert Advisor (EA) that adapts its permitted direction without allowing the forest to execute trades directly.


Contents

  1. From Classifier to Controller
  2. System Architecture
  3. Reusable Classifier Module
  4. Completed-Bar Inference
  5. Confidence and Regime Stability
  6. Regime-Dependent Position Policy
  7. Risk and Execution Boundaries
  8. Expert Advisor Lifecycle
  9. Input Parameters
  10. Operating the Expert Advisor
  11. Results and Testing
  12. Limitations
  13. Conclusion
  14. Key Lessons
  15. Attachments


From Classifier to Controller

In Part 15, we defined three target classes from the following bar's return. A return below the negative threshold became bearish, a return inside the threshold band became neutral, and a return above the positive threshold became bullish. These are directional classes. They should not be confused with broader descriptions such as trending, ranging, or high-volatility conditions. Throughout this article, regime is shorthand for the classifier's persistent directional state, not a complete market-structure regime such as trend or range.

In this part, we preserve the same five input features and three labels. The change is architectural: the script becomes a reusable classifier class, while an EA decides whether a classification is sufficiently stable and safe to affect a position. This takes us from Point A, where the model prints diagnostic results, to Point B, where the model supplies a guarded directional state to a complete trading program.

Layer Receives Produces Cannot do
Data layer Completed bars Five normalized features Read a future bar during live inference
Model layer Feature vector Three class scores Submit a trade request
Decision layer Class and confidence Confirmed directional state Bypass confirmation or cooldown
Execution layer Confirmed directional state Open, hold, close, or block Modify or close a position owned by another strategy


System Architecture

I prepared MQL5.zip as a merge-ready archive. It contains two code components placed in terminal-relative folders. MarketRegimeClassifier.mqh owns feature construction, normalization statistics, the decision forest, training, and prediction. RegimeAdaptiveEA.mq5 owns bar timing, regime confirmation, directional authorization, position ownership, risk calculation, and order execution.

Fig. 1. Components and safety boundaries of the regime-adaptive EA

Fig. 1. Components and safety boundaries of the regime-adaptive EA

Following the vertical path in Fig. 1, each stage restricts the authority of the previous one. A prediction must cross the decision boundary and then the execution boundary before it can become a trade request. The chart comment displays classifier output for observation only; it does not feed back into the trading decision.


Reusable Classifier Module

The reusable class continues to use the MetaQuotes ALGLIB package through Math\Alglib\dataanalysis.mqh. It owns CDecisionForestBuilder, CDecisionForest, CDFReport, and the arrays containing the training means and standard deviations. Keeping these objects together ensures that live observations are normalized using the same coordinate system as the training dataset.

//+------------------------------------------------------------------+
//| Builds and queries the decision-forest market classifier         |
//+------------------------------------------------------------------+
class CMarketRegimeClassifier
  {
private:
   CDecisionForestBuilder m_builder;
   CDecisionForest        m_forest;
   CDFReport              m_report;
   double                 m_means[];
   double                 m_sigmas[];
   int                    m_bars;
   int                    m_trees;
   int                    m_seed;
   double                 m_neutral_threshold;
   bool                   m_ready;

//--- Internal helpers used while building and querying the forest
   int    DirectionClass(const double future_return) const;
   bool   BuildDataset(MqlRates &rates[], const int total,
                       CMatrixDouble &xy, int &samples);
   bool   NormalizeFeatures(CMatrixDouble &xy, const int samples);
   bool   BuildFeatures(MqlRates &rates[], const int total,
                        double &features[]);
   void   NormalizeObservation(double &features[]);

public:
                          CMarketRegimeClassifier(void);
   bool                   Configure(const int bars, const int trees,
                                    const double neutral_threshold,
                                    const int seed);
   bool                   Train(const string symbol,
                                const ENUM_TIMEFRAMES timeframe);
   bool                   Predict(const string symbol,
                                  const ENUM_TIMEFRAMES timeframe,
                                  ENUM_MARKET_REGIME &regime,
                                  double &confidence,
                                  double &probabilities[]);
   bool                   Ready(void) const { return(m_ready); }
   double                 OOBClassificationError(void) const
                             { return(m_report.m_oobrelclserror); }
   string                 RegimeName(const ENUM_MARKET_REGIME regime) const;
  };

The class boundary is deliberate. Dataset construction, feature calculation, and normalization remain private because they must operate as one coordinated pipeline. When you reuse the classifier from an EA, you need only Configure(), Train(), and Predict(). Ready() blocks inference before training succeeds, while OOBClassificationError() exposes the diagnostic without exposing the forest report. This design also protects the learned means and standard deviations from accidental modification.

The training routine obtains history with CopyRates() beginning at shift 1. The open bar is therefore excluded. BuildDataset() retains one later completed bar inside the historical sample to create each label, but the five features for row i use information available at row i. This preserves the temporal separation established in Part 15.

//+------------------------------------------------------------------+
//| Trains the forest from completed historical bars                 |
//+------------------------------------------------------------------+
bool CMarketRegimeClassifier::Train(const string symbol,
                                    const ENUM_TIMEFRAMES timeframe)
  {
//--- The model is invalid while a new training run is in progress
   m_ready=false;
   MqlRates rates[];
   ArraySetAsSeries(rates, false);
   const int copied=CopyRates(symbol, timeframe, 1, m_bars, rates);
//--- Require enough history to build an adequate dataset
   if(copied<100)
     {
      //--- Report the shortfall so the caller knows why training failed
      Print("Classifier training needs more history. Copied=", copied);
      return(false);
     }

//--- Build the feature matrix and center it through normalization
   CMatrixDouble dataset;
   int samples=0;
   if(!BuildDataset(rates, copied, dataset, samples))
      return(false);
   if(!NormalizeFeatures(dataset, samples))
      return(false);

//--- Create the forest builder and feed it the prepared dataset
   CDForest::DFBuilderCreate(m_builder);
   CDForest::DFBuilderSetDataset(m_builder, dataset, samples,
                                 REGIME_FEATURES, REGIME_CLASSES);
   CDForest::DFBuilderSetRndVarsAuto(m_builder);
   CDForest::DFBuilderSetSubsampleRatio(m_builder, 0.50);
   CDForest::DFBuilderSetSeed(m_builder, m_seed);
   CDForest::DFBuilderSetImportancePermutation(m_builder);
//--- Build the random forest and capture the out-of-bag report
   CDForest::DFBuilderBuildRandomForest(m_builder, m_trees,
                                        m_forest, m_report);
   m_ready=true;

   PrintFormat("Classifier trained: samples=%d, OOB error=%.6f",
               samples, m_report.m_oobrelclserror);
   return(true);
  }

Train() begins by clearing m_ready, so a failed training attempt cannot leave prediction enabled with an uncertain model state. CopyRates() requests completed history from shift 1. BuildDataset() then creates the labeled matrix, while NormalizeFeatures() stores the statistics required by live observations. The forest builder receives the feature and class counts explicitly. Its final journal message records the sample count and out-of-bag error, creating a checkpoint for each rebuild.

A fixed positive seed makes repeated training on the same dataset reproducible. When we retrain later in the test, the dataset still changes because the historical window has advanced. The out-of-bag relative classification error is exposed to the EA for diagnosis, not used as a direct entry condition.


Completed-Bar Inference

The EA runs inference once after a new chart bar opens. At that moment, shift 1 is the most recently completed bar. Predict() copies eleven completed bars because Momentum10 needs the current completed close and the close ten bars earlier. ArraySetAsSeries(false) places the oldest copied observation first in physical memory, so the final array element represents the latest completed bar.

//+------------------------------------------------------------------+
//| Returns the current class and its forest-vote confidence         |
//+------------------------------------------------------------------+
bool CMarketRegimeClassifier::Predict(const string symbol,
                                      const ENUM_TIMEFRAMES timeframe,
                                      ENUM_MARKET_REGIME &regime,
                                      double &confidence,
                                      double &probabilities[])
  {
   regime=REGIME_UNKNOWN;
   confidence=0.0;
//--- A trained forest is required before any prediction
   if(!m_ready)
      return(false);

   MqlRates rates[];
   ArraySetAsSeries(rates, false);
//--- Fetch exactly the eleven bars of the feature window
   const int copied=CopyRates(symbol, timeframe, 1, 11, rates);
   if(copied!=11)
      return(false);

   double features[];
   if(!BuildFeatures(rates, copied, features))
      return(false);
//--- Scale the live observation with the training statistics
   NormalizeObservation(features);

   ArrayResize(probabilities, REGIME_CLASSES);
//--- Ask the forest for the class-vote probability distribution
   CDForest::DFProcess(m_forest, features, probabilities);
   int best=0;
//--- Pick the class with the largest share of votes
   for(int i=1; i<REGIME_CLASSES; i++)
      if(probabilities[i]>probabilities[best])
         best=i;

   regime=(ENUM_MARKET_REGIME)best;
   confidence=probabilities[best];
   return(true);
  }

Predict() starts with a defensive output contract: REGIME_UNKNOWN and zero confidence are assigned before any failure can occur. The eleven copied bars cover the complete ten-bar momentum window without reading the open bar. BuildFeatures() reconstructs the five training inputs, and NormalizeObservation() applies the stored training statistics. The final loop selects the largest forest output and maps that index directly to the regime enumeration.

DFProcess() returns one value for each class. When you inspect this three-class forest, the EA compares the bearish, neutral, and bullish values, selects the largest, and retains it as confidence. Confidence here is the forest's largest class score (normalized vote share). It is not a calibrated probability that the next bar will move in that direction.


Confidence and Regime Stability

A classifier can change its winning class on consecutive bars. Executing every change would make the EA vulnerable to rapid reversals and transaction costs. We therefore distinguish three states: the raw class, the candidate class, and the stable class.

  • The raw class is the largest output returned by the forest.
  • The candidate class is the raw class after the confidence threshold has been applied.
  • The stable class is accepted only after the candidate repeats for InpConfirmBars completed bars.

If confidence falls below InpMinConfidence, the candidate becomes REGIME_UNKNOWN. Unknown is not forced into the neutral class because the two states have different meanings. Neutral is the forest's positive classification of small forward movement; unknown means the EA does not trust the current winning class enough to allow an entry.

//+------------------------------------------------------------------+
//| Converts raw forest output into a confirmed, stable regime       |
//+------------------------------------------------------------------+
void UpdateRegimeState(const ENUM_MARKET_REGIME raw,
                       const double confidence)
  {
   ENUM_MARKET_REGIME accepted=raw;
//--- Downgrade a low-confidence vote to an unknown regime
   if(confidence<InpMinConfidence)
      accepted=REGIME_UNKNOWN;

//--- Reset the confirm counter whenever the candidate changes
   if(accepted!=g_candidate)
     {
      g_candidate=accepted;
      g_candidate_count=1;
     }
   else
      g_candidate_count++;

//--- Wait for enough confirming bars and a genuinely new regime
   if(g_candidate_count<InpConfirmBars || g_candidate==g_stable)
      return;

//--- Promote the candidate to the stable regime and arm the cooldown
   g_stable=g_candidate;
   g_cooldown=InpCooldownBars;
   PrintFormat("Stable regime changed to %s after %d confirmations.",
               g_classifier.RegimeName(g_stable), g_candidate_count);
  }

UpdateRegimeState() converts the winning class into a persistent directional state. Low confidence first becomes UNKNOWN. When the accepted class changes, the confirmation counter restarts at one; only consecutive repetitions can replace g_stable. Cooldown is armed only after promotion. UNKNOWN may become stable deliberately, because uncertainty must be able to withdraw entry authorization. Neutral and UNKNOWN have different analytical meanings, but the default position policy treats both as no-entry states and closes an owned position when InpCloseOnNeutral is true. The journal message makes each promotion auditable.


Fig. 2. Transformation from a raw forest class into trading permission

Fig. 2. Transformation from a raw forest class into trading permission

When the stable class changes, we begin the cooldown only after confirming and promoting that new state. It gives the program a configurable number of completed bars in which to observe the new state without opening a position. Confirmation and cooldown solve different problems: confirmation rejects short-lived candidates, while cooldown delays action after a candidate has already become stable.


Regime-Dependent Position Policy

The class does not prescribe a complete strategy for every market condition. It supplies an allowed direction to one simple position policy so that the integration remains testable.

Stable state Allowed entry Existing aligned position Existing opposing position
Bullish Long only Hold Close; reconsider on a later bar
Bearish Short only Hold Close; reconsider on a later bar
Neutral None Close when InpCloseOnNeutral is true Close when InpCloseOnNeutral is true
Unknown None Close when InpCloseOnNeutral is true Close when InpCloseOnNeutral is true

When an opposite stable state appears, the EA closes its position and returns. It does not close and reverse on the same bar. This single-action rule makes logs easier to interpret and avoids combining two server operations into one classification cycle.


Risk and Execution Boundaries

Trading operations use the Standard Library's CTrade class, while CPositionInfo selects positions by symbol and magic number. The EA also scans every position on the chart symbol. If another magic number owns a position there, the current cycle is blocked. This conservative policy prevents accidental interference on both netting and hedging accounts.

Position size is derived from equity risk and the monetary loss represented by the stop distance:

V = (E × R / 100) / ((D / Ts) × Tv)

where V is the requested volume in lots, E is account equity in the deposit currency, R is InpRiskPercent, D is the stop distance in price units, Ts is the symbol's tick size in price units, and Tv is the loss tick value for one lot in the deposit currency. The result is rounded downward to the symbol's volume step and rejected when it falls below the minimum permitted volume.

The requested stop distance is increased when necessary to exceed the symbol's current stops level. The EA checks the current spread before entry, normalizes Stop Loss and Take Profit prices to the symbol's digits, assigns a deterministic magic number, and selects the symbol's supported filling mode.

A true return from PositionOpen() does not guarantee successful execution. The EA must also inspect ResultRetcode() and its description after every open or close request.


Expert Advisor Lifecycle

OnInit() validates the inputs, configures CTrade, configures the classifier, and trains the initial forest. Initialization fails when the history is insufficient or training cannot complete. This is preferable to leaving an attached EA in an apparently active but untrained state.

OnTick() returns immediately until IsNewBar() detects a new bar. The remaining stages then run in a fixed order:

  1. Retrain only when InpRetrainBars is greater than zero and the configured completed-bar interval has elapsed.
  2. Call Predict() for the latest completed-bar window.
  3. Receive the raw class and three class scores from the classifier.
  4. Update the candidate and stable regimes.
  5. Refresh the chart comment.
  6. Apply the cooldown.
  7. Evaluate position policy and execution safeguards.

Periodic retraining uses only history available at the current terminal or Strategy Tester time. Setting InpRetrainBars to zero disables retraining and keeps the initialization forest for the entire run. That option is useful when comparing a fixed model with a rolling model.


Input Parameters

Input Default Purpose
InpTrainingBars 1500 Completed historical bars requested for each training window
InpTrees 100 Number of trees built by the decision forest
InpNeutralThreshold 0.00050 Absolute next-bar return boundary used to create the three training labels
InpSeed 2026 Reproducible random seed for identical datasets
InpMinConfidence 0.50 Minimum winning forest output accepted as a candidate
InpConfirmBars 2 Consecutive accepted classes needed for a stable regime
InpCooldownBars 1 Completed bars waited after a stable regime change
InpRetrainBars 250 Completed bars between rolling retraining operations
InpRiskPercent 1.00 Percentage of current equity risked at the initial stop
InpStopLossPoints 300 Requested stop distance in symbol points
InpRewardRisk 1.50 Take-profit distance divided by stop distance
InpMaxSpreadPoints 30 Maximum spread accepted for a new entry
InpMagicNumber 20260816 Identifier used to select positions belonging to this EA
InpDeviationPoints 20 Maximum permitted execution deviation in points
InpCloseOnNeutral true Closes an owned position when the stable state is neutral or unknown


Operating the Expert Advisor

Download MQL5.zip. Open the terminal's Data Folder and extract the archive into it. Merge the archive's top-level MQL5 folder with the existing MQL5 folder. This places RegimeAdaptiveEA.mq5 in MQL5\Experts\Article24161\ and MarketRegimeClassifier.mqh in MQL5\Include\Article24161\. Keep this structure because the EA includes the classifier through <Article24161\MarketRegimeClassifier.mqh>. Open RegimeAdaptiveEA.mq5 in MetaEditor and compile it. The include for dataanalysis.mqh resolves from the Standard Library distributed with MetaTrader 5.

Attach the EA to the symbol and timeframe that should define both the training dataset and live classification interval. Enable algorithmic trading only after reviewing the inputs. The chart comment displays the raw class, winning confidence, bearish/neutral/bullish outputs, stable state, confirmation count, cooldown, and most recent out-of-bag error.

The EA initialized successfully in the Strategy Tester. The next section examines its runtime state and journal sequence.


Results and Testing

I tested the EA in MetaTrader 5 on EURUSD H1 with Demo history and the 1-minute OHLC modeling method. The test was configured from January 1 through December 31, 2024, with an initial deposit of 10,000 USD, and the default EA inputs. The purpose of this run was to observe the complete classifier-to-controller path rather than to optimize profitability.

A low-confidence raw vote remains separated from the stable trading state

Fig. 3. A low-confidence raw vote remains separated from the stable trading state

Figure 3 captures the EA during Strategy Tester visualization on EURUSD H1. The forest ranks BULLISH first at 0.390, followed closely by NEUTRAL at 0.380 and BEARISH at 0.230. Because the winning value is below InpMinConfidence=0.50, the decision layer downgrades this raw BULLISH result to an UNKNOWN candidate. The confirmation counter is only one, so the candidate has not replaced the previously confirmed NEUTRAL state.

As you read the remaining fields, notice how they complete the interpretation. Cooldown is zero, which means no post-transition delay is active. The out-of-bag error is displayed as 0.450; this is a training diagnostic and not the current trade result. The trade area contains no position, while balance and equity both remain at 10,000 USD and floating profit is zero. These values describe this single captured state, not the performance of the complete test. Most importantly, the frame shows the intended safety boundary: the forest may prefer BULLISH, but a weak and unconfirmed vote cannot immediately change the confirmed trading state.

Journal Evidence

The journal lets us follow the same control path across several simulated hours. The classifier first trains on 1,489 samples. From the 1,500 requested completed bars, the ten-bar momentum lookback consumes ten leading rows and the next-bar target consumes one trailing row. The remaining 1,489 rows therefore form valid feature-label pairs rather than indicating an off-by-one error. A bearish class becomes stable only after two confirmations, and the one-bar cooldown delays entry until 11:00. After the first short reaches its take profit, the confirmed bearish state allows another short. Two low-confidence observations then promote UNKNOWN to the stable state, after which the EA closes its owned position on the following decision cycle.

2026.08.26 13:21:29.348  2024.01.01 00:00:00  Classifier trained: samples=1489, OOB error=0.449966
2026.08.26 13:22:05.216  2024.01.01 23:00:00  Stable regime changed to NEUTRAL after 2 confirmations.
2026.08.26 13:22:38.373  2024.01.02 10:00:00  Stable regime changed to BEARISH after 2 confirmations.
2026.08.26 13:22:38.501  2024.01.02 11:00:00  CTrade::OrderSend: market sell 0.33 EURUSD sl: 1.10366 tp: 1.09616 [done at 1.10066]
2026.08.26 13:22:38.501  2024.01.02 11:00:00  Entry: BEARISH, confidence=0.450 volume=0.33
2026.08.26 13:22:38.713  2024.01.02 12:37:40  take profit triggered #2 sell 0.33 EURUSD 1.10066 sl: 1.10366 tp: 1.09616 [#3 buy 0.33 EURUSD at 1.09616]
2026.08.26 13:22:38.763  2024.01.02 13:00:00  Entry: BEARISH, confidence=0.390 volume=0.33
2026.08.26 13:22:38.892  2024.01.02 14:00:00  Stable regime changed to UNKNOWN after 2 confirmations.
2026.08.26 13:22:39.023  2024.01.02 15:00:00  CTrade::OrderSend: market buy 0.33 position #4 EURUSD [done at 1.09641]
2026.08.26 13:22:39.023  2024.01.02 15:00:00  Owned position closed: neutral or uncertain regime

The two timestamps on each line serve different purposes. The first records when the tester produced the message on August 26, 2026, while the second is the simulated market time. The confidence printed with an entry belongs to that entry bar's raw output, while the entry decision uses the previously confirmed stable state. Consequently, the 0.450 and 0.390 entry messages do not mean that those raw observations passed the 0.50 threshold. They demonstrate persistence: the bearish state remains authoritative until another candidate receives the required confirmations. Together, the messages verify training, confirmation, cooldown, state persistence, entry, take-profit execution, and ownership-aware closure without treating those events as a profitability study.

Remaining Test Matrix

The run covers normal initialization, regime transitions, successful entries, a take-profit exit, an owned-position closure, rolling retraining, and a rejected position close request when the market was closed. The matrix below remains useful for reproducing those paths and completing the checks that are not visible in Fig. 3 or the selected journal excerpt.

Scenario Procedure Expected evidence
Compilation Compile the EA and included classifier in MetaEditor Zero errors; record the exact warning count
Insufficient history Run where fewer than 100 completed bars are available Initialization fails without submitting trades
Completed-bar gate Observe several ticks inside one bar Only one classification cycle occurs for that bar
Low confidence Raise InpMinConfidence near 1.00 Candidate becomes unknown and no entry is opened
Confirmation Set InpConfirmBars above one A raw class does not become stable until it repeats
Cooldown Set InpCooldownBars to two Two completed decision cycles pass before entry evaluation
Spread rejection Set a deliberately small maximum spread Entry is blocked while classification continues
Foreign ownership Open or simulate a position with another magic number The EA reports the block and does not manage that position
Opposite regime Reach a confirmed class opposite an owned position The position closes; reversal is not attempted on the same bar
Retraining Use a small InpRetrainBars value for a diagnostic run A new training message appears only at the configured interval

For the main Strategy Tester study, record: MetaTrader 5 build; broker data source; symbol/timeframe; date range; modeling method; spread/commission; slippage assumptions; input set; and margin mode. Compare a fixed model with rolling retraining. Use chronological out-of-sample and forward periods; do not optimize and evaluate on the same interval.


Limitations

You should interpret the label as a description of the following bar only. A bullish class therefore means that the model selected the class associated with a return above the training threshold; it does not establish a durable trend. The simple position policy may hold beyond the one-bar target horizon, so exit design deserves separate study.

The five features are derived from the same sequence of the price bars and can contain redundant information. The Part 15 principal component analysis and variable-importance diagnostics remain useful when deciding whether to add, remove, or transform features.

We use the out-of-bag error as an informative diagnostic, but it is not a substitute for chronological validation. Financial distributions change, overlapping observations are dependent, and transaction costs can eliminate a statistical advantage. The default thresholds are educational starting values, not recommended settings for a live account.

The ownership block is deliberately conservative. On a hedging account it blocks the EA when another strategy has a position on the same symbol, even though the platform could technically maintain several independent positions. Part 17 can revisit this policy when the series introduces a portfolio manager and explicit multi-strategy coordination.


Conclusion

We converted the Part 15 data-analysis experiment into a modular trading application. The classifier now owns its dataset preparation, normalization statistics, forest, and inference interface. The EA owns timing, confidence, regime stability, risk, position policy, and trade-result validation. This separation lets us investigate statistical behavior without granting the model unrestricted trading authority.

The result is not evidence that the classifier is profitable. It is a controlled framework for asking the correct next questions: whether the classes remain stable outside the training period, whether confidence thresholds improve decision quality, how retraining changes behavior, and whether the directional state remains useful after realistic costs.


Key Lessons

  • Training labels and live features must remain separated in time.
  • Live observations must use the means and standard deviations learned during training.
  • A raw class is not yet a trading command.
  • Confidence, confirmation, and cooldown address different sources of instability.
  • Position ownership and server return codes are part of strategy correctness.
  • Out-of-bag diagnostics complement but do not replace chronological testing.
  • A modular classifier can later become one node inside a multi-symbol portfolio manager.


Attachments

I prepared one merge-ready attachment named MQL5.zip. Its top-level MQL5 folder mirrors the terminal's Data Folder structure. The table below explains the individual source components contained in the archive and where each component is installed.

Component Type Folder structure inside MQL5.zip Description
RegimeAdaptiveEA.mq5 Expert Advisor MQL5\Experts\Article24161\RegimeAdaptiveEA.mq5 Coordinates completed-bar inference, regime stability, risk, execution, and position policy
MarketRegimeClassifier.mqh Include class MQL5\Include\Article24161\MarketRegimeClassifier.mqh Builds the Part 15 features, trains the decision forest, and returns class scores
Attached files |
MQL5.zip (9.82 KB)
Native Isolation Forest for Execution-Quality Anomaly Detection in MQL5 Native Isolation Forest for Execution-Quality Anomaly Detection in MQL5
A step-by-step guide to a native Isolation Forest in MQL5 focused on execution metrics rather than price. It details five features, tree construction and path‑length scoring, rolling‑window training, CSV logging, and FILE_COMMON persistence, all integrated into OnTradeTransaction(). The resulting circuit breaker flags unusual fills in real time and applies controlled responses to stabilize live trading under changing execution conditions.
MetaTrader 5 as a Kafka Producer: Event-Bus Architecture for Multi-Terminal Signal Fan-Out MetaTrader 5 as a Kafka Producer: Event-Bus Architecture for Multi-Terminal Signal Fan-Out
The article details a native MQL5 Kafka producer that speaks the wire protocol over raw TCP. It implements RecordBatch v2 encoding, varints, and CRC32C, and adds batching, acks, and retry logic, all without a sidecar or DLL. Use it to publish JSON-structured trading signals from a single terminal to Kafka, where dashboards and other services subscribe independently.
The ZeroMQ Message Transfer Protocol in MQL5: Implementing the REQ/REP pattern The ZeroMQ Message Transfer Protocol in MQL5: Implementing the REQ/REP pattern
This article presents a native MQL5 implementation of the ZeroMQ Message Transfer Protocol (ZMTP) built on raw MQL5 sockets. It explains the REQ/REP pattern via the CZmqReqSocket class, including framing, handshake, and strict send/receive alternation. A practical pipeline shows an MQL5 script streaming returns to a Python/R server running MS‑GARCH and receiving regime probabilities, enabling integration without DLLs.
Monte Carlo Simulation and Analysis for MetaTrader 5 Backtest Reports Monte Carlo Simulation and Analysis for MetaTrader 5 Backtest Reports
This article explains Monte Carlo simulation and analysis for trading and guides you through a Python tool that ingests MetaTrader 5 HTML reports. It generates many randomized equity paths, then summarizes them with max drawdown, bust/profit rates, and percentile envelopes around the mean curve. The workflow helps you assess uncertainty, separate normal behavior from outliers, and size positions accordingly.