Article-22714-Volatility-Mo.../Include/slsqp_article/Arch/Univariate/ljung.mqh
2026-06-03 20:14:05 +02:00

118 lines
4 KiB
MQL5

//+------------------------------------------------------------------+
//| ljung.mqh |
//| Copyright 2025, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2025, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#include"acf.mqh"
//+------------------------------------------------------------------+
//| Ljung-Box test of autocorrelation in residuals.
//+------------------------------------------------------------------+
matrix ljungboxtest(vector& x, ulong lags=0, ulong model_df=0, ulong period = 0, bool demean=false,bool boxpierce=false, bool autolag=false)
{
if(period==1)
{
Print(__FUNCTION__, " period must be >= 2");
return matrix::Zeros(0,0);
}
ulong nobs = x.Size();
vector laggs;
if(autolag)
{
ulong maxlag = nobs-1;
ACFResult sacf = acf(x,maxlag,0.05,false,demean,false);
if(!sacf.acf.Size())
return matrix::Zeros(0,0);
vector ssacf(maxlag);
vector r(maxlag);
for(ulong i = 1;i<(maxlag+1);ssacf[i-1]=sacf.acf[i],++i);
for(ulong i = 0;i<(maxlag);r[i] = double(i+1),++i);
vector qsacf;
if(!boxpierce)
{
vector n = pow(ssacf,2.)/(double(nobs)-r);
qsacf = nobs*(nobs+2.)*n.CumSum();
}
else
{
vector n = pow(ssacf,2.);
qsacf = nobs*n.CumSum();
}
double q = 2.4;
double threshold = sqrt(q*log(nobs));
double threshold_metric = MathAbs(sacf.acf).Max()*sqrt(nobs);
r = vector::Zeros(nobs-1);
for(ulong i = 0;i<r.Size(); r[i] = double(i+1),++i);
if(threshold_metric<=threshold)
qsacf = qsacf - (r*log(nobs));
else
qsacf = qsacf - (2.*r);
ulong m = qsacf.ArgMax();
laggs=vector::Zeros(m);
for(ulong i = 0;i<laggs.Size();laggs[i] = double(i+1),++i);
}
else
{
if(period)
{
ulong m = MathMin(nobs/5,2*period);
laggs = vector::Zeros(m);
for(ulong i = 0;i<laggs.Size();laggs[i] = double(i+1),++i);
}
else
{
if(!lags)
{
ulong m = MathMin(nobs/5,10);
laggs = vector::Zeros(m);
for(ulong i = 0;i<laggs.Size();laggs[i] = double(i+1),++i);
}
else
{
laggs = vector::Zeros(lags);
for(ulong i = 0;i<laggs.Size();laggs[i] = double(i+1),++i);
}
}
}
ulong maxlag = (ulong)laggs.Max();
ACFResult sacf = acf(x,maxlag,0.05,false,demean,false);
if(!sacf.acf.Size())
return matrix::Zeros(0,0);
vector ssacf(maxlag);
vector r(maxlag);
for(ulong i = 1;i<(maxlag+1);ssacf[i-1]=sacf.acf[i],++i);
for(ulong i = 0;i<(maxlag);r[i] = double(i+1),++i);
vector ssacf2 = pow(ssacf,2.)/(nobs-r);
vector temp = ssacf2.CumSum();
vector qljungbox(temp.Size());
for(ulong i = 0; i<laggs.Size(); qljungbox[i] = nobs*(nobs+2)*temp[ulong(laggs[i])-1], ++i);
vector adj_lags = laggs - double(model_df);
vector pval = qljungbox;
pval.Fill(double("nan"));
int e = 0;
for(ulong i = 0; i<adj_lags.Size(); ++i)
if(adj_lags[i]>0)
pval[i] = 1. - MathCumulativeDistributionChiSquare(qljungbox[i],adj_lags[i],e);
matrix out;
out = matrix::Zeros(adj_lags.Size(),2);
out.Col(qljungbox,0);
out.Col(pval,1);
if(boxpierce)
{
out.Resize(out.Rows(),4);
temp = pow(ssacf,2.0);
temp = temp.CumSum();
vector qboxpierce = temp;
for(ulong i = 0; i<laggs.Size(); qboxpierce[i] = nobs*temp[ulong(laggs[i])-1], ++i);
for(ulong i = 0; i<adj_lags.Size(); ++i)
if(adj_lags[i]>0)
pval[i] = 1. - MathCumulativeDistributionChiSquare(qboxpierce[i],adj_lags[i],e);
out.Col(qboxpierce,2);
out.Col(pval,3);
}
return out;
}
//+------------------------------------------------------------------+