返回《給 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), 選擇這支程式該放的資料夾——ExpertsIndicators 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 堂課。跑完範例或讀完這段之後, 把它勾起來,然後進下一堂課。