Diskussion zum Artikel "R-squared als Gütemaß der Saldenkurve einer Strategie" - Seite 2

 
Ich habe schräg gelesen, aber trotzdem - ich habe für mich wichtige Schlüsse gezogen. Vielen Dank an den Autor.
 
Vielen Dank für den hilfreichen Artikel! Habe ihn neu gepostet! :-)
 

Abbildung 19: LR-Korrelationsverteilung für 10.000 Random Walks


Abbildung 20: Verteilung von R^2 für 10.000 zufällige Spaziergänge

Ich verstehe nicht, wie R^2 die negativen Werte annehmen kann, die im zweiten Diagramm gezeigt werden? Ja, und es gibt Fragen zum ersten Diagramm. Wenn die lineare Regression korrekt dargestellt wird, sollte der Pearsonsche RQ (LR) nicht negativ sein. Aber in der Grafik ist er nicht negativ. Wo liege ich falsch?


Ich hab's. Ich liege nirgendwo falsch, es ist nur so, dass die Graphen benutzerdefinierte R^2 und LR haben - die Multiplikation mit -1 des realen Wertes tritt auf, wenn das letzte Element der numerischen Reihe kleiner ist als das erste. Es wäre gut, darüber zu schreiben, bevor die Graphen.

 

In diesem Papier wird die lineare Regression mit einem Fehler betrachtet - über CLinReg::LRLine.

Beweis

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

// Gibt die Y-Werte der Linie zurück (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;    
}

// Liefert eine lineare Regression über 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);    
}

// Liefert eine lineare Regression über 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;
//--- Arrays zum Speichern von Regressionsergebnissen
  double lr_coeff[];
//--- Berechnung der linearen Regressionskoeffizienten
  CAlglib::LRBuild(XY, Total, 1, retcode, lm, ar);
//--- Ermittlung der linearen Regressionskoeffizienten
  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);
}


Ergebnis

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


Das Vorzeichen ist falsch. Alternative LR-Implementierung (CAlglib::LRBuild + CAlglib::LRUnpack) zählt korrekt:


 
fxsaber:

Die Graphen der LR-Korrelations- und R^2-Verteilung für die 10.000 unabhängigen Beispiele, die in dem Artikel vorgestellt werden, zeigen, dass R^2 != LR^2 ist.

Ich verstehe nicht, warum der zweite Grad der ursprünglichen "konkaven" Verteilung sie "flach" macht?

Hier wurde ich eines Besseren belehrt. Für mich ist die Aussage überhaupt nicht offensichtlich

Erstaunlich ist, dass wirdurch eine einfache mathematische Maßnahme (durch Erhöhen auf den zweiten Grad) die unerwünschten Randeffekte der Verteilung vollständig beseitigt haben.

Also habe ich beschlossen, dies experimentell mit Hilfe einer Animation zu bestätigen (und mich nicht auf mein Wort zu verlassen)

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

// Gibt die Y-Werte der Linie zurück (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;    
}

// Liefert eine lineare Regression über 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;
//--- Arrays zum Speichern von Regressionsergebnissen
  double lr_coeff[];
//--- Berechnung der linearen Regressionskoeffizienten
  CAlglib::LRBuild(XY, Total, 1, retcode, lm, ar);
//--- Ermittlung der linearen Regressionskoeffizienten
  CAlglib::LRUnpack(lm, lr_coeff, retcode);

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

// Berechnet 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);
}

// Berechnet R zufällige Vektoren
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/de/docs/standardlibrary/mathematics/stat/normal
//+------------------------------------------------------------------+ 
//| Häufigkeiten für den Datensatz berechnen| 
//+------------------------------------------------------------------+ 
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); 
//--- die Zentren der Intervalle festlegen 
   for(int i=0; i<cells; i++) 
     { 
      intervals[i]=minv+(i+0.5)*width; 
      frequency[i]=0; 
     } 
//--- Ausfüllen der Intervallfrequenzen 
   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[];          // Histogramm-Intervallzentren 
  double Y[];          // Anzahl der Werte aus der Stichprobe, die in das Intervall fallen 
  double Max, Min;     // Höchst- und Mindestwerte in der Stichprobe 
  
  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);
    }
}



Es scheint so zu sein.

 

 

Abb. 21: R^2-Wert als benutzerdefiniertes Optimierungskriterium

Wo ist in MQL die LR-Korrelation, die auf dem Bild zu sehen ist? Oder werden dieser und viele andere Parameter nur für einzelne Läufe berechnet, so dass sie in ENUM_STATISTICS nicht vorhanden sind?

Wenn ja, schlagen sie vor, diesen Parameter aus den in diesem Artikel erwähnten vernünftigen Überlegungen zu berechnen: durch Eigenkapital ohne MM und quadriert.


ZЫ Ich habe gemessen, wie viel Zeit die Berechnung von GetCustomR für ein Array mit einer Million Werten (wie equity) in Anspruch nimmt - 2,5 Sekunden. Das ist eine Menge Zeit. Alles wird für die LR-Berechnung verwendet(CAlglib::LRBuild + CAlglib::LRUnpack). Aber manchmal ist gekrümmte LR durch CLinReg::LRLine um eine Größenordnung schneller. Wenn man es aufpeppt, wird es in Optimierungen als Optimierungskriterium tolerierbar.

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

Oh! Ich dachte immer, es wären 100. Danke, interessanter Artikel.

Ja, das ist eine Zahl, die mir in seriösen Büchern über R und Statistik begegnet ist. Aber leider konnte ich den Link nicht finden, tut mir leid.

Dennis Kirichenko:

Es ist auch üblich, Signifikanztests für den Regressionskoeffizienten durchzuführen. Sogar Alglib hat sie :-)

Offensichtlich sind die Tests für Normalverteilung. Wir haben eine Gleichverteilung.

PearsonCorrelationSignifikanz(), SpearmanRankCorrelationSignifikanz().

Danke für den Link, ich werde ihn mir merken.

 
fxsaber:

ZY Falsche Aussage

R^2 ist nichts anderes als die Korrelation zwischen einer Grafik und ihrem linearen Modell

//-- R^2 und sein Vorzeichen finden
   double r2 = MathPow(corr, 2.0);

Ja, in der Tat, ein grober Fehler in der Formulierung. Ich bin überrascht, dass ich so etwas überhaupt geschrieben habe. Ich werde es korrigieren.

Wenn man sich all die anderen MQL-Codes ansieht, versteht man nicht, warum sie angegeben sind, denn sie sind ohne CStrategy-Kenntnisse völlig unlesbar

CStrategy wird nur zum Sammeln von Requisiten benötigt. Der Hauptcode ist, wie schon richtig bemerkt wurde, die eigentliche Berechnung von R2.

Der Code zur Berechnung des "Eigenkapitals", geeignet für R^2. Er ist im MT4-Stil geschrieben, es ist nicht schwierig, ihn in MT5.... zu übersetzen.

Schauen wir ihn uns an.

 
Maxim Dmitrievsky:

Ich stimme dem zu, der ganze Rest muss aus den Klassen herausgerissen werden, um ihn in Ihr System einzufügen... es wäre besser, alles in separaten f-Fällen oder einem separaten includnik zu haben.

Nehmen Sie Ihre Equity-Berechnung (oder den von fxsaber vorgestellten Code) als Double-Array und fügen Sie es in die R^2-Berechnungsfunktion ein. Sie müssen nichts herausreißen, Sie müssen keine Klassen und CStrategy verwenden.

 
fxsaber:

Ich verstehe nicht, wie R^2 negative Werte annehmen kann, wie im zweiten Diagramm gezeigt? Auch beim ersten Diagramm gibt es Fragen. Wenn die lineare Regression richtig konstruiert ist, sollte Pearson's LR eigentlich nicht negativ sein. In der Grafik ist sie es aber nicht. Wo liege ich falsch?

Ich hab's. Ich liege nirgends falsch, es ist nur so, dass die Graphen ein individuelles R^2 und LR haben - die Multiplikation mit -1 des realen Wertes tritt auf, wenn das letzte Element der Zahlenreihe kleiner ist als das erste. Es wäre gut, dies vor den Graphen zu erwähnen.

Es ist in dem Artikel versteckt:

Unser Skript berechnet sowohl die LR-Korrelation als auch R^2. Wir werden den Unterschied zwischen beiden etwas später sehen. Es gibt einen kleinen Zusatz zum Skript. Wir multiplizieren den resultierenden Korrelationskoeffizienten mit dem endgültigen Vorzeichen des synthetischen Graphen. Wenn das Ergebnis kleiner als Null ist, ist die Korrelation negativ, wenn sie größer ist, positiv. Auf diese Weise lassen sich negative Ergebnisse schnell und einfach von positiven trennen, ohne dass man auf andere Statistiken zurückgreifen muss. So funktioniert die LR-Korrelation in MetaTrader 5, und R^2 wird nach demselben Prinzip erstellt.

Vielleicht hätte ich an anderer Stelle und mehrmals darüber schreiben sollen.