forked from Princeec13/mql5
473 lines
15 KiB
MQL5
473 lines
15 KiB
MQL5
//+------------------------------------------------------------------+
|
|
//| CorrelationMatrix.mqh |
|
|
//| Copyright 2025, Your Company Name |
|
|
//| https://www.yoursite.com |
|
|
//+------------------------------------------------------------------+
|
|
#property copyright "Copyright 2025, Your Company Name"
|
|
#property link "https://www.yoursite.com"
|
|
#property version "1.00"
|
|
#property strict
|
|
|
|
#include <Arrays\ArrayObj.mqh>
|
|
#include <Math\Stat\Math.mqh>
|
|
|
|
// Forward declaration
|
|
class CCorrelationMatrix;
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Correlation Pair Structure |
|
|
//+------------------------------------------------------------------+
|
|
struct SCorrelationPair
|
|
{
|
|
string symbol1; // First symbol
|
|
string symbol2; // Second symbol
|
|
double correlation; // Correlation coefficient (-1 to 1)
|
|
int period; // Lookback period (bars)
|
|
ENUM_TIMEFRAME timeframe; // Timeframe for calculation
|
|
datetime lastUpdate; // Last update time
|
|
|
|
// Constructor
|
|
SCorrelationPair() : symbol1(""), symbol2(""), correlation(0.0),
|
|
period(0), timeframe(PERIOD_CURRENT), lastUpdate(0) {}
|
|
|
|
SCorrelationPair(string s1, string s2, int p, ENUM_TIMEFRAME tf) :
|
|
symbol1(s1), symbol2(s2), correlation(0.0), period(p), timeframe(tf), lastUpdate(0) {}
|
|
|
|
// Comparison operator
|
|
bool operator==(const SCorrelationPair &other) const
|
|
{
|
|
return ((symbol1 == other.symbol1 && symbol2 == other.symbol2) ||
|
|
(symbol1 == other.symbol2 && symbol2 == other.symbol1)) &&
|
|
period == other.period && timeframe == other.timeframe;
|
|
}
|
|
};
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Correlation Matrix Class |
|
|
//+------------------------------------------------------------------+
|
|
class CCorrelationMatrix
|
|
{
|
|
private:
|
|
CArrayObj* m_pairs; // Array of correlation pairs
|
|
string m_symbols[]; // Array of symbols being tracked
|
|
int m_lookback; // Default lookback period (bars)
|
|
ENUM_TIMEFRAME m_timeframe; // Default timeframe
|
|
double m_minCorrelation; // Minimum correlation to track
|
|
bool m_isInitialized; // Initialization flag
|
|
|
|
// Private methods
|
|
bool CalculateCorrelation(SCorrelationPair &pair);
|
|
int FindPair(const string symbol1, const string symbol2) const;
|
|
bool UpdateSymbolList();
|
|
|
|
public:
|
|
// Constructor/Destructor
|
|
CCorrelationMatrix();
|
|
~CCorrelationMatrix();
|
|
|
|
// Initialization
|
|
bool Initialize(const int lookback = 100,
|
|
const ENUM_TIMEFRAME timeframe = PERIOD_CURRENT,
|
|
const double minCorrelation = 0.5);
|
|
void Deinitialize();
|
|
|
|
// Update methods
|
|
bool Update();
|
|
bool UpdatePair(const string symbol1, const string symbol2);
|
|
|
|
// Correlation access
|
|
double GetCorrelation(const string symbol1, const string symbol2);
|
|
bool GetCorrelationMatrix(const string &symbols[], double &matrix[][]);
|
|
|
|
// Risk management
|
|
bool ValidateNewPosition(const string symbol, const ENUM_ORDER_TYPE type,
|
|
const double price, const double size);
|
|
|
|
// Getters
|
|
int GetSymbolCount() const { return ArraySize(m_symbols); }
|
|
int GetPairCount() const { return (m_pairs != NULL) ? m_pairs.Total() : 0; }
|
|
bool IsInitialized() const { return m_isInitialized; }
|
|
|
|
// Configuration
|
|
bool SetLookback(const int lookback);
|
|
bool SetTimeframe(const ENUM_TIMEFRAME timeframe);
|
|
void SetMinCorrelation(const double minCorrelation) { m_minCorrelation = minCorrelation; }
|
|
|
|
// Utility
|
|
static double CalculateCorrelation(const double &x[], const double &y[], const int count);
|
|
};
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Constructor |
|
|
//+------------------------------------------------------------------+
|
|
CCorrelationMatrix::CCorrelationMatrix() :
|
|
m_pairs(NULL),
|
|
m_lookback(100),
|
|
m_timeframe(PERIOD_CURRENT),
|
|
m_minCorrelation(0.5),
|
|
m_isInitialized(false)
|
|
{
|
|
ArrayResize(m_symbols, 0);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Destructor |
|
|
//+------------------------------------------------------------------+
|
|
CCorrelationMatrix::~CCorrelationMatrix()
|
|
{
|
|
Deinitialize();
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Initialize correlation matrix |
|
|
//+------------------------------------------------------------------+
|
|
bool CCorrelationMatrix::Initialize(const int lookback, const ENUM_TIMEFRAME timeframe,
|
|
const double minCorrelation)
|
|
{
|
|
if (m_isInitialized)
|
|
return true;
|
|
|
|
if (lookback <= 0 || minCorrelation < 0.0 || minCorrelation > 1.0)
|
|
return false;
|
|
|
|
m_pairs = new CArrayObj();
|
|
if (m_pairs == NULL)
|
|
return false;
|
|
|
|
m_lookback = lookback;
|
|
m_timeframe = timeframe;
|
|
m_minCorrelation = minCorrelation;
|
|
|
|
// Update symbol list
|
|
if (!UpdateSymbolList())
|
|
{
|
|
Print("Failed to update symbol list");
|
|
return false;
|
|
}
|
|
|
|
m_isInitialized = true;
|
|
return true;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Deinitialize correlation matrix |
|
|
//+------------------------------------------------------------------+
|
|
void CCorrelationMatrix::Deinitialize()
|
|
{
|
|
if (m_pairs != NULL)
|
|
{
|
|
m_pairs.Clear();
|
|
delete m_pairs;
|
|
m_pairs = NULL;
|
|
}
|
|
|
|
ArrayFree(m_symbols);
|
|
m_isInitialized = false;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Update all correlation pairs |
|
|
//+------------------------------------------------------------------+
|
|
bool CCorrelationMatrix::Update()
|
|
{
|
|
if (!m_isInitialized)
|
|
return false;
|
|
|
|
// Update symbol list first
|
|
if (!UpdateSymbolList())
|
|
return false;
|
|
|
|
int symbolCount = ArraySize(m_symbols);
|
|
if (symbolCount < 2)
|
|
return false;
|
|
|
|
// Update all pairs
|
|
bool success = true;
|
|
for (int i = 0; i < symbolCount - 1; i++)
|
|
{
|
|
for (int j = i + 1; j < symbolCount; j++)
|
|
{
|
|
if (!UpdatePair(m_symbols[i], m_symbols[j]))
|
|
success = false;
|
|
}
|
|
}
|
|
|
|
return success;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Update correlation for a specific pair |
|
|
//+------------------------------------------------------------------+
|
|
bool CCorrelationMatrix::UpdatePair(const string symbol1, const string symbol2)
|
|
{
|
|
if (!m_isInitialized || symbol1 == "" || symbol2 == "" || symbol1 == symbol2)
|
|
return false;
|
|
|
|
// Find or create the correlation pair
|
|
int pairIndex = FindPair(symbol1, symbol2);
|
|
SCorrelationPair* pair = NULL;
|
|
|
|
if (pairIndex >= 0)
|
|
{
|
|
pair = (SCorrelationPair*)m_pairs.At(pairIndex);
|
|
}
|
|
else
|
|
{
|
|
pair = new SCorrelationPair(symbol1, symbol2, m_lookback, m_timeframe);
|
|
if (pair == NULL)
|
|
return false;
|
|
|
|
m_pairs.Add(pair);
|
|
}
|
|
|
|
// Calculate correlation
|
|
return CalculateCorrelation(*pair);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Calculate correlation for a pair |
|
|
//+------------------------------------------------------------------+
|
|
bool CCorrelationMatrix::CalculateCorrelation(SCorrelationPair &pair)
|
|
{
|
|
if (pair.symbol1 == "" || pair.symbol2 == "" || pair.period <= 0)
|
|
return false;
|
|
|
|
// Get close prices for both symbols
|
|
double close1[], close2[];
|
|
int count = pair.period;
|
|
|
|
if (CopyClose(pair.symbol1, pair.timeframe, 0, count, close1) != count ||
|
|
CopyClose(pair.symbol2, pair.timeframe, 0, count, close2) != count)
|
|
{
|
|
Print("Failed to get price data for correlation calculation");
|
|
return false;
|
|
}
|
|
|
|
// Calculate returns
|
|
double returns1[], returns2[];
|
|
ArrayResize(returns1, count-1);
|
|
ArrayResize(returns2, count-1);
|
|
|
|
for (int i = 0; i < count-1; i++)
|
|
{
|
|
if (close1[i+1] > 0.0 && close2[i+1] > 0.0)
|
|
{
|
|
returns1[i] = (close1[i] - close1[i+1]) / close1[i+1];
|
|
returns2[i] = (close2[i] - close2[i+1]) / close2[i+1];
|
|
}
|
|
else
|
|
{
|
|
returns1[i] = 0.0;
|
|
returns2[i] = 0.0;
|
|
}
|
|
}
|
|
|
|
// Calculate correlation
|
|
pair.correlation = CalculateCorrelation(returns1, returns2, count-1);
|
|
pair.lastUpdate = TimeCurrent();
|
|
|
|
return true;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Find correlation pair in the list |
|
|
//+------------------------------------------------------------------+
|
|
int CCorrelationMatrix::FindPair(const string symbol1, const string symbol2) const
|
|
{
|
|
if (!m_isInitialized || m_pairs == NULL)
|
|
return -1;
|
|
|
|
SCorrelationPair tempPair(symbol1, symbol2, m_lookback, m_timeframe);
|
|
|
|
for (int i = 0; i < m_pairs.Total(); i++)
|
|
{
|
|
SCorrelationPair* pair = (SCorrelationPair*)m_pairs.At(i);
|
|
if (pair != NULL && *pair == tempPair)
|
|
return i;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Update the list of symbols being tracked |
|
|
//+------------------------------------------------------------------+
|
|
bool CCorrelationMatrix::UpdateSymbolList()
|
|
{
|
|
// This is a simplified implementation
|
|
// In practice, you might want to get symbols from market watch or a predefined list
|
|
|
|
// For now, we'll just use a few major currency pairs
|
|
string defaultSymbols[] = {"EURUSD", "GBPUSD", "USDJPY", "AUDUSD", "USDCAD", "USDCHF", "NZDUSD"};
|
|
|
|
// Check which symbols are available
|
|
string availableSymbols[];
|
|
int count = 0;
|
|
|
|
for (int i = 0; i < ArraySize(defaultSymbols); i++)
|
|
{
|
|
if (SymbolSelect(defaultSymbols[i], true))
|
|
{
|
|
count++;
|
|
ArrayResize(availableSymbols, count);
|
|
availableSymbols[count-1] = defaultSymbols[i];
|
|
}
|
|
}
|
|
|
|
// Update symbols array
|
|
if (count > 0)
|
|
{
|
|
ArrayCopy(m_symbols, availableSymbols);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Get correlation between two symbols |
|
|
//+------------------------------------------------------------------+
|
|
double CCorrelationMatrix::GetCorrelation(const string symbol1, const string symbol2)
|
|
{
|
|
if (!m_isInitialized || symbol1 == "" || symbol2 == "" || symbol1 == symbol2)
|
|
return 0.0;
|
|
|
|
int pairIndex = FindPair(symbol1, symbol2);
|
|
if (pairIndex >= 0)
|
|
{
|
|
SCorrelationPair* pair = (SCorrelationPair*)m_pairs.At(pairIndex);
|
|
if (pair != NULL)
|
|
return pair.correlation;
|
|
}
|
|
|
|
// If pair not found, try to calculate it
|
|
if (UpdatePair(symbol1, symbol2))
|
|
{
|
|
pairIndex = FindPair(symbol1, symbol2);
|
|
if (pairIndex >= 0)
|
|
{
|
|
SCorrelationPair* pair = (SCorrelationPair*)m_pairs.At(pairIndex);
|
|
if (pair != NULL)
|
|
return pair.correlation;
|
|
}
|
|
}
|
|
|
|
return 0.0;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Get full correlation matrix |
|
|
//+------------------------------------------------------------------+
|
|
bool CCorrelationMatrix::GetCorrelationMatrix(const string &symbols[], double &matrix[][])
|
|
{
|
|
if (!m_isInitialized || ArraySize(symbols) < 2)
|
|
return false;
|
|
|
|
int size = ArraySize(symbols);
|
|
ArrayResize(matrix, size);
|
|
|
|
for (int i = 0; i < size; i++)
|
|
{
|
|
ArrayResize(matrix[i], size);
|
|
matrix[i][i] = 1.0; // Correlation with self is 1
|
|
|
|
for (int j = i + 1; j < size; j++)
|
|
{
|
|
double corr = GetCorrelation(symbols[i], symbols[j]);
|
|
matrix[i][j] = corr;
|
|
matrix[j][i] = corr; // Matrix is symmetric
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Validate if a new position would exceed correlation limits |
|
|
//+------------------------------------------------------------------+
|
|
bool CCorrelationMatrix::ValidateNewPosition(const string symbol, const ENUM_ORDER_TYPE type,
|
|
const double price, const double size)
|
|
{
|
|
if (!m_isInitialized || symbol == "" || size <= 0.0)
|
|
return false;
|
|
|
|
// This is a simplified implementation
|
|
// In practice, you would check correlation with all existing positions
|
|
|
|
return true; // Placeholder
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Set lookback period for correlation calculation |
|
|
//+------------------------------------------------------------------+
|
|
bool CCorrelationMatrix::SetLookback(const int lookback)
|
|
{
|
|
if (lookback <= 0)
|
|
return false;
|
|
|
|
m_lookback = lookback;
|
|
|
|
// Update all pairs
|
|
if (m_pairs != NULL)
|
|
{
|
|
for (int i = 0; i < m_pairs.Total(); i++)
|
|
{
|
|
SCorrelationPair* pair = (SCorrelationPair*)m_pairs.At(i);
|
|
if (pair != NULL)
|
|
pair.period = lookback;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Set timeframe for correlation calculation |
|
|
//+------------------------------------------------------------------+
|
|
bool CCorrelationMatrix::SetTimeframe(const ENUM_TIMEFRAME timeframe)
|
|
{
|
|
m_timeframe = timeframe;
|
|
|
|
// Update all pairs
|
|
if (m_pairs != NULL)
|
|
{
|
|
for (int i = 0; i < m_pairs.Total(); i++)
|
|
{
|
|
SCorrelationPair* pair = (SCorrelationPair*)m_pairs.At(i);
|
|
if (pair != NULL)
|
|
pair.timeframe = timeframe;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Static method to calculate correlation between two arrays |
|
|
//+------------------------------------------------------------------+
|
|
double CCorrelationMatrix::CalculateCorrelation(const double &x[], const double &y[], const int count)
|
|
{
|
|
if (count <= 1)
|
|
return 0.0;
|
|
|
|
double sumX = 0.0, sumY = 0.0;
|
|
double sumXSq = 0.0, sumYSq = 0.0;
|
|
double sumXY = 0.0;
|
|
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
sumX += x[i];
|
|
sumY += y[i];
|
|
sumXSq += x[i] * x[i];
|
|
sumYSq += y[i] * y[i];
|
|
sumXY += x[i] * y[i];
|
|
}
|
|
|
|
double numerator = sumXY - (sumX * sumY / count);
|
|
double denominator = MathSqrt((sumXSq - (sumX * sumX / count)) * (sumYSq - (sumY * sumY / count)));
|
|
|
|
if (denominator == 0.0)
|
|
return 0.0;
|
|
|
|
return numerator / denominator;
|
|
}
|