Why Matrix and Vector Classes Matter in MQL5
If you've written any half-decent Expert Advisor in MQL4 or MQL5, you've probably used arrays and loops to calculate moving averages, standard deviations, or correlation coefficients. It works, but it's slow — especially when you're iterating over hundreds of bars and multiple instruments. MQL5's native Matrix and Vector classes, introduced in build 2380, change that entirely. They let you write linear algebra operations that run an order of magnitude faster, and when paired with OpenBLAS, they can push that speed even further.
This guide walks you through using these classes for two practical tasks: computing a linear regression slope on price data, and calculating a simple portfolio variance matrix. You'll see exact code, understand the performance trade-offs, and learn how to integrate these operations into your own EAs without reinventing the wheel.
Prerequisites
Before you start, make sure you have:
- MetaTrader 5 build 2380 or newer — these classes won't work in MT4 or older MT5 builds. Check your version under Help → About.
- A demo account — you don't need a funded account for development, but you need one attached to the terminal to run the Strategy Tester.
- MetaEditor — comes with MT5. Open it from the terminal's Tools → MetaQuotes Language Editor or press F4.
- Optional: OpenBLAS enabled — go to Tools → Options → Expert Advisors and check "Enable OpenBLAS for matrix operations". This accelerates large matrix multiplications. Without it, the classes still work using native MQL5 loops.
You don't need any third-party libraries or DLLs. Everything is built into the standard library.
Understanding the Matrix and Vector Classes
The CMatrixDouble and CVectorDouble classes live in the Math\Alglib namespace, but MQL5 also provides a simpler, more modern wrapper: the matrix and vector types. These are native types, not classes, and they support operator overloading — so you can write C = A * B instead of calling multiplication functions. That's what we'll use.
Here's the core API surface you need to know:
| Operation | Syntax | Returns |
|---|---|---|
| Initialize from array | vector v = vector::FromArray(arr) | vector |
| Matrix multiplication | matrix m3 = m1 * m2 | matrix |
| Transpose | matrix mt = m.Transpose() | matrix |
| Inverse | matrix mi = m.Inv() | matrix |
| Dot product (vector) | double d = v1.Dot(v2) | double |
| Mean | double m = v.Mean() | double |
| Standard deviation | double s = v.Std() | double |
These types also support slicing with v[from:to] and range-based loops, but for performance-critical code you'll want to avoid creating too many temporary copies. More on that later.
Step-by-Step: Linear Regression Slope Using Vectors
Let's build a practical EA that calculates the linear regression slope over the last 50 closing prices. This is a common input for trend-following systems — a positive slope suggests an uptrend, negative suggests downtrend.
Step 1: Create the EA Skeleton
Open MetaEditor (F4), create a new Expert Advisor: File → New → Expert Advisor → Next. Name it "MatrixLinReg". Replace the generated code with this:
//+------------------------------------------------------------------+
//| MatrixLinReg.mq5 |
//| Copyright 2025, Your Name |
//+------------------------------------------------------------------+
#property copyright "Copyright 2025"
#property link ""
#property version "1.00"
input int LookbackBars = 50; // Number of bars for regression
input ENUM_TIMEFRAMES Timeframe = PERIOD_CURRENT;
double ExtLinRegSlope = 0.0;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
if(Bars(_Symbol, Timeframe) < LookbackBars)
return;
// Get close prices
double closeArray[];
ArraySetAsSeries(closeArray, true);
CopyClose(_Symbol, Timeframe, 0, LookbackBars, closeArray);
// Convert to vector
vector y = vector::FromArray(closeArray);
// Build x vector: 0, 1, 2, ..., LookbackBars-1
vector x(LookbackBars);
for(int i = 0; i < LookbackBars; i++)
x[i] = (double)i;
// Calculate means
double xMean = x.Mean();
double yMean = y.Mean();
// Center the vectors
vector xCentered = x - xMean;
vector yCentered = y - yMean;
// Slope = sum(xCentered * yCentered) / sum(xCentered^2)
double numerator = xCentered.Dot(yCentered);
double denominator = xCentered.Dot(xCentered);
if(denominator != 0.0)
ExtLinRegSlope = numerator / denominator;
Comment("Linear Regression Slope: ", ExtLinRegSlope);
}
//+------------------------------------------------------------------+Step 2: Compile and Attach
Press F7 to compile. If you get errors about unknown types, check your MT5 build version — older builds don't have the vector and matrix types. On build 2380+, it should compile cleanly.
In the terminal, drag the EA from the Navigator panel onto a EURUSD chart (any timeframe). Make sure the AutoTrading button is green and the EA's smiley face in the top-right corner of the chart is not crossed out.
Step 3: Verify in the Strategy Tester
Open the Strategy Tester (Ctrl+R), select your EA, set symbol to EURUSD, timeframe to H1, and date range to the last year. Under Settings → Optimization, uncheck "Use all symbols" and leave the LookbackBars input at 50. Run a single test (not optimization).
After the test completes, open the Results tab and look at the Journal. You should see no errors. The EA won't trade — it only calculates and displays the slope via Comment(). That's fine; you're here to learn the math, not to trade blindly.
Step-by-Step: Portfolio Variance Matrix
Now let's step up to a matrix operation: calculating the variance-covariance matrix for a portfolio of three symbols. This is useful for position sizing or risk parity strategies.
Step 1: Set Up the EA
Create another EA, call it "MatrixPortfolioVar". We'll hardcode three symbols for simplicity: EURUSD, GBPUSD, and USDJPY. In production, you'd use SymbolsTotal() and a loop.
//+------------------------------------------------------------------+
//| MatrixPortfolioVar.mq5 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2025"
#property version "1.00"
input int LookbackBars = 100;
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
string symbols[3] = {"EURUSD", "GBPUSD", "USDJPY"};
int n = ArraySize(symbols);
// Build a matrix where each column is a symbol's returns
matrix returns(LookbackBars - 1, n);
for(int s = 0; s < n; s++)
{
double prices[];
ArraySetAsSeries(prices, true);
if(CopyClose(symbols[s], PERIOD_D1, 0, LookbackBars, prices) < LookbackBars)
{
Print("Not enough data for ", symbols[s]);
return;
}
// Calculate daily log returns
for(int i = 0; i < LookbackBars - 1; i++)
{
returns[i][s] = MathLog(prices[i] / prices[i+1]);
}
}
// Center the returns (subtract column means)
vector colMeans = returns.Mean(0); // mean of each column
matrix centered = returns - colMeans;
// Covariance matrix = (1/(n-1)) * centered^T * centered
matrix cov = (1.0 / (LookbackBars - 2)) * centered.Transpose() * centered;
// Display the covariance matrix
string output = "Covariance Matrix:\n";
for(int r = 0; r < n; r++)
{
for(int c = 0; c < n; c++)
{
output += StringFormat("%.6f ", cov[r][c]);
}
output += "\n";
}
Comment(output);
// Example: portfolio variance with equal weights
vector weights(n);
weights.Fill(1.0 / n);
double portfolioVariance = weights.Dot(cov * weights);
Print("Portfolio Variance (equal weights): ", portfolioVariance);
}
//+------------------------------------------------------------------+Step 2: Run and Interpret
Compile this EA and run it on any chart in the Strategy Tester (single test, daily data). Watch the Journal tab for the printed portfolio variance. The covariance matrix will show you which pairs move together — for example, EURUSD and GBPUSD usually have a positive covariance, while USDJPY often has a negative covariance with the EURUSD.
Notice how we used returns.Mean(0) — the argument 0 means "mean along columns." If you pass 1, it averages along rows. This is a common gotcha when you're new to these classes.
Tips and Best Practices from Experience
I've been using these classes for about two years now, and here's what I've learned the hard way:
- Always pre-allocate vectors and matrices instead of growing them dynamically. The
vector(n)constructor creates a fixed-size vector. Avoidvector v;thenv.Resize(n)inside loops — it's slower and fragments memory. - Use
.Fill()for initialization rather than a loop.v.Fill(0.0)is vectorized and faster than aforloop. - OpenBLAS matters for large matrices. If you're working with matrices larger than about 50x50, you'll see a 2-4x speedup with OpenBLAS enabled. For small matrices like our 3x3 covariance, the overhead of OpenBLAS dispatch actually makes it slightly slower — so test both ways.
- Watch out for NaN propagation. If any price data is missing (e.g.,
EMPTY_VALUE






