2026-08-13 23:48:47 +03:00 | | | //+------------------------------------------------------------------+
|
| | | //| AsocRules.mqh |
|
| | | //| Copyright 2022, DNG |
|
| | | //| https://www.mql5.com/ru/users/dng |
|
2026-03-12 15:02:23 +02:00 | | | //+------------------------------------------------------------------+
|
| | | #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);
|
| | | };
|
| | | //+------------------------------------------------------------------+
|
2026-08-13 23:48:47 +03:00 | | | //| |
|
| | | //+------------------------------------------------------------------+
|
| | | //| | C As so cR ul es implementation. |
|
2026-03-12 15:02:23 +02:00 | | | //+------------------------------------------------------------------+
|
| | | CAssocRules::CAssocRules() : m_iSections(10)
|
| | | {
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-08-13 23:48:47 +03:00 | | | //| |
|
2026-03-12 15:02:23 +02:00 | | | //+------------------------------------------------------------------+
|
| | | CAssocRules::~CAssocRules()
|
| | | {
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-08-13 23:48:47 +03:00 | | | //| |
|
| | | //+------------------------------------------------------------------+
|
| | | //| | N ew Pa th implementation. |
|
2026-03-12 15:02:23 +02:00 | | | //+------------------------------------------------------------------+
|
| | | 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;
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-08-13 23:48:47 +03:00 | | | //| |
|
| | | //+------------------------------------------------------------------+
|
| | | //| | C re at eR ul es implementation. |
|
2026-03-12 15:02:23 +02:00 | | | //+------------------------------------------------------------------+
|
| | | 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;
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-08-13 23:48:47 +03:00 | | | //| |
|
| | | //+------------------------------------------------------------------+
|
| | | //| | P re pa er Da ta implementation. |
|
2026-03-12 15:02:23 +02:00 | | | //+------------------------------------------------------------------+
|
| | | 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;
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-08-13 23:48:47 +03:00 | | | //| |
|
| | | //+------------------------------------------------------------------+
|
| | | //| | P ro ba bi li ty implementation. |
|
2026-03-12 15:02:23 +02:00 | | | //+------------------------------------------------------------------+
|
| | | 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();
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-08-13 23:48:47 +03:00 | | | //| |
|
| | | //+------------------------------------------------------------------+
|
| | | //| | C re at eP at h implementation. |
|
2026-03-12 15:02:23 +02:00 | | | //+------------------------------------------------------------------+
|
| | | 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;
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-08-13 23:48:47 +03:00 | | | //| |
|
2026-03-12 15:02:23 +02:00 | | | //+------------------------------------------------------------------+
|
| | | 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;
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-08-13 23:48:47 +03:00 | | | //| |
|
| | | //+------------------------------------------------------------------+
|
| | | //| | C re at eP os it io ns implementation. |
|
2026-03-12 15:02:23 +02:00 | | | //+------------------------------------------------------------------+
|
| | | 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;
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-08-13 23:48:47 +03:00 | | | //| |
|
| | | //+------------------------------------------------------------------+
|
| | | //| | G ro ws Tr ee implementation. |
|
2026-03-12 15:02:23 +02:00 | | | //+------------------------------------------------------------------+
|
| | | 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;
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-08-13 23:48:47 +03:00 | | | //| |
|
| | | //+------------------------------------------------------------------+
|
| | | //| | P ro ba bi li ty implementation. |
|
2026-03-12 15:02:23 +02:00 | | | //+------------------------------------------------------------------+
|
| | | 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;
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-08-13 23:48:47 +03:00 | | | //| |
|
| | | //+------------------------------------------------------------------+
|
| | | //| | S av e implementation. |
|
2026-03-12 15:02:23 +02:00 | | | //+------------------------------------------------------------------+
|
| | | 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;
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-08-13 23:48:47 +03:00 | | | //| |
|
| | | //+------------------------------------------------------------------+
|
| | | //| | L oa d implementation. |
|
2026-03-12 15:02:23 +02:00 | | | //+------------------------------------------------------------------+
|
| | | 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;
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-08-13 23:48:47 +03:00 | | | //| |
|
| | | //+------------------------------------------------------------------+
|
| | | //| | S av e implementation. |
|
2026-03-12 15:02:23 +02:00 | | | //+------------------------------------------------------------------+
|
| | | 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;
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-08-13 23:48:47 +03:00 | | | //| |
|
| | | //+------------------------------------------------------------------+
|
| | | //| | L oa d implementation. |
|
2026-03-12 15:02:23 +02:00 | | | //+------------------------------------------------------------------+
|
| | | 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;
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-08-13 23:48:47 +03:00 | | |
|