English Русский 中文 Español Deutsch Português
利益のある取引戦略を見つける方法

利益のある取引戦略を見つける方法

MetaTrader 4トレーディングシステム | 6 10月 2015, 09:04
3 824 0
Yury Reshetov
Yury Reshetov

概論


テクニカル分析を適用して、成功した取引戦略を見つけるプロセスは、いくつかの段階に分けることができます。
  1. 金融商品の価格チャートウィンドウにいくつかのテクニカル指標を追加して、市場の相関関係や指標シグナルとしての規則性を調べます。
  2. 前の段階で得られたデータをまとめます。
  3. 機械的な取引システムを得たら、適切なプログラミング言語へ戦略を変換します。
  4. 履歴データに基づいて、取引システムをシュミレーターを通して実行し、その入力パラメータの収集を試みる、つまり最適化します。
  5. 前の段階で利益がなかった場合、項目「1」へ進みます。
  6. 前の段階で得られたシステムを、チェックをする目的でデモアカウントで実行します。
  7. 前の段階で利益がなかった場合、項目「1」へ進みます。。
  8. 実際の取引でシステムを使用し、時折、市場の変化に合わせて入力パラメータを調整します。
基本的にはこれで以上です。このようにして得られたシステムは、自動売買用だけでなく、テクニカルインディケータによって与えられる、最も重要なシグナル教えてくれる手動取引の為のエキスパートアドバイザとして使用することができます。
      
この全てのプロセスを丸ごとコンピュータにシフトしてみるとしたらどうでしょうか?

この記事は、ACオシレーターによる価格変動予測のための簡単なニューラルネットワークの使用について説明しています。
      

ニューラルネットワーク


パーセプトロン、またはニューラルネットワークとは何でしょうか?これは、線形不等式(線形フィルター)の方程式を使うアルゴリズムで、これを使うことで特定のクラスへ検査するオブジェクトを加算したり、反対にオブジェクトのクラスそのものから、それを除外することができます。不等式は以下のようになります。
      
      w1 * a1 + w2 * a2 + ... wn * an > d,
      
各値は、以下のようになります。
      
      wi - インデックスiを持つ重み係数

      ai - 分析するオブジェクトのインデックスiを持つ記号の数値

      d - 閾値、多くの場合0と等しい。

      
不等式の左側は閾値を超える場合、オブジェクトは特定のクラスに属し、もし閾値を超えない場合は、属していないことになります。このようにオブジェクトを2つのクラスに分ける場合、単層ニューラルネットワークで十分です。
      
多くの人は使用するニューラルネットワークでの不等式は、シャーマンの呪文と似ているように思うかもしれません。実際はそうではありません。ニューラルネットワークの動作原理は、幾何学的な意味を持っています。

実は、幾何学的平面は線形方程式で書かれます。例えば、3次元空間において平面方程式は、X、Y、Zの座標に関係しています。
      
A * X + B * Y + C * Z + D = 0

この空間において平面から一方方向に位置する全ての座標は、不等式を満たします。
      
A * X + B * Y + C * Z + D > 0


反対方向にある全ての点の座標は、不等式を満たします。
      
A * X + B * Y + C * Z + D < 0

このようにして、もし特定の平面の方程式と全ての点の座標がわかっている場合、私達はこの平面に区切られる空間内の全ての点の多くを2つに分けることができます。
      
したがって、ニューラルネットワークの不等式での重み係数は、オブジェクトの兆候の多次元空間における特定の平面方程式を与える定数です。不等式を使うことで、私たちはこれらのオブジェクトが、指定された平面のどの一方にあるかを正確に判別することができます。オブジェクトの正確な座標を見つけ、それを平面の方程式に代入し、これをゼロと比較するだけで十分です。


問題提起


もし私達がオブジェクトを、開いているロングポジションとショートポジションの2つのクラスに分類し、指標としてインディケータまたは、テクニカル分析オシレーターの値を用いるとしたら、残るは平面の方程式を見つけ、それを使って識別を行うだけです。問題の提起は明確になりました。
      
しかし、ニューラルネットワークには独特な問題が一つあります。例えば、XとYの座標で記される二次元空間を例として見てみましょう。この空間に正確な座標を持つオブジェクトを配置します。
      
     
            
上図では、赤い点の集合体が青い点の集合体と交わらない場合、2つの集合体は線を使って分けることができます。(2次元空間ではセパレーターは線ですが、3次元やそれ以上の空間では、平面になります)またこれらのセパレーターの線の式は、様々なものになることがあります。もう一つ例を見てみましょう。
      
     
      
ここでは、点の集合体は空間で交差し、これらの間に明確な境界線を引くことは不可能です。ここでの唯一、そして可能な解決策は、赤のオブジェクトの多くを一方に、青いオブジェクトの多くを他方にと分ける、2つの点の集合体を分ける線です。今回は最適化、つまり平面や線によってオブジェクトを2つのクラスに分ける方程式を探すことが課題ですが、1つのクラスに属する一部の点は、誤って他のクラスに属することがあります。
      
非線形フィルターや多層ネットワークといった、その他のニューロネットワークの実行方法があります。非線形フィルターによって、異なるクラスのオブジェクトの間の境界線として、高次面を使用することができます。多層ネットワークは、3次以上のクラスに属するオブジェクトの識別のための幾つかのフィルター(平面または表面で分割する)を使用するようなものではありません。
      
ここで、私達が解決しようとしている課題の定義を明確にしてみましょう。まず、利益のある取引の為に、トレーダーが知るべきことは、相場変動の傾向です。つまり、もし相場が上に動いているなら、ロングポジションを持つ必要があります。もし下に動いているなら、ショートポジションを持つ必要があります。そして、相場変動の傾向という、オブジェクトの2つのクラスを私達は持っています。テクニカル分析をしながら、トレーダーはテクニカルインディケータ、またはオシレーターと呼ばれる分析を、判断を下すために用います。私達はACオシレーターも分析していきます。
      
テクニカルオシレーターは、水平線からの傾きの数値のヒストグラムなので、線形フィルターを持つニューラルネットワークが必要です。オブジェクトの指標としてパターンを用います。つまり、現在の時点から始まる、履歴の7期間の段階から取られた4つの点のオシレーター値です。     

           
上図ではオシレーターの値はマルで囲まれています。それらをa1、a2、a3、a4として、分割平面の方程式に入れ、どちらの側からパターンがでるかを知るために、得られた数値をゼロと比較します。
      
残るは、上への価格変動を先行するパターンを、下への価格変動を先行するパターンから分けるための平面の方程式自体を取得するだけです。
      
この目的の為に、MetaTrader4の取引ターミナルに内蔵された、最適化プロセスを短縮する為の遺伝的アルゴリズムを使用します。簡単に言うと、履歴データにおける戦略の最適化による、残高の最大値の分割線の方程式を結果で得る為に、線形フィルターの重み係数値を選び出します。
      
この目的で少なくとも、アルゴリズムを実行し、MetaTrader4のEAのコードにアルゴリズムを移す、取引戦略の公式化が必要になります。
      
理論的に取引システムは、市場へのエントリーとイグジットの為のシグナルを予測しなければいけません。ただし、シグナルによるイグジットは、絶対に必要なものではないので、以下の条件で除外することができます。
  1. ストップオーダーの配置ーテイクプロフィットとストップロス。
  2. 市場の傾向の変化についてのシグナル受信時に反対方向でポジションが展開する。
取引システムの複雑化を避ける為に、ストップロスやシグナルの反転によるイグジットを使用します。この場合、ニューラルネットワークは、オブジェクトサインの値に基づいたイグジットで2つのシグナルを出します。       
  • 相場は上昇方向へ動く可能性が高い。
  • 相場は下降方向へ動く可能性が高い。
このようにして、ニューラルネットワークの為のオブジェクト識別の課題は、これらを2つのクラスに分けることで簡単になります。オーダーコントロールからテイクプロフィットを除外すること、つまり、テイクプロフィットを入力パラメータの選択から外すことで、取引システムの最適化も単純化することができます。この場合、トレーリングストップを使用すれば十分です。つまり、ニューラルネットワークが反対のシグナルを出す、または誤作動を起こさないうちは、徐々に利益のある方向へストップロスによって引っ張られます。ニューラルネットワークのあらゆるエラーは、テイクプロフィット作動につながります。この際、注文管理システムは複雑化していきます。反対方向でのポジションの速い反転は、2倍のロット数と反対のポジションを閉じる反対注文を通して実行したほうが良いです。この方法により、ニューラルネットワークからシグナルを受けとったらすぐに、全ての反転操作を実行することができます。

ニューラルネットワークからの誤作動数を減らすために、これらの計算と決定は、作成されたバーやこれらのバーの始値に基づいて行います。


問題解決


この取引戦略を実行するエキスパートアドバイザのソースコードは、以下のようになります。

//+------------------------------------------------------------------+
//|                                       ArtificialIntelligence.mq4 |
//|                               Copyright й 2006, Yury V. Reshetov |
//|                                         http://reshetov.xnet.uz/ |
//+------------------------------------------------------------------+
#property copyright "Copyright й 2006, Yury V. Reshetov ICQ:282715499  http://reshetov.xnet.uz/"
#property link      "http://reshetov.xnet.uz/"
//---- input parameters
extern int    x1 = 120;
extern int    x2 = 172;
extern int    x3 = 39;
extern int    x4 = 172;
// StopLoss level
extern double sl = 50;
extern double lots = 0.1;
extern int    MagicNumber = 888;
static int prevtime = 0;
static int spread = 3;
//+------------------------------------------------------------------+
//| expert initialization function                                   |
//+------------------------------------------------------------------+
int init()
  {
//----
   return(0);
  }
//+------------------------------------------------------------------+
//| expert deinitialization function                                 |
//+------------------------------------------------------------------+
int deinit()
  {
//----
   return(0);
  }
//+------------------------------------------------------------------+
//| expert start function                                            |
//+------------------------------------------------------------------+
int start()
  {
   if(Time[0] == prevtime) 
       return(0);
   prevtime = Time[0];
//----
   if(IsTradeAllowed()) 
     {
       spread = MarketInfo(Symbol(), MODE_SPREAD);
     } 
   else 
     {
       prevtime = Time[1];
       return(0);
     }
   int ticket = -1;
   // check for opened position
   int total = OrdersTotal();   
   for(int i = 0; i < total; i++) 
     {
       OrderSelect(i, SELECT_BY_POS, MODE_TRADES); 
       // check for symbol & magic number
       if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber) 
         {
           int prevticket = OrderTicket();
           // long position is opened
           if(OrderType() == OP_BUY) 
             {
               // check profit 
               if(Bid > (OrderStopLoss() + (sl * 2  + spread) * Point)) 
                 {               
                   if(perceptron() < 0) 
                     { 
                       // reverse
                       ticket = OrderSend(Symbol(), OP_SELL, lots * 2, Bid, 3, 
                                          Ask + sl * Point, 0, "AI", MagicNumber, 
                                          0, Red); 
                       Sleep(30000);
                       if(ticket < 0) 
                         {
                           prevtime = Time[1];
                         } 
                       else 
                         {
                           OrderCloseBy(ticket, prevticket, Blue);   
                         }
                     } 
                   else 
                     { 
                       // trailing stop
                       if(!OrderModify(OrderTicket(), OrderOpenPrice(), 
                          Bid - sl * Point, 0, 0, Blue)) 
                         {
                           Sleep(30000);
                           prevtime = Time[1];
                         }
                     }
                 }  
               // short position is opened
             } 
           else 
             {
               // check profit 
               if(Ask < (OrderStopLoss() - (sl * 2 + spread) * Point)) 
                 {
                   if(perceptron() > 0) 
                     { 
                       // reverse
                       ticket = OrderSend(Symbol(), OP_BUY, lots * 2, Ask, 3, 
                                          Bid - sl * Point, 0, "AI", MagicNumber,
                                          0, Blue); 
                       Sleep(30000);
                       if(ticket < 0) 
                         {
                           prevtime = Time[1];
                         } 
                       else 
                         {
                           OrderCloseBy(ticket, prevticket, Blue);   
                         }
                     } 
                   else 
                     { 
                       // trailing stop
                       if(!OrderModify(OrderTicket(), OrderOpenPrice(), 
                          Ask + sl * Point, 0, 0, Blue)) 
                         {
                           Sleep(30000);
                           prevtime = Time[1];
                         }  
                     }
                 }  
             }
           // exit
           return(0);
         }
     }
   // check for long or short position possibility
   if(perceptron() > 0) 
     { 
       //long
       ticket = OrderSend(Symbol(), OP_BUY, lots, Ask, 3, Bid - sl * Point, 0, 
                      "AI", MagicNumber, 0, Blue); 
       if(ticket < 0) 
         {
           Sleep(30000);
           prevtime = Time[1];
         }
     } 
   else 
     { 
       // short
       ticket = OrderSend(Symbol(), OP_SELL, lots, Bid, 3, Ask + sl * Point, 0, 
                      "AI", MagicNumber, 0, Red); 
       if(ticket < 0) 
         {
           Sleep(30000);
           prevtime = Time[1];
         }
     }
//--- exit
   return(0);
  }
//+------------------------------------------------------------------+
//|  The PERCEPRRON - a perceiving and recognizing function          |
//+------------------------------------------------------------------+
double perceptron() 
  {
   double w1 = x1 - 100.0;
   double w2 = x2 - 100.0;
   double w3 = x3 - 100.0;
   double w4 = x4 - 100.0;
   double a1 = iAC(Symbol(), 0, 0);
   double a2 = iAC(Symbol(), 0, 7);
   double a3 = iAC(Symbol(), 0, 14);
   double a4 = iAC(Symbol(), 0, 21);
   return (w1 * a1 + w2 * a2 + w3 * a3 + w4 * a4);
  }
//+------------------------------------------------------------------+
 
残るはニューラルネットワークの為の分割面の直線方程式の重み係数を選出するだけです。Ctrl + Rキーを押して、ストラテジーテスターを起動させます。
            



『設定』タブで市場のエミュレーションモデルを、始値のみによる方法で選択します。RecalculateとOptimizationにチェックを入れます。その後で『Expert properties』ボタンを押します。
      
『テスト』タブ:
      


     
頭金は3000ドルを選択し、最適化とテストはロングとショートポジションで行います。テスト期間の残高の最大値を、最適化の主要な指標とします。同様に、最適化のプロセスを速める為に、遺伝的アルゴリズムを有効にする必要があります。

『入力』タブ:
      


      
ニューラルネットワークの重み係数の為の、x1、x2、x3、x4のソースコードの遺伝的アルゴリズムで選択されるものにチェックを入れ、さらにストップロスレベルの許容値を選択する必要があります。ロット数は1とし、マジックナンバーはデフォルト値を残します。

『最適化』タブ:
      

      
最適化のプロセスを速める為、最大ドローダウンは35%に設定します。最大ドローダウンの許容レベルの確認の為に、始めはプロセスを様々な制限なしに行う必要があります。そして、最初の最適化の結果が出た後で、その数値を抽出しそれを四捨五入し、プロセスを止めてから制限を加えます。再度起動された最適化は、はるかに速く進みます。
      
エキスパートアドバイザの設定タブを閉じる為に、『OK』ボタンを押します。これで、『スタート』ボタンを押すことで、最適化のプロセスを開始することができます。また、無駄な結果の出力を無効にすることをお勧めします。
      

      
もしパソコンが弱くRAMが小さい場合、時々、最適化のプロセスの途中でログに溜まる情報をクリアすることをお勧めします。
      

      
Pentium IIIプロセッサでは、最適化は1時間ぐらいかかります。かかる時間は金融ツールによります。
     

      
後は行の上で右クリックし、[入力パラメータ設定]を選択して、履歴データによるテストを起動するだけです。
      
テスト結果はオプティマイザーが出したものと一致するでしょう。
      
これらの結果をこちらに掲載したいと思います。しかし「履歴データに合わせて調整した」と言われるかもしれません。では、もし市場が変化した場合、ストラテジーはどのようになるか?過去の期間に基づいたパターンは、どれだけ将来において現実的なのでしょうか?自動売買の大会の参加を例にとると、まだ大会が終了しないうちは、変更や追加を入力パラメータに加えることは禁止されています。
      
実験してみましょう。実験のために、最後の3ヶ月を算入せず履歴データに基づいたニューラルネットワークを見てみましょう。この目的の為に、テスターに内蔵された最適化の期間とテストの日付を使用します。

      
同期化を開始しましょう。入力パラメータは以下の様に定義します。x1 = 146, x2 = 25, x3 = 154, x4 = 121, sl = 45.



     

次に、同期が行われない期間の3ヶ月にあたるトレード戦略をチェックしましょう。[Use date]からチェックを外し、ストラテジーがどのように取引を続けるかを見てみましょう。


           
結果を見れば明らかです。取引戦略は結果的に利益をもたらしました。大会でみられた利益と比べると、この利益は十分に低いと言われています。しかし、エキスパートアドバイザーでは資本管理や危機管理を使用していないことは忘れてはならず、ロット数を指定したポジションだけを想定しています。勿論、3ヶ月に1回よりもっと頻繁に実際の取引で再最適化を行う必要があります。 


まとめ


D.カッツとD.マコーミックの『取引戦略百科辞典』のニューラルネットワークに関する結論をどう捉えたらいいでしょうか?
      
第一に『信じろ、しかし確認しろ』という原則があります。こう呼ばれるやり方は、最大限にこのような分析を省く為にあります。簡単に言えば、再現を除外する非科学的なアプローチです。トレードではなく、出版ビジネスをしているならわかります。彼らの課題は、内容に関係なく、書いたものを良く売ることにあります。これを理解する為には、『500に無駄なアドバイス』のスタイルに書かれている、刷り損じた紙の山はどのように作られてしまうのかを理解すれば十分です。それでは整理してみましょう。

  • D.カッツとD.マコーミックのやり方は、期間中に実際にはないインディケータ、より正確には、タイムマシンを自分の中から与える、遅い%Kの使用統計を作成すること、つまり先行する10のバーに対する情報を用いて、それに沿って以前の10のバーに対し自分の読みを出します。もしこのようなインディケータが私にあれば、ビル・ゲイツやジョージ・ソロスも私と競うことはできなかったでしょう。
  • 次のステップは、あるデータを使い、それに基づいてテレパシーの能力を持つこの統計の予測を得ることでした。簡単に言えば、彼らは、関数の論拠を知りつつその数値を得るという、近似課題を提起しました。近似とは、カッツとマコーミックが頭よさげに意味深長に、自身の分厚い本のページで語っているものです。
  • 近似値がどう得られたかは重要ではなく、この目的の為にニューラルネットワークが基本的に適していないことが重要です。同じような問題はスペクトル分析で決定したほうがいいです。
  • ニューラルネットワークにおける補間問題・外挿問題が複雑ですが、オブジェクトのクラスを定義せずにオブジェクトの値を取得してみる場合、外挿問題は当然の結果です。
  • 疑わしく見える推計学的なものの近似式を思い出して、カッツとマコーミックはいわゆる「トレード戦略」を作成しました。筆者のトレード戦略は、「%Kラインが制限を超える場合価格が上限か下限となる傾向」などありそうもない指数の予測を行います。その後で、こういった全ての見掛け倒しは自動取引システムへ追い込まれ、そこで統計を取得し早計な結論を出し、著者はそれらを読者へ勧めたのです。
結果は早いものでした。典型的なサンプルはだいたい大丈夫だったのに、典型的なサンプル以外に利益をもたらす可能性がなくなりました。

しかし、カッツとマコーミックだけでなく、他のエコノミストもニューラルネットワークに関する理論は失敗に終わりました。パーセプトロンという階層型のネットワークも作成者の期待に答えられませんでした。第一歩が常に最も難しいということです。客観解析がもっと遅く生まれて、マービン・ミンスキーとシーモア・パパートによって書かれました。したがって、特定の問題をニューラルネットワークで解き始める前に、同じ轍を踏まないようにしてください。

  1. 問題定義にはどこかいつかという、ありそうもない予測を含めてはいけません。予測状態を幾つかの相互排他的な状態に分けて問題を決定できます。例えば、もし問題が天気に関することなら、秒単位までの正確さでいつ雨が降り、ミリメートル単位までの降水量を知ろうとはしないでしょう。晴れになるか、雨になるかという天気の変化としての、可能性のある状況についての予測に止めるでしょう。
  2. 全ての無駄な『オッカムの剃刀』は切り取ってしまいましょう。何人かの実験者は、ニューラルネットワークにより多くの層があればあるほど、そしてそのアクティブ化の機能が複雑であればあるほど、結果は良いと考えています。実際には、勿論、このようにして、識別されたオブジェクトを、より正確に分ける境界線を引くことは可能です。これについては誰も反論しないでしょう。しかし、何の為に?このようなアプローチは砂の城を建てるような空しい業に過ぎないです。境界線が時間的に不明で、他の状況から独立した規定のアウトラインを持っていた場合、最大限の正確化を目的として複雑化は意味を持ったことでしょう。しかし、ニューラルネットワークを使って解く問題の主要部分は、このカテゴリにあてはまりません。金融ツールもまた止まってはいません。つまり、少数の入力数で単層の簡単なニューラルネットワークは、使い捨ての効率で、より複雑な構造のものよりもより許容できると認められます。
これで、私がこの記事で述べたかった事は以上です。


参考文献

  1. Minsky, M. and Papert, S. (1969) PERCEPTRON; an Introduction to Computational Geometry, MIT Press, Massachussetts . パーセプトロン:英語からの翻訳1971年。

MetaQuotes Ltdによってロシア語から翻訳されました。
元の記事: https://www.mql5.com/ru/articles/1447

添付されたファイル |
MQL5での「スネーク」ゲームの作成 MQL5での「スネーク」ゲームの作成
本稿では『スネーク』ゲームのプログラム例を述べていきます。MQL5では、主にイベントハンドル機能によりゲームのプログラムが可能となりました。オブジェクト指向プログラミングによりこのプロセスが格段に簡素化されます。本稿では、イベント処理機能 標準的な MQL5 ライブラリクラスの使用例、また定期的関数呼び出しの詳細を学習します。
MQL5でICQを用いたExpert Advisorの連携 MQL5でICQを用いたExpert Advisorの連携
本稿は、Expert Advisor と ICQ ユーザー間の情報交換について述べていきます。いくつかの例を提供します。ICQ クライアントを使用し、携帯電話やPDAでクライアント端末から遠隔でトレーディング情報を受け取りたい方には興味を引かれる資料を提供することとなるでしょう。
MQL4からMQL5へのインディケータ変換 MQL4からMQL5へのインディケータ変換
本稿では、MQL4で書かれた価格コンストラクションをMQL5に変換する特徴に特化して述べます。 MQL4からMQL5へのインディケータ変換計算プロセスを簡単にする手法として関数のmql4_2_mql5.mqhライブラリを提案します。その使用法はMACD、ストキャスティック、RSIインディケータの変換基礎に記載されています。
MQL5におけるトレーディング用コントロールパネルの作成 MQL5におけるトレーディング用コントロールパネルの作成
この記事は、MQL5のコントロールパネルの開発における問題を取り扱っています。インターフェイスは、イベントハンドリングによって管理されています。加えて、管理の柔軟なセットアップ方法が複数あります。コントロールパネルは、ポジションを扱い、また、設定、修正、削除や、未決注文も管理します。