このスクリプトは、「機械学習:サポートベクターマシンをトレーディングに活かす方法」というMQL5サイトに掲載された記事の一部として書かれました。
仮想のシナリオを考えてみましょう。あなたは、北極の奥深くに生息する珍しい動物「シュニック」を研究している研究者です。これらの動物は非常に希少で、これまでに見つかったのは約5000匹です。あなたは、「シュニック」を特定するにはどうしたら良いのかという問題に直面しています。
あなたが利用できるのは、シュニックを見た少数の研究者が書いた研究論文だけです。これらの論文では、見つけたシュニックの特徴(身長、体重、足の数など)が記述されていますが、それらの特徴には明確なパターンはありません…。
このデータを使って、新しい動物をシュニックとして識別するにはどうすれば良いでしょうか?
問題を解決する一つの方法は、サポートベクターマシンを使用してデータのパターンを特定し、動物をシュニックかどうか分類するためのフレームワークを作成することです。最初のステップは、シュニックを特定するためにサポートベクターマシンをトレーニングするためのデータセットを作成することです。このトレーニングデータは、サポートベクターマシンが分析し、パターンを抽出するための入力と対応する出力のセットです。
このスクリプトは、MQL5マーケットで利用可能なサポートベクターマシン学習ツールを使用して、分類スタイルの問題を解決するための強力な手段を示しています。この仮想の問題とスクリプトの詳細については、記事「機械学習:サポートベクターマシンをトレーディングに活かす方法」をご覧ください。記事には、スクリプトの使い方と、この問題が市場トレンドの評価における機械学習の利用にどのような洞察を与えるかについての説明が含まれています。
コード:
//+------------------------------------------------------------------+ //| Schnick_Demo.mq5 | //| Copyright 2011, MetaQuotes Software Corp. | //| http://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2011, MetaQuotes Software Corp." #property link "http://www.mql5.com" #property version "1.00" //+------------------------------------------------------------------+ //| このスクリプトはサポートベクターマシン学習ツールの機能を示します //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| 次のステートメントは、サポートベクターマシンツール 'svMachineTool.ex5' に含まれるすべての関数をインポートします //+------------------------------------------------------------------+ #import "svMachineTool_demo.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 //--- 使用する入力の数 int N_Inputs=7; //+------------------------------------------------------------------+ //| エキスパート初期化関数 | //+------------------------------------------------------------------+ int OnInit() { double inputs[]; //トレーニング入力用の空の配列 bool outputs[]; //トレーニング出力用の空の配列 int N_TrainingPoints=5000; //生成するトレーニングサンプルの数 int N_TestPoints=5000 //テスト用のサンプル数 genTrainingData(inputs,outputs,N_TrainingPoints); //svm用の入力と出力を生成 int handle1=initSVMachine(); //サポートベクターマシンを初期化し、ハンドルを返す setInputs(handle1,inputs,7); //入力をサポートベクターマシンに渡す setOutputs(handle1,outputs); //出力をサポートベクターマシンに渡す setParameter(handle1,OP_TOLERANCE,0.01); //誤差許容パラメータを設定 training(handle1); //トレーニングを実施 insertRandomErrors(inputs,outputs,500); //元の入力/出力にランダムエラーを追加 int handle2=initSVMachine(); //新しいサポートベクターマシンを初期化し、ハンドルを返す setInputs(handle2,inputs,7); //サポートベクターマシンに入力を渡す setOutputs(handle2,outputs); //サポートベクターマシンに出力を渡す setParameter(handle2,OP_TOLERANCE,0.01); //誤差許容パラメータを設定 training(handle2); //トレーニングを実施 double t1=testSVM(handle1,N_TestPoints); //トレーニングされたサポートベクターマシンの精度をテスト double t2=testSVM(handle2,N_TestPoints); //トレーニングされたサポートベクターマシンの精度をテスト Print("SVMの精度は ",NormalizeDouble(t1,2),"% (エラーなしのトレーニング入力/出力を使用)"); Print("SVMの精度は ",NormalizeDouble(t2,2),"% (エラーありのトレーニング入力/出力を使用)"); deinitSVMachine(); //SVM生成に使用したメモリをクリーンアップ return(0); } //+------------------------------------------------------------------+ //| エキスパートデイニシャライゼーション関数 | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- OnDeinit()内で実行される関数はありません } //+------------------------------------------------------------------+ //| エキスパートティック関数 | //+------------------------------------------------------------------+ void OnTick() { //--- OnTick()内で実行される関数はありません } //+------------------------------------------------------------------+ //| この関数は観察された動物の特性を取得し、選択した基準に基づいて、 //| シュニックかどうかを真または偽で返します //+------------------------------------------------------------------+ 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); //身長がパラメータ外の場合はfalseを返す if(weight < 40 || weight > 50) return(false); //体重がパラメータ外の場合はfalseを返す if(N_legs < 8 || N_legs > 10) return(false); //足の数がパラメータ外の場合はfalseを返す if(N_eyes < 3 || N_eyes > 4) return(false); //目の数がパラメータ外の場合はfalseを返す if(L_arm < 400 || L_arm > 450) return(false); //腕の長さがパラメータ外の場合はfalseを返す if(av_speed < 2 || av_speed > 2.5) return(false); //平均速度がパラメータ外の場合はfalseを返す if(f_call < 11000 || f_call > 15000) return(false); //鳴き声の周波数がパラメータ外の場合はfalseを返す return(true); //それ以外はtrueを返す } //+------------------------------------------------------------------+ //| この関数は空のdouble配列と空のboolean配列を受け取り、 //| SVMのトレーニングに使用する入力/出力を生成します //+------------------------------------------------------------------+ void genTrainingData(double &inputs[],bool &outputs[],int N) { double in[]; //使用する空のdouble配列を作成 //一時的に生成された入力を格納 ArrayResize(in,N_Inputs); //in[]配列のサイズをN_Inputsにリサイズ ArrayResize(inputs,N*N_Inputs); //inputs[]配列のサイズをN*N_Inputsにリサイズ ArrayResize(outputs,N); //outputs[]配列のサイズをNにリサイズ for(int i=0;i<N;i++) { in[0]= randBetween(980,1120); //身長のために生成されたランダム入力 in[1]= randBetween(38,52); //体重のために生成されたランダム入力 in[2]= randBetween(7,11); //足の数のために生成されたランダム入力 in[3]= randBetween(3,4.2); //目の数のために生成されたランダム入力 in[4]= randBetween(380,450); //腕の長さのために生成されたランダム入力 in[5]= randBetween(2,2.6); //平均速度のために生成されたランダム入力 in[6]= randBetween(10500,15500); //鳴き声のために生成されたランダム入力 //--- 新しく生成されたランダム入力をトレーニング入力配列にコピー ArrayCopy(inputs,in,i*N_Inputs,0,N_Inputs); //--- ランダム入力を評価し、シュニックかどうかを判定 outputs[i]=isItASchnick(in[0],in[1],in[2],in[3],in[4],in[5],in[6]); } } //+------------------------------------------------------------------+ //| この関数はトレーニングされたSVMのハンドルを受け取り、 //| 新しいランダム入力を分類する成功率をテストします //+------------------------------------------------------------------+ 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); //身長のために生成されたランダム入力 in[1]= randBetween(38,52); //体重のために生成されたランダム入力 in[2]= randBetween(7,11); //足の数のために生成されたランダム入力 in[3]= randBetween(3,4.2); //目の数のために生成されたランダム入力 in[4]= randBetween(380,450); //腕の長さのために生成されたランダム入力 in[5]= randBetween(2,2.6); //平均速度のために生成されたランダム入力 in[6]= randBetween(10500,15500); //鳴き声のために生成されたランダム入力 //--- isItASchnick関数を使用して、実際の出力を判定 Actual_Output=isItASchnick(in[0],in[1],in[2],in[3],in[4],in[5],in[6]); //--- トレーニングされたSVMを使用して予測された出力を返す Predicted_Output=classify(handle,in); if(Actual_Output==Predicted_Output) { N_correct++; //予測出力が正しい回数をカウント } } //--- トレーニングされたSVMの精度をパーセントで返す return(100*((double)N_correct/(double)N)); } //+------------------------------------------------------------------+ //| この関数は正しいトレーニング入力と出力を受け取り、 //| N個のランダムエラーをデータに挿入します //+------------------------------------------------------------------+ void insertRandomErrors(double &inputs[],bool &outputs[],int N) { int nTrainingPoints=ArraySize(outputs); //トレーニングポイントの数を計算 int index; //新しい整数'index'を作成 bool randomOutput; //新しいbool 'randomOutput' double in[]; //使用する空のdouble配列を作成 //一時的に生成された入力を格納 ArrayResize(in,N_Inputs); //in[]配列のサイズをN_Inputsにリサイズ for(int i=0;i<N;i++) { in[0]= randBetween(980,1120); //身長のために生成されたランダム入力 in[1]= randBetween(38,52); //体重のために生成されたランダム入力 in[2]= randBetween(7,11); //足の数のために生成されたランダム入力 in[3]= randBetween(3,4.2); //目の数のために生成されたランダム入力 in[4]= randBetween(380,450); //腕の長さのために生成されたランダム入力 in[5]= randBetween(2,2.6); //平均速度のために生成されたランダム入力 in[6]= randBetween(10500,15500); //鳴き声のために生成されたランダム入力 //--- トレーニング入力の1つにエラーを挿入 index=(int)MathRound(randBetween(0,nTrainingPoints-1)); //--- ランダムなブール出力を生成してエラーを作成 if(randBetween(0,1)>0.5) randomOutput=true; else randomOutput=false; //--- 新しく生成されたランダム入力をトレーニング入力配列にコピー ArrayCopy(inputs,in,index*N_Inputs,0,N_Inputs); //--- 新しく生成されたランダム出力をトレーニング出力配列にコピー outputs[index]=randomOutput; } } //+------------------------------------------------------------------+ //| この関数はt1とt2の間のランダム値を生成します //+------------------------------------------------------------------+ double randBetween(double t1,double t2) { return((t2-t1)*((double)MathRand()/(double)32767)+t1); } //+------------------------------------------------------------------+