返回《給 CFD 交易者的 MetaTrader 5 與 MQL5》
第三部分

讀一份回測而不自欺

獲利因子、最大回撤、期望報酬、交易筆數——以及如何看出一個曲線配適。

中級閱讀時間約 11 分鐘初學 → 進階第 12 / 17 堂
在 MetaEditor 實際跑一次
印出測試器自己的統計數字

存成 MQL5/Scripts/Lesson12TesterStats.mq5。在策略測試器裡執行(不是掛在即時圖表上),它會吐出報告的關鍵數字。

//+------------------------------------------------------------------+
//| Lesson 12 - Dump Strategy Tester statistics                      |
//| Run this FROM INSIDE the Strategy Tester, not on a live chart.   |
//+------------------------------------------------------------------+
#property copyright "Strategist Academy"
#property version   "1.00"

void OnStart()
{
   if(!MQLInfoInteger(MQL_TESTER))
   {
      Print("This script only reports inside the Strategy Tester. ");
      Print("Open the tester, pick this script, and run it.");
      return;
   }

   Print("========== Strategy Tester report ==========");
   Print("Initial deposit:   ", DoubleToString(TesterStatistics(STAT_INITIAL_DEPOSIT), 2));
   Print("Net profit:        ", DoubleToString(TesterStatistics(STAT_PROFIT), 2));
   Print("Gross profit:      ", DoubleToString(TesterStatistics(STAT_GROSS_PROFIT), 2));
   Print("Gross loss:        ", DoubleToString(TesterStatistics(STAT_GROSS_LOSS), 2));
   Print("Profit factor:     ", DoubleToString(TesterStatistics(STAT_PROFIT_FACTOR), 3));
   Print("Expected payoff:   ", DoubleToString(TesterStatistics(STAT_EXPECTED_PAYOFF), 2));
   Print("Recovery factor:   ", DoubleToString(TesterStatistics(STAT_RECOVERY_FACTOR), 3));
   Print("Sharpe ratio:      ", DoubleToString(TesterStatistics(STAT_SHARPE_RATIO), 3));
   Print("");
   Print("Max drawdown:      ", DoubleToString(TesterStatistics(STAT_EQUITY_DD), 2),
                              "  (", DoubleToString(TesterStatistics(STAT_EQUITY_DDREL_PERCENT), 2), "%)");
   Print("");
   Print("Total trades:      ", (int)TesterStatistics(STAT_TRADES));
   Print("Win rate:          ", DoubleToString(TesterStatistics(STAT_PROFIT_TRADES) /
                                  MathMax(1.0, TesterStatistics(STAT_TRADES)) * 100.0, 1), "%");
   Print("Largest win:       ", DoubleToString(TesterStatistics(STAT_LARGEST_PROFIT_TRADE), 2));
   Print("Largest loss:      ", DoubleToString(TesterStatistics(STAT_LARGEST_LOSS_TRADE), 2));
   Print("Average bars held: ", DoubleToString(TesterStatistics(STAT_BARS_HOLD_TOTAL) /
                                  MathMax(1.0, TesterStatistics(STAT_TRADES)), 1));
   Print("===========================================");
   Print("Sanity checks:");
   Print(" - Fewer than ~100 trades? Treat every figure above as noise.");
   Print(" - Profit factor under 1.2? Costs will likely erase it live.");
   Print(" - Equity curve too smooth? Suspect a curve-fit.");
}
如何執行
  1. 1. 從 MT5 開啟 MetaEditor(按 F4), 選擇這支程式該放的資料夾——Experts、Indicators 或 Scripts。
  2. 2. 開新檔案、把這段程式貼上去,然後按 F7 編譯。Errors 分頁顯示的錯誤 都修掉。
  3. 3. 回到 MT5,把它拖到圖表上——如果是 EA,就打開 Strategy Tester。

先選對建模模式

策略測試器提供數種模式。Every tick based on real ticks(以真實 tick 逐筆計算)是日內 CFD 系統唯一值得信任的模式;較快的那些模式會做內插,並會美化任何倚賴停損位置的系統。如果你的券商不提供真實 tick,就把結果當成指示性就好。

重要的數字

  • 期望報酬(expected payoff)——扣除成本後每筆交易的平均金額。如果它沒有明確為正,其他什麼都救不了你。
  • 獲利因子(profit factor)——毛利除以毛損。搭配像樣的樣本數時,約 1.5 以上開始有意思;低於 1.2 是噪音區。
  • 最大回撤與相對回撤——你必須撐過去的痛苦。拿它跟你的帳戶比,不是跟獲利比。
  • 回復因子(recovery factor)——淨利除以最大回撤。獎勵那些不必挖深坑就能賺錢的系統。
  • 交易筆數——初學者最會跳過的那一個。五十筆幾乎什麼都沒告訴你;幾百筆才開始有意義。

一個曲線配適長什麼樣

一個曲線配適有平滑的權益曲線、高得可疑的獲利因子,以及一組坐在尖銳尖峰上的參數:把週期挪一格,結果就崩塌。真實效果坐落在一片高原上——相鄰的參數值也有效,只是稍微差一點。

永遠做 walk-forward

把你的歷史切開。在第一段上最佳化,在最佳化器從沒看過的那一段上測試。然後把窗口往前移,重複。一個只在它被調校的那段窗口上表現良好的系統不是一個系統;它是一段記憶。

成本不是選項

對 CFD 來說,手續費、隔夜利息與滑價都不是四捨五入的誤差。一個每筆賺 40 點的系統,在抱一週的部位上扣掉隔夜利息之後可能是虧錢的。在測試器裡輸入真實的成本然後重查:如果優勢消失了,它從來就不是優勢。

這堂課的腳本

在策略測試器裡執行它,它會把報告的關鍵數字直接印進 journal——就是你在 Results 分頁裡應該要看的那幾個數字。

你剛完成了什麼

《給 CFD 交易者的 MetaTrader 5 與 MQL5》的第 12 / 17 堂課。跑完範例或讀完這段之後, 把它勾起來,然後進下一堂課。