連続ウォークフォワード最適化(パート4):最適化マネージャ(オートオプティマイザ)

11 6月 2020, 17:10
Andrey Azatskiy
0
434

イントロダクション

これは"連続ウォークフォワード最適化(Continuous Forward Optimization)" のシリーズものの記事です。 ここでは、プログラムされた自動最適化を実装する作成されたプログラムを紹介します。 以前の記事では、生成された最適化レポートを操作するために使用する、ターミナル側とライブラリ側の両方でのプログラム実装の詳細について説明しました。 以下のリンクから記事をチェックすることができます。

  1. 連続ウォークフォワード最適化(パート1):最適化レポートの操作
  2. 連続ウォークフォワード最適化(パート2):ロボットの最適化レポート作成機構
  3. 連続ウォークフォワード最適化(パート3):ロボットをオートオプティマイザに適応させる

現在の記事では、作成されたプロダクトの一般的な図を示し、インストラクションとして機能します。 作成された自動オプティマイザの機能は拡張できます。 したがって、アルゴリズムは、任意の希望のアイデアを実装できるように、独自の最適化アルゴリズムに置き換えることができます。 また、作成されたプログラムの内部構造を示します。 この記事の主な目的は、結果として得られるアプリケーションとその機能を操作するメカニズムについて説明することです。 実は、私の同僚は今回のテーマをすぐに理解するのは難しいと言っていました。 しかし、自動オプティマイザはセットアップと使用が簡単です - そして、そのさらに先を示します。 したがって、この記事はアプリケーションの使用法として扱われ、考えられるすべての落とし穴と設定の詳細を説明します。


自動オプティマイザ操作の説明

作成したプログラムの分析を進めるには、まずこのプロジェクトの目的を定義する必要があります。 トレードに科学的なアプローチを使用することを決定し、明確にプログラムされたトレードアルゴリズムを作成し始めました(インジケータベースのロボットを扱うか、ファジーロジックとニューラルネットワークを使用している人を扱うかどうかにかかわらず、すべては特定のタスクを実行するプログラムアルゴリズムです)。 したがって、最適化結果の選択に対するアプローチも形式化する必要があります。 言い換えれば、トレードプロセスでランダム性を適用することを拒否している間に、トレードの準備プロセスも自動化されるべきです。 それ以外の場合は、システムトレードよりも直感に近いランダムに好きな結果を選択できます。 このアイデアは、このアプリケーションを作成することを奨励した最初の動機です。 次の例は、アルゴリズムを最適化してテストします 。   


連続的なウォークフォワード最適化は、特定の時間間隔でのヒストリー(黄色)と前方(緑)最適化パスの間で交互に行われます。 例えば、10年分のヒストリーがあるとします。 最適化期間は、1 年に等しい間隔と 1 4半期 (または 3 か月) の順方向の間隔で構成する必要があります。 その結果、1つの最適化合格+フォワードテストの1.25年(1年+14半期)に等しい間隔があります。 図では、各行がこの時間間隔を特徴付けます。 

次に、同じタイプのプロセスを作成します。

  1. 選択したヒストリー期間(1年)で最適化します。
  2. 固定メソッドを使用して、最適化間隔の結果の中から最適なパラメータを選択します。
  3. 転送時間間隔に移行し、テストを実行し、最初のステップに戻ります。 現在の期間に達するまで繰り返します。
  4. 各4半期のテスト結果を収集した結果、アルゴリズムの実行可能性の最終評価を取得します。
  5. 直近の最適化パス(フォワードテストがない)は、トレードに移ることができます。

そこで、最適化を通じてアルゴリズムの持続可能性をテストする方法を得ます。 ただし、この場合は、転送期間の満了ごとにアルゴリズムを再最適化する必要があります。 言い換えれば、アルゴリズムの再最適化の一定の間隔を設定し、パラメータを選択するための方法論を修正し、最初にヒストリーにこのステップを実行し、後で、フォワードテスト期間に等しいトレード期間が満了するたびに繰り返します。 

まず、この最適化手法は、人の介入から解放された結果を受け取ることができる明確に定義された最適化ロジックを持ちます。

第2に、同様の手法を用いて新しい資産や新しいアルゴリズムの最適化を行うことで、アルゴリズムのストレステストの全体像を把握できます。 パラメータ選択方法と最適化パラメータの両方が、すべてのフォワード最適化で固定され、変更されていない場合、継続的なストレステストを受け、相場が戦略に適さなくなった場合に気づくことが可能になります。

第3に、実行されたテストの信頼性を高める、小さな期間内に多くの最適化フレームを受け取ります。 たとえば、上記の分割を 1 年の最適化と 1/4 の順に行う場合、2 年間隔で 4 つのストレス テストと 1 つの最終最適化を行います。


最適化起動セットアップ

アプリケーションが実行するプロセスについて説明したので、その使用方法を考えてみましょう。 この一連の記事は、最適化プロセス管理のグラフィカルインタフェースに関する以前の記事の論理的な継続です:

  1. 最適化管理 (パートI)
  2. 最適化管理(パートII)

この記事では、制御されたプロセスとしてターミナルで最適化またはテストを実行する方法について説明します。 同じ方法をこのシリーズで使用します。 しかし、基本的な差の1つは、制御プロセスがターミナルへの追加としてではなく、独立したプログラムとして実装されるということです。 この方法では、コンピュータにインストールされているすべてのターミナルを使用できます。 前の一連の記事では、タスクターミナルから起動できる拡張機能を作成しました。 拡張機能は、起動されたものに加えて、コンピュータにインストールされているすべてのターミナルで使用することができます。 現在のアプリケーションは、コンピュータにインストールされているすべてのターミナルにアクセスできますが、一度に1つのターミナルでのみ動作し、任意のターミナルを起動できます。

自動オプティマイザの正常な動作を保証するには、アプリを起動する前に、選択したターミナルが閉じられていることを確認します。 

アプリケーションは次のように動作します。

  1. 次のプロセスの起動中に、最適化またはテストのいずれであっても、アプリケーションはターミナルを起動し、テストプロセス全体をターミナルに委任します。 テストまたは最適化が完了すると、ターミナルはシャットダウンします。
  2. テストまたは最適化の後、ロボットは最適化結果を含むレポートを生成します(詳細については、このシリーズの前の記事をお読みください)。
  3. 自動オプティマイザはレポートの場所を認識するため、レポートの読み取りと処理を行います。 処理が完了すると、新しい最適化とテストの段階が起動されるか、最適化が完了し、結果が "Result" タブに表示されます。 

実装された最適化メカニズムは後で検討されますが、現在の部分の目的は、プログラムの操作プロセスを最小限のテクニカル要素で記述することです。 最適化を担当するコード部分に独自のアルゴリズムを追加できることを忘れないでください。 自動オプティマイザーは、最適化プロセスを開始する制御プログラムですが、プロセスのロジックは異なる場合があります。 次の図は、結果のアプリケーションのメイン タブのスクリーンショットです。


スクリーンショットを詳しく見ると、最初のコンボボックスは "Optimiser" と呼ばれ、緑色の領域に位置し、プログラムに実装されている最適化の種類の選択を提供します。 

アプリケーションのグラフィカルインターフェイスは、2つの主要なタブに分かれています。 メインタブは[設定]です。 ここで、最適化を起動またはストップする必要があるときにタスクを開始します。 このタブは、第2部で詳細に説明しました。もう 1 つのタブ "結果" は、最適化結果が表示される場所です。

まず、オートオプティマイザを起動する際には、使用するターミナルを選択する必要があります。 ターミナル選択の原則は、最適化の起動に使用した以前のグラフィカル・インターフェースと同じです。 つまり、自動オプティマイザは、このコンピュータにインストールされているすべてのターミナルを検索します(ただし、標準インストールを使用するターミナルのみを検出し、ポータブルターミナルを使用しない場合)。 

"設定"タブは4つのセクションに分かれています。 各画面部分の枠線をドラッグできます。 インプットパラメータが多いアルゴリズムを操作する場合に特に便利です。

  • 画面の最初の部分は、MetaTraderオプティマイザからのパラメータのリストを提供します。 EA「エキスパート」のリストは、選択したターミナルが変更されるたびに更新されます。 このリストには、選択したターミナルの適切なディレクトリに配置されているすべてのEAがあります。 EAは、ネストになったディレクトリを考慮して指定します。 
  • 画面の 2 番目の部分には、選択したアルゴリズムのパラメータのリストがあります。 パラメータのリストは、"MQL5/Profiles/Tester/{Expertname}.set"にある適切なファイルにあります。 選択したEAのファイルがない場合は、最初の画面領域でEAを選択した後、テスターのあるターミナルが最初に開きます。 その後、リクエストされたファイルがデフォルト設定で作成されます。 その後、ターミナルを閉じます。 このリストは、"利用可能なエキスパート"リストから別のEAを選択するたびに変更されます。 ロードされたパラメータの一覧を更新する場合は、"Update (*.set) ファイル" をクリックするだけで、その後、ターミナルを開いて閉じてリストが更新されます。 この前に、既存のファイルが削除され、同じディレクトリの下に新しいファイルが作成されます。
  • 画面の 3 番目の部分には、アンロードされたデータの配列のフィルタ処理と並べ替え条件の一覧という重要なパラメータがあります。 このシリーズの最初の記事では、並べ替えステップについて詳しく説明しました。 最初の記事で説明したように、フィルタ条件は">=", "<=", "< || >"などです。 
  • 画面の 4 番目のセクションには、一連の転送時間とヒストリーの時間が経過します。 このインターバルの論理は上述しました。 パス間のソートと相互作用の実装は、このサイクル内の最初の記事で取り上げられました。 最適化されていないテストを起動する場合 (パラメータOptimisation model = Disabled)、このフィールドには、1 つのヒストリー時間間隔または 2 つの間隔 (ヒストリーと前方) のいずれかを指定する必要があります。 オートオプティマイザの起動時にデータをインプットすることは退屈な(自身の経験で検証される)ため、データをファイルに保存するメカニズムが実装されました。 [保存/読み込み]をクリックすると、パラメータのリストにインプット済みのデータが利用可能かどうかがチェックされます。 リストがインプットされている場合は、受信したパラメータをファイルに保存します。 リストが空の場合、最適化の日付が渡されたリストがロードされるファイルが選択されます。 内部ファイル構造については、さらに詳しい記事で説明します。 プログラムによって生成された他のすべてのファイルと同様に、このファイルは xml 形式です。 日付インプット形式は "DD.MM.YYYY であることに注意してください。一方、データ表示フォーマットは"MM.DD.YYYY"です。 これは、日付が自動的に文字列に変換されるためです。 これが、この動作を変更しないことに決めた理由です。      

また、セットファイルのテキスト形式のため、アルゴリズムパラメータの形式を区別することはできません。 たとえば、すべての列挙型パラメータは int として表示されます。 そのため、画面の2番目の部分にパラメータのリストを文字列として表示することにしました。 自動オプティマイザで最適化ステップやその他のロボットパラメータを直接設定するのが便利でない場合は、ターミナルで必要なすべての設定を実行できます。 テスターのタブを変更した後(またはターミナルが閉じられた後)、設定は目的のファイルに書き込まれます。 必要性があるのは、自動オプティマイザで必要なアルゴリズムを選択することだけです - 設定ですぐにロードされます。

最適化または自動オプティマイザからのテストを開始するには、以下のフィールドを設定する必要があります。

  1. EAの選択
  2. 最適化するパラメータを確認し、範囲を選択します(ターミナルと同様)。
  3. 少なくとも 1 つのソート基準を選択: ロボットによって生成されるデータのソートに影響し、結果の最良のものは、順方向に起動されます (テスト実行では省略できます)。
  4. ウォークフォワード最適化の日付(またはテストを実行する場合はテスト日)を選択します。   
  5. 最適化を実行する場合は、必要なオプティマイザを選択します ("Optimiser を選択:"ドロップダウン リスト)。 
  6. "資産名(Asset Name)" — リクエストされた操作を実行するシンボルの名前を指定します。 エラーが発生した場合、ターミナルはテストまたは最適化を実行できません。
  7. "ディレクトリプレフィックス" を使用して、保存する最適化パスの名前を追加指定できます。 最適化結果を含むフォルダは、最適化終了後に特別な内部プログラムディレクトリに作成されます。 フォルダ名は次のように設定されます: "{Directory prefix} {Selected optimiser} {Expert name} {Asset name}" これらが"最適化:"に示されている名前です。リストを表示し、さらに分析するためにアップロードすることができます。
  8. "Rewrite" または "Append"パラメータを含むドロップダウン リストもオプションです。 このダイアログ ボックスは、保存されたファイル間で同じ名前の結果を見つけた場合に、自動オプティマイザが実行するアクションを設定します。 "Rewrite" を選択すると、すべてのファイルが新しいファイルで書き換えられます。 "Append" が選択されている場合、対応する最適化の日付は上書きされます。 現在の最適化間隔のリストと、以前に保存された間隔のリストに同じ間隔が見つかった場合、保存された結果は新しい間隔で上書きされます。 範囲が新しい場合は、既存の範囲に追加されます。

セットアップが完了したら、[開始/ストップ]をクリックしてプロセスを起動します。 このボタンを繰り返しクリックすると、最適化プロセスが中断されます。 最適化プロセス中、そのステータスは プログレスバー(ProgressBar)と自動オプティマイザウィンドウの下部にあるテキストラベルに表示されます。 最適化の終了後、最適化結果は "結果" タブにアップロードされ、ProgressBar は初期状態にリセットされます。 ただし、"スタート/ストップ"をクリックしてテストを実行すると、ターミナルは自動的に閉じられます。 これは便宜上行われ、必要なデータをすべて調べることができます。 必要なデータを調べていると、手動でターミナルを閉じて、自動オプティマイザの操作を続行します。 アプリケーションは独立してターミナルを管理できなければならないので、ターミナルは常に閉じなければならないことを忘れないでください。

また、最適化を起動する前に、オプティマイザ自体を構成する必要があります。 必須要件ではありませんが、最適化マネージャーの構造によって、カスタムオプティマイザを作成したり、それぞれのパラメータを個別に設定したりできます。 設定は、オプティマイザセレクタのコンボボックスの横にある"GUI"ボタンをクリックして開くことができます。 実装されたオプティマイザの設定は次のとおりです。

  1. ティックでのテスト — ヒストリーテストおよびフォワードテストにおけるデータテストの方法を示します。 最適化方法は "Settings" ウィンドウの最初の部分で指定され、テストメソッドはオプティマイザー設定で示されます。 このオプションが有効な場合、ティックを使用してテストが実行されます。 無効にした場合、テストはOHLC 1分モードで実行されます。 
  2. 設定する実際の日付を置き換える — 実際の最適化の開始日と終了日を、渡された日付に置き換えるかどうかを設定します。 最適化の開始時間と終了時間は、1分の時間枠を使用して保存されます。 トレードがない場合や休日の場合、実際の開始日と終了日が指定の日付と異なる場合があります。 このオプションが有効になっている場合、オプティマイザはより使い慣れたデータを設定し、結果が属する間隔を確認します。 ただし、実際のトレード日を表示したい場合は、オプションをオフにします。
  3. ティックテストに異なるシフトを使用する - 2番目の記事では、スリッページとシフトを結果に追加できることを説明しました。 ティックをテストに使用する場合、スリッページを無効にしたり、完全に減らしたりすることができます。 このオプションは、この場合に対して正確に追加されました。 "ティック時のテスト" が有効になっている場合にのみアクティブになります。 このオプションを使用するには、コミッションとスリッページの表示を担当するアルゴリズムパラメータを指定し、新しい値を設定します。 スリッページを担当するロボットパラメータを指定し、0に設定すると、ティックテストモードで結果からスリッページを削除できます。 パラメータとその値を指定した後、"Add" パラメータを使用してこのパラメータをテーブルに追加して、このパラメータを保存します。

インプットしたパラメータは自動的に保存されるため、(保存ボタンはありません)、保存する必要はありません。 最適化プロセス中にパラメータが誤って変更されるのを防ぐために、最適化を起動する前にこのウィンドウを閉じます。 


最適化結果の操作

最適化を起動した後、プロセスに干渉しないでください。 また、オプティマイザがストップするまで、EAをチャートから削除しないでください。 そうしないと、オプティマイザはこの状況をエラーと見なします。 プロセスが完了し、ターミナルが閉じられると、オプティマイザは最適化レポートを[結果]タブにアップロードし、そこで完了したタスクを評価できます。 タブ構造は、以下のタブに表示されます。

 

結果タブも、説明を容易にするために数字でマークされている部分に分割されています。 最初の部分は、タブ間で分割された最適化パスを特徴としています(選択パスと最適化)。 "選択されたパス" という最初のコンテナタブには、選択した最適化パスがあります。 これらのパスは、2 つのタブ ("フォワード" と "ヒストリー") に分かれています。 タブ間で最適化パラメータがどのように分布されているかを見てみましょう。 たとえば、次の日付が指定されます。

  1. 01.01.2012 - 07.12.2012 - ヒストリー
  2. 10.12.2012 - 07.03.2012 - フォワード

最適化はヒストリー間隔で実行されます。 次に、最適なパラメータは、フィルタリングとソートを使用して選択されます(前の章の説明を参照)。 選択後に 2 つのテストが実行されます。 さらに、最良のパラメータのテスト結果は "選択されたパス" タブに追加され、"History" タブと "Forward" タブに分割されます。 最適化パスは "最適化" タブに追加され、ヒストリーの間隔の最適化の一覧全体を表示できます。 [最適化] タブの詳細を検討してください。


テーブル構造 ("最適化" タブの最初の部分) は、"進む" タブと "ヒストリー" タブの構造に似ています。 しかし、この表は、リクエストされた間隔内のすべての最適化パスを示します。 目的の時間間隔は、"最適化日"コンボボックスから選択することができます。 新しい間隔を選択すると、最適化パスを持つテーブル全体が更新されます。 タブの 2 番目の部分は、"Settings" ウィンドウの 3 番目の部分に似ており、タブのすべての変更が同期されます。

"最適化" タブと"選択されたパス"タブには、"保存先(*.csv)"ボタンがあります。 このボタンをクリックすると、"選択パス"、ヒストリーと転送の最適化パスのリストを含む*.csvファイルが作成されます。 ボタンをクリックすると "最適化"、実行されたすべての最適化に関する情報が適切な *csv ファイルにダウンロードされます。 ボタン"並べ替え" と "フィルタ" は、"最適化" タブでのみ使用できます。 その目的は、"最適化"タブの2番目の部分で指定された設定に従って、結果の最適化パスのフィルタリングとソートを提供することです。 実際には、自動オプティマイザは同じメカニズムを使用するため、このオプションは必要ありません。 ただし、このオプションでは、任意のカスタム フィルタを使用できます。 

どちらのテーブルもインタラクティブです。 テーブル行を 1 回クリックすると、選択した最適化パスに従って "Result" タブの 2 番目と 3 番目の部分が更新されます。 ダブルクリックすると、ターミナルでテストが開始されます。 この場合、ターミナルはテスト終了後に閉じられます。 したがって、結果を調査した後、手動で閉じる必要があります。 テストを開始する前に、テストのパラメータの一部を構成できます。

  

テストの開始日と終了日は、選択した時間間隔に従って自動的に更新されます。 ただし、目的の行をダブルクリックすることで変更できます。 また、実行遅延とテストの種類(ティック、OHLCなど)を選択することもできます。 "遅延なし"と"すべてのティック"はデフォルトで設定されています。 

タブの 3 番目の部分には、選択した最適化パス (日 PL と最大 PL/DD) のトレード統計と、選択したパスのロボット パラメータ (Bot params タブ) が表示されます。 "最大PL/DD"タブには、最終的な損益の値は表示されませんが、総利益(すべての収益性の高いトレードの合計)と合計損失(すべての損失トレードの合計)のみが表示されます。 トレード完了時に登録された利益と最大ドローダウンが、最適化とテスト結果とともに表に表示されます。 [日次 PL] タブには、ターミナルで利用可能なレポートと同様に、1 日の平均利益と 1 日の平均損失が表示されます。

オートオプティマイザを操作するためのもう一つの最も簡単なアルゴリズム

オートオプティマイザを使用して機能するロボットの準備例を考えてみましょう。 このシリーズの第 3 の記事では、アルゴリズム テンプレートを既に検討しました。 さて、Cスタイルのアルゴリズムにテンプレートを適応させましょう。 まず、アルゴリズム自体を考察します。 2移動平均のアルゴリズムです。 ポジションは固定 ストップロス または固定TPによって決済されます。 EAロジックを記述する関数の実装は、以下のコードから削除されます。

//+------------------------------------------------------------------+
//|                                                     SimpleMA.mq5 |
//|                        Copyright 2019, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2019, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"

#include <Trade/Trade.mqh>
#define TESTER_ONLY

input int ma_fast = 10; // MA fast
input int ma_slow = 50; // MASLow
input int _sl_ = 20; //SL
input int _tp_ = 60; //TP
input double _lot_ = 1; // Lot size

int ma_fast_handle,ma_slow_handle;
const double tick_size = SymbolInfoDouble(_Symbol,SYMBOL_TRADE_TICK_SIZE);
CTrade trade;

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---

#ifdef TESTER_ONLY
   if(MQLInfoInteger(MQL_TESTER)==0 &&
      MQLInfoInteger(MQL_OPTIMIZATION)==0)
     {
      Print("This expert was created for demonstration! It is not enabled for real trading !");
      ExpertRemove();
      return(INIT_FAILED);
     }
#endif

   ma_fast_handle = iMA(_Symbol,PERIOD_CURRENT,ma_fast,0,MODE_EMA,PRICE_CLOSE);
   ma_slow_handle = iMA(_Symbol,PERIOD_CURRENT,ma_slow,0,MODE_EMA,PRICE_CLOSE);

   if(ma_fast_handle == INVALID_HANDLE ||
      ma_slow_handle == INVALID_HANDLE)
     {
      ExpertRemove();
      return(INIT_FAILED);
     }
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   if(ma_fast_handle != INVALID_HANDLE)
      IndicatorRelease(ma_fast_handle);
   if(ma_slow_handle != INVALID_HANDLE)
      IndicatorRelease(ma_slow_handle);
  }

enum Direction
  {
   Direction_Long,
   Direction_Short,
   Direction_None
  };

//+------------------------------------------------------------------+
//| Calculate stop                                                   |
//+------------------------------------------------------------------+
double get_sl(const double price, const Direction direction)
  {
   ...
  }

//+------------------------------------------------------------------+
//| Calculate take                                                   |
//+------------------------------------------------------------------+
double get_tp(const double price, const Direction direction)
  {
   ...
  }

//+------------------------------------------------------------------+
//| Open position according to direction                             |
//+------------------------------------------------------------------+
void open_position(const double price,const Direction direction)
  {
   ...
  }

//+------------------------------------------------------------------+
//| Get direction                                                    |
//+------------------------------------------------------------------+
Direction get_direction()
  {
   ...
  }

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
   if(!PositionSelect(_Symbol))
     {
      Direction direction = get_direction();
      if(direction != Direction_None)
         open_position(iClose(_Symbol,PERIOD_CURRENT,0),direction);
     }
  }
//+------------------------------------------------------------------+

このEAコードは基本的です。 EAをオートオプティマイザで利用できるようにするために、生成する必要がある変更を分析する必要があります。 

このタスクは、効率的なEAを必要としなかったことに注意してください。ほとんどの場合、このロボットは負けるでしょう。 EAには、実際のトレードでの偶発的な起動を回避するための制限があります。 制限を削除するには(そしてトレードで起動できるようにするには)TESTER_ONLYの定義をコメントします。 

OnOnit で行うことは、移動平均インジケータをインスタンス化することです。 したがって、インジケータはOnDeinitで削除する必要があります。 コードで宣言されたDirection列挙型は、方向を決定するために使用します。 ポジションは、open_position関数の CTrade クラスによって開かれます。 ロジック全体は、OnTick コールバックの 4 つのコード行で記述されています。 次に、必要な関数の接続をロボットに追加しましょう。

//+------------------------------------------------------------------+
//|                                                     SimpleMA.mq5 |
//|                        Copyright 2019, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2019, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"

#include <Trade/Trade.mqh>
#include <History manager/AutoLoader.mqh> // Include CAutoUploader
#define TESTER_ONLY

input int ma_fast = 10; // MA fast
input int ma_slow = 50; // MASLow
input int _sl_ = 20; //SL
input int _tp_ = 60; //TP
input double _lot_ = 1; // Lot size

// Comission and price shift (Article 2) 
input double _comission_ = 0; // Comission
input int _shift_ = 0; // Shift

int ma_fast_handle,ma_slow_handle;
const double tick_size = SymbolInfoDouble(_Symbol,SYMBOL_TRADE_TICK_SIZE);
CTrade trade;
CAutoUploader * auto_optimiser; // Pointer to CAutoUploader class (Article 3)
CCCM _comission_manager_; // Comission manager (Article 2)

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---

#ifdef TESTER_ONLY
   if(MQLInfoInteger(MQL_TESTER)==0 &&
      MQLInfoInteger(MQL_OPTIMIZATION)==0)
     {
      Print("This expert was created for demonstration! It is not enabled for real trading !");
      ExpertRemove();
      return(INIT_FAILED);
     }
#endif

   ma_fast_handle = iMA(_Symbol,PERIOD_CURRENT,ma_fast,0,MODE_EMA,PRICE_CLOSE);
   ma_slow_handle = iMA(_Symbol,PERIOD_CURRENT,ma_slow,0,MODE_EMA,PRICE_CLOSE);

   if(ma_fast_handle == INVALID_HANDLE ||
      ma_slow_handle == INVALID_HANDLE)
     {
      ExpertRemove();
      return(INIT_FAILED);
     }

   // Set Commission and shift
   _comission_manager_.add(_Symbol,_comission_,_shift_);

   // Add robot params
   BotParams params[];
   APPEND_BOT_PARAM(ma_fast,params);
   APPEND_BOT_PARAM(ma_slow,params);
   APPEND_BOT_PARAM(_sl_,params);
   APPEND_BOT_PARAM(_tp_,params);
   APPEND_BOT_PARAM(_lot_,params);
   APPEND_BOT_PARAM(_comission_,params);
   APPEND_BOT_PARAM(_shift_,params);

   // Add Instance CAutoUploader class (Article3)
   auto_optimiser = new CAutoUploader(&_comission_manager_,"SimpleMAMutex",params);
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   if(ma_fast_handle != INVALID_HANDLE)
      IndicatorRelease(ma_fast_handle);
   if(ma_slow_handle != INVALID_HANDLE)
      IndicatorRelease(ma_slow_handle);

   // Delete CAutoUploaderclass (Article 3)
   delete auto_optimiser; 
  }

enum Direction
  {
   Direction_Long,
   Direction_Short,
   Direction_None
  };

//+------------------------------------------------------------------+
//| Calculate stop                                                   |
//+------------------------------------------------------------------+
double get_sl(const double price, const Direction direction)
  {
   ...
  }

//+------------------------------------------------------------------+
//| Calculate take                                                   |
//+------------------------------------------------------------------+
double get_tp(const double price, const Direction direction)
  {
   ...
  }

//+------------------------------------------------------------------+
//| Open position according to direction                             |
//+------------------------------------------------------------------+
void open_position(const double price,const Direction direction)
  {
   ...   
  }

//+------------------------------------------------------------------+
//| Get direction                                                    |
//+------------------------------------------------------------------+
Direction get_direction()
  {
   ...
  }

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
   auto_optimiser.OnTick(); // Save current date (Article 3)

   if(!PositionSelect(_Symbol))
     {
      Direction direction = get_direction();
      if(direction != Direction_None)
         open_position(iClose(_Symbol,PERIOD_CURRENT,0),direction);
     }
  }
//+------------------------------------------------------------------+

新しい追加はすべて緑色でマークされます。 外観の順に考えてみましょう。 まず、3番目の記事で説明した AutoLoader ヘッダファイルを接続します。 このファイルには、累積トレーディングヒストリーをダウンロードする CAutoUploader クラスがあります。 OnInit コールバックでは、2番目の記事で説明した適切な CCCM クラスにコミッションを追加します。 また、EAパラメータを追加した後に CAutoUploader クラスをインスタンス化します。 CAutoUploader クラスのインスタンスは、トレードレポートが xml ファイルに保存されるデストラクタの呼び出しを初期化する OnDeinit コールバックで削除されます (記事 1)。 

EAロジックは変更されませんが、CAutoUploader クラスの OnTick メソッドが呼び出される OnTick コールバックを除いてです。 このリクエストにより、テストの開始日と終了日を正しく保存できます。 CAutoUploader クラスはテスターでのみ動作し、実際のトレードではアクションを実行しません。 


結論

この記事では、作成した最適化マネージャの関数について説明しました。 この記事の冒頭で既に説明したように、この記事は、結果として生成されるアプリケーションの取説になります。 アプリケーション実装の技術的側面については、さらなる記事で説明します。 この記事には、次のものが添付されています。

  • 自動オプティマイザープロジェクト
  • 記載されたEAコード

自動オプティマイザ プログラムを実行するには、Visual Studio IDE を使用してコンパイルします。 MQL5/Include/Librariesディレクトリには、最初の記事で説明した "ReportManager.dll" ライブラリが含まれている必要があります。 また、アタッチされた自動オプティマイザプロジェクトでも使用できます(コンパイルが必要です)。    

MetaQuotes Software Corp.によりロシア語から翻訳された
元の記事: https://www.mql5.com/ru/articles/7538

添付されたファイル |
Auto_Optimiser.zip (125.71 KB)
DoEasyライブラリの時系列(第35部): バーオブジェクトと銘柄の時系列リスト DoEasyライブラリの時系列(第35部): バーオブジェクトと銘柄の時系列リスト

本稿は、簡単で迅速なプログラム開発のためのDoEasyライブラリの作成に関する新しいシリーズの始まりとなります。本稿では、銘柄の時系列データにアクセスして操作するためのライブラリ機能を実装します。メインおよび拡張時系列バーデータを格納するバーオブジェクトを作成し、オブジェクトの検索と並び替えを容易にするために、時系列リストにバーオブジェクトを配置します。

トレードシグナルの多通貨監視(パート2):アプリケーションのビジュアル部分の実装 トレードシグナルの多通貨監視(パート2):アプリケーションのビジュアル部分の実装

前回の記事では、アプリケーションフレームワークを作成し、以降のすべてのタスクの基礎としました。 このパートでは、開発工程を進めます: アプリケーションのビジュアル部分を作成し、インターフェイス要素の基本的な相互作用を構成します。

このプロジェクトは、収益性の高いトレーディングロボットを作成する手助けになります! 少なくとも、そうなるでしょう。 このプロジェクトは、収益性の高いトレーディングロボットを作成する手助けになります! 少なくとも、そうなるでしょう。

大きなプログラムは小さなファイルから始まり、関数やオブジェクトを追加し続けるにつれてサイズが大きくなります。 ほとんどのトレードロボット開発者は、この問題を処理するためにインクルードファイルを利用しています。 しかし、より良い解決策があります。:それは、プロジェクト内の任意のトレードアプリケーションの開発を開始することです。 そうする理由はたくさんあります。

時系列の予測(第1部):経験的分解モード(EMD)法 時系列の予測(第1部):経験的分解モード(EMD)法

この記事では、経験的分解モードに基づいて時系列を予測するアルゴリズムの理論と実際の使用法について説明します。また、このメソッドのMQL実装を提案し、テスト指標とエキスパートアドバイザーを提示します。