最適化の罠にはまらない方法?

Shashev Sergei | 16 2月, 2016


最適化のことを考えずにトレーディングシステムが作成できればすばらしいことです。
ですが、現実的には収益性あるトレーディング戦略を作成するのは
試行錯誤です。そこでは最適化のなんらかの形態がつねにある役割を果たします。
オプティマイザは常についてまわるもので、テーブルに表示されていなくても、陰に潜んでいるものです。

J. Katz, D. Mccormick. The Encyclopedia of trading Strategies.


トレーディングシステムの最適化とは?


まずトレーディングシステムの作成はロングまたはショートポジションをオープンそしてクローズするルールを形作ることです。通常こういったルールにはインディケータとパラメータが関与します。それらが変化すれば、トレーディングシステムの収益性も変わります。ひじょうに頻繁に出る質問があります。:トレーディングシステムを最適化する必要はあるのか?またこれは履歴データに対するシステムにちょうど適しているのか?

人が変われば『トレーディングシステムの最適化』手順は全く変わる、という事実におろらくもっとも結びついているでしょう。というわけで、まず最適化とは何か定義します。
まず、『最適化』から理解するのは、他のシステムよりもよりよくわれわれの問題を解決するであろうトレーディングシステムの選択または作成です。たとえば、現時点で円/ドルについてもっとも利益を出すようなシステムを探しているとします。このために、システムのある多様性から固定されたパラメータをいくつか持つシステムを選択します。たとえばこれは異なるインディケータを基にしたシステムの中からの選択かもしれません。これを『最適化タイプ1』と呼びましょう。

次に『最適化』から理解するのは、最良の結果を出すことのできる選ばれたトレーディングシステムに対するパラメータを見つけることです。これは平均を計算する期間や、ストキャスティック構造を計算する期間を選ぶことかもしれません。これを『最適化タイプ2』と呼びましょう。

トレーディング戦略を作成するトレードは、明示的にまたは暗黙的にどちらの最適化も使おうとする、ということに疑問を感じる人はいないと思います。実際、作業するトレーディングシステムを選択するや否や、もてる限り最高のトレーディングシステムを使うのだ、と思うものです。すなわち、最適化タイプ1です。ただし、どんなシステムもなにかパラメータを持つもので、最良の結果を取得するための方法でこういったパラメータを値を検索使用するのです。これは明らかに最適化タイプ2です。また、トレーディングシステムを作成するとき、これら2つの最適化タイプを分離することは可能です。これはトレーディングシステムを作成する際最適化を行うべきか否かという質問の答えが明確であるためです。:最適化は行わねばなりません。もう一つ別の問題はこれをどのように行うか、です。トレーディングシステムを作成するには複数の段階があります。
  • トレーディングシステムの基礎に何がくるか考え始める
  • ルールの基準や判断の選択
  • システムのパラメータ決定
  • システムの検証、そして
  • システムに変更が必要な場合は、前の項に戻る

最適化タイプ2の問題点

自動トレーディングシステムを作成する場合、開発者はすべて最適化タイプ1、2の両方を行います。基準と判断ルールの検索は、ニューラルネットワーク、遺伝的アルゴリズム、そしてもちろん人間の脳-現時点でもっとも強力なシステム、などヒューリスティックシステムに対するタスクです。これは最適化タイプ1で、この最適化に対する全責任はトレーダーにあります。

最適化タイプ2は最良のパラメータの検索です。問題がおこるのはこの部分です。というのも、データを履歴に一致させ、『莫大な利益』を得ることはひじょうにたやすいことだからです。残念ながら、これは履歴でしか役に立ちません。そのような『過最適化』は避けがたく、そのため一部のトレーダーはそれに対して否定的になります。なぜでしょうか?

理由はシンプルです。初心者は最大の利益を出すパラメータを見つけます。その際、インディケータのベストな期間の大幅な変動で利益が激しく落ち込む近隣エリアに注意を払っていないのです。これがトレーディングシステムの不安定性を招きます。そして彼らはデモアカウントでこのシステムを使い始めます。システムが処理不能だということを確認するために最低数か月そこで作業をする忍耐があれば、これはひじょうに良いことです。そうでなければ、神はみなさんに実アカウントでそのようなシステムを起動することをお許しになりません。デポジットにお別れを言って、屋外の無料作業に取り組んでください。

過最適化問題はどうすれば解決できるのか?

どうすればよいのでしょうか?誤って見つけたパラメータのおかげで最良のソリューションや潜在的利益を投げ出すわけにはいかないので、最適化を無視することはないでしょう。ただし、過最適化も深刻な問題につながります。私たちは、中庸を見つける必要があります。

それでは、数学的に最適化にアプローチしましょう。一般的に、最適化するパラメータがかなり多いと、利益が安定しており、パラメータが少し変更されたら多かれ少なかれ変動するような場所である超平面を探すものです。最適化では、それに対する利益が最大で、最適なソリューションからの有意な偏差が利益に激しい変化をもたらさないようなソリューションを見つけようとします。

問題は、利益は最大であるが、パラメータにおいて有意でない変化が損失を導くエリアである、極大値エリアに入ることです。そのため、そのようなパラメータはおそらく市場における些細な変化においてもデポジットの損失を招くことになるでしょう。そして Forex はそのような変化が頻繁に起こることで知られています。システムは極値をすべて避ける必要があります。

残念ながら、自分で最適なソリューションを検索するアルゴリズムはまだ MetaTrader には組み込まれていません。KRAB はそのような問題を解決するもっとも力強いアルゴリズムの一つです。それは N. Zagoruyko 著 "Applied Methods of Data and Knowledge Analysis" (数学研究所出版、ノボシビルスク、1999年(ロシア語))で説明されています。それが次のビルドで実現されればすばらしいことです。が、すべてが悪いわけではありません。

MetaTrader は最適化のパラメータ1つまたは2つに対して最適化グラフを作成することができるのです。これは、理論的には最適化結果を平面に予測することで最適なソリューションを見つけることができることを意味します。すなわち、2つのパラメータを2ずつ最適化すると、ベストなソリューションの領域を見つけることができるのです。

パラメータ3つに対しては、この手順を繰り返す必要があります。

回数

ただ、パラメータ5個に対しては、

などとなります。パラメータの数を過度に使わない方がよいものです。

2つのパラメータを最適化する場合、以下のような最適化グラフを取得します。

暗いエリアは大きな利益を伴うエリアです。この最適化グラフはひじょうに優れています。極大値がなく、グラフの右上角から利益が一様に減少しているからです。みなさんがご自身の最適化でこのような結果を見られればうれしいのですが。

下のグラフはそれほど明白ではありません。このグラフには最大値のあるエリアが表示されています。何を選択すべきか?


経験ある方は右下角のソリューション領域にお気づきでしょう。グラフのはじめに比べると、近隣の正方形のエリアが完全に小さな利益の下降を示しているからです。そこで、デポジットを守るために、注意深くグラフを分析することをお薦めします。

シンプルなExpert Advisor を調べます。3つのパラメータを分析し、最適なソリューション領域を見つけるのです。この EA の名前は SP です。これは買い過ぎ/売り過ぎマーケット分析モメンタムのエリアで動作します。

//+------------------------------------------------------------------+
//|                                                           SP.mq4 |
//|                      Copyright © 2006, MetaQuotes Software Corp. |
//|                                        https://www.metaquotes.net |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2006, MetaQuotes Software Corp."
#property link      "https://www.metaquotes.net"
 
//---- input parameters
extern int       TakeProfit=50;
extern int       StopLoss=30;
extern int       RsiLen=4;
extern int       KLen=8;
extern int       Momlength=10;
extern int       Lots=1;
extern int       rsi_oversold=39;
extern int       stoc_oversold=29;
extern int       rsi_overbought=60;
extern int       stoc_overbought=70;
extern int       Mom_Sell=-2;
extern int       Mom_Buy=2;
 
int expertBars;
double RSIlevel;
double Stoclevel;
double MomLevel;
double DLen=3;
 
//+------------------------------------------------------------------+
//| returns true if a new bar has come, otherwise returns false      |
//+------------------------------------------------------------------+
bool isNewBar()
  {
//----
   bool res=false; 
   if (expertBars!=Bars) 
      {
      expertBars=Bars;
      res=true;
      } 
//----
   return(res);
  }
//+------------------------------------------------------------------+
//| expert initialization function                                   |
//+------------------------------------------------------------------+
int init()
  {
//----
   
//----
   return(0);
  }
//+------------------------------------------------------------------+
//| expert deinitialization function                                 |
//+------------------------------------------------------------------+
int deinit()
  {
//----
   
//----
   return(0);
  }
//+------------------------------------------------------------------+
//| expert start function                                            |
//+------------------------------------------------------------------+
int start()
  {
  double price;
  double stop;
  double profit;
//----
   if ((isNewBar())&& (OrdersTotal()==0)&& (AccountBalance()>5000))
   {
      RSIlevel=iRSI(NULL,0,RsiLen,PRICE_CLOSE,0);
      Stoclevel=iStochastic(NULL,0,KLen,DLen,3,MODE_SMA,0,MODE_MAIN,0);
      MomLevel=100 - iMomentum(NULL,0,Momlength,PRICE_CLOSE,0);
      /*if (AccountBalance()>50000)
         {Lots=NormalizeDouble( AccountBalance()/10000,0)-4;}
      else 
         Lots=1;*/
      if ((RSIlevelrsi_oversold)&&(Stoclevelstoc_oversold)&&(MomLevel>Mom_Sell))
      {
         price=Ask;
         stop=NormalizeDouble(price-StopLoss*Point,Digits);
         profit=NormalizeDouble(price+TakeProfit*Point,Digits);
         OrderSend(Symbol(),OP_BUY,Lots,price,3,stop,profit,NULL,0,0,Green); 
         //Print(AccountBalance());          
      }
      if ((RSIlevel>rsi_overbought)&&(Stoclevel>stoc_overbought)&&(MomLevelMom_Buy))
      {
         price=Bid;
         stop=NormalizeDouble(price+StopLoss*Point,Digits);
         profit=NormalizeDouble(price-TakeProfit*Point,Digits);
         OrderSend(Symbol(),OP_SELL,Lots,price,3,stop,profit,NULL,0,0,Green); 
         //Print(AccountBalance());            
      }      
   } 
    
//----
   return(0);
  }
//+------------------------------------------------------------------+

最適化するパラメータは、ストキャスティック、RSI 期間、ストップロスレベルです。

それらを最適化したあと、3つのグラフを取得します。


ストキャスティックおよび RSI 期間からの利益の依存性


RSI 期間およびストップロスからの利益の依存性


ストキャスティックおよびストップロスからの利益の依存性

ベスト領域は以下です。

  • グラフ 1 – (4;5)&(3;6);
  • グラフ 2 – (80;90)&(3;6);
  • グラフ 3 – (80;90)&(4;5).

それらを融合すると、ベストなソリューションを得ます- (5,4,80)。

ストップロスは最適化では10 ステップと大きいものであることに注意が必要です。必要に応じ、取得したソリューションは小さなステップでも分析することが可能です。

おわりに

セルの緑色の彩度で領域がどれほど収益性のあるものか判断できるのはもちろんひじょうに良いことです。ただし、損失を出している領域がそれにつれて赤で色づけられたらさらに良いでしょう。これはまったく異なるレベルで戦略を推測するのに役立ちます。実際には、最適化のフル 3D 画像を取得します。

最後なりましたが、最適化についていくつか推奨事項があります。

  • 最適化用のデータサンプルは代表的なものであること日次タイムフレームに対しては3年を超えていること
  • 最適化サンプル以外でも戦略を検証すること。これで選択したパラメータを推定することができます。
  • 同時に最適化するパラメータは多すぎないこと。履歴との一致可能性が高くなりすぎます。
  • 最適化時間を減らすため、ステップを増やすこと。ベスト領域を軽視しないこと。取得したクラスターはのちに詳しく分析することが可能です(ふるい分け技術)。
  • 最適化に時間をかけないでください。Expert Advisor のアルゴリズムを最新化するほうが得策です。
本稿が『有害な最適化』を避けるのに役立つことを願っています。