English Русский 中文 Español 日本語 Português
Wie die Testergebnisse des Experten selbstständig  bewerten

Wie die Testergebnisse des Experten selbstständig bewerten

MetaTrader 4Tester | 18 Januar 2016, 08:47
759 0
Slava
Slava

    Zunächst ein paar Worte über Testverfahren. Vor dem Test-Start lädt das Test-Untersystem den Experten, stellt seine Parameter, die zuvor vom Benutzer bestimmt wurden und ruft die Funktion init() auf. Dann "bearbeitet" der Tester der erzeugten Reihenfolge und jedes mal ruft die Funktion start() auf. Wenn die Test-Reihenfolge beendet ist, ruft der Tester die Funktion deinit() auf. Dabei steht im Experten  die ganze Handelshistorie zur Verfügung, die während dem Testlaufe zusammengefasst wurde. Der Experte kann in diesem Moment analysiert werden.

    Die folgende Funktion CalculateSummary liefert die Testergebnisse - eigentlich die Daten, die im Standard-Bericht des Strategy Testers angegeben wurden.
void CalculateSummary(double initial_deposit)
  {
   int    sequence=0, profitseqs=0, lossseqs=0;
   double sequential=0.0, prevprofit=EMPTY_VALUE, drawdownpercent, drawdown;
   double maxpeak=initial_deposit, minpeak=initial_deposit, balance=initial_deposit;
   int    trades_total=HistoryTotal();
//---- initialize summaries
   InitializeSummaries(initial_deposit);
//----
   for(int i=0; i<trades_total; i++)
     {
      if(!OrderSelect(i,SELECT_BY_POS,MODE_HISTORY)) continue;
      int type=OrderType();
      //---- initial balance not considered
      if(i==0 && type==OP_BALANCE) continue;
      //---- calculate profit
      double profit=OrderProfit()+OrderCommission()+OrderSwap();
      balance+=profit;
      //---- drawdown check
      if(maxpeak<balance)
        {
         drawdown=maxpeak-minpeak;
         if(maxpeak!=0.0)
           {
            drawdownpercent=drawdown/maxpeak*100.0;
            if(RelDrawdownPercent<drawdownpercent)
              {
               RelDrawdownPercent=drawdownpercent;
               RelDrawdown=drawdown;
              }
           }
         if(MaxDrawdown<drawdown)
           {
            MaxDrawdown=drawdown;
            if(maxpeak!=0.0) MaxDrawdownPercent=MaxDrawdown/maxpeak*100.0;
            else MaxDrawdownPercent=100.0;
           }
         maxpeak=balance;
         minpeak=balance;
        }
      if(minpeak>balance) minpeak=balance;
      if(MaxLoss>balance) MaxLoss=balance;
      //---- market orders only
      if(type!=OP_BUY && type!=OP_SELL) continue;
      SummaryProfit+=profit;
      SummaryTrades++;
      if(type==OP_BUY) LongTrades++;
      else             ShortTrades++;
      //---- loss trades
      if(profit<0)
        {
         LossTrades++;
         GrossLoss+=profit;
         if(MinProfit>profit) MinProfit=profit;
         //---- fortune changed
         if(prevprofit!=EMPTY_VALUE && prevprofit>=0)
           {
            if(ConProfitTrades1<sequence ||
               (ConProfitTrades1==sequence && ConProfit2<sequential))
              {
               ConProfitTrades1=sequence;
               ConProfit1=sequential;
              }
            if(ConProfit2<sequential ||
               (ConProfit2==sequential && ConProfitTrades1<sequence))
              {
               ConProfit2=sequential;
               ConProfitTrades2=sequence;
              }
            profitseqs++;
            AvgConWinners+=sequence;
            sequence=0;
            sequential=0.0;
           }
        }
      //---- profit trades (profit>=0)
      else
        {
         ProfitTrades++;
         if(type==OP_BUY)  WinLongTrades++;
         if(type==OP_SELL) WinShortTrades++;
         GrossProfit+=profit;
         if(MaxProfit<profit) MaxProfit=profit;
         //---- fortune changed
         if(prevprofit!=EMPTY_VALUE && prevprofit<0)
           {
            if(ConLossTrades1<sequence ||
               (ConLossTrades1==sequence && ConLoss2>sequential))
              {
               ConLossTrades1=sequence;
               ConLoss1=sequential;
              }
            if(ConLoss2>sequential ||
               (ConLoss2==sequential && ConLossTrades1<sequence))
              {
               ConLoss2=sequential;
               ConLossTrades2=sequence;
              }
            lossseqs++;
            AvgConLosers+=sequence;
            sequence=0;
            sequential=0.0;
           }
        }
      sequence++;
      sequential+=profit;
      //----
      prevprofit=profit;
     }
//---- final drawdown check
   drawdown=maxpeak-minpeak;
   if(maxpeak!=0.0)
     {
      drawdownpercent=drawdown/maxpeak*100.0;
      if(RelDrawdownPercent<drawdownpercent)
        {
         RelDrawdownPercent=drawdownpercent;
         RelDrawdown=drawdown;
        }
     }
   if(MaxDrawdown<drawdown)
     {
      MaxDrawdown=drawdown;
      if(maxpeak!=0) MaxDrawdownPercent=MaxDrawdown/maxpeak*100.0;
      else MaxDrawdownPercent=100.0;
     }
//---- consider last trade
   if(prevprofit!=EMPTY_VALUE)
     {
      profit=prevprofit;
      if(profit<0)
        {
         if(ConLossTrades1<sequence ||
            (ConLossTrades1==sequence && ConLoss2>sequential))
           {
            ConLossTrades1=sequence;
            ConLoss1=sequential;
           }
         if(ConLoss2>sequential ||
            (ConLoss2==sequential && ConLossTrades1<sequence))
           {
            ConLoss2=sequential;
            ConLossTrades2=sequence;
           }
         lossseqs++;
         AvgConLosers+=sequence;
        }
      else
        {
         if(ConProfitTrades1<sequence ||
            (ConProfitTrades1==sequence && ConProfit2<sequential))
           {
            ConProfitTrades1=sequence;
            ConProfit1=sequential;
           }
         if(ConProfit2<sequential ||
            (ConProfit2==sequential && ConProfitTrades1<sequence))
           {
            ConProfit2=sequential;
            ConProfitTrades2=sequence;
           }
         profitseqs++;
         AvgConWinners+=sequence;
        }
     }
//---- collecting done
   double dnum, profitkoef=0.0, losskoef=0.0, avgprofit=0.0, avgloss=0.0;
//---- average consecutive wins and losses
   dnum=AvgConWinners;
   if(profitseqs>0) AvgConWinners=dnum/profitseqs+0.5;
   dnum=AvgConLosers;
   if(lossseqs>0)   AvgConLosers=dnum/lossseqs+0.5;
//---- absolute values
   if(GrossLoss<0.0) GrossLoss*=-1.0;
   if(MinProfit<0.0) MinProfit*=-1.0;
   if(ConLoss1<0.0)  ConLoss1*=-1.0;
   if(ConLoss2<0.0)  ConLoss2*=-1.0;
//---- profit factor
   if(GrossLoss>0.0) ProfitFactor=GrossProfit/GrossLoss;
//---- expected payoff
   if(ProfitTrades>0) avgprofit=GrossProfit/ProfitTrades;
   if(LossTrades>0)   avgloss  =GrossLoss/LossTrades;
   if(SummaryTrades>0)
     {
      profitkoef=1.0*ProfitTrades/SummaryTrades;
      losskoef=1.0*LossTrades/SummaryTrades;
      ExpectedPayoff=profitkoef*avgprofit-losskoef*avgloss;
     }
//---- absolute drawdown
   AbsoluteDrawdown=initial_deposit-MaxLoss;
  }

    Für die korrekte Berechnung muss man den Wert des ersten Deposits kennen. Dafür muss man in der Funktion init() die Funktion AccountBalance() aufrufen, die den Balance-Wert am Testanfang geben wird.
void init()
  {
   ExtInitialDeposit=AccountBalance();
  }
    In der obigen Funktion CalculateSummary, genauso wie in einem Standard-Bericht, wird der Gewinn in der Deposit-Währung berechnet. Und andere Handelsergebnisse, wie beispielsweise der "größte Gewinn im Handel" oder der "maximale aufeinander folgende Verlust", die auf Basis vom Gewinn berechnet werden, werden auch in Geld gemessen. Es ist einfach, zu machen, wenn wir den Gewinn in Punkten berechnen wollen.
...
      //---- market orders only
      if(type!=OP_BUY && type!=OP_SELL) continue;
      //---- calculate profit in points
      profit=(OrderClosePrice()-OrderOpenPrice())/MarketInfo(OrderSymbol(),MODE_POINT);
      SummaryProfit+=profit;
...

    Die Ergebnisse kann man in die Berichtsdatei mit der Funktion WriteReport liefern.
void WriteReport(string report_name)
  {
   int handle=FileOpen(report_name,FILE_CSV|FILE_WRITE,'\t');
   if(handle<1) return;
//----
   FileWrite(handle,"Initial deposit           ",InitialDeposit);
   FileWrite(handle,"Total net profit          ",SummaryProfit);
   FileWrite(handle,"Gross profit              ",GrossProfit);
   FileWrite(handle,"Gross loss                ",GrossLoss);
   if(GrossLoss>0.0)
      FileWrite(handle,"Profit factor             ",ProfitFactor);
   FileWrite(handle,"Expected payoff           ",ExpectedPayoff);
   FileWrite(handle,"Absolute drawdown         ",AbsoluteDrawdown);
   FileWrite(handle,"Maximal drawdown          ",
                     MaxDrawdown,
                     StringConcatenate("(",MaxDrawdownPercent,"%)"));
   FileWrite(handle,"Relative drawdown         ",
                     StringConcatenate(RelDrawdownPercent,"%"),
                     StringConcatenate("(",RelDrawdown,")"));
   FileWrite(handle,"Trades total                 ",SummaryTrades);
   if(ShortTrades>0)
      FileWrite(handle,"Short positions(won %)    ",
                        ShortTrades,
                        StringConcatenate("(",100.0*WinShortTrades/ShortTrades,"%)"));
   if(LongTrades>0)
      FileWrite(handle,"Long positions(won %)     ",
                        LongTrades,
                        StringConcatenate("(",100.0*WinLongTrades/LongTrades,"%)"));
   if(ProfitTrades>0)
      FileWrite(handle,"Profit trades (% of total)",
                        ProfitTrades,
                        StringConcatenate("(",100.0*ProfitTrades/SummaryTrades,"%)"));
   if(LossTrades>0)
      FileWrite(handle,"Loss trades (% of total)  ",
                        LossTrades,
                        StringConcatenate("(",100.0*LossTrades/SummaryTrades,"%)"));
   FileWrite(handle,"Largest profit trade      ",MaxProfit);
   FileWrite(handle,"Largest loss trade        ",-MinProfit);
   if(ProfitTrades>0)
      FileWrite(handle,"Average profit trade      ",GrossProfit/ProfitTrades);
   if(LossTrades>0)
      FileWrite(handle,"Average loss trade        ",-GrossLoss/LossTrades);
   FileWrite(handle,"Average consecutive wins  ",AvgConWinners);
   FileWrite(handle,"Average consecutive losses",AvgConLosers);
   FileWrite(handle,"Maximum consecutive wins (profit in money)",
                     ConProfitTrades1,
                     StringConcatenate("(",ConProfit1,")"));
   FileWrite(handle,"Maximum consecutive losses (loss in money)",
                     ConLossTrades1,
                     StringConcatenate("(",-ConLoss1,")"));
   FileWrite(handle,"Maximal consecutive profit (count of wins)",
                     ConProfit2,
                     StringConcatenate("(",ConProfitTrades2,")"));
   FileWrite(handle,"Maximal consecutive loss (count of losses)",
                     -ConLoss2,
                     StringConcatenate("(",ConLossTrades2,")"));
//----
   FileClose(handle);
  }

    Ein Beispiel, wie ein Bericht zusammengefasst werden kann, ist unten angegeben.
void deinit()
  {
   if(!IsOptimization())
     {
      if(!IsTesting()) ExtInitialDeposit=CalculateInitialDeposit();
      CalculateSummary(ExtInitialDeposit);
      WriteReport("MACD_Sample_Report.txt");
     }
  }

    Sie können im Beispiel sehen, dass die Berichte nicht nur nach einem Test zusammengefasst werden können, sondern auch bei Deinitialisierung des live funktionierenden Expert Advisors generiert werden können. Sie fragen sich vielleicht, wie man die Anzahl des ersten Deposits erfahren kann, wenn die Handelshistory im Terminal nicht ganz, nur teilweise heruntergeladen wird. Die Funktion CalculateInitialDeposit ermöglicht, das Problem zu lösen.
double CalculateInitialDeposit()
  {
   double initial_deposit=AccountBalance();
//----
   for(int i=HistoryTotal()-1; i>=0; i--)
     {
      if(!OrderSelect(i,SELECT_BY_POS,MODE_HISTORY)) continue;
      int type=OrderType();
      //---- initial balance not considered
      if(i==0 && type==OP_BALANCE) break;
      if(type==OP_BUY || type==OP_SELL)
        {
         //---- calculate profit
         double profit=OrderProfit()+OrderCommission()+OrderSwap();
         //---- and decrease balance
         initial_deposit-=profit;
        }
      if(type==OP_BALANCE || type==OP_CREDIT)
         initial_deposit-=OrderProfit();
     }
//----
   return(initial_deposit);
  }

    Eben nach dieser Art werden die Berichte im MetaTrader 4 generiert.



  
    Man kann die Daten, die man selbständig erhalten hat, vergleichen.

Initial deposit             10000
Total net profit            -13.16
Gross profit                20363.32
Gross loss                  20376.48
Profit factor               0.99935416
Expected payoff             -0.01602923
Absolute drawdown           404.28
Maximal drawdown            1306.36 (11.5677%)
Relative drawdown           11.5966%    (1289.78)
Trades total                    821
Short positions(won %)      419 (24.821%)
Long positions(won %)       402 (31.592%)
Profit trades (% of total)  231 (28.1364%)
Loss trades (% of total)    590 (71.8636%)
Largest profit trade        678.08
Largest loss trade          -250
Average profit trade        88.15290043
Average loss trade          -34.53640678
Average consecutive wins    1
Average consecutive losses  4
Maximum consecutive wins (profit in money)  4   (355.58)
Maximum consecutive losses (loss in money)  15  (-314.74)
Maximal consecutive profit (count of wins)  679.4   (2)
Maximal consecutive loss (count of losses)  -617.16 (8)

    Im Anhang zum Artikel gibt es die Datei SummaryReport.mq4, die empfehlen wir im Verzeichnis experts\include hinzuzufügen und sie mit Hilfe vom Verzeichnis #include zu verbinden.
#include <SummaryReport.mq4>
 
double ExtInitialDeposit;

Übersetzt aus dem Russischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/ru/articles/1403

Beigefügte Dateien |
Genetische Algorithmen - Mathematik Genetische Algorithmen - Mathematik
Genetische Algorithmen sind für die Lösung der Optimierungsaufgaben vorgesehen. Als Beispiel für eine solche Aufgabe, können wir das Lernen in Neuronet nehmen, das heißt, es werden solche Gewichtswerte ausgewählt, die den minimalen Fehler zulassen. Im Grunde des genetischen Algorithmus liegt ein Zufallssuchverfahren.
Verwendung von Ressourcen in MQL5 Verwendung von Ressourcen in MQL5
MQL5 Programme automatisieren nicht nur Routineberechnungen, sondern können auch vollfunktionale graphische Umgebungen erzeugen. Die Funktionen zur Erzeugung wirklich interaktiver Kontrollen sind nun virtuell genauso vollwertig wie in in klassischen Programmiersprachen. Wenn Sie ein voll funktionsfähiges, eigenständiges Programm in MQL5 schreiben wollen, dann sollten Sie seine Ressourcen verwenden. Programme mit Ressourcen sind leichter zu pflegen und zu verbreiten.
Genetische Algorithmen in MetaTrader 4. Im Vergleich zur direkten Sortierung des Optimizers Genetische Algorithmen in MetaTrader 4. Im Vergleich zur direkten Sortierung des Optimizers
Im Artikel wurden die Schnelligkeit und Ergebnisse der Advisors-Optimierung mit den genetischen Algorithmen im Vergleich zur direkten Sortierung durchgeführt.
Die Grundlagen für Tests in MetaTrader 5 Die Grundlagen für Tests in MetaTrader 5
Worin unterscheiden sich die drei Testmethoden in MetaTrader 5, und worauf sollte man ganz besonders achten? Wir laufen Tests eines Expert Advisors, der gleichzeitig auf verschiedenen Finanzinstrumenten handelt, ab? Wann und wie werden Indikatorwerte während der Tests berechnet und wie werden die Ereignisse behandelt? Wie synchronisiert man Bars aus unterschiedlichen Instrumenten während der Tests im Mosud "nur offene Kurse"? Der vorliegende Artikel versucht all diese und weitere Fragen zu beantworten.