362 Zeilen
13 KiB
MQL5
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;
|
|
}
|
|
//+------------------------------------------------------------------+
|