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

362 Zeilen
13 KiB
MQL5

//+------------------------------------------------------------------+
//| AsocRules.mqh |
//| Copyright 2022, DNG |
//| https://www.mql5.com/ru/users/dng |
//+------------------------------------------------------------------+
#property copyright "Copyright 2022, DNG"
#property link "https://www.mql5.com/ru/users/dng"
#property version "1.00"
//---
#include "MyTreeNode.mqh"
//---
class CAssocRules : public CObject
{
protected:
CMyTreeNode m_cRoot;
CMyTreeNode m_cBuyRules;
CMyTreeNode m_cSellRules;
vectorf m_vMin;
vectorf m_vStep;
int m_iSections;
matrixf m_mPositions;
matrixf m_BuyPositions;
matrixf m_SellPositions;
//---
bool NewPath(CMyTreeNode *root, matrixf &path);
CMyTreeNode *CheckPath(CMyTreeNode *root, vectorf &path);
//---
bool PrepaerData(matrixf &data, matrixf &bin_data, vectorf &buy, vectorf &sell, const int sections = 10, const float min_sup = 0.03f);
matrixf CreatePath(vectorf &bin_data, matrixf &positions);
matrixf CreatePositions(vectorf &support, const float min_sup = 0.03f);
bool GrowsTree(CMyTreeNode *root, matrixf &bin_data, matrixf &positions);
float Probability(CMyTreeNode *root, vectorf &data, matrixf &positions);
public:
CAssocRules();
~CAssocRules();
//---
bool CreateRules(matrixf &data, vectorf &buy, vectorf &sell, int sections = 10, float min_freq = 0.03f, float min_prob = 0.3f);
bool Probability(vectorf &data, float &buy, float &sell);
//--- methods for working with files
virtual bool Save(const int file_handle);
virtual bool Load(const int file_handle);
virtual bool Save(const string file_name);
virtual bool Load(const string file_name);
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
CAssocRules::CAssocRules() : m_iSections(10)
{
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
CAssocRules::~CAssocRules()
{
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CAssocRules::NewPath(CMyTreeNode *root, matrixf &path)
{
ulong total = path.Cols();
if(total <= 0)
return false;
CMyTreeNode *parent = root;
root.IncreaseSupport(path[1, 0]);
for(ulong i = 0; i < total; i++)
{
CMyTreeNode *temp = parent.GetNext((ulong)path[0, i]);
if(!temp)
{
temp = parent.AddNode((int)path[0, i], 0);
if(!temp)
return false;
}
temp.IncreaseSupport(path[1, i]);
parent = temp;
}
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CAssocRules::CreateRules(matrixf &data, vectorf &buy, vectorf &sell, int sections = 10, float min_sup = 0.03f, float min_conf = 0.3f)
{
if(data.Rows() <= 0 || data.Cols() <= 0 || sections <= 0 ||
data.Rows() != buy.Size() || data.Rows() != sell.Size())
return false;
//---
matrixf binary_data;
if(!PrepaerData(data, binary_data, buy, sell, sections))
return false;
//---
double k = 1.0 / (double)(binary_data.Rows());
if(!GrowsTree(GetPointer(m_cRoot), binary_data * k, m_mPositions))
return false;
//--- create buy rules
vectorf supports = vectorf::Zeros(binary_data.Cols());
binary_data = matrixf::Zeros(0, binary_data.Cols());
if(!m_cRoot.Mining(supports, binary_data, m_cBuyRules.ID(), min_conf))
return false;
supports[m_cBuyRules.ID()] = 0;
m_BuyPositions = CreatePositions(supports, min_sup);
if(m_BuyPositions.Rows() > 0)
if(!GrowsTree(GetPointer(m_cBuyRules), binary_data, m_BuyPositions))
return false;
//--- create sell rules
supports = vectorf::Zeros(binary_data.Cols());
binary_data = matrixf::Zeros(0, binary_data.Cols());
if(!m_cRoot.Mining(supports, binary_data, m_cSellRules.ID(), min_conf))
return false;
supports[m_cSellRules.ID()] = 0;
m_SellPositions = CreatePositions(supports, min_sup);
if(m_SellPositions.Rows() > 0)
if(!GrowsTree(GetPointer(m_cSellRules), binary_data, m_SellPositions))
return false;
//---
m_cRoot.Clear();
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CAssocRules::PrepaerData(matrixf & data, matrixf & bin_data, vectorf & buy, vectorf & sell, const int sections = 10, const float min_sup = 0.03f)
{
//---
m_iSections = sections;
m_vMin = data.Min(0);
vectorf max = data.Max(0);
vectorf delt = max - m_vMin;
m_vStep = delt / sections + 1e-8;
m_cBuyRules.ID(data.Cols() * m_iSections);
m_cSellRules.ID(m_cBuyRules.ID() + 1);
bin_data = matrixf::Zeros(data.Rows(), m_cSellRules.ID() + 1);
for(ulong r = 0; r < data.Rows(); r++)
{
vectorf pos = (data.Row(r) - m_vMin) / m_vStep;
if(!pos.Clip(0, m_iSections - 1))
return false;
for(ulong c = 0; c < pos.Size(); c++)
bin_data[r, c * sections + (int)pos[c]] = 1;
}
if(!bin_data.Col(buy, m_cBuyRules.ID()) ||
!bin_data.Col(sell, m_cSellRules.ID()))
return false;
vectorf supp = bin_data.Sum(0) / bin_data.Rows();
m_mPositions = CreatePositions(supp, min_sup);
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
float CAssocRules::Probability(CMyTreeNode * root, vectorf & data, matrixf & positions)
{
if(m_cRoot.Total() <= 0)
return 0;
if(data.Size() != m_vMin.Size())
return 0;
vectorf pos = (data - m_vMin) / m_vStep;
if(!pos.Clip(0, m_iSections - 1))
return 0;
vectorf bin_data = vectorf::Zeros(data.Size() * m_iSections);
for(ulong c = 0; c < pos.Size(); c++)
bin_data[c * m_iSections + (int)pos[c]] = 1;
matrixf path = CreatePath(bin_data, positions);
CMyTreeNode *temp = CheckPath(root, path.Row(0));
if(!temp)
return 0;
if(temp.Total() > 0)
return 0;
//---
return temp.GetConfidence();
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
matrixf CAssocRules::CreatePath(vectorf & bin_data, matrixf & positions)
{
ulong size = bin_data.Size();
//---
ulong total = positions.Rows();
int vect_pos = 0;
matrixf path = matrixf::Zeros(2, total);
for(ulong c = 0; c < total; c++)
{
ulong pos = (ulong)positions[c, 0];
if(pos >= size)
continue;
if(bin_data[pos] == 0)
continue;
path[0, vect_pos] = (float)pos;
path[1, vect_pos] = bin_data[pos];
vect_pos++;
}
if(!path.Resize(2, vect_pos))
return matrixf::Zeros(0, 0);
//---
return path;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
CMyTreeNode *CAssocRules::CheckPath(CMyTreeNode * root, vectorf & path)
{
ulong total = path.Size();
CMyTreeNode *node = root;
for(ulong i = 0; i < total; i++)
{
node = node.GetNext((ulong)path[i]);
if(!node)
break;
}
//---
return node;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
matrixf CAssocRules::CreatePositions(vectorf &support, const float min_sup = 0.03f)
{
matrixf result = matrixf::Ones(support.Size(), 2);
result = result.CumSum(0) - 1;
if(!result.Col(support, 1))
return matrixf::Zeros(0, 0);
bool change = false;
do
{
change = false;
ulong total = result.Rows() - 1;
for(ulong i = 0; i < total; i++)
{
if(result[i, 1] >= result[i + 1, 1])
continue;
if(result.SwapRows(i, i + 1))
change = true;
}
}
while(change);
int i = 0;
while(result[i, 1] >= min_sup)
i++;
if(!result.Resize(i, 2))
return matrixf::Zeros(0, 0);
//---
return result;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CAssocRules::GrowsTree(CMyTreeNode * root, matrixf & bin_data, matrixf &positions)
{
ulong rows = bin_data.Rows();
for(ulong r = 0; r < rows; r++)
{
matrixf path = CreatePath(bin_data.Row(r), positions);
ulong size = path.Cols();
if(size <= 0)
continue;
if(!NewPath(root, path))
return false;
}
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CAssocRules::Probability(vectorf &data, float &buy, float &sell)
{
buy = Probability(GetPointer(m_cBuyRules), data, m_BuyPositions);
sell = Probability(GetPointer(m_cSellRules), data, m_BuyPositions);
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CAssocRules::Save(const string file_name)
{
if(file_name == NULL)
return false;
//---
int handle = FileOpen(file_name, FILE_WRITE | FILE_BIN);
bool result = Save(handle);
FileClose(handle);
return result;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CAssocRules::Load(const string file_name)
{
if(file_name == NULL)
return false;
//---
int handle = FileOpen(file_name, FILE_READ | FILE_BIN);
bool result = Load(handle);
FileClose(handle);
return result;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CAssocRules::Save(const int file_handle)
{
if(!m_cBuyRules.Save(file_handle) ||
!m_cSellRules.Save(file_handle))
return false;
//---
ulong rows = m_BuyPositions.Rows();
ulong cols = m_BuyPositions.Cols();
if(FileWriteLong(file_handle, rows) < sizeof(rows) ||
FileWriteLong(file_handle, cols) < sizeof(cols))
return false;
for(ulong r = 0; r < rows; r++)
for(ulong c = 0; c < cols; c++)
if(FileWriteDouble(file_handle, m_BuyPositions[r, c]) < sizeof(m_BuyPositions[r, c]))
return false;
//---
rows = m_SellPositions.Rows();
cols = m_SellPositions.Cols();
if(FileWriteLong(file_handle, rows) < sizeof(rows) ||
FileWriteLong(file_handle, cols) < sizeof(cols))
return false;
for(ulong r = 0; r < rows; r++)
for(ulong c = 0; c < cols; c++)
if(FileWriteDouble(file_handle, m_SellPositions[r, c]) < sizeof(m_SellPositions[r, c]))
return false;
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CAssocRules::Load(const int file_handle)
{
if(!m_cBuyRules.Load(file_handle) ||
!m_cSellRules.Load(file_handle))
return false;
//---
ulong rows = FileReadLong(file_handle);
ulong cols = FileReadLong(file_handle);
if(!m_BuyPositions.Resize(rows, cols))
return false;
for(ulong r = 0; r < rows; r++)
for(ulong c = 0; c < cols; c++)
m_BuyPositions[r, c] = (float)FileReadDouble(file_handle);
//---
rows = FileReadLong(file_handle);
cols = FileReadLong(file_handle);
if(!m_SellPositions.Resize(rows, cols))
return false;
for(ulong r = 0; r < rows; r++)
for(ulong c = 0; c < cols; c++)
m_SellPositions[r, c] = (float)FileReadDouble(file_handle);
//---
return true;
}
//+------------------------------------------------------------------+