NN_in_Trading/Experts/Unsupervised/PCA/pca.mqh
2026-03-12 15:02:23 +02:00

363 lines
11 KiB
MQL5

//+------------------------------------------------------------------+
//| pca.mqh |
//| Copyright 2022, Dmitriy Gizlyk |
//| https://www.mql5.com/ru/users/dng |
//+------------------------------------------------------------------+
#property copyright "Copyright 2022, Dmitriy Gizlyk"
#property link "https://www.mql5.com/ru/users/dng"
#property version "1.00"
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
#include "..\\K-means\\kmeans.mqh"
//+------------------------------------------------------------------+
//| Defines |
//+------------------------------------------------------------------+
#define defUnsupervisedPCA 0x7902
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
class CPCA : public CObject
{
private:
bool b_Studied;
matrixf m_Ureduce;
vectorf v_Means;
vectorf v_STDs;
//---
CBufferFloat *FromMatrix(matrixf &data);
CBufferFloat *FromVector(vectorf &data);
matrixf FromBuffer(CBufferFloat *data, ulong vector_size);
vectorf FromBuffer(CBufferFloat *data);
public:
CPCA();
~CPCA();
//---
bool Study(CBufferFloat *data, int vector_size);
bool Study(matrixf &data);
CBufferFloat *Reduce(CBufferFloat *data);
CBufferFloat *Reduce(matrixf &data);
matrixf ReduceM(CBufferFloat *data);
matrixf ReduceM(matrixf &data);
//---
bool Studied(void) { return b_Studied; }
ulong VectorSize(void) { return m_Ureduce.Cols();}
ulong Inputs(void) { return m_Ureduce.Rows(); }
//---
virtual bool Save(const int file_handle);
virtual bool Load(const int file_handle);
//---
virtual int Type(void) { return defUnsupervisedPCA; }
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
CPCA::CPCA() : b_Studied(false)
{
m_Ureduce.Init(0, 0);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
CPCA::~CPCA()
{
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
matrixf CPCA::FromBuffer(CBufferFloat *data, ulong vector_size)
{
matrixf result;
if(CheckPointer(data) == POINTER_INVALID)
{
result.Init(0, 0);
return result;
}
//---
if((data.Total() % vector_size) != 0)
{
result.Init(0, 0);
return result;
}
//---
ulong rows = data.Total() / vector_size;
if(!result.Init(rows, vector_size))
{
result.Init(0, 0);
return result;
}
for(ulong r = 0; r < rows; r++)
{
ulong shift = r * vector_size;
for(ulong c = 0; c < vector_size; c++)
result[r, c] = data[(int)(shift + c)];
}
//---
return result;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
vectorf CPCA::FromBuffer(CBufferFloat *data)
{
vectorf result;
result.Init(0);
if(CheckPointer(data) == POINTER_INVALID)
return result;
//---
ulong rows = data.Total();
if(!result.Init(rows))
return result;
for(ulong r = 0; r < rows; r++)
result[r] = data[(int)r];
//---
return result;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
CBufferFloat *CPCA::FromMatrix(matrixf &data)
{
CBufferFloat *result = new CBufferFloat();
if(CheckPointer(result) == POINTER_INVALID)
return result;
//---
ulong rows = data.Rows();
ulong cols = data.Cols();
if(!result.Reserve((int)(rows * cols)))
{
delete result;
return result;
}
//---
for(ulong r = 0; r < rows; r++)
for(ulong c = 0; c < cols; c++)
if(!result.Add(data[r, c]))
{
delete result;
return result;
}
//---
return result;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
CBufferFloat *CPCA::FromVector(vectorf &data)
{
CBufferFloat *result = new CBufferFloat();
if(CheckPointer(result) == POINTER_INVALID)
return result;
//---
ulong rows = data.Size();
if(!result.Reserve((int)rows))
{
delete result;
return result;
}
//---
for(ulong r = 0; r < rows; r++)
if(!result.Add(data[r]))
{
delete result;
return result;
}
//---
return result;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
CBufferFloat *CPCA::Reduce(CBufferFloat *data)
{
matrixf result = ReduceM(data);
//---
return FromMatrix(result);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
CBufferFloat *CPCA::Reduce(matrixf &data)
{
matrixf result = ReduceM(data);
//---
return FromMatrix(result);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
matrixf CPCA::ReduceM(CBufferFloat *data)
{
matrixf result;
result.Init(0, 0);
if(!b_Studied || (data.Total() % m_Ureduce.Rows()) != 0)
return result;
result = FromBuffer(data, m_Ureduce.Rows());
//---
return ReduceM(result);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
matrixf CPCA::ReduceM(matrixf &data)
{
matrixf result;
if(!b_Studied || data.Cols() != m_Ureduce.Rows())
{
result.Init(0, 0);
return result;
}
//---
ulong total = data.Rows();
if(!result.Init(total, data.Cols()))
{
result.Init(0, 0);
return result;
}
for(ulong r = 0; r < total; r++)
{
vectorf temp = data.Row(r) - v_Means;
temp /= v_STDs;
result.Row(temp, r);
}
//---
return result.MatMul(m_Ureduce);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CPCA::Study(matrixf &data)
{
matrixf X;
ulong total = data.Rows();
if(!X.Init(total, data.Cols()))
return false;
v_Means = data.Mean(0);
v_STDs = data.Std(0) + 1e-8;
for(ulong i = 0; i < total; i++)
{
vectorf temp = data.Row(i) - v_Means;
temp /= v_STDs;
X.Row(temp, i);
}
//---
X = X.Transpose().MatMul(X / total);
matrixf U, V;
vectorf S;
if(!X.SVD(U, V, S))
return false;
//---
double sum_total = S.Sum();
if(sum_total <= 0)
return false;
S = S.CumSum() / sum_total;
int k = 0;
while(S[k] < 0.99)
k++;
if(!U.Resize(U.Rows(), k + 1))
return false;
//---
m_Ureduce = U;
b_Studied = true;
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CPCA::Study(CBufferFloat *data, int vector_size)
{
matrixf d = FromBuffer(data, vector_size);
return Study(d);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CPCA::Save(const int file_handle)
{
if(file_handle == INVALID_HANDLE)
return false;
//---
if(FileWriteInteger(file_handle, (int)b_Studied) < INT_VALUE)
return false;
if(!b_Studied)
return true;
//---
CBufferFloat *temp = FromMatrix(m_Ureduce);
if(CheckPointer(temp) == POINTER_INVALID)
return false;
if(FileWriteLong(file_handle, (long)m_Ureduce.Cols()) <= 0)
{
delete temp;
return false;
}
if(!temp.Save(file_handle))
{
delete temp;
return false;
}
delete temp;
//---
temp = FromVector(v_Means);
if(CheckPointer(temp) == POINTER_INVALID)
return false;
if(!temp.Save(file_handle))
{
delete temp;
return false;
}
delete temp;
//---
temp = FromVector(v_STDs);
if(CheckPointer(temp) == POINTER_INVALID)
return false;
if(!temp.Save(file_handle))
{
delete temp;
return false;
}
delete temp;
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CPCA::Load(const int file_handle)
{
if(file_handle == INVALID_HANDLE)
return false;
//---
b_Studied = (bool)FileReadInteger(file_handle);
if(!b_Studied)
return true;
//---
CBufferFloat *temp = new CBufferFloat();
if(CheckPointer(temp) == POINTER_INVALID)
return false;
long cols = FileReadLong(file_handle);
if(!temp.Load(file_handle))
{
delete temp;
return false;
}
m_Ureduce = FromBuffer(temp, cols);
//---
if(!temp.Load(file_handle))
{
delete temp;
return false;
}
v_Means = FromBuffer(temp);
//---
if(!temp.Load(file_handle))
{
delete temp;
return false;
}
v_STDs = FromBuffer(temp);
//---
delete temp;
//---
return true;
}
//+------------------------------------------------------------------+