//+------------------------------------------------------------------+
//|                                             CorrelationTypes.mqh |
//+------------------------------------------------------------------+
#ifndef CORRELATIONTYPES_MQH
#define CORRELATIONTYPES_MQH

//+---------------------------------------------------------------------+
//| CSymbolReturnSeries                                                 |
//| Holds one symbol's bar-to-bar return series for the current rolling |
//| window. A return here is a simple percentage change between two     |
//| consecutive closed bars, not the raw close prices themselves, since |
//| correlation is computed on returns rather than on price levels.     |
//+---------------------------------------------------------------------+
class CSymbolReturnSeries
  {
public:
   string            m_symbol;    // symbol this series belongs to
   double            m_returns[]; // bar-to-bar percentage returns, most recent first
   int               m_count;     // number of returns currently held
                     CSymbolReturnSeries(void);
  };

//+------------------------------------------------------------------+
//| Constructor                                                      |
//| Initializes an explicit, empty default state so a series that has|
//| not yet been populated can never be mistaken for a real result.  |
//+------------------------------------------------------------------+
CSymbolReturnSeries::CSymbolReturnSeries(void)
  {
   m_symbol = "";
   m_count  = 0;
   ::ArrayResize(m_returns, 0);
  }

//+-----------------------------------------------------------------------+
//| CCorrelationMatrix                                                    |
//| Holds a square matrix of pairwise Pearson correlation values, one     |
//| row and one column per monitored symbol. The matrix is stored as a    |
//| flat one-dimensional array rather than a true two-dimensional array,  |
//| since MQL5 class members cannot hold a dynamically sized array of     |
//| arrays; Index() converts a (row, column) pair into the flat offset    |
//| that both SetValue() and GetValue() use. Every accessor trusts the    |
//| caller to pass a row and column between 0 and Size() minus 1; every   |
//| call site in this project loops within that range, so no bounds check |
//| is performed here. A parallel m_defined[] array                       |
//| tracks whether each cell's correlation could actually be computed,    |
//| since a symbol with no price movement across the window produces an   |
//| undefined result rather than a genuine zero.                          |
//+-----------------------------------------------------------------------+
class CCorrelationMatrix
  {
private:
   string            m_symbols[];
   double            m_values[];
   bool              m_defined[];
   int               m_size;

public:
                     CCorrelationMatrix(void);
                    ~CCorrelationMatrix(void);
   void              Initialize(const string &symbols[], int count);
   int               Index(int row, int col) const;
   void              SetValue(int row, int col, double value, bool is_defined);
   double            GetValue(int row, int col) const;
   bool              IsDefined(int row, int col) const;
   int               Size(void) const;
   string            GetSymbol(int index) const;
  };

//+------------------------------------------------------------------+
//| Constructor                                                      |
//| Starts with an empty, zero-sized matrix until Initialize() is    |
//| called.                                                          |
//+------------------------------------------------------------------+
CCorrelationMatrix::CCorrelationMatrix(void)
  {
   m_size = 0;
   ::ArrayResize(m_symbols, 0);
   ::ArrayResize(m_values, 0);
   ::ArrayResize(m_defined, 0);
  }

//+------------------------------------------------------------------+
//| Destructor                                                       |
//| No resources are owned beyond plain arrays, so no cleanup beyond |
//| default destruction is required.                                 |
//+------------------------------------------------------------------+
CCorrelationMatrix::~CCorrelationMatrix(void)
  {
  }

//+--------------------------------------------------------------------+
//| Initialize                                                         |
//| Sets the symbol labels and allocates the flat value and defined    |
//| arrays at count * count, resetting every cell to an explicit zero, |
//| undefined state before any correlation has actually been computed. |
//+--------------------------------------------------------------------+
void CCorrelationMatrix::Initialize(const string &symbols[],const int count)
  {
   m_size = count;
   ::ArrayResize(m_symbols, count);
   for(int i = 0; i < count; i++)
      m_symbols[i] = symbols[i];
   ::ArrayResize(m_values, count * count);
   ::ArrayResize(m_defined, count * count);
   for(int i = 0; i < count * count; i++)
     {
      m_values[i]  = 0.0;
      m_defined[i] = false;
     }
  }

//+-----------------------------------------------------------------------+
//| Index                                                                 |
//| Converts a (row, column) pair into the flat array offset row *        |
//| m_size + col. This is the one calculation the rest of the class       |
//| depends on, and it is exactly where an off-by-one error would first   |
//| show up, so it is kept in its own small, directly testable method.    |
//+-----------------------------------------------------------------------+
int CCorrelationMatrix::Index(const int row,const int col) const
  {
   return(row * m_size + col);
  }

//+------------------------------------------------------------------------+
//| SetValue                                                               |
//| Writes one cell's correlation value and whether that value is          |
//| actually defined. This method mutates the class's own m_values and     |
//| m_defined members directly, so it cannot be const, independent of any  |
//| rule about array parameters: writing to a member array always requires |
//| a non-const method.                                                    |
//+------------------------------------------------------------------------+
void CCorrelationMatrix::SetValue(const int row,const int col,const double value,const bool is_defined)
  {
   int index = Index(row, col);
   m_values[index]  = value;
   m_defined[index] = is_defined;
  }

//+------------------------------------------------------------------+
//| GetValue                                                         |
//| Reads one cell's correlation value. The value is only meaningful |
//| when IsDefined() also returns true for the same cell.            |
//+------------------------------------------------------------------+
double CCorrelationMatrix::GetValue(const int row,const int col) const
  {
   return(m_values[Index(row, col)]);
  }

//+------------------------------------------------------------------+
//| IsDefined                                                        |
//| Reports whether a cell's correlation could actually be computed. |
//+------------------------------------------------------------------+
bool CCorrelationMatrix::IsDefined(const int row,const int col) const
  {
   return(m_defined[Index(row, col)]);
  }

//+------------------------------------------------------------------+
//| Size                                                             |
//| Returns the number of symbols, and therefore the number of rows  |
//| and columns, in the matrix.                                      |
//+------------------------------------------------------------------+
int CCorrelationMatrix::Size(void) const
  {
   return(m_size);
  }

//+------------------------------------------------------------------+
//| GetSymbol                                                        |
//| Returns the symbol label for a given row or column index.        |
//+------------------------------------------------------------------+
string CCorrelationMatrix::GetSymbol(const int index) const
  {
   return(m_symbols[index]);
  }

#endif // CORRELATIONTYPES_MQH
//+------------------------------------------------------------------+