
自分の最適化基準を実装する方法
はじめに
ときどき、MT4 テスターの最適化基準を拡張する必要性についての意見を聞くことがあります。作成者がどんな基準を追加しても、別の基準を必要とするユーザーや状況がつねにあることは予想がつきます。MQL4 や MetaTrader 内部でこの問題は解決可能でしょうか?できますとも。本稿では標準 Expert Advisor 移動平均例でカスタム最適化基準を使う実装を説明します。ここでの基準は利益/ドローダウンに関連したものです。
Expert Advisor
最適化基準から始めます。それを計算するには、検証中に最大残高とドローダウンを追跡する必要があります。Expert Advisor 動作のロジックに依存しないように、関数 start() の一番最初に既存コードの文字列を追加します。
if (AccountEquity() > MaxEqu) MaxEqu = AccountEquity(); if (MaxEqu-AccountEquity() > MaxDD) MaxDD = MaxEqu-AccountEquity();
最終ティックを処理するために、deinit() でそれらを複製します。その後、最適化基準値を計算します。
Criterion = (AccountBalance()-StartBalance)/MaxDD;
ここでメインパート-最適化手順の維持、を開始します。一つ問題があります。MQL4 には最適化の終了を判断するための組み込み手段がありません。私が知っている唯一の解決法は、いわゆる『カウンターでの最適化』です。その意味は以下です。:Expert Advisor の変更可能な唯一のパラメータは特殊外部変数-counter です。重大な結果があります。標準的な方法では Expert Advisor の実際のパラメータはを変更する機能を失ってしまうので、これを自分で付けなければなりません。もう一つ別の欠点は、友達からの最適化キャッシュが敵に変わってしまうのです。しかし、目的は手段を正当化する。よって続けます。
外部変数を追加します。
extern int Counter = 1; // Counter of the tester's running extern int TestsNumber = 200; // he check digit - total number of runs extern int MovingPeriodStepsNumber = 20; // Number of optimization steps for MovingPeriod extern int MovingShiftStepsNumber = 10; // Number of optimization steps for MovingShift extern double MovingPeriodLow = 150; // Lower limit of the optimization range for MovingPeriod extern double MovingShiftLow = 1; // Lower limit of the optimization range for MovingShift extern double MovingPeriodStep = 1; // Optimization step for MovingPeriod extern double MovingShiftStep = 1; // Optimization step for MovingShift
まずカウンターが来ます。次の変数は1(と情報)のチェックです。そしてステップ番号を割り当て、限度と、最適化を行う移動平均の2つの組み込み関数に対する最適化ステップを下げます。いくつか無理が見えます。:完全な試験を受けるならば(そしてそれを行うつもりで)、MovingPeriodStepsNumber および MovingShiftStepsNumberからできるものは TestsNumber に等しくなります。
各検証実行後、Expert Advisor は完全に動作を停止し、次の実行は再生と考えることができます。『遺伝的ストレージ』を作る方法は2とおりあります。グローバル変数と個別ファイルです。どちらも使用します。
関数 init() を修正します。
int init() { if (IsTesting() && TestsNumber > 0) { if (GlobalVariableCheck("FilePtr")==false || Counter == 1) { FilePtr = 0; GlobalVariableSet("FilePtr",0); } else { FilePtr = GlobalVariableGet("FilePtr"); } MovingPeriod = MovingPeriodLow+((Counter-1)/MovingShiftStepsNumber)*MovingPeriodStep; MovingShift = MovingShiftLow+((Counter-1)%MovingShiftStepsNumber)*MovingShiftStep; StartBalance = AccountBalance(); MaxEqu = 0; MaxDD = 0; } return(0); }
われわれの追加はテスター内だけの処理条件内部と、ゼロ以外の TestsNumber にあります。タスクTestsNumber=0 は標準移動平均に Expert Advisor を返します。最適化手順について話すと同時に、処理のスピードアップ機能を何か使う必要があります。コードがグローバル変数によってファイルポインタをすべて(テスター実行を通して)管理する規定で始まるのはそのためです。それから変更可能なパラメータ値を計算し、最適化基準計算に使われる変数を初期化します。
主な作業は関数 deinit() で行われます。検証結果については、最適化基準のテキストファイル値、最適化済みパラメータ値、検証実行数の値に保存します。最適化が終わると、最適化基準に応じた結果がソートされ同一ファイルに保存されます。というわけで、3とおりの状況を処理する必要があります。最初のスタート、最後のスタート、その他、です。分離のためにテスター実行カウンターを使用します。
最初のスタート処理:
if (Counter == 1) { // First run, create/initialize a datafile. h=FileOpen("test.txt",FILE_CSV|FILE_WRITE,';'); FileWrite(h,Criterion,MovingPeriod,MovingShift,Counter); // Remember the position of the file pointer after writing in the global variable FilePtr = FileTell(h); GlobalVariableSet("FilePtr",FilePtr); FileClose(h);
その他のスタート処理は、新規データがファイルに追加されることが特殊です。
} else { // After the first start is processed, the data are added into the file h=FileOpen("test.txt",FILE_CSV|FILE_READ|FILE_WRITE,';'); // It is time to use the file pointer written in the global variable FilePtr = GlobalVariableGet("FilePtr"); FileSeek(h,FilePtr, SEEK_SET); FileWrite(h,Criterion,MovingPeriod,MovingShift,Counter); // Remember the file pointer position once again FilePtr = FileTell(h); GlobalVariableSet("FilePtr",FilePtr);
ここで最終スタートを処理します。
if (Counter == TestsNumber) { ArrayResize(Data,TestsNumber); // Returns the file pointer to the beginning FileSeek(h,0,SEEK_SET); // Read from the file the results of all testings int i = 0; while (i<TestsNumber && FileIsEnding(h)== false) { for (int j=0;j<4;j++) { Data[i][j]=FileReadNumber(h); } i++; } // Sort the array according to our optimization criterion ArraySort(Data,WHOLE_ARRAY,0,MODE_DESCEND); // Now let us arrange the results. Reopen the file FileClose(h); h=FileOpen("test.txt",FILE_CSV|FILE_WRITE,' '); FileWrite(h," Criterion"," MovingPeriod"," MovingShift"," Counter"); for (i=0;i<TestsNumber;i++) { FileWrite(h,DoubleToStr(Data[i][0],10)," ",Data[i][1]," ",Data[i][2]," ",Data[i][3]); }
配列は事前にダブル Data[][4] として初期化されています。以上です。整えます。
GlobalVariableDel("FilePtr"); } FileClose(h); } }
コンパイルし、テスターを開き、Expert Advisor を選択します。そして Expert Advisor のプロパティシートを開き、4か所にチェックを入れます。
-MovingShiftStepsNumberによる MovingPeriodStepsNumber のプロダクトは TestsNumber に等しく「なければならない」。
-最適化はカウンターに対して「のみ」行われる必要がある。
-最適化範囲は1からステップ1の TestsNumber までで「なければならない」。
-遺伝的アルゴリズムは無効にしなければならない。
最適化を開始します。終了後、フォルダ [Meta Trader]\tester\files へ移動し、ファイル test.txt 内の結果を見ます。私は2004年の半ばから EURUSD_H1 について始値で最適化を行い、以下の結果を取得しました。
ここから、キャッシュが敵であるという見解に戻ります。何かというと、キャッシュから検証結果を取る際、関数 init() と deinit() は開始されません。結果、最適化再開時、バリアントすべてまたは一部はカウントされないのです。また、実際の実行回数が TestsNumber より小さければ、配列 Data はゼロをいくつか持つことになります。私は、『キャッシュ効果』を消す方法を2とおり提案します。:Expert Advisor の再コンパイル、またはテスターウィンドウをクローズ/ポーズ/オープンすることです。
キャッシュのインターフェースは検証実行を個別にカウントすることで検出可能です。添付の EA コード内で提供されている特殊なグローバル変数によって、そのようなカウントを作成するのに、3つコメント付の挿入があります。
// Code of the independent counter if (GlobalVariableCheck("TestsCnt")==false || Counter == 1) { TestsCnt = 0; GlobalVariableSet("TestsCnt",0); } else { TestsCnt = GlobalVariableGet("TestsCnt"); }
// Code of the independent counter TestsCnt++; GlobalVariableSet("TestsCnt",TestsCnt);
// Code of the independent counter GlobalVariableDel("TestsCnt");
そして最後に。注意深い読者の方は、変数 FilePtr(とそれに伴うグローバル変数)を使わなくてもできることにお気づきでしょう。データはファイルの末尾に書かれ、最初から読みだされるのです。それでは、それは何のためなのでしょうか?答えは以下です。:この Expert Advisor は最適化維持方法を説明するためのものです。この方法で前回の検証結果によって急いで動作を管理することができます。そしてここで、独立カウンターと共に、スルーファイルポインタがかなり有用なのです。急いで前回結果を処理する必要のあるタスク例として、サンプル外検証の管理および自分の遺伝的アルゴリズム実装を挙げることができます。
おわりに
この課題に対する興味の元はフォーラム http://forum.mql4.comのトピックにありました。
MetaQuotes Ltdによってロシア語から翻訳されました。
元の記事: https://www.mql5.com/ru/articles/1498



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