文章 "运用 R-平方 评估策略余额曲线的品质" - 页 2

 
非常感谢作者。
 
感谢您提供的有用文章!转发了!:-)
 

图 19:10,000 次随机游走的 LR 相关性分布


图 20:10,000 次随机游走的 R^2 分布

我不明白 R^2 怎么会出现第二幅图中显示的负值?是的,第一幅图也有问题。如果线性回归 绘制正确,皮尔逊 RQ (LR) 似乎不应该是负值。但在图表中却不是。我错在哪里了?


找到了。我哪里都没说错,只是图表中的 R^2 和 LR 是自定义的--如果数值序列的最后一个元素小于第一个元素,就会出现实值乘以-1 的 情况。最好能在图表之前写一下。

 

本文通过 CLinReg::LRLine 考虑了线性回归 的误差。

证明

#include <Graphics\Graphic.mqh> 
#include <Math\Stat\Normal.mqh>
#include <Math\Alglib\Alglib.mqh>

// 返回直线的 Y 值 (y(x)=a*x+b)
void GetLine( const double a, const double b, const int Amount, double &Result[] )
{
  ArrayResize(Result, Amount);
  
  for (int i = 0; i < Amount; i++)
    Result[i] = a * i + b;    
}

// 通过 CLinReg::LRLine 返回线性回归结果
void GetLinearRegression( const double &Array[], double &Result[] )
{
  const int Total = ArraySize(Array);
  
  CMatrixDouble XY(Total, 2);
  
  for (int i = 0; i < Total; i++)
  {
    XY[i].Set(0, i);
    XY[i].Set(1, Array[i]);
  }
  
  int retcode;
  double a, b;
  
  CLinReg::LRLine(XY, Total, retcode, a, b);

  GetLine(a, b, Total, Result);    
}

// 通过 CAlglib::LRBuild + CAlglib::LRUnpack 返回线性回归结果
void GetLinearRegression2( const double &Array[], double &Result[] )
{
  const int Total = ArraySize(Array);
  
  CMatrixDouble XY(Total, 2);
  
  for (int i = 0; i < Total; i++)
  {
    XY[i].Set(0, i);
    XY[i].Set(1, Array[i]);
  }
  
  int retcode;
  
  CLinearModelShell lm;
  CLRReportShell    ar;
//-- 用于存储回归结果的数组
  double lr_coeff[];
//--- 线性回归系数的计算
  CAlglib::LRBuild(XY, Total, 1, retcode, lm, ar);
//--- 获得线性回归系数
  CAlglib::LRUnpack(lm, lr_coeff, retcode);

  GetLine(lr_coeff[0], lr_coeff[1], Total, Result);      
}

void ToChart( const double &Array1[], const double &Array2[], const int X = 0, const int Y = 0, const int Width = 780, const int Height = 380 )
{
  static const string Name = __FILE__;
  
  CGraphic Graphic; 

  if (ObjectFind(0, Name) < 0) 
    Graphic.Create(0, Name, 0, X, Y, Width, Height); 
  else 
    Graphic.Attach(0, Name); 

  Graphic.CurveAdd(Array1, CURVE_LINES);
  Graphic.CurveAdd(Array2, CURVE_LINES);
  
  Graphic.CurvePlotAll(); 
  Graphic.Update();  
}

void GetRandomArray( double &Array[], const int Amount = 1 e3 )
{
  double Random[];
  
  MathSrand(GetTickCount()); 

  MathRandomNormal(0, 1, Amount, Random); 
  MathCumulativeSum(Random, Array);
}

#define  TOSTRING(A) #A + " = " + (string)(A) + "\n"

void OnStart() 
{   
  double Array[];
  
  GetRandomArray(Array);  
  
  double Estimate[];
  double Estimate2[];
     
  GetLinearRegression(Array, Estimate);
  GetLinearRegression2(Array, Estimate2);

  const double R = CAlglib::PearsonCorr2(Array, Estimate);
  const double R2 = CAlglib::PearsonCorr2(Array, Estimate2);
  
  Print(TOSTRING(R) +
        TOSTRING((Array[0] > Array[ArraySize(Array) - 1]) ? -R : R) +
        TOSTRING(R2));
  
  ToChart(Array, Estimate2);
}


结果

R = -0.5864718581193301
(Array[0]>Array[ArraySize(Array)-1])?-R:R = -0.5864718581193301
R2 = 0.58647185811933


符号不正确。另一种线性回归实现(CAlglib::LRBuild + CAlglib::LRUnpack)计算正确:


 
fxsaber:

文章中展示的 10,000 个独立例子的 LR 相关性和 R^2 分布图显示,R^2 != LR^2

我不明白为什么原始 "凹 "分布的二度分布会使其成为 "平 "分布?

事实证明我错就错在这里。对我来说,这种说法一点也不明显

令人惊讶的是,通过 一个简单的数学运算(提升到二度) ,我们就完全消除了该分布不需要的边际效应。

因此,我决定通过动画来进行实验验证(不要相信我的话)

#include <Graphics\Graphic.mqh> 
#include <Math\Stat\Normal.mqh>
#include <Math\Alglib\Alglib.mqh>

// 返回直线的 Y 值 (y(x)=a*x+b)
void GetLine( const double a, const double b, const int Amount, double &Result[] )
{
  ArrayResize(Result, Amount);
  
  for (int i = 0; i < Amount; i++)
    Result[i] = a * i + b;    
}

// 通过 CAlglib::LRBuild + CAlglib::LRUnpack 返回线性回归结果
void GetLinearRegression( const double &Array[], double &Result[] )
{
  const int Total = ArraySize(Array);
  
  CMatrixDouble XY(Total, 2);
  
  for (int i = 0; i < Total; i++)
  {
    XY[i].Set(0, i);
    XY[i].Set(1, Array[i]);
  }
  
  int retcode;
  
  CLinearModelShell lm;
  CLRReportShell    ar;
//-- 用于存储回归结果的数组
  double lr_coeff[];
//--- 线性回归系数的计算
  CAlglib::LRBuild(XY, Total, 1, retcode, lm, ar);
//--- 获得线性回归系数
  CAlglib::LRUnpack(lm, lr_coeff, retcode);

  GetLine(lr_coeff[0], lr_coeff[1], Total, Result);      
}

// 计算 R
double GetCustomR( const double &Array[] )
{
  double Estimate[];
   
  GetLinearRegression(Array, Estimate);
   
  const double R = CAlglib::PearsonCorr2(Array, Estimate);

  return((Array[0] > Array[ArraySize(Array) - 1]) ? -R : R);
}

// 计算 R 随机向量
void GetRandomCustomR( const int Amount, const int VectorSize, double &Result[] )
{
  double Random[];
  double Sum[];
  
  MathSrand(GetTickCount()); 

  ArrayResize(Result, Amount);
  
  for (int i = 0; i < Amount; i++)
  {
    MathRandomNormal(0, 1, VectorSize, Random); 
    MathCumulativeSum(Random, Sum);
    
    Result[i] = GetCustomR(Sum);
  }  
}

void ToChart( const double &X[],  const double &Y[], const string Str = NULL, const int X0 = 0, const int Y0 = 0, const int Width = 780, const int Height = 380 )
{
  static const string Name = __FILE__;
  
  CGraphic Graphic; 

  if (ObjectFind(0, Name)<0) 
    Graphic.Create(0, Name, 0, X0, Y0, Width, Height); 
  else 
    Graphic.Attach(0, Name); 

  Graphic.BackgroundMain(Str); 
  Graphic.BackgroundMainSize(16); 

  Graphic.CurveAdd(X, Y, CURVE_HISTOGRAM).HistogramWidth(6);
  
  Graphic.CurvePlotAll(); 
  Graphic.Update();  
}

void MathPow( double &Result[], const double &Array[], const double Pow )
{
  const int Size = ArrayResize(Result, ArraySize(Array));
  
  for (int i = 0; i < Size; i++)
    Result[i] = (Array[i] < 0) ? -MathPow(-Array[i], Pow) : MathPow(Array[i], Pow);
}

//https://www.mql5.com/zh/docs/standardlibrary/mathematics/stat/normal
//+------------------------------------------------------------------+ 
//| 计算数据集的频率| 
//+------------------------------------------------------------------+ 
bool CalculateHistogramArray(const double &data[],double &intervals[],double &frequency[], 
                             double &maxv,double &minv,const int cells=10) 
  { 
   if(cells<=1) return (false); 
   int size=ArraySize(data); 
   if(size<cells*10) return (false); 
   minv=data[ArrayMinimum(data)]; 
   maxv=data[ArrayMaximum(data)]; 
   double range=maxv-minv; 
   double width=range/cells; 
   if(width==0) return false; 
   ArrayResize(intervals,cells); 
   ArrayResize(frequency,cells); 
//--- 设置区间的中心点 
   for(int i=0; i<cells; i++) 
     { 
      intervals[i]=minv+(i+0.5)*width; 
      frequency[i]=0; 
     } 
//--- 填入间隔频率 
   for(int i=0; i<size; i++) 
     { 
      int ind=int((data[i]-minv)/width); 
      if(ind>=cells) ind=cells-1; 
      frequency[ind]++; 
     } 
   return (true); 
  } 

void DistributionToChart( const double &Array[], const string Str = NULL, const int NCells = 51 )
{
  double X[];          // 直方图区间中心 
  double Y[];          // 样本中属于区间的数值个数 
  double Max, Min;     // 样本中的最大值和最小值 
  
  CalculateHistogramArray(Array, X, Y, Max, Min, NCells);   

  ToChart(X, Y, Str);
}

void OnInit() 
{   
  double R[];
  
  GetRandomCustomR(1 e3, 1 e4, R);
  
  double Array[];

  const int Max = 50;
  
  while (!IsStopped())
    for (int i = 1; !IsStopped() && i < (Max << 1); i++)
    {
      const double Pow = (i > Max) ? ((Max << 1) - i) * 0.1 : i * 0.1;
      
      MathPow(Array, R, Pow);
      DistributionToChart(Array, "Distribution of R^" + DoubleToString(Pow, 1));      
      
      Sleep(100);
    }
}



似乎是这样的

 

 

图 21:作为自定义优化标准的 R^2 值

图片 的 LR Correlation在 MQL 中处于什么位置?或者这个参数和许多其他参数只计算单次运行,所以ENUM_STATISTICS 中没有

如果是这样,建议根据本文中提到的合理考虑来计算该参数:通过不含 MM 和平方的权益计算。


ZY 我测量了计算一个百万数值数组(如权益)的 GetCustomR 所需的时间 - 2.5 秒。这是一个很长的时间。所有时间都花在 LR 计算上(CAlglib::LRBuild + CAlglib::LRUnpack)。但有时通过CLinReg::LRLine 计算的 LR 曲线会快上一个数量级。如果将其掺杂在一起,在优化中就可以将其作为优化标准。

Документация по MQL5: Стандартные константы, перечисления и структуры / Состояние окружения / Статистика тестирования
Документация по MQL5: Стандартные константы, перечисления и структуры / Состояние окружения / Статистика тестирования
  • www.mql5.com
Максимальная просадка баланса в процентах. В процессе торговли баланс может испытать множество просадок, для каждой фиксируется относительное значение просадки в процентах. Возвращается наибольшее значение Максимальная...
 
Dennis Kirichenko:

我一直以为是100我一直以为是100。谢谢,这篇文章很有意思。

是的,这是我在著名的 R 和统计书籍中看到的数字。但抱歉找不到链接,所以很抱歉。

丹尼斯-基里琴科

对回归系数进行显著性检验也很常见。甚至 Alglib 也有 :-)

显然,这些检验是针对正态分布的。我们得到的是均匀分布

PearsonCorrelationSignificance(), SpearmanRankCorrelationSignificance().

谢谢你的链接,我会记住的。

 
fxsaber:

ZY 错误声明

R^2 不过是图形与其线性模型之间的相关性而已

//-- 求 R^2 及其符号
   double r2 = MathPow(corr, 2.0);

的确,这是一个严重的用词错误。我竟然写出了这样的东西。我会改正的。

当你看到所有其他的 MQL 代码时,你不会明白为什么要给出它们,因为如果没有 CStrategy 知识,它们是完全无法阅读的

CStrategy 仅用于收集必要条件。正如有人正确指出的那样,主要代码是 R2 的实际计算。

适合 R^2 的 "权益 "计算代码。它是以 MT4 风格编写的,将其翻译为 MT5 并不困难....。

让我们来学习一下。

 
Maxim Dmitrievsky:

我同意这一点,所有其他内容都必须从类中删除才能添加到系统中......最好将所有内容都放在单独的 f-iases 或单独的 includnik 中。

将您的权益计算(或 fxsaber 提供的代码)作为双数组,并将其插入 R^2 计算函数。您不需要删除任何内容,也不需要使用类和CStrategy

 
fxsaber:

我不明白 R^2 怎么会像第二幅图中显示的那样取负值?第一幅图也有问题。如果线性回归 构造正确,皮尔逊 LR 似乎不应该是负值。但在图中却不是。我错在哪里了?

找到了。我哪里都没说错,只是图中的 R^2 和 LR 是自定义的--如果数值序列的最后一个元素小于第一个元素,就会出现实值乘以-1 的 情况。最好在图表之前写明这一点。

这一点隐藏在文章中:

我们的脚本同时计算 LR 相关性和 R^2。我们稍后会看到它们之间的区别。脚本中还有一个小补充。我们会将计算出的相关系数乘以合成图的最终符号。如果结果小于零,则相关系数为负,如果大于零,则为正。这样做是为了快速、轻松地将负结果与正结果区分开来,而无需借助其他统计方法。这就是 MetaTrader 5 中 LR Correlation 的工作原理,R^2 也将根据同样的原理建立。

也许我应该在其他地方多次写到这一点。