Measuring What Matters (Part 1) : Portfolio Risk Decomposition in MQL5
Introduction
There is a moment almost every multi-symbol trader experiences at least once. Three positions are open, each carefully sized. Stop losses are placed. Risk per trade is a modest one percent on each instrument. By the standard calculation, total exposure is three percent: manageable, controlled, sensible.
Then Non-Farm Payroll drops.
EURUSD falls eighty pips in thirty seconds. GBPUSD follows immediately seventy pips down. Gold spikes briefly, then reverses with everything else as the dollar surges. All three positions are hit at the same moment, in the same direction, by the same underlying event. Three one-percent risks just became a single three-percent loss in under a minute.
This is not bad luck. This is correlation working exactly as it always does silently, invisibly— until the moment it matters most. Most traders ignore it because of tooling: risk-measurement tools are built for single instruments, not portfolios.
This article is Part 1 of a ten-part series titled "Measuring What Matters: Portfolio Risk Decomposition in MQL5". By the end of the series, you will have built a deployable system for measuring portfolio risk like quantitative traders do. It uses covariance matrices, eigenvalue decomposition, and the OpenBLAS linear-algebra library integrated into recent Metatrader 5 builds.
Part 1 covers the foundation: what single-instrument volatility can and cannot capture; why covariance is the minimum correct tool for multi-symbol risk; and how to measure the gap between naive and true portfolio risk using live market data. The practical project for this part is a script called PortfolioRiskAnalyzer.mq5 that you will build step by step alongside the explanation. By the end, you will know how MQL5 vectors and matrices work, how to fetch multi-symbol data, and how to compute log returns. You will also learn how to invoke OpenBLAS-accelerated matrix operations to compute true portfolio risk. The full script is attached to this article for download. Let us start with the problem.
The Problem: A One-Dimensional Ruler for a Multi-Dimensional World
Standard deviation is the backbone of almost every volatility measure in retail trading. It takes a single time series, measures how spread out the returns are around their average, and produces one number. That number is genuinely useful. It tells you how active or quiet an instrument has been. It forms the basis of ATR-based position sizing, Bollinger Bands width, and dozens of other tools traders depend on daily.
The limitation is not that standard deviation is wrong. It is that it is incomplete the moment you hold more than one position. Standard deviation is one-dimensional. It captures how much one thing moves. It says nothing about how two things move in relation to each other.
Consider EURUSD and GBPUSD. Both currency pairs react to the same underlying driver—the strength or weakness of the US Dollar Index. When the dollar surges, both pairs typically fall together. When the dollar weakens, both pairs typically rise together. Their movements are not identical, but they are far from independent. They share a common factor, and that shared factor means holding both simultaneously is not the same as holding two separate, uncorrelated risks.
Standard deviation will tell you EURUSD moved 0.42% per hour on average and GBPUSD moved 0.51% per hour. What it will never tell you is that in the hours when EURUSD fell sharply, GBPUSD fell in the same direction roughly 70% of the time. That tendency to co-move that 70% figure is the information that determines whether your two positions genuinely diversify each other or quietly amplify the same underlying risk. It is entirely outside what individual volatility can see.
The mathematical object that captures this relationship is the covariance matrix. Before we compute it, we need to understand it.
What Covariance Captures
Covariance between two instruments measures how their returns tend to move together across time. For two return series X and Y, with sample means μₓ and μᵧ, the sample covariance is:
Cov(X, Y) = (1 / N−1) × Σᵢ (Xᵢ − μₓ)(Yᵢ − μᵧ)
On each bar, you take how far X deviated from its own average and multiply it by how far Y deviated from its own average. If both deviated upward on the same bar, the product is positive. If both deviated downward, the product is also positive. If one went up while the other went down, the product is negative. Summing all these products and dividing by N minus one gives the average tendency of the two instruments to deviate together.
A large positive covariance means the instruments move together strongly. A covariance near zero means they move independently. A negative covariance means they tend to offset each other, which is where true diversification actually comes from.
Now extend this to three instruments. Instead of one number, you have a three-by-three matrix one entry for every pair of instruments plus the variance of each instrument with itself along the diagonal:
| EURUSD | GBPUSD | XAUUSD | |
|---|---|---|---|
| EURUSD | Var(EUR) | Cov(EUR,GBP) | Cov(EUR,XAU) |
| GBPUSD | Cov(GBP,EUR) | Var(GBP) | Cov(GBP,XAU) |
| XAUUSD | Cov(XAU,EUR) | Cov(XAU,GBP) | Var(XAU) |
This is the covariance matrix. It does not replace individual volatilities — those are still sitting on the diagonal as variance values. What it adds are the off-diagonal relationships that individual volatility discards. For three instruments you have three diagonal entries and three unique off-diagonal pairs. For ten instruments the matrix is ten-by-ten, with forty-five unique pairwise relationships. The matrix scales to handle all of them simultaneously.
The practical consequence of ignoring these off-diagonal entries is visible in the portfolio variance formula.
The Portfolio Variance Formula: Making the Gap Concrete
If you hold three instruments with weights w₁, w₂, and w₃ — each weight representing the fraction of total risk allocated to that instrument — the true portfolio variance is:
True Variance = wᵀ × Σ × w
Where Σ is the full covariance matrix and w is the weights vector. Expanded out for three instruments, this becomes:
True Variance = w₁²Var₁ + w₂²Var₂ + w₃²Var₃ + 2w₁w₂Cov(1,2) + 2w₁w₃Cov(1,3) + 2w₂w₃Cov(2,3)
Most traders, without realizing it, compute only the first three terms:
Naive Variance = w₁²Var₁ + w₂²Var₂ + w₃²Var₃
The difference is entirely in the cross terms. Each cross term is a pairwise covariance multiplied by two (because the full matrix expansion counts each pair twice) and by the product of the two weights. When instruments are positively correlated — as EURUSD and GBPUSD almost always are — these cross terms are positive, which means the true portfolio variance is higher than the naive sum. Your real risk is larger than you calculated.
When some instruments are negatively correlated, the cross terms reduce the true variance below the naive sum. That reduction is genuine diversification benefit — something you are getting but not measuring when you work only with individual volatilities.
What makes the script in this article different from a straightforward implementation of that expanded formula is how the calculation is done. Rather than computing each cross term manually, the script uses the matrix formulation wᵀ × Σ × w directly — which is evaluated using OpenBLAS-accelerated matrix multiplication under the hood. The result is identical, but the method is exact, scalable to any number of instruments, and runs on the same high-performance library used by NumPy and SciPy in Python. That is not a trivial distinction. It is the foundation everything in this series is built on.
The script computes both the naive number and the true number from your own live market data and prints the difference. When you run it on EURUSD, GBPUSD, and XAUUSD during a period of strong US dollar directionality, that gap often reaches twenty to forty percent of the naive estimate. That is not a rounding error — it is a material misjudgment of actual portfolio risk.
OpenBLAS in MetaTrader 5: Why It Matters Here
Before getting into the code, it is worth spending a moment on what OpenBLAS actually is and why its presence in MetaTrader 5 matters for this series.
OpenBLAS is an open-source implementation of the BLAS specification — Basic Linear Algebra Subprograms — a set of routines for operations like vector dot products, matrix-vector multiplication, and matrix-matrix multiplication that form the computational backbone of virtually all numerical software. It is heavily optimized at the hardware level, using CPU-specific instruction sets to run these operations far faster than equivalent hand-written loops.
MetaQuotes integrated OpenBLAS into the MetaTrader 5 platform so that MQL5's native matrix type methods are backed by these optimized routines automatically. When you call matrix.Cov() or matrix.MatMul() in your script, you are not calling a generic MQL5 loop — you are calling into the OpenBLAS library, which dispatches to processor-optimized assembly code under the surface.
For this article's purposes, there are two specific calls that trigger OpenBLAS:
all_returns.Cov() — computes the full 3×3 covariance matrix from the return data matrix in a single call, using BLAS routines for the underlying dot products.
cov_matrix.MatMul(w) — performs the matrix-vector product Σ×w, which is then dot-multiplied with w to get the true portfolio variance. This is standard BLAS Level 2 (matrix-vector) multiplication.
Both of these are highlighted explicitly in the code comments. The reason for calling this out is not performance on a three-instrument portfolio — at that scale any approach is fast. The reason is correctness and scalability. As this series progresses to eigenvalue decomposition and risk factor analysis across ten or more instruments, the matrix approach becomes the only practical option. Part 1 establishes the habit of working with matrices from the start.
Building the Script: Setting Up the Project
Before writing any logic, every MQL5 script needs its property declarations and input parameters. Open MetaEditor, create a new Script file named PortfolioRiskAnalyzer.mq5, and start with the following:
#property copyright "Measuring What Matters Series" #property link "" #property version "1.00" #property script_show_inputs
The first three property lines are standard metadata. The fourth line, script_show_inputs, tells MetaTrader 5 to show the input dialog before execution begins. Without it, the script would run immediately using default values every time. Adding this line gives the trader the chance to configure their symbols, timeframe, and weights before a single calculation runs — which is what Image 1 will capture.
Now add the inputs directly below the properties:
//--- Input parameters input string Symbol1 = "EURUSD"; // First symbol input string Symbol2 = "GBPUSD"; // Second symbol input string Symbol3 = "XAUUSD"; // Third symbol input ENUM_TIMEFRAMES TF = PERIOD_H1; // Timeframe input int LookbackBars = 100; // Lookback period (bars) input double Weight1 = 0.3333; // Portfolio weight for Symbol 1 input double Weight2 = 0.3333; // Portfolio weight for Symbol 2 input double Weight3 = 0.3334; // Portfolio weight for Symbol 3
The three symbol strings default to EURUSD, GBPUSD, and XAUUSD a combination that demonstrates the correlation problem clearly because two of them share a common driver (the US Dollar) while the third (Gold) has a more complex relationship with both. The trader can change any of these to any symbol available in their broker's Market Watch.
The ENUM_TIMEFRAMES type for TF presents a dropdown list of valid timeframes in the input dialog automatically no risk of typing an invalid value. PERIOD_H1 gives hourly bars, which balances having enough data points against capturing meaningful multi-hour correlations.
LookbackBars set to 100 means the script uses the last 100 completed bars of each symbol. This is the sample size N in the covariance formula. Larger values give more statistically stable estimates but react more slowly to recent regime changes. Smaller values are more responsive but noisier. 100 bars on H1 covers roughly four trading weeks a solid default.
The three Weight inputs represent fraction of total risk allocated to each instrument. They default to equal thirds. If you run a larger position on XAUUSD than on the currency pairs, increase Weight3 and reduce the others. The weights should sum to 1.0 the script checks this at runtime and warns you if they do not.

Step 1 — The PrintDivider Helper
Before getting to the main logic, add this small utility function above OnStart(). It does nothing mathematically complex it prints a line of repeated characters to the journal to separate sections of the output report cleanly:
//+------------------------------------------------------------------+ //| Helper: Print a formatted divider line | //+------------------------------------------------------------------+ void PrintDivider(string ch = "-", int len = 55) { string line = ""; for(int i = 0; i < len; i++) line += ch; Print(line); }The function accepts a character string and a length, both with defaults. Calling PrintDivider() prints a row of 55 dashes. Calling PrintDivider("=") prints a row of equals signs. These will frame the sections of the output report, making the journal readable at a glance rather than a wall of identically formatted lines.
Step 2 — Fetching Price Data and Computing Log Returns
The first meaningful task is collecting price history for each symbol. MQL5's native vector type handles this cleanly it is a one-dimensional array of doubles with built-in methods for statistical operations and a CopyRates() method that downloads price history directly from the terminal's data cache in a single call.
Add the ComputeLogReturns function above OnStart():
//+------------------------------------------------------------------+ //| Helper: Compute log returns from a close price vector | //+------------------------------------------------------------------+ bool ComputeLogReturns(const string symbol, ENUM_TIMEFRAMES tf, int bars, vector &log_returns) { vector prices; if(!prices.CopyRates(symbol, tf, COPY_RATES_CLOSE, 0, bars + 1)) { PrintFormat("ERROR: Could not copy rates for %s. Error: %d", symbol, GetLastError()); return false; } log_returns.Init(bars); for(int i = 0; i < bars; i++) { if(prices[i] <= 0.0 || prices[i + 1] <= 0.0) { log_returns[i] = 0.0; continue; } log_returns[i] = MathLog(prices[i] / prices[i + 1]); } return true; }
The function signature takes the symbol name, timeframe, number of bars, and an output vector passed by reference the & before log_returns means the function modifies the caller's vector directly rather than working on a copy. This avoids the overhead of copying large data structures and is the correct pattern for returning numerical data from functions in MQL5.
Inside the function, the first call requests bars + 1 prices rather than bars. This is because computing N logarithmic returns requires N+1 price observations you need a "before" and "after" for each return. The COPY_RATES_CLOSE flag retrieves only closing prices, which are the standard input for return calculations in financial statistics and represent the final agreed price for each completed bar.
We use logarithmic returns rather than simple percentage returns for a specific reason: log returns are additive over time and have better statistical properties when computing covariance. They also handle the asymmetry of gains and losses correctly a 10% gain followed by a 10% loss does not bring you back to where you started in percentage terms, but in log returns the math works symmetrically. For the covariance calculations ahead, this matters for accuracy.
Inside OnStart(), the function is called three times:
//--- 2. Gather Return Vectors vector returns1, returns2, returns3; if(!ComputeLogReturns(Symbol1, TF, LookbackBars, returns1)) return; if(!ComputeLogReturns(Symbol2, TF, LookbackBars, returns2)) return; if(!ComputeLogReturns(Symbol3, TF, LookbackBars, returns3)) return;If any call fails because a symbol is not in Market Watch, or history is unavailable the script exits cleanly rather than continuing with incomplete data and producing meaningless output.
Step 3 — Assembling the Returns Matrix
This is where the script diverges from a conventional MQL5 implementation and begins using OpenBLAS properly. Rather than computing covariances one pair at a time, the script assembles all three return vectors into a single matrix object and computes the full covariance matrix in one call.
//--- 1. Prepare Weights Vector //--- Validate weights sum to approximately 1.0 //--- 3. Construct Matrix (Rows = Assets, Columns = Bars) //--- MQL5's Cov() treats each ROW as a variable (asset), so we lay out //--- assets as rows and bars as columns — opposite of the original layout. vector w = {Weight1, Weight2, Weight3}; double weight_sum = w.Sum(); if(MathAbs(weight_sum - 1.0) > 0.001) PrintFormat("WARNING: Weights sum to %.4f, not 1.0.", weight_sum); matrix all_returns; all_returns.Init(3, LookbackBars); all_returns.Row(returns1, 0); all_returns.Row(returns2, 1); all_returns.Row(returns3, 2);
The matrix is laid out with assets as rows and bars as columns a 3×LookbackBars matrix. This orientation is required because MQL5's .Cov() method treats each row as a separate variable (asset) and each column as an observation. The layout is the opposite of what you might naturally assume if you think of data as a table of observations. Getting this right is essential: if the matrix were transposed, the .Cov() call would return nonsense.
The weights vector w is also initialized here rather than later, using MQL5's brace initializer syntax. This makes it available for the OpenBLAS matrix-vector multiplication step that comes after the covariance matrix is computed. The weight sum check is a lightweight guard that prints a warning rather than stopping execution close enough to 1.0 is usable, and the trader may have intentionally left a small cash allocation.
Step 4 — Computing the Full Covariance Matrix (OpenBLAS)
With the returns matrix assembled, one line computes the full 3×3 covariance matrix:
//--- 4. Compute Full Covariance Matrix (TRIGGERS OPENBLAS) //--- With assets as rows, Cov() now correctly returns a [3x3] matrix //--- where each entry [i,j] is the covariance between asset i and asset j. matrix cov_matrix = all_returns.Cov();
This single call triggers OpenBLAS. Internally, .Cov() computes the mean-adjusted cross-products for all pairs of rows simultaneously using BLAS routines, then divides by N−1 to produce the sample covariance matrix. The result is a symmetric 3×3 matrix where each diagonal entry is the variance of one asset and each off-diagonal entry is the covariance between two assets.
A shape guard immediately follows to make sure the result is what we expect:
//--- Guard: must be 3x3 if(cov_matrix.Rows() != 3 || cov_matrix.Cols() != 3) { PrintFormat("ERROR: Unexpected covariance matrix shape [%dx%d]. Expected [3x3].", cov_matrix.Rows(), cov_matrix.Cols()); return; }
This check costs nothing in performance and catches any edge case where the matrix might have been built incorrectly for example, if one of the return vectors had a different length than the others.
Extracting the variances from the diagonal is a single method call:
//--- Extract individual variances from the diagonal of the covariance matrix vector variances = cov_matrix.Diag(); vector volatilities = MathSqrt(variances) * 100.0;The .Diag() method returns the diagonal elements as a vector these are Var(EURUSD), Var(GBPUSD), and Var(XAUUSD) in order. Taking the element-wise square root and multiplying by 100 converts them to percentage volatilities. The output lines print both values for each symbol:
PrintFormat(" %-10s | Volatility: %.4f%% | Variance: %.8f", Symbol1, volatilities[0], variances[0]); PrintFormat(" %-10s | Volatility: %.4f%% | Variance: %.8f", Symbol2, volatilities[1], variances[1]); PrintFormat(" %-10s | Volatility: %.4f%% | Variance: %.8f", Symbol3, volatilities[2], variances[2]);
Printing both variance and volatility is deliberate. The variance values go directly into the portfolio calculations seeing them alongside the volatilities helps build the mental connection between the numbers you are used to reading and the raw inputs the formula actually needs.
Step 5 — Naive Risk via Dot Product (OpenBLAS)
With variances in hand, the naive portfolio variance is computed as a dot product between the squared weights vector and the variances vector:
//--- 5. Compute Naive Risk (Ignoring correlations) //--- Algebraically: sum(w_i^2 * var_i). Done via OpenBLAS vector dot product. vector w_squared = MathPow(w, 2.0); double naive_variance = w_squared.Dot(variances); // TRIGGERS OPENBLAS double naive_vol = MathSqrt(naive_variance) * 100.0;
This is algebraically equivalent to summing w₁²Var₁ + w₂²Var₂ + w₃²Var₃ but expressed as a vector dot product which is a BLAS Level 1 operation and executes through the OpenBLAS path. MathPow(w, 2.0) squares each element of the weights vector in one call rather than needing a loop.
The naive calculation deliberately excludes all covariance terms. This is not a simplification made for convenience it is the exact calculation that most position sizing tools perform implicitly when they compute risk on each instrument separately and add the results. By producing this number explicitly and naming it "naive," the script makes visible what is normally hidden in the calculation.
Step 6 — True Portfolio Risk via Matrix Multiplication (OpenBLAS)
The true portfolio variance uses the full matrix formulation wᵀ × Σ × w, evaluated in two OpenBLAS-accelerated steps:
//--- 6. Compute True Portfolio Risk (TRIGGERS OPENBLAS) //--- Matrix formulation: True Variance = w^T * Covariance_Matrix * w //--- MatMul uses OpenBLAS level 2/3 BLAS matrix-vector multiplication gems. vector intermediate = cov_matrix.MatMul(w); // Step A: Σ × w double true_variance = w.Dot(intermediate); // Step B: wᵀ × (Σ × w)
Step A calls .MatMul(w), which performs a BLAS Level 2 matrix-vector multiplication: the 3×3 covariance matrix multiplied by the 3-element weights vector, producing a 3-element intermediate vector. Step B takes the dot product of the original weights vector with that intermediate result, collapsing the full quadratic form to a single scalar the true portfolio variance.
This two-step evaluation of a quadratic form is standard numerical linear algebra. Written as loops it would require two nested iterations; as matrix operations it reads almost like the mathematical notation and executes through the same optimized code paths that power quantitative finance libraries across the industry.
From the true variance, the remaining numbers follow directly:
double true_vol = MathSqrt(MathAbs(true_variance)) * 100.0; double cross_terms = true_variance - naive_variance; double hidden_gap = true_vol - naive_vol; double gap_percent = (naive_vol > 0) ? (hidden_gap / naive_vol) * 100.0 : 0.0;
The cross_terms variable is the difference between true and naive variance it captures the total contribution of all pairwise covariances to portfolio risk. When positive (which it will be when instruments are positively correlated), it tells you how much additional variance you are carrying that the naive calculation ignored. The MathAbs() around true_variance before the square root is a safety guard for floating-point edge cases near zero.
Step 7 — Reading the Output
The final section of the script prints the full risk comparison:
//--- 7. Risk Gap Summary PrintFormat(" Naive Risk (correlation ignored): %.4f%%", naive_vol); PrintFormat(" True Risk (covariance included): %.4f%%", true_vol); PrintFormat(" Hidden Risk Gap : %+.4f%%", hidden_gap); PrintFormat(" Gap as %% of naive estimate : %+.2f%%", gap_percent); if(hidden_gap > 0.0001) PrintFormat(" RESULT: Portfolio is RISKIER than naive suggests by %.4f%%.", hidden_gap); else if(hidden_gap < -0.0001) PrintFormat(" RESULT: Diversification benefits found. True risk is %.4f%% LOWER.", MathAbs(hidden_gap)); else Print(" RESULT: Correlations are near zero.");
The %+.4f format specifier with the explicit plus sign makes the direction of the hidden gap immediately clear without reading the number carefully positive gaps print with a leading +, negative gaps with a leading.

Reading the Results and What They Tell You
The first thing worth noticing when the script runs is the confirmation line at the very top of the journal: "OpenBLAS threads limit is 3". This is MetaTrader 5 itself printing that line automatically when the OpenBLAS library initializes before any of the script's own output runs. It is the platform confirming that the matrix computations ahead will go through the optimized library path rather than generic MQL5 loops.
Looking at the individual asset volatilities, EURUSD came in at 0.0616% per bar, GBPUSD at 0.0859%, and XAUUSD at 0.3318%. Gold is running at more than five times the per-bar volatility of EURUSD on this lookback window, which reflects its characteristically wider range relative to the tight pip movements of the major currency pairs. Viewed in isolation, these three numbers tell you how active each instrument has been nothing more.
The naive portfolio volatility, computed by squaring the weights and dot-multiplying with the variances while ignoring all cross-instrument relationships, came out to 0.1161%. That is the number a conventional position sizing tool would give you the answer you get when you treat the three instruments as if they existed in complete isolation from each other.
The cross-covariance contribution tells a different story. The matrix computation returned a contribution of 0.00000013 positive, which confirms that the instruments in this portfolio are moving together more often than not during the lookback window. Adding that into the true portfolio variance and taking the square root gives a true portfolio volatility of 0.1215%.
The hidden risk gap is +0.0054%, and expressed as a percentage of the naive estimate, the gap is +4.66%. The result line states it directly: the portfolio is riskier than the naive estimate suggests by 0.0054%.
A gap of 4.66% is more modest than what you might see during a high-correlation macro event like an NFP release or a Federal Reserve decision, but it is not trivial either. It means the naive calculation is systematically underestimating the portfolio's true risk every single bar this correlation structure holds. Over time, and especially during periods when correlations tighten further which they tend to do precisely when markets move violently this underestimation compounds. Sizing positions based on 0.1161% when the true exposure is 0.1215% is a quiet, consistent error that only becomes visible when you measure it the way this script does.
Try changing the lookback period to cover a different market regime and run the script again. During periods of strong dollar directionality or major scheduled events, the correlations between EURUSD and GBPUSD tighten significantly, and the gap will widen. During quieter, range-bound periods with less macro direction, the gap may narrow. The 4.66% figure you see here is a snapshot of the current correlation environment not a fixed property of these instruments.
Conclusion
Volatility, measured for a single instrument in isolation, tells you only part of the story. The moment you hold more than one position, the relationships between your instruments become as important as their individual movements and those relationships are entirely invisible to standard deviation alone.
The script built in this article PortfolioRiskAnalyzer.mq5 makes those relationships visible using OpenBLAS-accelerated matrix operations. It assembles your asset returns into a matrix, computes the full covariance structure in one call, and then evaluates the true portfolio variance using the matrix formulation wᵀ × Σ × w . The result is two numbers: the risk estimate that ignores correlation and the risk estimate that accounts for it fully. The difference between those two numbers is the gap that determines whether you are sizing positions based on reality or on an oversimplification of it.
Run the script. Look at the hidden risk gap. Change the lookback period and run it again during a different market period. The numbers will shift as the correlation environment changes, and as they do, you will develop an intuition for how correlated instruments behave differently from what individual volatility suggests an intuition that will inform everything built in the parts that follow.
The attached file PortfolioRiskAnalyzer.mq5 contains the complete script ready to compile and run in MetaTrader 5. In Part 2, we take the covariance matrix computed here and apply eigenvalue decomposition to it the first step toward a full spectral analysis of where your portfolio risk actually lives.
Attached File: PortfolioRiskAnalyzer.mq5
Next: Part 2 — Building the Covariance Matrix: Eigenvalue Decomposition and Risk Factor Analysis in MQL5
Warning: All rights to these materials are reserved by MetaQuotes Ltd. Copying or reprinting of these materials in whole or in part is prohibited.
This article was written by a user of the site and reflects their personal views. MetaQuotes Ltd is not responsible for the accuracy of the information presented, nor for any consequences resulting from the use of the solutions, strategies or recommendations described.
Engineering Trading Discipline into Code (Part 8): Building a Setup Confirmation and Trade Authorization Layer in MQL5
Feature Engineering for ML (Part 8): Entropy Features in MQL5
Features of Experts Advisors
Engineering a Self-Healing Expert Advisor in MQL5 (Part 4): Trade-State Reconciliation and Safe Mode Recovery
- Free trading apps
- Over 8,000 signals for copying
- Economic news for exploring financial markets
You agree to website policy and terms of use