mirror of
https://github.com/softwaredevelop/mql5.git
synced 2026-08-22 00:38:07 +00:00
refactor: Added support for dynamic anchored window sizes
This commit is contained in:
@@ -1,11 +1,11 @@
|
|||||||
//+------------------------------------------------------------------+
|
//+------------------------------------------------------------------+
|
||||||
//| PairsTrading_Calculator.mqh |
|
//| PairsTrading_Calculator.mqh |
|
||||||
//| Engine for Dynamic Rolling OLS Pairs Trading Cointegration. |
|
//| Engine for Dynamic Rolling/Anchored OLS Pairs Cointegration |
|
||||||
//| Strictly O(1) Incremental Optimized. |
|
//| Strictly O(1) Incremental Optimized. |
|
||||||
//| Copyright 2026, xxxxxxxx |
|
//| Copyright 2026, xxxxxxxx |
|
||||||
//+------------------------------------------------------------------+
|
//+------------------------------------------------------------------+
|
||||||
#property copyright "Copyright 2026, xxxxxxxx"
|
#property copyright "Copyright 2026, xxxxxxxx"
|
||||||
#property version "1.00"
|
#property version "1.10" // Added support for dynamic anchored window sizes
|
||||||
|
|
||||||
#ifndef PAIRS_TRADING_CALCULATOR_MQH
|
#ifndef PAIRS_TRADING_CALCULATOR_MQH
|
||||||
#define PAIRS_TRADING_CALCULATOR_MQH
|
#define PAIRS_TRADING_CALCULATOR_MQH
|
||||||
@@ -16,7 +16,7 @@
|
|||||||
class CPairsTradingCalculator
|
class CPairsTradingCalculator
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
int m_lookback;
|
int m_max_window;
|
||||||
|
|
||||||
//--- Dynamic rolling arrays
|
//--- Dynamic rolling arrays
|
||||||
double m_arr_A[];
|
double m_arr_A[];
|
||||||
@@ -32,59 +32,60 @@ public:
|
|||||||
CPairsTradingCalculator();
|
CPairsTradingCalculator();
|
||||||
~CPairsTradingCalculator() {};
|
~CPairsTradingCalculator() {};
|
||||||
|
|
||||||
bool Init(int lookback);
|
bool Init(int max_window);
|
||||||
|
|
||||||
//--- Processes the raw synchronized prices and computes the rolling Z-Score
|
//--- Upgraded: Accepts a dynamic window_size for VWAP-style anchored resets
|
||||||
double CalculateZScore(int rates_total, int current_index,
|
double CalculateZScore(int rates_total, int current_index, int window_size,
|
||||||
const double &sync_price_A[], const double &sync_price_B[]);
|
const double &sync_price_A[], const double &sync_price_B[]);
|
||||||
};
|
};
|
||||||
|
|
||||||
//+------------------------------------------------------------------+
|
//+------------------------------------------------------------------+
|
||||||
//| Constructor |
|
//| Constructor |
|
||||||
//+------------------------------------------------------------------+
|
//+------------------------------------------------------------------+
|
||||||
CPairsTradingCalculator::CPairsTradingCalculator() : m_lookback(120) {}
|
CPairsTradingCalculator::CPairsTradingCalculator() : m_max_window(120) {}
|
||||||
|
|
||||||
//+------------------------------------------------------------------+
|
//+------------------------------------------------------------------+
|
||||||
//| Init |
|
//| Init |
|
||||||
//+------------------------------------------------------------------+
|
//+------------------------------------------------------------------+
|
||||||
bool CPairsTradingCalculator::Init(int lookback)
|
bool CPairsTradingCalculator::Init(int max_window)
|
||||||
{
|
{
|
||||||
m_lookback = (lookback < 10) ? 10 : lookback;
|
m_max_window = (max_window < 10) ? 10 : max_window;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
//+------------------------------------------------------------------+
|
//+------------------------------------------------------------------+
|
||||||
//| CalculateZScore (OLS Rolling Hedge Ratio & Z-Score) |
|
//| CalculateZScore (OLS Dynamic Window Cointegration) |
|
||||||
//+------------------------------------------------------------------+
|
//+------------------------------------------------------------------+
|
||||||
double CPairsTradingCalculator::CalculateZScore(int rates_total, int current_index,
|
double CPairsTradingCalculator::CalculateZScore(int rates_total, int current_index, int window_size,
|
||||||
const double &sync_price_A[], const double &sync_price_B[])
|
const double &sync_price_A[], const double &sync_price_B[])
|
||||||
{
|
{
|
||||||
if(current_index < m_lookback)
|
// Safety 1: Enforce minimum of 15 bars for statistical significance on anchored starts
|
||||||
|
if(window_size < 15 || current_index < window_size)
|
||||||
return 0.0;
|
return 0.0;
|
||||||
|
|
||||||
//--- Resize internal rolling buffers
|
//--- Dynamic array allocation based on the current active anchor size
|
||||||
if(ArraySize(m_arr_A) != m_lookback)
|
if(ArraySize(m_arr_A) != window_size)
|
||||||
{
|
{
|
||||||
ArrayResize(m_arr_A, m_lookback);
|
ArrayResize(m_arr_A, window_size);
|
||||||
ArrayResize(m_arr_B, m_lookback);
|
ArrayResize(m_arr_B, window_size);
|
||||||
ArrayResize(m_spread_history, m_lookback);
|
ArrayResize(m_spread_history, window_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
//--- Extract rolling window from synchronized prices
|
//--- Extract rolling/anchored window from synchronized prices
|
||||||
for(int k = 0; k < m_lookback; k++)
|
for(int k = 0; k < window_size; k++)
|
||||||
{
|
{
|
||||||
int src_idx = current_index - m_lookback + 1 + k;
|
int src_idx = current_index - window_size + 1 + k;
|
||||||
m_arr_A[k] = sync_price_A[src_idx];
|
m_arr_A[k] = sync_price_A[src_idx];
|
||||||
m_arr_B[k] = sync_price_B[src_idx];
|
m_arr_B[k] = sync_price_B[src_idx];
|
||||||
}
|
}
|
||||||
|
|
||||||
//--- Calculate means
|
//--- Calculate means
|
||||||
double mean_A = GetMean(m_arr_A, m_lookback);
|
double mean_A = GetMean(m_arr_A, window_size);
|
||||||
double mean_B = GetMean(m_arr_B, m_lookback);
|
double mean_B = GetMean(m_arr_B, window_size);
|
||||||
|
|
||||||
//--- Calculate Variance of Benchmark (B) and Covariance (A, B)
|
//--- Calculate Variance of Benchmark (B) and Covariance (A, B)
|
||||||
double var_B = GetVariance(m_arr_B, mean_B, m_lookback);
|
double var_B = GetVariance(m_arr_B, mean_B, window_size);
|
||||||
double cov_AB = GetCovariance(m_arr_A, mean_A, m_arr_B, mean_B, m_lookback);
|
double cov_AB = GetCovariance(m_arr_A, mean_A, m_arr_B, mean_B, window_size);
|
||||||
|
|
||||||
if(var_B <= 1.0e-9)
|
if(var_B <= 1.0e-9)
|
||||||
return 0.0; // Div-by-zero protection
|
return 0.0; // Div-by-zero protection
|
||||||
@@ -93,20 +94,19 @@ double CPairsTradingCalculator::CalculateZScore(int rates_total, int current_ind
|
|||||||
double beta = cov_AB / var_B;
|
double beta = cov_AB / var_B;
|
||||||
double alpha = mean_A - (beta * mean_B);
|
double alpha = mean_A - (beta * mean_B);
|
||||||
|
|
||||||
//--- Calculate the historical spreads over the window to find the standard deviation
|
//--- Calculate the historical spreads over the active window (Mean is algebraically 0.0)
|
||||||
double sum_sq_spread = 0.0;
|
double sum_sq_spread = 0.0;
|
||||||
for(int k = 0; k < m_lookback; k++)
|
for(int k = 0; k < window_size; k++)
|
||||||
{
|
{
|
||||||
// Spread_t = A_t - Beta * B_t - Alpha (Mean is algebraically 0.0)
|
|
||||||
m_spread_history[k] = m_arr_A[k] - (beta * m_arr_B[k]) - alpha;
|
m_spread_history[k] = m_arr_A[k] - (beta * m_arr_B[k]) - alpha;
|
||||||
sum_sq_spread += m_spread_history[k] * m_spread_history[k];
|
sum_sq_spread += m_spread_history[k] * m_spread_history[k];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sample standard deviation of the spread
|
// Sample standard deviation of the active spread window
|
||||||
double std_dev_spread = MathSqrt(sum_sq_spread / (m_lookback - 1));
|
double std_dev_spread = MathSqrt(sum_sq_spread / (window_size - 1));
|
||||||
|
|
||||||
if(std_dev_spread <= 1.0e-9)
|
if(std_dev_spread <= 1.0e-9)
|
||||||
return 0.0; // Protection against flat/dead spreads
|
return 0.0; // Protection against dead spreads
|
||||||
|
|
||||||
//--- Calculate the final current Z-Score
|
//--- Calculate the final current Z-Score
|
||||||
double current_spread = sync_price_A[current_index] - (beta * sync_price_B[current_index]) - alpha;
|
double current_spread = sync_price_A[current_index] - (beta * sync_price_B[current_index]) - alpha;
|
||||||
|
|||||||
Reference in New Issue
Block a user