Article-22610-Joint-Recurre.../Include/RQA/JRQAMatrix.mqh
2026-05-30 13:14:34 +05:00

167 lines
6.2 KiB
MQL5

//+------------------------------------------------------------------+
//| JRQAMatrix.mqh |
//| RQA Library for MQL5 |
//| Joint Recurrence Matrix Core Module |
//| |
//| JRQA: builds an NxN joint recurrence matrix from two series. |
//| JR(i,j) = R_X(i,j) AND R_Y(i,j) |
//| where R_X(i,j) = 1 iff ||x_i - x_j|| <= epsilonX |
//| R_Y(i,j) = 1 iff ||y_i - y_j|| <= epsilonY |
//| |
//| Both series must have the same length. Each can have its own |
//| epsilon for scale-independent analysis. |
//+------------------------------------------------------------------+
#ifndef JRQAMATRIX_MQH
#define JRQAMATRIX_MQH
#include "RQAMatrix.mqh" // reuse ENUM_RQA_NORM
//+------------------------------------------------------------------+
//| CJRQAMatrix — NxN joint recurrence matrix for two series |
//+------------------------------------------------------------------+
class CJRQAMatrix
{
private:
int m_N; // number of embedded vectors
int m_embDim;
int m_delay;
double m_epsilonX;
double m_epsilonY;
ENUM_RQA_NORM m_norm;
bool m_R[]; // flattened NxN joint boolean matrix
double m_embX[]; // embedded X [N x embDim]
double m_embY[]; // embedded Y [N x embDim]
void Embed(const double &series[], int seriesLen,
double &embedded[], int &numVec);
double Distance(const double &emb[], int i, int j) const;
public:
CJRQAMatrix();
~CJRQAMatrix() {}
bool Build(const double &seriesX[], const double &seriesY[],
int seriesLen,
double epsilonX, double epsilonY,
int embDim = 1,
int delay = 1,
ENUM_RQA_NORM norm = RQA_NORM_EUCLIDEAN);
bool Get(int i, int j) const;
int Size() const { return m_N; }
double EpsilonX() const { return m_epsilonX; }
double EpsilonY() const { return m_epsilonY; }
int EmbDim() const { return m_embDim; }
int Delay() const { return m_delay; }
ENUM_RQA_NORM Norm() const { return m_norm; }
};
//+------------------------------------------------------------------+
//| Default constructor |
//+------------------------------------------------------------------+
CJRQAMatrix::CJRQAMatrix()
: m_N(0), m_embDim(1), m_delay(1),
m_epsilonX(0.0), m_epsilonY(0.0), m_norm(RQA_NORM_EUCLIDEAN)
{
}
//+------------------------------------------------------------------+
//| Embed a single series into delay-coordinate vectors |
//+------------------------------------------------------------------+
void CJRQAMatrix::Embed(const double &series[], int seriesLen,
double &embedded[], int &numVec)
{
numVec = seriesLen - (m_embDim - 1) * m_delay;
if(numVec <= 0) { numVec = 0; return; }
ArrayResize(embedded, numVec * m_embDim);
for(int i = 0; i < numVec; i++)
for(int d = 0; d < m_embDim; d++)
embedded[i * m_embDim + d] = series[i + d * m_delay];
}
//+------------------------------------------------------------------+
//| Distance between embedded vectors i and j in a given embedding |
//+------------------------------------------------------------------+
double CJRQAMatrix::Distance(const double &emb[], int i, int j) const
{
double dist = 0.0;
for(int d = 0; d < m_embDim; d++)
{
double diff = emb[i * m_embDim + d] - emb[j * m_embDim + d];
switch(m_norm)
{
case RQA_NORM_MAX:
dist = MathMax(dist, MathAbs(diff));
break;
case RQA_NORM_MANHATTAN:
dist += MathAbs(diff);
break;
case RQA_NORM_EUCLIDEAN:
default:
dist += diff * diff;
break;
}
}
if(m_norm == RQA_NORM_EUCLIDEAN)
dist = MathSqrt(dist);
return dist;
}
//+------------------------------------------------------------------+
//| Build the NxN joint recurrence matrix |
//| JR(i,j) = (||x_i - x_j|| <= epsX) AND (||y_i - y_j|| <= epsY) |
//+------------------------------------------------------------------+
bool CJRQAMatrix::Build(const double &seriesX[], const double &seriesY[],
int seriesLen,
double epsilonX, double epsilonY,
int embDim,
int delay,
ENUM_RQA_NORM norm)
{
if(seriesLen < 2 || epsilonX <= 0.0 || epsilonY <= 0.0 ||
embDim < 1 || delay < 1)
{
Print("JRQAMatrix::Build — invalid parameters");
return false;
}
m_epsilonX = epsilonX;
m_epsilonY = epsilonY;
m_embDim = embDim;
m_delay = delay;
m_norm = norm;
int nX = 0, nY = 0;
Embed(seriesX, seriesLen, m_embX, nX);
Embed(seriesY, seriesLen, m_embY, nY);
m_N = MathMin(nX, nY);
if(m_N <= 0)
{
Print("JRQAMatrix::Build — series too short for given embedding");
return false;
}
ArrayResize(m_R, m_N * m_N);
for(int i = 0; i < m_N; i++)
for(int j = 0; j < m_N; j++)
m_R[i * m_N + j] = (Distance(m_embX, i, j) <= m_epsilonX) &&
(Distance(m_embY, i, j) <= m_epsilonY);
return true;
}
//+------------------------------------------------------------------+
//| Bounds-checked access to joint recurrence element JR(i,j) |
//+------------------------------------------------------------------+
bool CJRQAMatrix::Get(int i, int j) const
{
if(i < 0 || i >= m_N || j < 0 || j >= m_N)
return false;
return m_R[i * m_N + j];
}
#endif // JRQAMATRIX_MQH