
マシンラーニング:サポートベクターマシンをトレーディングで利用する方法
「サポートベクターマシン」とはどんなものなのでしょうか?
サポートベクターマシンとはマシン学習の一手法でインプットデータを取得し1~2個のカテゴリーに分類する試みです。サポートベクターマシンが効果的なものとなるように、まずトレーニングの入力と出力データセットを使用し、新しいデータを分類するのに使うサポートベクターマシンモデルを構築します。
サポートベクターマシンはトレーニング用インプットを取り、そのデータを多次元スペースにマッピングし、2 種類のインプットを分離するのにベストな 超平面(超平面とはスペースを二分割するn次元空間における表面)を見つけるために回帰を利用してこのモデルを開発します。ひとたびサポートベクターマシンがトレーニングされると、超平面を分離することに関して新しいインプットを評価し、2種類のカテゴリーの一つに分類することができます。
サポートベクターマシンは基本的にインプット/アウトプットマシンです。ユーザーはインプットを入れ、トレーニングによって発展したモデルを基にそれがアウトプットを返します。既定のサポートベクターマシンに対するインプット数は理論的には1から無限の範囲ですが、実践的には計算力によって制限されます。たとえば、入力数 N が特定のサポートベクターマシンに対して使われると(N の整数値は1から無限の範囲です)、サポートベクターマシンは各インプットセットを N次元空間にマップしトレーニングデータをもっともよく区別する (N-1)次元の超平面を見つけます。
図1 サポートベクターマシンはインプット/アウトプットマシンです。
サポートベクターマシンがどのように役立つかにつコンセプト化する最良の方法は二次元のケースを考察することです。インプットを2つ持ち、2種類のカテゴリーの内の1つに属するデータ点を分類する単独のアウトプットを返すサポートベクターマシンを作成したいとします。これを以下のチャートのような2次元チャートにプロットして可視化することができます。
図2 左: 2Dチャートにマップされたサポートベクターマシンのインプット赤い丸とブルーのバツは2種類のインプットを示すのに使われています。
図3 右: 2Dチャートにマップされたサポートベクターマシンのインプット超平面を分離することを指している黒の線を伴い、赤い丸とブルーのバツは2種類のインプットを示すのに使われています。
この例では、ブルーのバツはカテゴリー1に属するデータ点を指し、赤の丸はカテゴリー2に属するデータ点を指しています。個別データ点はそれぞれユニークなインプット値1(X 軸上のそれらの位置によって表される)、ユニークなインプット値2(Y 軸上のそれらの位置によって表される)を持ち、そしてこの点は2次元空間にマップされています。
サポートベクターマシンはこれら点のモデルを2次元スペースに作成することでデータ分類を行うことが可能です。サポートベクターマシンは2次元空間でデータを観測し、もっとも正確に2種類のカテゴリーにデータを分離する1次元超平面(線としても知られる)を検索するために回帰アルゴリズムを使用します。この分離線はサポートベクターマシンによって新しいデータ点をカテゴリー1 かカテゴリー2 のどちらかに分類するために使われます。
下のアニメーションは新しいサポートベクターマシンのトレーニングプロセスを表しています。そのアルゴリズムはあてずっぽうに分離超平面を見つけることでスタートし、超平面の精度を反復的に改良します。ご覧のようにアルゴリズムはきわめて積極的にスタートしていますが、好ましい解決に近づくにつれおちついていきます。
図4 サポートベクターマシンのトレーニングを示すアニメーション超平面は次第に2種類のデータを分離するための理想的な形状に収束していきます。
上記の2次元の筋書きはサポートベクターマシンの処理を視覚化することを可能にしますが、2つのインプットによってデータ点を分類することができるだけです。より多くのインプットを使用したければどうなるのでしょうか?ありがたいことにサポートベクターマシンのアルゴリズムにより、コンセプト化はかなり困難になりますが、高次元でも同じことができます。
これを配慮し、インプットを 20 持ち、これらインプットを使って任意のデータ点をカテゴリー1 かカテゴリー2 のいずれかに分類するサポートベクターマシンを作成したいと思います。このためにサポートベクターマシンは 20 次元空間でデータをモデル化し、データ点を2 種類のカテゴリーに分離する19 次元超平面を検索するための回帰アルゴリズムを使用する必要があります。これは視覚化をことのほか 困難にします。というのもわれわれにとって3 次元を超えるものを理解することが困難だからです。ただ、知るべきはそれも2 次元の場合とまったく同じように動作するということです。
サポートベクターマシンはどのように役立つのでしょうか?例:それはシュニックなのでしょうか?
この仮定シナリオをイメージしてください。みなさんは北極のかなたでしか見られないシュニックと呼ばれるまぼろしの生き物を調査している研究者です。この生き物は人になつかないためひじょうに少数の固体しかこれまでに見つかっていません(たとえば5,000体)。研究者として疑問に行き詰っています。どのようにシュニックだと確認できるのだろう?と。
自由に入手できるものは、この生き物を1体だけ見た一握りの研究者によって以前に出版された研究論文だけです。こういった研究論文では、著者は見つけたシュニックについてある特性を述べています。すなわち体高、体重、足の本数などです。しかしこれら特性はすべてが論文ごとに異なり、識別できるパターンはありません。
シュニックのような新種の生物を特定するためにこのデータをどのように利用することができるのでしょうか?
この問題の解決策として可能性があるのは、データ内のパターンを特定するためにサポートベクターマシンを利用し、生物がシュニック であるかシュニックでないか分類するために使うことのできる枠組みを作成することです。まず最初のステップは シュニックを特定するためにサポートベクターマシンをトレーニングするデータセットを作成することです。トレーニングデータはインプット1 セット、およびサポートベクターマシン向けに分析しそこからパターンを抽出するインプットに一致したアウトプットです。
そのためどのインプットをいくつ使用するか判断する必要があります。理論的には望む限り多くのインプットを持つことができますが、そうすると往々にしてトレーニング速度を下げることになります(インプット数が多いほど、サポートベクターマシンがパターンを抽出するのに時間がかかります)。また、全シュニックについて比較的一貫性のあるインプット値を選択したいと思います。たとえば、この生物の体高や体重はインプットの好例です。というのもこれが全シュニックにに比較的に一貫していると予想するためです。ただし、生き物の平均年齢はインプットとして好ましくない選択です。なぜなら特定される生物の年齢はひじょうに多様だからです。
この理由により次のインプットが選択されました。
- 体高
- 体重
- 足の本数
- 目の数
- 腕の長さ
- 平均移動速度
- 交尾時の鳴き声の周波数
選択したインプットによりトレーニングデータのコンパイルを始めることができます。サポートベクターマシン用の効果的なトレーニングデータは特定の要件を満たす必要があります。
- データはシュニックという生物の例を持つ必要があります。
- データはシュニックではない生物の例も持つ必要があります。
そして、首尾よくシュニックを確認し特質をリスト化した科学者の研究論文があります。これら研究論文を読んで、各インプットの対象データを抽出し、各例に対して真または偽のアウトプットに配分することができます。この場合のトレーニングデータは以下の表のようなものになるでしょう。
トレーニングサンプル | 体高 [mm] | 体重 [kg] | 足の数 | 目の数 | 腕の長さ [mm] | 平均速度 [m/s] | 鳴き声の周波数[Hz] | シュニック(真/偽) |
---|---|---|---|---|---|---|---|---|
例1 | 1030 | 45 | 8 | 3 | 420 | 2.1 | 14000 | 真 |
例2 | 1010 | 42 | 8 | 3 | 450 | 2.2 | 14000 | 真 |
例3 | 900 | 40 | 7 | 6 | 600 | 6 | 13000 | 偽 |
例4 | 1050 | 43 | 9 | 4 | 400 | 2.4 | 12000 | 真 |
例5 | 700 | 35 | 2 | 8 | 320 | 21 | 13500 | 偽 |
例6 | 1070 | 42 | 8 | 3 | 430 | 2.4 | 12000 | 真 |
例7 | 1100 | 40 | 8 | 3 | 430 | 2.1 | 11000 | 真 |
例N | ... | ... | ... | ... | ... | ... | ... | ... |
表1 シュニック観察例の表
トレーニング用インプットおよびアウトプットすべてに対するデータが集まったら、サポートベクターマシンをトレーニングするために使用することができます。トレーニングプロセス中、サポートベクターマシンは各トレーニングサンプルを真または偽にソートするのに使用することができる7次元空間でモデルを作成します。サポートベクターマシンはトレーニングデータを正確に表すモデルを取得するまでこれを続けます(指定のエラー許容範囲内にて)。トレーニングが完了すると、このモデルは新しいデータ点を真か偽かに分類するのに使用できます。
サポートベクターマシンはほんとうに役立つのでしょうか?
シュニックのシナリオを利用して、サポートベクターマシンがどのくらいうまく新しいシュニックを特定することができるかテストするスクリプトを書きました。このために「マーケット」からダウンロードできる『サポートベクターマシン学習ツール』関数ライブラリを使用しました。
このシナリオを効果的にモデル化するために、まず決めなければならないことはシュニックの実際の特性が何であるか、ということです。このケースで想定した特性は下記の表にリストアップしました。ある生き物が下記の基準をすべて満たせば、それはシュニックであるということになります。
パラメータ | 低い方のレンジ | 高い方のレンジ |
---|---|---|
体高 [mm] | 1000 | 1100 |
体重 [kg] | 40 | 50 |
足の数 | 8 | 10 |
目の数 | 3 | 4 |
腕の長さ [mm] | 400 | 450 |
平均速度 [m/s] | 2 | 2.5 |
鳴き声の周波数[Hz] | 11000 | 15000 |
表2 シュニックを定義するパラメータの概要
シュニックを定義したところで、この定義をサポートベクターマシンの実験に利用します。最初のステップは与えられた生物に対して7個のインプットを取る関数を作成しその生物がシュニックであるか否か実分類を返すことです。この関数はサポートベクターマシンに対するトレー二ングデータを作成し、最後にそのパフォーマンスを評価します。これは下記の関数を使用して行うことができます。
//+------------------------------------------------------------------+ //| This function takes the observation properties of the observed //| animal and based on the criteria we have chosen, returns true/false whether it is a schnick //+------------------------------------------------------------------+ bool isItASchnick(double height,double weight,double N_legs,double N_eyes,double L_arm,double av_speed,double f_call) { if(height < 1000 || height > 1100) return(false); // If the height is outside the parameters > return(false) if(weight < 40 || weight > 50) return(false); // If the weight is outside the parameters > return(false) if(N_legs < 8 || N_legs > 10) return(false); // If the N_Legs is outside the parameters > return(false) if(N_eyes < 3 || N_eyes > 4) return(false); // If the N_eyes is outside the parameters > return(false) if(L_arm < 400 || L_arm > 450) return(false); // If the L_arm is outside the parameters > return(false) if(av_speed < 2 || av_speed > 2.5) return(false); // If the av_speed is outside the parameters > return(false) if(f_call < 11000 || f_call > 15000) return(false); // If the f_call is outside the parameters > return(false) return(true); // Otherwise > return(true) }
次のステップはトレーニング用インプットおよびアウトプットを作成することができる関数を作ることです。この場合のインプットは7個のインプット値それぞれに対する設定範囲内でランダムな数を作成することで作り出されます。そして作成されたランダムなインプットそれぞれのセットに対して上記の isItASchnick() 関数が対応する望みのアウトプットを作成するのに使用されます。これは以下の関数で行われます。
//+------------------------------------------------------------------+ //| This function takes an empty double array and an empty boolean array, //| and generates the inputs/outputs to be used for training the SVM //+------------------------------------------------------------------+ void genTrainingData(double &inputs[],bool &outputs[],int N) { double in[]; // Creates an empty double array to be used for temporarily storing the inputs generated ArrayResize(in,N_Inputs); // Resize the in[] array to N_Inputs ArrayResize(inputs,N*N_Inputs); // Resize the inputs[] array to have a size of N*N_Inputs ArrayResize(outputs,N); // Resize the outputs[] array to have a size of N for(int i=0;i<N;i++) { in[0]= randBetween(980,1120); // Random input generated for height in[1]= randBetween(38,52); // Random input generated for weight in[2]= randBetween(7,11); // Random input generated for N_legs in[3]= randBetween(3,4.2); // Random input generated for N_eyes in[4]= randBetween(380,450); // Random input generated for L_arms in[5]= randBetween(2,2.6); // Random input generated for av_speed in[6]= randBetween(10500,15500); // Random input generated for f_call ArrayCopy(inputs,in,i*N_Inputs,0,N_Inputs); // Copy the new random inputs generated into the training input array outputs[i]=isItASchnick(in[0],in[1],in[2],in[3],in[4],in[5],in[6]); // Assess the random inputs and determine if it is a schnick } } //+------------------------------------------------------------------+ //| This function is used to create a random value between t1 and t2 //+------------------------------------------------------------------+ double randBetween(double t1,double t2) { return((t2-t1)*((double)MathRand()/(double)32767)+t1); }
これでトレーニング用インプットとアウトプットのセットを取得しました。ここからは「マーケット」で入手可能な「サポートベクターマシン学習ツール」を使用してサポートベクターマシンを作成していきます。新しいサポートベクターマシンが作成されれば、トレーニング用インプットおよびアウトプットをそれに渡し、トレーニングを実行します。
void OnStart() { double inputs[]; // Empty double array to be used for creating training inputs bool outputs[]; // Empty bool array to be used for creating training inputs int N_TrainingPoints=5000; // Defines the number of training samples to be generated int N_TestPoints=5000; // Defines the number of samples to be used when testing genTrainingData(inputs,outputs,N_TrainingPoints); //Generates the inputs and outputs to be used for training the SVM int handle1=initSVMachine(); // Initializes a new support vector machine and returns a handle setInputs(handle1,inputs,7); // Passes the inputs (without errors) to the support vector machine setOutputs(handle1,outputs); // Passes the outputs (without errors) to the support vector machine setParameter(handle1,OP_TOLERANCE,0.05); // Sets the error tolerance parameter to <5% training(handle1); // Trains the support vector machine using the inputs/outputs passed }
シュニックの特定に関してトレーニングされたサポートベクターマシンをうまく手に入れました。新しいデータ点の分類を依頼し最終のサポートベクターマシンを検証することで、このことを確認します。これは最初にランダムなインプットを作成し、つづいてこれらインプットが実際のシュニックに対応しているかどうか判断する isItASchnick() 関数を用いて行います。そしてサポートベクターマシンをを使いインプットを分類したら、予想の結果が実際の 結果に一致しているか判断します。これは以下の関数で行われます。
//+------------------------------------------------------------------+ //| This function takes the handle for the trained SVM and tests how //| successful it is at classifying new random inputs //+------------------------------------------------------------------+ double testSVM(int handle,int N) { double in[]; int atrue=0; int afalse=0; int N_correct=0; bool Predicted_Output; bool Actual_Output; ArrayResize(in,N_Inputs); for(int i=0;i<N;i++) { in[0]= randBetween(980,1120); // Random input generated for height in[1]= randBetween(38,52); // Random input generated for weight in[2]= randBetween(7,11); // Random input generated for N_legs in[3]= randBetween(3,4.2); // Random input generated for N_eyes in[4]= randBetween(380,450); // Random input generated for L_arms in[5]= randBetween(2,2.6); // Random input generated for av_speed in[6]= randBetween(10500,15500); // Random input generated for f_call Actual_Output=isItASchnick(in[0],in[1],in[2],in[3],in[4],in[5],in[6]); // Uses the isItASchnick fcn to determine the actual desired output Predicted_Output=classify(handle,in); // Uses the trained SVM to return the predicted output. if(Actual_Output==Predicted_Output) { N_correct++; // This statement keeps count of the number of times the predicted output is correct. } } return(100*((double)N_correct/(double)N)); // Returns the accuracy of the trained SVM as a percentage }
サポートベクターマシンをが異なる条件下でどのように処理するか確認するために上記関数内の値でいろいろやってみるのをお薦めします。
サポートベクターマシンはなぜそんなに便利なのでしょうか?
データから複雑なパターンを抽出するのにサポートベクターマシンを使用するメリットはデータの振る舞いを前もって理解する必要がないことです。サポートベクターマシンはデータを分析し、その洞察と関係のみを抽出することができるのです。 この方法により、インプットを受け取り、アウトプットを作成するブラックボックスに似た機能を持ちます。それは複雑すぎて判りにくいデータ内にパターンを見出すのにたいへん有用であることを証明することができるものです。
サポートベクターマシンの一番の特徴の一つはデータ内のエラーやノイズをひじょうにうまく処理することができる点です。データ内の基本パターンを確認し、データの異常値やその他複雑なものを除去することができます。 次のシナリオを考察します。シュニックの調査を行う間、はなはだしく異なる特性に言及する(体重が200㎏で体高が15,000mmのシュニックなど)複数の研究論文に出くわします。
このようなエラーはシュニックが何であるかというモデルをゆがめることにつながります。それは新しいシュニックの発見を分類する際、潜在的にエラーを作る原因となることでしょう。サポートベクターマシンのメリットはトレーニングデータ点にすべて一致するモデルに反し、基本的パターンを満たすモデルを作成することができる点にあります。これはモデル内で特定レベルのエラーを許容しサポートベクターマシンがデータにあるエラーを見逃がすことで行われます。
シュニックのサポートベクターマシンでは、エラー許容が 5% だとすると、トレーニングによりトレーニングデータの 95% を満たすモデルを作成するようにすればよいだけです。これは好都合です。なぜならトレーニングは小さいパーセントの異常値を無視することができるからです。
サポートベクターマシンのこの特性の調査は、シュニックのスクリプトを変更することでのちに行います。以下の関数はトレーニングデータセット内に意図的なランダムエラーを招くために追加されました。この関数は無作為にトレーニング点を選び、インプットをランダム変数に対応するアウトプットと置き換えます。
//+------------------------------------------------------------------+ //| This function takes the correct training inputs and outputs generated //| and inserts N random errors into the data //+------------------------------------------------------------------+ void insertRandomErrors(double &inputs[],bool &outputs[],int N) { int nTrainingPoints=ArraySize(outputs); // Calculates the number of training points int index; // Creates new integer 'index' bool randomOutput; // Creates new bool 'randomOutput' double in[]; // Creates an empty double array to be used for temporarily storing the inputs generated ArrayResize(in,N_Inputs); // Resize the in[] array to N_Inputs for(int i=0;i<N;i++) { in[0]= randBetween(980,1120); // Random input generated for height in[1]= randBetween(38,52); // Random input generated for weight in[2]= randBetween(7,11); // Random input generated for N_legs in[3]= randBetween(3,4.2); // Random input generated for N_eyes in[4]= randBetween(380,450); // Random input generated for L_arms in[5]= randBetween(2,2.6); // Random input generated for av_speed in[6]= randBetween(10500,15500); // Random input generated for f_call index=(int)MathRound(randBetween(0,nTrainingPoints-1)); // Randomly chooses one of the training inputs to insert an error if(randBetween(0,1)>0.5) randomOutput=true; // Generates a random boolean output to be used to create an error else randomOutput=false; ArrayCopy(inputs,in,index*N_Inputs,0,N_Inputs); // Copy the new random inputs generated into the training input array outputs[index]=randomOutput; // Copy the new random output generated into the training output array } }
この関数により、トレーニングデータに意図的なエラーを招くことができます。このエラーが書き込まれたデータを使って、新しいサポートベクターマシンを作成、トレーニングし、そのパフォーマンスを元のサポートベクターマシンのパフォーマンスと比較します。
void OnStart() { double inputs[]; // Empty double array to be used for creating training inputs bool outputs[]; // Empty bool array to be used for creating training inputs int N_TrainingPoints=5000; // Defines the number of training samples to be generated int N_TestPoints=5000; // Defines the number of samples to be used when testing genTrainingData(inputs,outputs,N_TrainingPoints); // Generates the inputs and outputs to be used for training the svm int handle1=initSVMachine(); // Initializes a new support vector machine and returns a handle setInputs(handle1,inputs,7); // Passes the inputs (without errors) to the support vector machine setOutputs(handle1,outputs); // Passes the outputs (without errors) to the support vector machine setParameter(handle1,OP_TOLERANCE,0.05); // Sets the error tolerance parameter to <5% training(handle1); // Trains the support vector machine using the inputs/outputs passed insertRandomErrors(inputs,outputs,500); // Takes the original inputs/outputs generated and adds random errors to the data int handle2=initSVMachine(); // Initializes a new support vector machine and returns a handle setInputs(handle2,inputs,7); // Passes the inputs (with errors) to the support vector machine setOutputs(handle2,outputs); // Passes the outputs (with errors) to the support vector machine setParameter(handle2,OP_TOLERANCE,0.05); // Sets the error tolerance parameter to <5% training(handle2); // Trains the support vector machine using the inputs/outputs passed double t1=testSVM(handle1,N_TestPoints); // Tests the accuracy of the trained support vector machine and saves it to t1 double t2=testSVM(handle2,N_TestPoints); // Tests the accuracy of the trained support vector machine and saves it to t2 Print("The SVM accuracy is ",NormalizeDouble(t1,2),"% (using training inputs/outputs without errors)"); Print("The SVM accuracy is ",NormalizeDouble(t2,2),"% (using training inputs/outputs with errors)"); deinitSVMachine(); // Cleans up all of the memory used in generating the SVM to avoid memory leak }
スクリプトが実行されているとき、それは「エキスパートログ」に次のような結果を生じます。5000 のトレーニング点を持つデータセットをトレーニングするなかで、ランダムなエラーを 500 発生させることができました。エラーが書き込まれたこのサポートベクターマシンのパフォーマンスを元のサポートベクターマシンのものと比較するとき、パフォーマンスの低下はたった<1% です。これはサポートベクターマシンがトレーニング中データセット内の異常値を見逃すことができ、それでもなお真のデータの見事に正確なモデルを作成することができるためです。これはサポートベクターマシンが潜在的にノイズを含むデータセットから複雑なパターンと洞察を抽出するのにより便利なツールであることを意味しています。
図5 エキスパートログ結果に続いて MetaTrader 5で『シュニック』のスクリプトを実行します。
デモバージョン
上記コードの完全バージョンは「コードベース」からダウンロードすることができますが、このスクリプトは、「サポートベクターマシン学習ツール」の完全版を「マーケット」から購入した場合ご自身の端末でのみ実行可能です。このツールのデモバージョンのみダウンロードしているなら、このツールはストラテジーテスタを介して制限付き使用となります。ツールのデモバージョンを使って『シュニック』コードを検証することができるようにするため、ストラテジーテスタを用いて展開可能な Expert Advisor 内へのスクリプトコピーを書きなおしました。これらコードバージョンは両方以下のリンクからダウンロード可能です。
-
完全バージョン - MetaTrader 5 ターミナル内に展開される「スクリプト」を使用しています (有料の「サポートベクターマシン学習ツール」が必要です。)
-
デモバージョン- MetaTrader 5 ストラテジーテスタに展開される Expert Advisor を使用しています(「サポートベクターマシン学習ツール」のデモバージョンのみ必要です。)
サポートベクターマシンはマーケットでどのように利用されるのでしょうか?
前述のシュニック例はひじょうにシンプルです。ただしこの例とマーケットのテクニカル分析用サポートベクターマシンの間にはかなり多くの類似性があります。
テクニカル分析は根本的に将来の価格変動を予想するためにマーケットの履歴データを使用することです。シュニック例でも同じように、新しい生物がシュニックであるか否か予想するために過去の科学者の観察を利用しました。その上、マーケットはサポートベクターマシンの利用をおもしろくするノイズ、エラー、統計的異常値に悩まされます。
かなりの数の基礎的テクニカル分析トレーディング方法には以下のステップが含まれます。
- 複数インディケータの監視
- 潜在的に成功するトレードに関連する各インディケータに対する条件特定
- 各インディケータをよく見、それらすべて(またはそれらのほとんど)がいつトレードに信号を送るか決定
似た方法で新しいトレードに信号を送るためにサポートベクターマシンを使用する類似方法を導入することは可能です。サポートベクターマシン学習ツールはこれを念頭に開発されました。このツールの使用方法に関する詳細は「マーケット」で確認することができるので、ここではざっと見るだけにします。このツールを使用する手順は以下です。
図6 Expert Advisor にサポートベクターマシンツールを実装する手順を示すブロック図
サポートベクターマシン学習ツールを使用する前に、まずトレーニング用インプットおよびアウトプットがどのように作成されるか理解することが重要です。
トレーニング用インプットはどのように作成されるのでしょうか?
さて、インプットとして使用したいインディケータはすでに新しいサポートベクターマシンとともに初期化済みです。次のステップは新しいサポートベクターマシンにインディケータハンドルを渡し、それにトレーニングデータを作成する方法を教えることです。setIndicatorHandles() 関数を呼ぶことでこれを行います。この関数により初期化されたインディケータのハンドルをサポートベクターマシンに渡すことができます。これはハンドルを持つ整数配列を渡すことで行われます。この関数へのもう2 個のインプットはオフセット値およびデータ点数です。
オフセット値は現在バーとトレーニングインプット作成に使用される開始バーの間の補正を示し、トレーニング点の数(Nで表記される)はトレーニングデータサイズを設定します。下図はこれら値の使用方法を示しています。オフセット値 4 と N 値 6 はサポートベクターマシンにトレーニング用インプットおよびアウトプットを作成するために白の四角の中にあるバーだけを使用するように指示します。同様にオフセット値 8 と N 値 8 はトレーニング用インプットおよびアウトプットを作成するためにブルーの四角の中にあるバーだけを使用するように指示します。
ひとたびsetIndicatorHandles() 関数が呼ばれると、genInputs() 関数を呼ぶことが可能です。この関数はトレーニングに使用されるインプットデータの配列を作成するために渡されるインディケータハンドルを使用します。
図7 オフセット値および N 値を説明するろうそく足チャート
トレーニング用アウトプットはどのように作成されるのでしょうか?
トレーニング用アウトプットは履歴価格を基に仮想トレードをシミュレーションし、そのようなトレードが成功するかしないかを判断することで作成されます。このために、サポートベクターマシン学習ツールに仮想トレードを成功か不成功か評価する方法を教えるために使うパラメータが数個あります。
最初の変数は OP_TRADEです。この値は「買い」または「売り」の可能性があり、仮想の売りまたは買いトレードのどちらかに対応します。この値が「買い」であれば、アウトプットを作成するとき、それは成功しそうな仮想の買いトレードのみを見ます。また、この値が「売り」であれば、アウトプットを作成するとき、それは成功しそうな仮想の売りトレードのみを見ます。
使われる次の値はこれら仮想トレードについての「ストップロス」および「テイクプロフィット」です。値は pips に設定され、各仮想トレードについてストップレベルとリミットレベルを設定します。
最後のパラメータはトレード継続時間です。この変数は時間で計測され、確実にこの最大継続時間内に完了したトレードのみ成功とみなされます。この変数をインクルードする理由は横方向にゆっくり変動する マーケットでトレードシグナルを送るサポートベクターマシンを避けるためです。
インプット選択の際の配慮
トレーディングにサポートベクターマシンを導入するときインプット選択にはいくらか配慮することが重要です。シュニックの例のように、異なる事柄について類似性を持つと予想されるインプットを選ぶことが重要です。たとえば、インプットとして移動平均を利用したいと思うかもしれません。ただし、長期平均価格は時間の経過とともに大幅に変動する傾向にあるため、移動平均だけを利用するのは最良のインプットではないかもしれません。これは本日の移動平均値と6か月前の移動平均値の間に際立った類似性がないからです。
「買い」トレード信号を送る移動平均インプットを持つサポートベクターマシンを使って EURUSD をトレードするとします。現在価格が 1.10 ですが、価格が 0.55 だった 6 か月前からトレーニングデータを作成しているとします。サポートベクターマシンをトレーニングするとき、それが見つけるパターンは価格が 0.55 のあたりであれば信号を送るトレードに導くだけかもしれません。というのもそれが知っている唯一のデータだからです。よってこのようなサポートベクターマシンは価格が 0.55 に戻るまでトレード信号を送らない可能性があります。
代わりにサポートベクターマシンに対して使うよりよいインプットは MACD または類似のオシレータです。なぜなら MACD 値は平均価格レベルから独立していて関連した変動のシグナルのみ送るからです。何が最良の結果を出すのか見るためにこれで実験することをお薦めします。
インプット選択時にもうひとつ配慮すべきことは、サポートベクターマシンが必ず新規トレードの信号を送るインディケータの適切なスナップショットを持つようにすることです。みなさんはご自身のトレード経験で過去 5 本のバーを見る場合、トレンドを表すという点で MACD が唯一便利だと感じるかもしれません。MACD のバー1本は上向きか下向きか判らなければ単独では役に立ちません。よってサポートベクターマシンに対しては MACD インディケータのバーは過去数本分渡す必要があります。これには可能な方法が2つあります。
-
MACD インディケータの過去5本のバーを使うカスタムインディケータを新たに作成し、一つの値としてトレンドを計算するのです。このカスタムインディケータは単一インプットとしてサポートベクターマシンに渡されます。または
-
サポートベクターマシン内の MACD インディケータの前回5本のバーを5つの個別インプットとして使用することができます。これをする方法はMACD インディケータの異なる5個のインスタンスを初期化することです。各インディケータは現在バーからの異なるオフセットによって初期化することができます。そして個別のインディケータからハンドルはが5個サポートベクターマシンに渡されます。注意点としては、オプション2は Expert Advisorの実行時間が長くなる傾向にあることです。インプットが多ければ多いほど、問題なくトレーニングするのに長い時間がかかります。
Expert Advisorへのサポートベクターマシン実装
だれでも自分のトレーディングでサポートベクターマシンを使用する可能性のある方法例としての Expert Advisor を準備しました(このコピーはリンク https://www.mql5.com/ja/code/1229から入手可能です)。Expert Advisor によりサポートベクターマシンをすこし実験できるとよいのですが。ご自身のトレードスタイルに合わせて Expert Advisor をコピー/変更/改良することをお薦めします。EA は以下のように動作します。
-
svMachineTool ライブラリを用いて新しいサポートベクターマシンが2件作成されます。1件は新規「買い」トレードのシグナルを、もう1件は新規「売り」トレードシグナルを送るよう設定されます。
-
7つの標準インディケータは整数配列に格納するよう各ハンドルで初期化されます(注意:インディケータの組合せはどれもインプットとして使用され、単一整数配列内の SVM に渡される必要があるだけです)。
-
インディケータハンドルの配列は新しいサポートベクターマシンに渡されます。
-
インディケータハンドルおよびその他のパラメータを使用して、履歴価格データはサポートベクターマシンがトレーニングするのに使用される正確なインプットとアウトプットを作成するのに使われます。
-
ひとたびインプットおよびアウトプットがすべて作成されると、両サポートベクターマシンはトレーニングされます。
-
トレーニングされたサポートベクターマシンは新規「買い」トレードおよび「売り」トレードの信号を送るために EA で使用されます。新規「買い」トレードおよび「売り」トレードの信号が送られると、マニュアルの「ストップロス」と「テイクプロフィット」と主にトレードがオープンされます。
サポートベクターマシンの初期化とトレーニングは onInit() 関数によって実行されます。参考までに、svTrader EA のこの部分を注意書きとともに以下に記載します。
#property copyright "Copyright 2011, MetaQuotes Software Corp." #property link "https://www.mql5.com" #property version "1.00" #property indicator_buffers 7 //+---------Support Vector Machine Learning Tool Functions-----------+ //| The following #import statement imports all of the support vector //| machine learning tool functions into the EA for use. Please note, if //| you do not import the functions here, the compiler will not let you //| use any of the functions //+------------------------------------------------------------------+ #import "svMachineTool.ex5" enum ENUM_TRADE {BUY,SELL}; enum ENUM_OPTION {OP_MEMORY,OP_MAXCYCLES,OP_TOLERANCE}; int initSVMachine(void); void setIndicatorHandles(int handle,int &indicatorHandles[],int offset,int N); void setParameter(int handle,ENUM_OPTION option,double value); bool genOutputs(int handle,ENUM_TRADE trade,int StopLoss,int TakeProfit,double duration); bool genInputs(int handle); bool setInputs(int handle,double &Inputs[],int nInputs); bool setOutputs(int handle,bool &Outputs[]); bool training(int handle); bool classify(int handle); bool classify(int handle,int offset); bool classify(int handle,double &iput[]); void deinitSVMachine(void); #import #include <Trade\Trade.mqh> #include <Trade\PositionInfo.mqh> #include <Trade\HistoryOrderInfo.mqh> //+-----------------------Input Variables----------------------------+ input int takeProfit=100; // TakeProfit level measured in pips input int stopLoss=150; // StopLoss level measured in pips input double hours=6; // The maximum hypothetical trade duration for calculating training outputs. input double risk_exp=5; // Maximum simultaneous order exposure to the market input double Tolerance_Value=0.1; // Error Tolerance value for training the SVM (default is 10%) input int N_DataPoints=100; // The number of training points to generate and use. //+---------------------Indicator Variables--------------------------+ //| Only the default indicator variables have been used here. I //| recommend you play with these values to see if you get any //| better performance with your EA. //+------------------------------------------------------------------+ int bears_period=13; int bulls_period=13; int ATR_period=13; int mom_period=13; int MACD_fast_period=12; int MACD_slow_period=26; int MACD_signal_period=9; int Stoch_Kperiod=5; int Stoch_Dperiod=3; int Stoch_slowing=3; int Force_period=13; //+------------------Expert Advisor Variables------------------------+ int tickets[]; bool Opn_B,Opn_S; datetime New_Time; int handleB,handleS; double Vol=1; //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ int OnInit() { New_Time=0; int handles[];ArrayResize(handles,7); //+------------------------------------------------------------------+ //| The following statements are used to initialize the indicators to be used for the support //| vector machine. 返されるハンドルは int[] 配列に格納されます。I have used standard //| indicators in this case however, you can also you custom indicators if desired //+------------------------------------------------------------------+ handles[0]=iBearsPower(Symbol(),0,bears_period); handles[1]=iBullsPower(Symbol(),0,bulls_period); handles[2]=iATR(Symbol(),0,ATR_period); handles[3]=iMomentum(Symbol(),0,mom_period,PRICE_TYPICAL); handles[4]=iMACD(Symbol(),0,MACD_fast_period,MACD_slow_period,MACD_signal_period,PRICE_TYPICAL); handles[5]=iStochastic(Symbol(),0,Stoch_Kperiod,Stoch_Dperiod,Stoch_slowing,MODE_SMA,STO_LOWHIGH); handles[6]=iForce(Symbol(),0,Force_period,MODE_SMA,VOLUME_TICK); //----------Initialize, Setup and Training of the Buy-Signal support vector machine---------- handleB=initSVMachine(); // Initializes a new SVM and stores the handle to 'handleB' setIndicatorHandles(handleB,handles,0,N_DataPoints); // Passes the initialized indicators to the SVM with the desired offset // and number of data points setParameter(handleB,OP_TOLERANCE,Tolerance_Value); // Sets the maximum error tolerance for SVM training genInputs(handleB); // Generates inputs using the initialized indicators genOutputs(handleB,BUY,stopLoss,takeProfit,hours); // Generates the outputs based on the desired parameters for taking hypothetical trades //----------Initialize, Setup and Training of the Sell-Signal support vector machine---------- handleS=initSVMachine(); // Initializes a new SVM and stores the handle to 'handleS' setIndicatorHandles(handleS,handles,0,N_DataPoints); // Passes the initialized indicators to the SVM with the desired offset // and number of data points setParameter(handleS,OP_TOLERANCE,Tolerance_Value); // Sets the maximum error tolerance for SVM training genInputs(handleS); // Generates inputs using the initialized indicators genOutputs(handleS,SELL,stopLoss,takeProfit,hours); // Generates the outputs based on the desired parameters for taking hypothetical trades //---------- training(handleB); // Executes training on the Buy-Signal support vector machine training(handleS); // Executes training on the Sell-Signal support vector machine return(0); }
サポートベクターマシンの高度なトレーニング
よりレベルの高いユーザー向けにその他機能がサポートベクターマシン学習ツールに組み込まれています。このツールによりユーザーは独自のカスタムインプットデータおよびアウトプットデータを渡すことができます(シュニックの例にあるように)。サポートベクターマシンのインプットとアウトプットの独自の基準を作り、トレーニングのためにマニュアルでこのデータに渡すことを可能にします。これによりトレーニングのあらゆる側面でサポートベクターマシンを使用するチャンスが開かれるのです。
サポートベクターマシンが新規トレードの信号を送ることができるようになるだけでなく、トレードの終了、資金管理、新らしい高度なインディケータの信号を送るために利用することができるのです。ただし、確実にエラーを受け取らないようにするため、こういった独自のインプットとアウトプットがどのように構築されるのか理解することは重要です。
インプット: インプットはダブル値の1次元配列として SVM に渡されます。ご自身が作成するインプットはどれもダブル値として渡される必要があることにご注意ください。ブールタイプ、整数タイプなどの値はすべてサポートベクターマシンに渡される前にダブル値に変換される必要があります。インプットは次のような形式である必要があります。kたとえば、インプットを3インプット×5トレーニング点で渡すと仮定します。そのためこの場合のダブル配列はフォーマットで15ユニットの長さとなります。
| A1 | B1 | C1 | A2 | B2 | C2 | A3 | B3 | C3 | A4 | B4 | C4 | A5 | B5 | C5 |
また、インプット数に対する値が渡される必要があります。N_Inputs=3 の場合
アウトプット: アウトプットはブール値配列として渡されます。これらブール値は渡されたそれぞれのインプットセットに対応するSVMのアウトプットとして望ましいものです。上記例に従い、5個のトレーニング点があるとします。このシナリオでは、5ユニットの長さのアウトプット値のブール配列を渡すことになります。
一般的な注意
-
ご自身のインプットとアウトプットを作成するときは、かならずその配列長が渡す値と一致しているようにします。一致していなければ、不一致を告げるエラーが発生します。たとえば、N_Inputs=3 を渡し、インプットが長さ 16 の配列であれば、エラーが通知されます(3 というN_inputs 値はあらゆるインプット配列の長さが 3 の倍数であることを意味します)。同様に、渡すインプットセット数とアウトプット数はかならず等しくなるようにします。インプットの長さが15 の N_Inputs=3 でアウトプットの長さが 6 であると、別のエラーが通知されます(インプット 5 セット、アウトプット 6 セットとなっているため)。
-
ご自身のトレーニングアウトプットに十分なバリエーションがあることを確認してみてください。たとえば、トレーニング点を100渡すと、それはアウトプット配列の長さが100であることを意味し、真はただ1つであとはすべて偽です。そのとき真の場合と偽の場合の相違は十分とは言えません。これは SVM のトレーニング速度を早めますが、最終的なソリューションはひじょうにお粗末なものとなります。もっと多様性に富むトレーニングセットだとより影響力のある SVMが導かれます。
MetaQuotes Ltdにより英語から翻訳されました。
元の記事: https://www.mql5.com/en/articles/584





- 無料取引アプリ
- 8千を超えるシグナルをコピー
- 金融ニュースで金融マーケットを探索