【MQL4学习】如何评估智能交易测试结果

0
回复
7777
查看
[复制链接]

41

主题

32

回帖

248

积分

中级会员

积分
248
来源: 2019-10-14 23:08:58 显示全部楼层 |阅读模式
首先,我们来谈谈测试程序。在测试开始之前,测试的子系统加载智能交易,设定用户指定的先前参量并且调用init()函数。随后通过生成次序测试开始,并且每次都会调用 start()函数。当测试的次序耗尽,会调用 deinit()函数。这样,整个交易历史在测试期间产生测试数据。在此时这个智能交易的效率可以进行分析。

CalculateSummary函数提供以下测试结果计算,即,在策略测试的标准报告中给出数据。


  1. void CalculateSummary(double initial_deposit)
  2.   {
  3.    int    sequence=0, profitseqs=0, lossseqs=0;
  4.    double sequential=0.0, prevprofit=EMPTY_VALUE, drawdownpercent, drawdown;
  5.    double maxpeak=initial_deposit, minpeak=initial_deposit, balance=initial_deposit;
  6.    int    trades_total=HistoryTotal();
  7. //---- 初始化总结
  8.    InitializeSummaries(initial_deposit);
  9. //----
  10.    for(int i=0; i<trades_total; i++)
  11.      {
  12.       if(!OrderSelect(i,SELECT_BY_POS,MODE_HISTORY)) continue;
  13.       int type=OrderType();
  14.       //---- 不考虑初始差额
  15.       if(i==0 && type==OP_BALANCE) continue;
  16.       //---- 计算赢利
  17.       double profit=OrderProfit()+OrderCommission()+OrderSwap();
  18.       balance+=profit;
  19.       //---- 检测借款
  20.       if(maxpeak<balance)
  21.         {
  22.          drawdown=maxpeak-minpeak;
  23.          if(maxpeak!=0.0)
  24.            {
  25.             drawdownpercent=drawdown/maxpeak*100.0;
  26.             if(RelDrawdownPercent<drawdownpercent)
  27.               {
  28.                RelDrawdownPercent=drawdownpercent;
  29.                RelDrawdown=drawdown;
  30.               }
  31.            }
  32.          if(MaxDrawdown<drawdown)
  33.            {
  34.             MaxDrawdown=drawdown;
  35.             if(maxpeak!=0.0) MaxDrawdownPercent=MaxDrawdown/maxpeak*100.0;
  36.             else MaxDrawdownPercent=100.0;
  37.            }
  38.          maxpeak=balance;
  39.          minpeak=balance;
  40.         }
  41.       if(minpeak>balance) minpeak=balance;
  42.       if(MaxLoss>balance) MaxLoss=balance;
  43.       //---- 仅限市场定单
  44.       if(type!=OP_BUY && type!=OP_SELL) continue;
  45.       SummaryProfit+=profit;
  46.       SummaryTrades++;
  47.       if(type==OP_BUY) LongTrades++;
  48.       else             ShortTrades++;
  49.       //---- 亏损交易
  50.       if(profit<0)
  51.         {
  52.          LossTrades++;
  53.          GrossLoss+=profit;
  54.          if(MinProfit>profit) MinProfit=profit;
  55.          //---- fortune changed
  56.          if(prevprofit!=EMPTY_VALUE && prevprofit>=0)
  57.            {
  58.             if(ConProfitTrades1<sequence ||
  59.                (ConProfitTrades1==sequence && ConProfit2<sequential))
  60.               {
  61.                ConProfitTrades1=sequence;
  62.                ConProfit1=sequential;
  63.               }
  64.             if(ConProfit2<sequential ||
  65.                (ConProfit2==sequential && ConProfitTrades1<sequence))
  66.               {
  67.                ConProfit2=sequential;
  68.                ConProfitTrades2=sequence;
  69.               }
  70.             profitseqs++;
  71.             AvgConWinners+=sequence;
  72.             sequence=0;
  73.             sequential=0.0;
  74.            }
  75.         }
  76.       //---- 赢利交易(profit>=0)
  77.       else
  78.         {
  79.          ProfitTrades++;
  80.          if(type==OP_BUY)  WinLongTrades++;
  81.          if(type==OP_SELL) WinShortTrades++;
  82.          GrossProfit+=profit;
  83.          if(MaxProfit<profit) MaxProfit=profit;
  84.          //---- fortune changed
  85.          if(prevprofit!=EMPTY_VALUE && prevprofit<0)
  86.            {
  87.             if(ConLossTrades1<sequence ||
  88.                (ConLossTrades1==sequence && ConLoss2>sequential))
  89.               {
  90.                ConLossTrades1=sequence;
  91.                ConLoss1=sequential;
  92.               }
  93.             if(ConLoss2>sequential ||
  94.                (ConLoss2==sequential && ConLossTrades1<sequence))
  95.               {
  96.                ConLoss2=sequential;
  97.                ConLossTrades2=sequence;
  98.               }
  99.             lossseqs++;
  100.             AvgConLosers+=sequence;
  101.             sequence=0;
  102.             sequential=0.0;
  103.            }
  104.         }
  105.       sequence++;
  106.       sequential+=profit;
  107.       //----
  108.       prevprofit=profit;
  109.      }
  110. //---- 最终借款检验
  111.    drawdown=maxpeak-minpeak;
  112.    if(maxpeak!=0.0)
  113.      {
  114.       drawdownpercent=drawdown/maxpeak*100.0;
  115.       if(RelDrawdownPercent<drawdownpercent)
  116.         {
  117.          RelDrawdownPercent=drawdownpercent;
  118.          RelDrawdown=drawdown;
  119.         }
  120.      }
  121.    if(MaxDrawdown<drawdown)
  122.      {
  123.       MaxDrawdown=drawdown;
  124.       if(maxpeak!=0) MaxDrawdownPercent=MaxDrawdown/maxpeak*100.0;
  125.       else MaxDrawdownPercent=100.0;
  126.      }
  127. //---- 考虑最后交易
  128.    if(prevprofit!=EMPTY_VALUE)
  129.      {
  130.       profit=prevprofit;
  131.       if(profit<0)
  132.         {
  133.          if(ConLossTrades1<sequence ||
  134.             (ConLossTrades1==sequence && ConLoss2>sequential))
  135.            {
  136.             ConLossTrades1=sequence;
  137.             ConLoss1=sequential;
  138.            }
  139.          if(ConLoss2>sequential ||
  140.             (ConLoss2==sequential && ConLossTrades1<sequence))
  141.            {
  142.             ConLoss2=sequential;
  143.             ConLossTrades2=sequence;
  144.            }
  145.          lossseqs++;
  146.          AvgConLosers+=sequence;
  147.         }
  148.       else
  149.         {
  150.          if(ConProfitTrades1<sequence ||
  151.             (ConProfitTrades1==sequence && ConProfit2<sequential))
  152.            {
  153.             ConProfitTrades1=sequence;
  154.             ConProfit1=sequential;
  155.            }
  156.          if(ConProfit2<sequential ||
  157.             (ConProfit2==sequential && ConProfitTrades1<sequence))
  158.            {
  159.             ConProfit2=sequential;
  160.             ConProfitTrades2=sequence;
  161.            }
  162.          profitseqs++;
  163.          AvgConWinners+=sequence;
  164.         }
  165.      }
  166. //---- 收集完毕
  167.    double dnum, profitkoef=0.0, losskoef=0.0, avgprofit=0.0, avgloss=0.0;
  168. //---- 连续盈利和亏损的平均数
  169.    dnum=AvgConWinners;
  170.    if(profitseqs>0) AvgConWinners=dnum/profitseqs+0.5;
  171.    dnum=AvgConLosers;
  172.    if(lossseqs>0)   AvgConLosers=dnum/lossseqs+0.5;
  173. //---- 绝对值
  174.    if(GrossLoss<0.0) GrossLoss*=-1.0;
  175.    if(MinProfit<0.0) MinProfit*=-1.0;
  176.    if(ConLoss1<0.0)  ConLoss1*=-1.0;
  177.    if(ConLoss2<0.0)  ConLoss2*=-1.0;
  178. //---- 赢利原因
  179.    if(GrossLoss>0.0) ProfitFactor=GrossProfit/GrossLoss;
  180. //----期待盈利
  181.    if(ProfitTrades>0) avgprofit=GrossProfit/ProfitTrades;
  182.    if(LossTrades>0)   avgloss  =GrossLoss/LossTrades;
  183.    if(SummaryTrades>0)
  184.      {
  185.       profitkoef=1.0*ProfitTrades/SummaryTrades;
  186.       losskoef=1.0*LossTrades/SummaryTrades;
  187.       ExpectedPayoff=profitkoef*avgprofit-losskoef*avgloss;
  188.      }
  189. //---- 绝对借款
  190.    AbsoluteDrawdown=initial_deposit-MaxLoss;
  191.   }
复制代码

计算正确,机会得知初始化存款额的值 。这样,在init() 函数中AccountBalance()函数必须被调用,在测试开始时将给出差额。


  1. void init()
  2.   {
  3.    ExtInitialDeposit=AccountBalance();
  4.   }
复制代码

在上面的CalculateSummary 函数中, 与标准的报告一样,盈利在当前的存款额中计算。其他交易结果,像"最大盈利交易" 或 "最大连续亏损"在赢利基础上计算,同样要测量金钱数。随后重新以点数计算赢利。
  1. ...
  2.       //---- 仅限市场定单
  3.       if(type!=OP_BUY && type!=OP_SELL) continue;
  4.       //---- 以点数计算赢利
  5.       profit=(OrderClosePrice()-OrderOpenPrice())/MarketInfo(OrderSymbol(),MODE_POINT);
  6.       SummaryProfit+=profit;
  7. ...
复制代码

使用函数将得到结果写入报告文件中。


  1. void WriteReport(string report_name)
  2.   {
  3.    int handle=FileOpen(report_name,FILE_CSV|FILE_WRITE,'\t');
  4.    if(handle<1) return;
  5. //----
  6.    FileWrite(handle,"Initial deposit           ",InitialDeposit);
  7.    FileWrite(handle,"Total net profit          ",SummaryProfit);
  8.    FileWrite(handle,"Gross profit              ",GrossProfit);
  9.    FileWrite(handle,"Gross loss                ",GrossLoss);
  10.    if(GrossLoss>0.0)
  11.       FileWrite(handle,"Profit factor             ",ProfitFactor);
  12.    FileWrite(handle,"Expected payoff           ",ExpectedPayoff);
  13.    FileWrite(handle,"Absolute drawdown         ",AbsoluteDrawdown);
  14.    FileWrite(handle,"Maximal drawdown          ",
  15.                      MaxDrawdown,
  16.                      StringConcatenate("(",MaxDrawdownPercent,"%)"));
  17.    FileWrite(handle,"Relative drawdown         ",
  18.                      StringConcatenate(RelDrawdownPercent,"%"),
  19.                      StringConcatenate("(",RelDrawdown,")"));
  20.    FileWrite(handle,"Trades total                 ",SummaryTrades);
  21.    if(ShortTrades>0)
  22.       FileWrite(handle,"Short positions(won %)    ",
  23.                         ShortTrades,
  24.                         StringConcatenate("(",100.0*WinShortTrades/ShortTrades,"%)"));
  25.    if(LongTrades>0)
  26.       FileWrite(handle,"Long positions(won %)     ",
  27.                         LongTrades,
  28.                         StringConcatenate("(",100.0*WinLongTrades/LongTrades,"%)"));
  29.    if(ProfitTrades>0)
  30.       FileWrite(handle,"Profit trades (% of total)",
  31.                         ProfitTrades,
  32.                         StringConcatenate("(",100.0*ProfitTrades/SummaryTrades,"%)"));
  33.    if(LossTrades>0)
  34.       FileWrite(handle,"Loss trades (% of total)  ",
  35.                         LossTrades,
  36.                         StringConcatenate("(",100.0*LossTrades/SummaryTrades,"%)"));
  37.    FileWrite(handle,"Largest profit trade      ",MaxProfit);
  38.    FileWrite(handle,"Largest loss trade        ",-MinProfit);
  39.    if(ProfitTrades>0)
  40.       FileWrite(handle,"Average profit trade      ",GrossProfit/ProfitTrades);
  41.    if(LossTrades>0)
  42.       FileWrite(handle,"Average loss trade        ",-GrossLoss/LossTrades);
  43.    FileWrite(handle,"Average consecutive wins  ",AvgConWinners);
  44.    FileWrite(handle,"Average consecutive losses",AvgConLosers);
  45.    FileWrite(handle,"Maximum consecutive wins (profit in money)",
  46.                      ConProfitTrades1,
  47.                      StringConcatenate("(",ConProfit1,")"));
  48.    FileWrite(handle,"Maximum consecutive losses (loss in money)",
  49.                      ConLossTrades1,
  50.                      StringConcatenate("(",-ConLoss1,")"));
  51.    FileWrite(handle,"Maximal consecutive profit (count of wins)",
  52.                      ConProfit2,
  53.                      StringConcatenate("(",ConProfitTrades2,")"));
  54.    FileWrite(handle,"Maximal consecutive loss (count of losses)",
  55.                      -ConLoss2,
  56.                      StringConcatenate("(",ConLossTrades2,")"));
  57. //----
  58.    FileClose(handle);
  59.   }
复制代码



以下给出范例,如何使用这些函数生成报告。


  1. void deinit()
  2.   {
  3.    if(!IsOptimization())
  4.      {
  5.       if(!IsTesting()) ExtInitialDeposit=CalculateInitialDeposit();
  6.       CalculateSummary(ExtInitialDeposit);
  7.       WriteReport("MACD_Sample_Report.txt");
  8.      }
  9.   }
复制代码


在上边的范例中,您能够看到报告结果不仅是在测试结束后生成, 智能交易的运作中。您也许会问如果在终端内账户历史没有全部下载(例如,在账户栏中仅下载一个月的账户历史),怎样获取初始存款额的大小呢。 CalculateInitialDeposit 函数将会帮助解决这个问题。


  1. double CalculateInitialDeposit()
  2.   {
  3.    double initial_deposit=AccountBalance();
  4. //----
  5.    for(int i=HistoryTotal()-1; i>=0; i--)
  6.      {
  7.       if(!OrderSelect(i,SELECT_BY_POS,MODE_HISTORY)) continue;
  8.       int type=OrderType();
  9.       //---- 不考虑初始化差额
  10.       if(i==0 && type==OP_BALANCE) break;
  11.       if(type==OP_BUY || type==OP_SELL)
  12.         {
  13.          //---- 计算赢利
  14.          double profit=OrderProfit()+OrderCommission()+OrderSwap();
  15.          //---- 并减少差额
  16.          initial_deposit-=profit;
  17.         }
  18.       if(type==OP_BALANCE || type==OP_CREDIT)
  19.          initial_deposit-=OrderProfit();
  20.      }
  21. //----
  22.    return(initial_deposit);
  23.   }
复制代码
在MetaTrader 4 客户端内测试报告会以这种形式生成。

report.png

可以比较使用于独立程序的计算数据。


  1. Initial deposit             10000
  2. Total net profit            -13.16
  3. Gross profit                20363.32
  4. Gross loss                  20376.48
  5. Profit factor               0.99935416
  6. Expected payoff             -0.01602923
  7. Absolute drawdown           404.28
  8. Maximal drawdown            1306.36 (11.5677%)
  9. Relative drawdown           11.5966%    (1289.78)
  10. Trades total                    821
  11. Short positions(won %)      419 (24.821%)
  12. Long positions(won %)       402 (31.592%)
  13. Profit trades (% of total)  231 (28.1364%)
  14. Loss trades (% of total)    590 (71.8636%)
  15. Largest profit trade        678.08
  16. Largest loss trade          -250
  17. Average profit trade        88.15290043
  18. Average loss trade          -34.53640678
  19. Average consecutive wins    1
  20. Average consecutive losses  4
  21. Maximum consecutive wins (profit in money)  4   (355.58)
  22. Maximum consecutive losses (loss in money)  15  (-314.74)
  23. Maximal consecutive profit (count of wins)  679.4   (2)
  24. Maximal consecutive loss (count of losses)  -617.16 (8)
复制代码

该文章的附加文件SummaryReport.mq4 建议保存在目录experts\include 中并且使用 #include 开启。


  1. #include <SummaryReport.mq4>

  2. double ExtInitialDeposit;
复制代码





回复

使用道具 举报

您需要登录后才可以回帖 登录 | 免费注册
关注微信