640 lines
22 KiB
MQL5
640 lines
22 KiB
MQL5
//+------------------------------------------------------------------+
| |||
//| EconometricsA.mqh |
| |||
//| Copyright 2000-2026, MetaQuotes Ltd. |
| |||
//| www.mql5.com |
| |||
//+------------------------------------------------------------------+
| |||
#include <Math\Stat\T.mqh>
| |||
#include <Math\Stat\ChiSquare.mqh>
| |||
#include <Math\Stat\F.mqh>
| |||
#include <Math\Stat\Math.mqh>
| |||
#include <Graphics\Graphic.mqh>
| |||
//---
| |||
//+------------------------------------------------------------------+
| |||
//| Computation of parameters and residuals |
| |||
//| for regression on a constant |
| |||
//+------------------------------------------------------------------+
| |||
void regression0(double& y[], double& a, double& c, double& e[])
| |||
{
| |||
//--- Initialization and input data validation
| |||
a = c = 0.0;
| |||
ArrayResize(e, 0);
| |||
int ny = ArraySize(y);
| |||
if(ny < 1)
| |||
{
| |||
Print("no data for regression0()");
| |||
return;
| |||
}
| |||
ArrayResize(e, ny);
| |||
//--- Parameters computation
| |||
a = MathMean(y);
| |||
c = MathStandardDeviation(y);
| |||
//--- Residuals computation
| |||
for(int i = 0; i < ny; ++i)
| |||
e[i] = y[i] - a;
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| Calculation of confidence interval for parameter A |
| |||
//| in regression on a constant |
| |||
//+------------------------------------------------------------------+
| |||
void Aconf0(double a, double c, int n, double conf_level)
| |||
{
| |||
//--- Initialization and input data validation
| |||
if(c <= 0.0)
| |||
{
| |||
Print("c must be positive in Aconf0()");
| |||
return;
| |||
}
| |||
if(n < 2)
| |||
{
| |||
Print("n must be greater 1 in Aconf0()");
| |||
return;
| |||
}
| |||
if(conf_level <= 0.0 || conf_level >= 1.0)
| |||
{
| |||
Print("conf_level must be between 0 and 1 in Aconf0()");
| |||
return;
| |||
}
| |||
int err = 0;
| |||
//--- t-statistic calculation
| |||
//--- double t = MathQuantileT((1.0 - conf_level) / 2.0, n - 1, err); // faulty library function
| |||
double t = MathQuantileT_TMP((1.0 - conf_level) / 2.0, n - 1, err); // custom implementation
| |||
if(err != 0)
| |||
{
| |||
Print("in MathQuantileT() error ", err);
| |||
return;
| |||
}
| |||
t *= c / MathSqrt(n);
| |||
//--- Print result
| |||
PrintFormat("A between %.4f and %.4f with confidence level %.3f", a + t, a - t, conf_level);
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| Test of hypothesis H₀: A = 0 vs H₁: A > 0 |
| |||
//| for regression on a constant |
| |||
//+------------------------------------------------------------------+
| |||
void Aeq0_test0(double a, double c, int n)
| |||
{
| |||
Print("test H0: A = 0 vs H1: A > 0 (for regession on constant) result:");
| |||
//--- Input data validation
| |||
if(c <= 0.0)
| |||
{
| |||
Print("c must be positive in Aeq0_test0()");
| |||
return;
| |||
}
| |||
if(n < 2)
| |||
{
| |||
Print("n must be greater 1 in Aeq0_test0()");
| |||
return;
| |||
}
| |||
//--- t-statistic calculation
| |||
double t = a * MathSqrt(n) / c;
| |||
int err = 0;
| |||
//--- p-value calculation
| |||
double p_value = MathCumulativeDistributionT(t, n - 1, false, false, err);
| |||
if(err != 0)
| |||
{
| |||
Print("in MathCumulativeDistributionT() error ", err);
| |||
return;
| |||
}
| |||
//--- Print result if success
| |||
PrintFormat("t = %.3f, p-value = %.3f", t, p_value);
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| Calculation of prediction interval for Y |
| |||
//| in regression on a constant |
| |||
//+------------------------------------------------------------------+
| |||
void prognose_interval0(double a, double c, int n, double conf_level)
| |||
{
| |||
//--- Input data validation
| |||
if(c <= 0.0)
| |||
{
| |||
Print("c must be positive in prognose_interval0()");
| |||
return;
| |||
}
| |||
if(n < 2)
| |||
{
| |||
Print("n must be greater 1 in prognose_interval0()");
| |||
return;
| |||
}
| |||
if(conf_level <= 0.0 || conf_level >= 1.0)
| |||
{
| |||
Print("conf_level must be between 0 and 1 in prognose_interval0()");
| |||
return;
| |||
}
| |||
int err = 0;
| |||
//--- t-statistic calculation
| |||
//--- double t = MathQuantileT((1.0 - conf_level) / 2.0, n - 1, err); // faulty library function
| |||
double t = MathQuantileT_TMP((1.0 - conf_level) / 2.0, n - 1, err); // custom implementation
| |||
if(err != 0)
| |||
{
| |||
Print("in MathQuantileT() error ", err);
| |||
return;
| |||
}
| |||
t *= c * MathSqrt(1.0 + 1.0 / n);
| |||
//--- Print result if success
| |||
PrintFormat("Y between %.4f and %.4f with confidence level %.3f", a + t, a - t, conf_level);
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| Computation of parameters and residuals for |
| |||
//| simple linear regression |
| |||
//+------------------------------------------------------------------+
| |||
void regression1(double& y[], double& x[], double& a, double& b, double& c, double& e[])
| |||
{
| |||
//--- Initialization and input data validation
| |||
a = b = c = 0.0;
| |||
ArrayResize(e, 0);
| |||
int ny = ArraySize(y);
| |||
if(ny < 3)
| |||
{
| |||
Print("no data for regression1()");
| |||
return;
| |||
}
| |||
if(ny != ArraySize(x))
| |||
{
| |||
Print("arrays y[] and x[] have different lengths in regression1()");
| |||
return;
| |||
}
| |||
//--- Check x[] is not constant
| |||
double Sx = MathStandardDeviation(x);
| |||
if(Sx <= DBL_MIN)
| |||
{
| |||
Print("x[]==const, use regression0()");
| |||
return;
| |||
}
| |||
//--- Parameters A and B estimation
| |||
if(!MathCorrelationPearson(y, x, b))
| |||
{
| |||
Print("MathCorrelationPearson() error in regression1()");
| |||
return;
| |||
}
| |||
ArrayResize(e, ny);
| |||
b *= MathStandardDeviation(y) / Sx;
| |||
a = MathMean(y) - b * MathMean(x);
| |||
//--- Residuals computation
| |||
for(int i = 0; i < ny; ++i)
| |||
e[i] = y[i] - a - b * x[i];
| |||
//--- Parameter C estimation
| |||
c = MathStandardDeviation(e) * MathSqrt(1.0 + 1.0 / (ny - 2.0));
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| Test of hypothesis H₀: B = 0 vs H₁: B ≠ 0 for |
| |||
//| simple linear regression |
| |||
//+------------------------------------------------------------------+
| |||
void Beq0_test1(double b, double c, double var_x, int n)
| |||
{
| |||
Print("test H0: B = 0 vs H1: B != 0 (for pair regession) result:");
| |||
//--- Input data validation
| |||
if(c <= 0.0)
| |||
{
| |||
Print("c must be positive in Beq0_test1()");
| |||
return;
| |||
}
| |||
if(var_x <= 0.0)
| |||
{
| |||
Print("var_x must be positive in Beq0_test1()");
| |||
return;
| |||
}
| |||
if(n < 3)
| |||
{
| |||
Print("n must be 3 or greater in Beq0_test1()");
| |||
return;
| |||
}
| |||
//--- t-statistic calculation
| |||
double t = MathAbs(b * MathSqrt(var_x * (n - 1)) / c);
| |||
int err = 0;
| |||
//--- p-value computation
| |||
double p_value = 2.0 * MathCumulativeDistributionT(t, n - 2, false, false, err);
| |||
if(err != 0)
| |||
{
| |||
Print("in MathCumulativeDistributionT() error ", err);
| |||
return;
| |||
}
| |||
//--- Print result if success
| |||
PrintFormat("t = %.3f, p-value = %.3f", t, p_value);
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| Calculation of prediction interval for Y in |
| |||
//| simple linear regression |
| |||
//+------------------------------------------------------------------+
| |||
void prognose_interval1(double x_new, double a, double b, double c, double var_x, double mean_x, int n, double conf_level)
| |||
{
| |||
//--- Input data validation
| |||
if(c <= 0.0)
| |||
{
| |||
Print("c must be positive in prognose_interval1()");
| |||
return;
| |||
}
| |||
if(n < 2)
| |||
{
| |||
Print("n must be greater 2 in prognose_interval1()");
| |||
return;
| |||
}
| |||
if(conf_level <= 0.0 || conf_level >= 1.0)
| |||
{
| |||
Print("conf_level must be between 0 and 1 in prognose_interval1()");
| |||
return;
| |||
}
| |||
int err = 0;
| |||
//--- t-statistic calculation
| |||
//--- double t = MathQuantileT((1.0 - conf_level) / 2.0, n - 1, err); // faulty library function
| |||
double t = MathQuantileT_TMP((1.0 - conf_level) / 2.0, n - 1, err); // custom implementation
| |||
if(err != 0)
| |||
{
| |||
Print("in MathQuantileT() error ", err);
| |||
return;
| |||
}
| |||
t *= c * MathSqrt(1.0 + 1.0 / n + MathPow((x_new - mean_x), 2) * (n - 1) / var_x);
| |||
//--- Print result if success
| |||
PrintFormat("Y between %.4f and %.4f with confidence level %.3f", a + b * x_new + t, a + b * x_new - t, conf_level);
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| Residuals plot vs. price bar index |
| |||
//+------------------------------------------------------------------+
| |||
void t_residuals_plot(double& residuals[])
| |||
{
| |||
int n_residuals = ArraySize(residuals);
| |||
//--- Input data validation
| |||
if(n_residuals < 1)
| |||
{
| |||
Print("no data for t_residuals_plot()");
| |||
return;
| |||
}
| |||
//--- Array T[] as x on plot
| |||
double T[];
| |||
if(!MathSequenceByCount(1, n_residuals, n_residuals, T))
| |||
{
| |||
Print("MathSequenceByCount() error");
| |||
return;
| |||
}
| |||
//--- Plot construction
| |||
ChartSetInteger(0, CHART_SHOW, false);
| |||
CGraphic graphic;
| |||
graphic.Create(0, "G", 0, 0, 0, 750, 300);
| |||
graphic.CurveAdd(T, residuals, CURVE_LINES, "Residuals");
| |||
graphic.CurvePlotAll();
| |||
graphic.Update();
| |||
MessageBox("Press OK to close graph", "Close graph");
| |||
ChartSetInteger(0, CHART_SHOW, true);
| |||
graphic.Destroy();
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| EPDF of residuals vs. normal density with residual SD |
| |||
//| nofx - number of points on plot |
| |||
//+------------------------------------------------------------------+
| |||
void epdf_vs_normalpdf(double& residuals[], int nofx = 30)
| |||
{
| |||
int n_residuals = ArraySize(residuals);
| |||
//--- Input data validation
| |||
if(n_residuals < 1)
| |||
{
| |||
Print("no data for epdf_vs_normalpdf()");
| |||
return;
| |||
}
| |||
//--- Array for x
| |||
double x[];
| |||
if(!MathSequenceByCount(MathMin(residuals), MathMax(residuals), nofx, x))
| |||
{
| |||
Print("sequence error");
| |||
return;
| |||
}
| |||
//--- Array for EPDF
| |||
double epdf[];
| |||
if(!MathProbabilityDensityEmpirical(residuals, nofx, x, epdf))
| |||
{
| |||
Print("MathProbabilityDensityEmpirical() error");
| |||
return;
| |||
}
| |||
//--- Array for theoretical PDF
| |||
double normal_pdf[];
| |||
if(!MathProbabilityDensityNormal(x, 0.0, MathStandardDeviation(residuals), normal_pdf))
| |||
{
| |||
Print("MathProbabilityDensityNormal() error");
| |||
return;
| |||
}
| |||
//--- Plot construction
| |||
ChartSetInteger(0, CHART_SHOW, false);
| |||
CGraphic graphic;
| |||
graphic.Create(0, "G", 0, 0, 0, 750, 400);
| |||
graphic.CurveAdd(x, epdf, CURVE_LINES, "Residuals");
| |||
graphic.CurveAdd(x, normal_pdf, CURVE_LINES, "Normal");
| |||
graphic.CurvePlotAll();
| |||
graphic.Update();
| |||
MessageBox("Press OK to close graph", "Close graph");
| |||
ChartSetInteger(0, CHART_SHOW, true);
| |||
graphic.Destroy();
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| QQ-plot of residuals vs. normal distribution with residual SD |
| |||
//+------------------------------------------------------------------+
| |||
void qq_plot(double& residuals[])
| |||
{
| |||
int n_residuals = ArraySize(residuals);
| |||
//--- Input data validation
| |||
if(n_residuals < 1)
| |||
{
| |||
Print("no data for qq_plot()");
| |||
return;
| |||
}
| |||
//--- Copy input array and sort this copy
| |||
double residuals_copy[];
| |||
ArrayResize(residuals_copy, n_residuals);
| |||
ArrayCopy(residuals_copy, residuals);
| |||
ArraySort(residuals_copy);
| |||
//--- Probability sequence
| |||
double pseq[];
| |||
if(!MathSequenceByCount(0.5 / n_residuals, 1.0 - 0.5 / n_residuals, n_residuals, pseq))
| |||
{
| |||
Print("MathSequenceByCount() error");
| |||
return;
| |||
}
| |||
//--- Theoretical quantiles
| |||
double normal_qs[];
| |||
if(!MathQuantileNormal(pseq, 0.0, MathStandardDeviation(residuals_copy), normal_qs))
| |||
{
| |||
Print("MathQuantileNormal() error");
| |||
return;
| |||
}
| |||
//--- Plot construction
| |||
ChartSetInteger(0, CHART_SHOW, false);
| |||
CGraphic graphic;
| |||
graphic.Create(0, "G", 0, 0, 0, 750, 550);
| |||
graphic.CurveAdd(normal_qs, residuals_copy, CURVE_LINES, "QQ-plot");
| |||
graphic.CurveAdd(residuals_copy, residuals_copy, CURVE_LINES, "Y=X");
| |||
graphic.CurvePlotAll();
| |||
graphic.Update();
| |||
MessageBox("Press OK to close graph", "Close graph");
| |||
ChartSetInteger(0, CHART_SHOW, true);
| |||
graphic.Destroy();
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| Correlogram of residuals |
| |||
//+------------------------------------------------------------------+
| |||
void correlogram(double& residuals[])
| |||
{
| |||
int n_residuals = ArraySize(residuals);
| |||
//--- Input data validation
| |||
if(n_residuals < 2)
| |||
{
| |||
Print("no data for correlogram()");
| |||
return;
| |||
}
| |||
//--- Number of lags
| |||
int ncg = (int)MathSqrt(n_residuals);
| |||
//--- Significance levels
| |||
double bound = 1.96 / MathSqrt(n_residuals);
| |||
double cg0 = 0.0, xb[2] = {0, ncg + 1}, upb[2] = {bound, bound}, lowb[2] = {-bound, -bound};
| |||
//--- Lags array creation
| |||
double lags[];
| |||
if(!MathSequenceByCount(1, ncg, ncg, lags))
| |||
{
| |||
Print("MathSequenceByCount() error");
| |||
return;
| |||
}
| |||
//--- ACF array calculation
| |||
double cg[];
| |||
ArrayResize(cg, ncg);
| |||
ArrayFill(cg, 0, ncg, 0.0);
| |||
for(int i = 0; i < n_residuals; ++i)
| |||
cg0 += residuals[i] * residuals[i];
| |||
for(int k = 1; k <= ncg; ++k)
| |||
{
| |||
for(int i = 0; i < n_residuals - k; ++i)
| |||
cg[k - 1] += residuals[i] * residuals[i + k];
| |||
cg[k - 1] /= cg0;
| |||
}
| |||
//--- Plot construction
| |||
ChartSetInteger(0, CHART_SHOW, false);
| |||
CGraphic graphic;
| |||
graphic.Create(0, "G", 0, 0, 0, 750, 300);
| |||
graphic.CurveAdd(lags, cg, CURVE_HISTOGRAM, "Correlogram");
| |||
graphic.CurveAdd(xb, upb, CURVE_LINES, "Upper bound");
| |||
graphic.CurveAdd(xb, lowb, CURVE_LINES, "Lower bound");
| |||
graphic.CurvePlotAll();
| |||
graphic.Update();
| |||
MessageBox("Press OK to close graph", "Close graph");
| |||
ChartSetInteger(0, CHART_SHOW, true);
| |||
graphic.Destroy();
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| Scatter plot of (x, y) points with line y = a * x + b |
| |||
//+------------------------------------------------------------------+
| |||
void scatter_plot(double& x[], double& y[], bool add_line = false, double a = 0.0, double b = 0.0)
| |||
{
| |||
int ny = ArraySize(y);
| |||
//--- Input data validation
| |||
if(ny < 1)
| |||
{
| |||
Print("no data for regression1()");
| |||
return;
| |||
}
| |||
if(ny != ArraySize(x))
| |||
{
| |||
Print("arrays y[] and x[] have different lengths in scatter_plot()");
| |||
return;
| |||
}
| |||
//--- Regression line points calculation
| |||
double xreg[2] = {MathMin(x), MathMax(x)};
| |||
double yreg[2] = {a + b*xreg[0], a + b*xreg[1]};
| |||
//--- Plot construction
| |||
ChartSetInteger(0, CHART_SHOW, false);
| |||
CGraphic graphic;
| |||
graphic.Create(0, "G", 0, 0, 0, 750, 550);
| |||
graphic.CurveAdd(x, y, CURVE_POINTS, "scatter plot");
| |||
if(add_line)
| |||
graphic.CurveAdd(xreg, yreg, CURVE_LINES, "y = a * x + b");
| |||
graphic.CurvePlotAll();
| |||
graphic.Update();
| |||
MessageBox("Press OK to close graph", "Close graph");
| |||
ChartSetInteger(0, CHART_SHOW, true);
| |||
graphic.Destroy();
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| Ljung-Box test for autocorrelation in residuals |
| |||
//| m - lags number, pq - sum of p and q in ARMA(p,q) model |
| |||
//+------------------------------------------------------------------+
| |||
void Ljung_Box_test(double& residuals[], int m = 10, int pq = 0)
| |||
{
| |||
Print("Ljung-Box test result:");
| |||
//--- Input data validation
| |||
if(pq < 0)
| |||
{
| |||
Print("pq must be nonnegative");
| |||
return;
| |||
}
| |||
if(m <= pq)
| |||
{
| |||
Print("m must be greater pq");
| |||
return;
| |||
}
| |||
int n_residuals = ArraySize(residuals);
| |||
if(n_residuals < m + 1)
| |||
{
| |||
Print("not enough data");
| |||
return;
| |||
}
| |||
//--- Initialization
| |||
double Q = 0.0, cov0 = 0.0, cov, ro;
| |||
//--- Test statistic calculation
| |||
for(int i = 0; i < n_residuals; ++i)
| |||
cov0 += residuals[i] * residuals[i];
| |||
for(int k = 1; k <= m; ++k)
| |||
{
| |||
cov = 0.0;
| |||
for(int i = 0; i < n_residuals - k; ++i)
| |||
cov += residuals[i] * residuals[i + k];
| |||
ro = cov / cov0;
| |||
Q += ro * ro / (n_residuals - k);
| |||
}
| |||
Q *= n_residuals * (n_residuals + 2);
| |||
//--- p-value computation
| |||
int err = 0;
| |||
double p_value = MathCumulativeDistributionChiSquare(Q, m - pq, false, false, err);
| |||
if(err != 0)
| |||
{
| |||
Print("MathCumulativeDistributionChiSquare() error: ", err);
| |||
return;
| |||
}
| |||
//--- Print result
| |||
PrintFormat("Q = %.3f, p-value = %.3f", Q, p_value);
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| Jarque-Bera test for normality of distribution |
| |||
//+------------------------------------------------------------------+
| |||
void Jarque_Bera_test(double& residuals[])
| |||
{
| |||
Print("Jarque-Bera test result:");
| |||
//--- Input data validation
| |||
int n_residuals = ArraySize(residuals);
| |||
if(n_residuals < 1)
| |||
{
| |||
Print("not enough data");
| |||
return;
| |||
}
| |||
//--- Skewness calculation
| |||
double S = MathSkewness(residuals);
| |||
//--- Kurtosis calculation
| |||
double K = MathKurtosis(residuals);
| |||
//--- Test statistic calculation
| |||
double JB = n_residuals * (S * S + K * K / 4.0) / 6.0;
| |||
//--- p-value computation
| |||
double p_value = MathExp(-JB / 2.0);
| |||
//--- Print result
| |||
PrintFormat("JB = %.3f, p-value = %.3f", JB, p_value);
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| Pettitt test for structural break (abrupt change in mean) |
| |||
//+------------------------------------------------------------------+
| |||
void Pettitt_test(double& residuals[])
| |||
{
| |||
Print("Pettitt test result:");
| |||
//--- Input data validation
| |||
int n_residuals = ArraySize(residuals);
| |||
if(n_residuals < 2)
| |||
{
| |||
Print("not enough data");
| |||
return;
| |||
}
| |||
//--- Initialization
| |||
double K = 0.0, U, W = 0.0;
| |||
int t_change = 0;
| |||
//--- Sample ranking computation
| |||
double rank[];
| |||
MathRank(residuals, rank);
| |||
//--- Test statistic calculation
| |||
for(int t = 1; t < n_residuals; ++t)
| |||
{
| |||
W += rank[t - 1];
| |||
U = MathAbs(2.0 * W - t * (n_residuals + 1.0));
| |||
if(U > K)
| |||
{
| |||
K = U;
| |||
t_change = t;
| |||
}
| |||
}
| |||
//--- p-value computation
| |||
double p_value = MathMin(2.0 * MathExp(-6.0 * K * K / (n_residuals * n_residuals * (n_residuals + 1.0))), 1.0);
| |||
//--- Print result
| |||
PrintFormat("K = %.3f, p-value = %.3f, change-point = %d", K, p_value, t_change);
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| Student's t-distribution quantile |
| |||
//| (custom implementation replacing faulty library function) |
| |||
//| JUST A TEMPORARY REPLACEMENT! (Based on library variant) |
| |||
//+------------------------------------------------------------------+
| |||
double MathQuantileT_TMP(const double prob, const double nu, int &error_code)
| |||
{
| |||
if(!MathIsValidNumber(prob) || !MathIsValidNumber(nu))
| |||
{
| |||
error_code = ERR_ARGUMENTS_NAN;
| |||
return QNaN;
| |||
}
| |||
if(nu <= 0.0 || nu != MathRound(nu))
| |||
{
| |||
error_code = ERR_ARGUMENTS_INVALID;
| |||
return QNaN;
| |||
}
| |||
if(prob < 0.0 || prob > 1.0)
| |||
{
| |||
error_code = ERR_ARGUMENTS_INVALID;
| |||
return QNaN;
| |||
}
| |||
error_code = ERR_RESULT_INFINITE;
| |||
if(prob == 0.0)
| |||
return QNEGINF;
| |||
if(prob == 1.0)
| |||
return QPOSINF;
| |||
error_code = ERR_OK;
| |||
if(prob == 0.5)
| |||
return 0.0;
| |||
if(nu == 1.0)
| |||
return MathTan(M_PI * (prob - 0.5));
| |||
int err_code = 0;
| |||
double x_low = -1.0;
| |||
double x_high = 1.0;
| |||
while(MathCumulativeDistributionT(x_low, nu, err_code) > prob && x_low > -1e6)
| |||
x_low *= 2.0;
| |||
while(MathCumulativeDistributionT(x_high, nu, err_code) < prob && x_high < 1e6)
| |||
x_high *= 2.0;
| |||
double x = 0.0;
| |||
int max_iterations = 100;
| |||
double precision = 1e-12; // Высокая точность
| |||
for(int i = 0; i < max_iterations; i++)
| |||
{
| |||
x = (x_low + x_high) / 2.0;
| |||
double cdf = MathCumulativeDistributionT(x, nu, err_code);
| |||
if(MathAbs(x_high - x_low) < precision)
| |||
break;
| |||
if(cdf < prob)
| |||
x_low = x;
| |||
else
| |||
x_high = x;
| |||
if(i == max_iterations - 1)
| |||
error_code = ERR_NON_CONVERGENCE;
| |||
}
| |||
return x;
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| Helper function to export array to text file |
| |||
//| (for data analysis in other programs) |
| |||
//+------------------------------------------------------------------+
| |||
void array2csv(double& a[], string fldr, string fnm)
| |||
{
| |||
//--- Initialization and input data validation
| |||
int ftxt = FileOpen(fldr + "\\" + fnm, FILE_WRITE | FILE_TXT | FILE_ANSI | FILE_COMMON);
| |||
if(ftxt == INVALID_HANDLE)
| |||
{
| |||
Print("FileOpen() error");
| |||
return;
| |||
}
| |||
int na = ArraySize(a);
| |||
if(na < 1)
| |||
{
| |||
Print("No data for array2csv()");
| |||
return;
| |||
}
| |||
//--- Writing array to file
| |||
FileWriteString(ftxt, DoubleToString(a[0]));
| |||
for(int i = 1; i < na; ++i)
| |||
FileWriteString(ftxt, "\n" + DoubleToString(a[i]));
| |||
FileClose(ftxt);
| |||
}
| |||
//+------------------------------------------------------------------+
|