English Русский 中文 Español Deutsch Português
preview
Frames Analyzerツールによるタイムトレード間隔の魔法

Frames Analyzerツールによるタイムトレード間隔の魔法

MetaTrader 5テスター | 11 1月 2023, 09:41
224 0
Anatoli Kazharski
Anatoli Kazharski

内容


はじめに

この記事では、あらゆる取引アルゴリズムの最適化結果を詳しく調べることができる、かなり興味深いツールを紹介したいと思います。最小限の労力とコストで、実際の自動取引の結果を改善することさえ可能です。

Frames Analyzerとは何でしょうか。これは、パラメータ最適化の直後に作成されたMQDファイルまたはデータベースを読み取ることにより、ストラテジーテスター内外でパラメータ最適化中に最適化フレームを分析するためのエキスパートアドバイザー(EA)のプラグインモジュールです。

3年以上前に実装されたのですが、この形式ではどこにもデモされていない独自のソリューションです。MQLコミュニティのアクティブなメンバーfxsaberによって、初めてそのアイデアが詳細に策定され、コードに実装されました。

最適化フレーム分析アプリケーションのいくつかの中間実装は、私の記事のいくつかでカバーされています。

これらすべてのアイデアを組み合わせることで、かなり興味深く有益なツールが得られました。この記事で詳しく説明します。


ツールの説明

このモジュールには、EasyAndFastGUI v2.0ライブラリを使用して作成されたグラフィカルインターフェイスが組み込まれており、追加のコーディングは必要ありません。MQLアプリケーションのいくつかの主要な機能に接続する必要があります(以下を参照)。

グラフィカルインターフェイスは、いくつかのセクションで構成されています。それらを見ていきましょう。


[Frames]タブ

要素は次の通りです。

  • 最適化フレームを含むデータベースを開くための[Open DB]ボタン:このボタンはFrames Analyzerでのみ表示されます。テスターの外部では、EAはパラメータ最適化後にEAによって作成されたDBファイルの読み取りモードで動作します 
  • 最適化フレームを含むMQDファイルを開くための[Open MQD-file]ボタン:このボタンはFrames Analyzerでのみ表示されます。テスターの外部では、パラメータの最適化後にテスターによって作成されたMQDファイルの読み取りモードでEAが動作します(これは、有料配布用のバージョンでは削除される予定です)
  • チャートに同時に表示される残高の数を指定するための[Curves total]入力フィールド
  • フレームの再生を開始するための[Replay frames]ボタン
  • 残高グラフ(最適化結果)
  • すべての結果(利益/損失)のグラフ

Frames AnalyzerモジュールがライブラリとしてEAに接続されている場合、Frames Analyzer EAを含むグラフがパラメータの最適化中にテスターで開かれ、すべての中間結果(残高)をすぐに確認することができます。 

パラメータ最適化中の結果の視覚化

パラメータ最適化中の結果の視覚化


[Results]タブ

上部に2つの表があります。

  • 結果をお気に入りに追加するための[Add to favorites]ボタン
  • 不採算系列の除外区間数を指定するための[Removed intervals]入力フィールド
  • 指定された基準に従って結果を選択するためのCriterionドロップダウンリストを含むコンボボックス
    • Profit - 最大残高によって合計数から100件の結果が選択される(他の基準も同様)
    • Trades - 最大取引数によって100件の結果が選択される
    • DD(ドローダウン)- 最小ドローダウンによって100件の結果が選択される
    • RF(リカバリーファクター)- 最大回復係数によって100件の結果が選択される
    • BI_プレフィックスを持つ同じ基準は、一連の不採算の取引を除外した後の同じ値を示します。
  • 上位100の最大残高結果を含む表:改善された結果に関連する列セル(BI_プレフィックスを特徴とする)は、視覚的にすばやく区別できるように異なる色になっています(下のスクリーンショットを参照)。外部パラメータを含む列セルも独自の色で強調表示され、すばやく識別できます。
  • 取引履歴から損失期間を削除した後の結果とすべての中間結果を含む表

マウスカーソルが特定の表に合わせられた場合、UPDOWNPAGEUPPAGEDOWNHOMEENDキーを使用して行を切り替えることができます。LEFTRIGHTキーを使用すると、表を最初から最後まで水平方向にすばやくナビゲートできます。

下部には、[Balances]と[Top 100 results]の2つのタブがある領域があります。それらを見ていきましょう。


[Balances]タブ

ここには2つのグラフがあります。

  • 左側には、一連の負け取引を削除した後の初期残高とすべての中間改善結果を示すチャートがあります。不採算系列を除外した後の残高グラフの変化がわかります。
  • 右側には、残高の最終結果が改善されたグラフ(左側のチャートで最高)と、各取引期間のすべての残高が個別に示されています。

グラフは、表内の行を強調表示することによっても更新されます。

結果の最終残高と不採算区間を除いた改善残高

結果の最終残高と不採算区間を除いた改善残高


[Top100 results]タブ

ここにも2つのグラフがあります。

  • 左側には、上位100の収益結果のグラフがあります。
  • 右側には、指定された基準(ProfitTradesDDRFBI_ProfitBI_TradesBI_DDBI_RF)による上位100件の結果のグラフがあります。

表の行を強調表示すると、グラフの結果が更新されます。たとえば、以下では、左側で強調表示されている結果(黒の残高曲線)と、右側のグラフで一連の取引の損失を除外した後の結果を確認できます。

不採算区間を削除した後の最終的な改善された最良の100の残高

不採算区間を削除した後の最終的な改善された最良の100の残高

結果を改善するために、履歴から削除する不採算区間の数を指定することもできます。

一連の不採算取引が検出された期間を除外しながら、これらのEAパラメータで取引を継続することで、トレーダーは取引結果を大幅に改善できると考えられます。実際、一見採算の取れない取引アルゴリズムでさえ、このアプローチで採算が取れる場合があります。

前述のように、お気に入りの結果は適切な表に保存できます。これをおこなうには、[Add to favorites]ボタンを使用します。追加された結果は、全体の結果の表で別の色で強調表示されます。

お気に入りに追加された結果は別の色で強調表示される

お気に入りに追加された結果は別の色で強調表示される


[Favorites]タブ

このタブには、2つの表と2つのグラフもあります。すべてのパラメータの背後にある考え方は、[Results]タブと同じです。唯一の違いは、これらの選択した結果をファイル(EAセット)およびデータベースに保存できることです。ここでは、表とグラフに加えて、次のボタンがウィンドウの上部にあります。

  • Delete selected - 選択した結果を、左側の表のお気に入りとデータベースから削除する
  • Delete all - すべての結果を左側の表のお気に入りとデータベースから削除する
  • Save parameters - パラメータをファイルとデータベースに保存する

選択した結果のデータとグラフ

選択した結果のデータとグラフ

選択したすべての結果をお気に入りとして保存するには、[Save parameters]をクリックします。

  • データベース(FAVORITE_RESULTSの表)
  • ファイル: MQL5/Files/Reports/FramesA/[CURRENT_TIME] - MQDファイル読み込みモードの場合
  • MQL5/Files/Reports/[CURRENT_TIME][EXPERT_NAME] - FRAME_MODEの場合(最適化直後)

すべての結果は、パス番号がフォルダ名として使用される別のフォルダに保存されます。上記の表とチャートの外部EAパラメータといくつかのスクリーンショットを含む設定ファイルです。パス番号は、すべてのファイルの名前のプレフィックスとして使用されます。

  • 422462.set - 外部EAパラメータを含む設定ファイル
  • 422462_balance_sub_bi.png - 不採算の一連の取引があるすべての期間を除外した後の残高のスクリーンショットと、残りの期間ごとに個別にすべての残高
  • 422462_balances_bi.png -不採算の一連の取引ですべての期間を除外した後のすべての残高のスクリーンショット
  • 422462_bi_table.png - 不採算の一連の取引ですべての期間を除外した後のすべての最終結果を含む表のスクリーンショット
  • 422462_gui.png - 完全なGUIスクリーンショット

次は、EAパラメータを含むサンプル設定ファイルです。

; this file contains last used input parameters for testing/optimizing FA expert advisor
; Experts\Advisors\ExpertMACD.ex5
;
Inp_Expert_Title=ExpertMACD||0.0||0.0||0.0||N
Inp_Signal_MACD_PeriodFast=15||5.0||5.0||30.0||Y
Inp_Signal_MACD_PeriodSlow=25||5.0||5.0||30.0||Y
Inp_Signal_MACD_PeriodSignal=25||5.0||5.0||30.0||Y
Inp_Signal_MACD_TakeProfit=270||30.0||5.0||300.0||Y
Inp_Signal_MACD_StopLoss=115||20.0||5.0||200.0||Y


最適化結果のデータベース

前述のように、Frames Analyzerは、テスターでパラメータを最適化した直後に、すべての最適化結果をデータベースに保存します。しかもそれだけではありません。パラメータを最適化するたびに、ターミナルのローカルディレクトリMQL5/Files/DBに新しいデータベースが作成されます。データベースの名前は、作成時の現在時刻とEAの名前で構成されます([CURRENT_TIME][EXPERT_NAME].db)。

全部で3つの表があります。

OPTIMIZATION_RESULTSには、次のデータ(列)が格納されます。

  • Pass - パスインデックス
  • Profit - 得られた利益
  • Trades - 取引数
  • PF - プロフィットファクター
  • DD - ドローダウン
  • RF - リカバリーファクター
  • すべてのEA外部パラメータを含む列:
    • パラメータ1
    • パラメータ2
    • など
  • Deals - 各パスの残高を計算するために使用される取引の履歴

すべての最適化パスに関するデータを含む表

すべての最適化パスに関するデータを含む表

EXPERT_PARAMETERSには、EAの外部パラメータと、パラメータの最適化中に配置されたディレクトリへの名前とパスが含まれています。表には次の2つの列があります。

  • Parameter - パラメータ名
  • Value - パラメータ値

以下は、ターミナルで標準内蔵されているExpertMACD EAのサンプルです。外部パラメータ(INPUT_n)の場合、[Value]列には、この最適化に使用される外部パラメータの名前と最適化パラメータ(||で区切られている)が保存されます。

EAデータ表

EAデータの表

EA操作に必要なその他のパラメータは、後で表に追加できます。

FAVORITE_RESULTSには、お気に入りとして選択された最適化結果が保存されます。ここには3つの列しかありません。

  • FavoriteID - ポジションID
  • Pass - OPTIMIZATION_RESULTS表内のすべてのデータを取得するパスのインデックス
  • RemovedIntervals - 実際の取引が無効になっているはずの削除済み間隔

期間が削除された一部の最適化結果の表

期間が削除された一部の最適化結果の表

したがって、将来のEA操作のために得られた結果の最適化と分析の後、データベースから必要なものすべてを取得できます。


Frames Analyzerツールの使い方

まず、このページでFrames Analyzerをダウンロードします。このEAをターミナルで実行すると、このツールには最適化結果が必要なため、Frames Analyzerのすべてのグラフと表が空であることがわかります。試してみたい場合は、最適化結果が添付されたデータベースファイルを以下にダウンロードしてください。このファイルをMQL5/Files/DBに配置します。これで、Frames Analyzer EAのグラフィカルインターフェイスからダウンロードできます。[Frames]タブで、[OpenDB]をクリックします。以下に示すように、ダイアログボックスが開き、データベースファイルを選択できます。このディレクトリには、すでにいくつかのデータベースファイルがあります。

ダイアログボックスでデータベースファイルを選択する

ダイアログボックスでデータベースファイルを選択する

Frames AnalyzerがEAの最適化結果を保存するには、それをライブラリとしてEAコードに含める必要があります。以下は詳細な例です。

Frames Analyzerをコンピュータにダウンロードすると、MQL5/Experts/Marketで見つけることができます。次に、次の方法でEAのメインファイル(*.mq5)に含めることができます。

#import "..\Experts\Market\FramesA.ex5"
  void OnEvent(const int id, const long &lparam, const double &dparam, const string &sparam);
  void OnTesterEvent(void);
  void OnTesterInitEvent(void);
  void OnTesterPassEvent(void);
  void OnTesterDeinitEvent(void);
#import

上記のように、Frames Analyzer EAからいくつかの関数をインポートする必要があります。これらは、GUI操作でイベントを処理したり、テスターでEAパラメータの最適化中にデータを収集したりするために必要です。以下に示すように、同様のEA関数でこれらの関数を呼び出すだけです。

//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) {
  FramesA::OnEvent(id, lparam, dparam, sparam);
}
//+------------------------------------------------------------------+
//| Test completion event handler                                    |
//+------------------------------------------------------------------+
double OnTester(void) {
  FramesA::OnTesterEvent();
  return(0.0);
}
//+------------------------------------------------------------------+
//| TesterInit function                                              |
//+------------------------------------------------------------------+
void OnTesterInit(void) {
  FramesA::OnTesterInitEvent();
}
//+------------------------------------------------------------------+
//| TesterPass function                                              |
//+------------------------------------------------------------------+
void OnTesterPass(void) {
  FramesA::OnTesterPassEvent();
}
//+------------------------------------------------------------------+
//| TesterDeinit function                                            |
//+------------------------------------------------------------------+
void OnTesterDeinit(void) {
  FramesA::OnTesterDeinitEvent();
}
//+------------------------------------------------------------------+

ご覧のとおり、ここではすべてが簡単です。

ところで、プロジェクトでEasyAndFastGUI v2.0ライブラリを使用してグラフィカルインターフェイスを作成する場合(ライブラリはFrames Analyzerの一部です)、それらが1つのMQLアプリケーションで連携するために必要なことは他に何もありません。EAに組み込まれているFrames Analyzerは、フレームモード(FRAME_MODE))で個別に動作し、アプリケーションのグラフィカルインターフェイスの操作を妨げません。

EasyAndFastGUI v2.0ライブラリがなくても、Frames Analyzerは動作します。

Frame Analyzerモジュールが組み込まれた標準内蔵のExpertMACD EAのサンプルを以下に添付します。


エキスパートアドバイザー(EA)で削除された間隔を適用する

これで、Frames Analyzerツールの準備ができました。それを取引EAに接続し、パラメータの最適化を実行しました。これで、すべての外部パラメータの値を持つすべてのパスの結果を含むデータベースができました。別の表に、お気に入りの最適化結果を期間を削除して保存しました。これを取引戦略に適用できるようになりました。

これを実装する方法を見てみましょう。

グラフィカルユーザーインターフェイスを介してタイムトレード間隔の選択を実装するとします。グラフィカルインターフェイスに削除された期間を視覚化する要素があればいいのですが、その間は取引が推奨されません。高度なGUIを作成するためのEasyAndFastGUI 2.0ライブラリをお持ちの場合は、そのような機会が既にあります。最新の更新の1つで、別のユニークな要素が追加されました。CTimeRangesです。これにより、期間で作業できます。次に、この要素を使用してGUIを作成し、より詳細に検討します。

GUIは次の要素で構成されます。

  • コントロールのフォーム - CWindow
  • データベースファイルを開くためのボタン - CButton
  • 選択された最適化結果の表からのパスインデックスを含むドロップダウンリスト - CComboBox
  • 取引に推奨されない間隔を示す時間スケール - CTimeRanges

このようなGUIを作成するには、数行のコードのみが必要です。

void CApp::CreateGUI(void) {

//--- Form
  m_window1.ResizeMode(true);
  m_window1.ThemeButtonIsUsed(true);
  CCoreCreate::CreateWindow(m_window1, "TIME TRADE RANGES", 1, 1, 350, 100, true, true, true, true);
  
//--- Button
  CCoreCreate::CreateButton(m_button1, m_window1, 0, "Open DB...", 10, 30, 100);
  
//--- Combobox
  string items1[] = {"12345", "19876", "45678", "23456", "67890"};
  CCoreCreate::CreateCombobox(m_combobox1, m_window1, 0, "Passes: ", 120, 30, 135, 90, items1, 103, 0);
  
//--- Time ranges
  string time_ranges[] = {
    "00:45:00 - 01:20:01",
    "08:55:00 - 09:25:01",
    "12:55:00 - 13:50:01",
    "15:30:00 - 17:39:59",
    "20:10:00 - 21:05:00"
  };
  m_time_ranges1.SetTimeRanges(time_ranges);
  m_time_ranges1.AutoXResizeMode(true);
  m_time_ranges1.AutoXResizeRightOffset(5);
  CCoreCreate::CreateTimeRanges(m_time_ranges1, m_window1, 0, 5, 60, 390);
}

上記の例は、TimeRanges要素に期間を設定する方法を示しています。

このようなグラフィカルインターフェイスでMQLアプリケーションを起動すると、次のように表示されます。

EasyAndFastGUI v2.0ライブラリのTimeRanges要素

EasyAndFastGUI v2.0ライブラリのTimeRanges要素

上のスクリーンショットは、日中の時間スケールであるGUI要素を示しています。これは、親要素(この場合はフォーム)の幅に自動的に調整できる動的要素です。一点鎖線は現在の時刻を示し、その近くに現在の時刻を示すテキストラベルが表示されます。マウスカーソルをタイムスケールに合わせると、マウスカーソルの下に垂直の実線が描画され、カーソルが指している時間のテキストラベルが表示されます。 

非常に参考になることがわかりましたが、それだけではありません。スケールをクリックすると、要素はON_CLICK_TIME_RANGE IDを持つカスタムイベントを生成し、カスタムMQLアプリケーションで処理できます。dparamパラメータには、1日の始まりから経過した秒数が含まれます。一方、sparamパラメータには、削除された時間範囲、またはクリック中に設定された範囲のいずれもカーソルの下にない場合は空の文字列が含まれます。さらに、TimeRanges要素を1回のクリックでグラフ全体に展開できるモードを有効にすることができます。

このイベントをインターセプトして処理できるようにするコードは次のとおりです。

void CApp::OnEvent(const int id, const long &lparam, const double &dparam, const string &sparam) {

  if(id == CHARTEVENT_CUSTOM + ON_CLICK_TIME_RANGE) {
    
    if(m_time_ranges1.Id() == lparam) {
      Print(__FUNCTION__, " > pressed time: ", ::TimeToString((datetime)dparam, TIME_MINUTES|TIME_SECONDS), "; pressed time range: ", sparam);
      
      string time_ranges[];
      m_time_ranges1.GetTimeRanges(time_ranges);
      
      ArrayPrint(time_ranges);
      return;
    }
    return;
  }
}

上記のコードリストからわかるように、最初にイベントのIDを確認し、これがON_CLICK_TIME_RANGEユーザーイベントである場合は、イベントlparamパラメータで渡された要素IDを確認します。次に、取得したデータがログに送信されます。この例では、CTimeRanges::GetTimeRanges()メソッドを使用して要素に設定された間隔を取得し、取得した配列を操作ログに表示する方法も示しています。

EAログ([エキスパート]タブ)では、次のように表示されます。

CApp::OnEvent > pressed time: 16:34:54; pressed time range: 15:30:00 - 17:39:59
"00:45:00-01:20:01" "08:55:00-09:25:01" "12:55:00-13:50:01" "15:30:00-17:39:59" "20:10:00-21:05:00"

次の例は、データベース内のお気に入りの結果の表(FAVORITE_RESULTS)からパスインデックスの配列を取得する方法を示しています。

void CApp::GetPassNumbersOfFavoriteResults(const string db_filename, ulong &passes[]) {

  ::ResetLastError();
  uint flags = DATABASE_OPEN_READWRITE | DATABASE_OPEN_CREATE;
  int db_handle = ::DatabaseOpen(db_filename, flags);
  if(db_handle == INVALID_HANDLE) {
    ::Print(__FUNCTION__, " > DB: ", db_filename, " open failed with code: ", ::GetLastError());
    return;
  }
  
  string command = "SELECT (Pass) FROM FAVORITE_RESULTS;";
  
  int db_query = ::DatabasePrepare(db_handle, command);
  if(db_query == INVALID_HANDLE) {
    ::Print(__FUNCTION__, " > DB: ", db_filename, " request failed with code ", ::GetLastError());
    ::DatabaseClose(db_handle);
    return;
  }

  for(int i = 0; ::DatabaseRead(db_query); i++) {
    int pass_number;
    ::ResetLastError();
    if(::DatabaseColumnInteger(db_query, 0, pass_number)) {
      int prev_size = ::ArraySize(passes);
      ::ArrayResize(passes, prev_size + 1);
      passes[prev_size] = (ulong)pass_number;
    } 
    else {
      ::Print(__FUNCTION__, " > DatabaseColumnInteger() error: ", ::GetLastError());
    }
  }
//--- Finish working with the database
  ::DatabaseFinalize(db_query);
  ::DatabaseClose(db_handle);
}

パスインデックスを受け取ったら、GetFavoriteRemovedIntervalsByPassNumber()メソッドを使用してパスインデックスを指定することで、削除された間隔を取得できます。

string CApp::GetFavoriteRemovedIntervalsByPassNumber(const ulong pass_number) {

  ::ResetLastError();
  uint flags = DATABASE_OPEN_READWRITE | DATABASE_OPEN_CREATE;
  int db_handle = ::DatabaseOpen(m_db_filename, flags);
  if(db_handle == INVALID_HANDLE) {
    ::Print(__FUNCTION__, " > DB: ", m_db_filename, " open failed with code: ", ::GetLastError());
    return(NULL);
  }
  
  string command = "SELECT (RemovedIntervals) FROM FAVORITE_RESULTS WHERE Pass=" + (string)pass_number + ";";
  
  int db_query = ::DatabasePrepare(db_handle, command);
  if(db_query == INVALID_HANDLE) {
    ::Print(__FUNCTION__, " > DB: ", m_db_filename, " request failed with code ", ::GetLastError());
    ::DatabaseClose(db_handle);
    return(NULL);
  }
  
  string time_ranges = "";
  
  if(::DatabaseRead(db_query)) {
    ::ResetLastError();
    if(!::DatabaseColumnText(db_query, 0, time_ranges)) {
      ::Print(__FUNCTION__, " > DatabaseColumnText() error: ", ::GetLastError());
    }
  }
//--- Finish working with the database
  ::DatabaseFinalize(db_query);
  ::DatabaseClose(db_handle);
  
  return(time_ranges);
}

OpenDB...をクリックしてデータベースを含むファイルを開くと、OnClickOpenDB()が呼び出されます。これは、プログラムがダイアログウィンドウを開いてMQL5/Files/DB内のファイルを選択する方法です。ファイルが選択されている場合は、他のメソッドでさらに使用するためです。次に、前にコードを示したGetPassNumbersOfFavoriteResults()メソッドを使用して、お気に入りの結果の表からパスのインデックスを取得します。このデータをドロップダウンリストに追加し、最初の項目を選択します。

bool CApp::OnClickOpenDB(const int id) {

  if(m_button1.Id() != id) {
    return(false);
  }

  string filenames[];
  string folder = "DB";
  string filter = "DB files (*.db)|*.db|SQLite files (*.sqlite)|*.sqlite|All files (*.*)|*.*";
  if(::FileSelectDialog("Select database file to upload", folder, filter,
                        FSD_FILE_MUST_EXIST, filenames) > 0) {
    
    int filenames_total = ::ArraySize(filenames);
    if(filenames_total < 1) {
      return(false);
    }
    
    m_db_filename = filenames[0];
    
    ::Print(__FUNCTION__, " > m_db_filename: ", m_db_filename);
    
    ulong passes[];
    GetPassNumbersOfFavoriteResults(m_db_filename, passes);
    
    ::ArrayPrint(passes);
    
    CListView *list_view = m_combobox1.GetListViewPointer();
    
    int passes_total = ::ArraySize(passes);
    if(passes_total > 0) {
      list_view.Clear();
      for(int i = 0; i < passes_total; i++) {
        list_view.AddItem(i, (string)passes[i]);
      }
      m_combobox1.SelectItem(0);
      m_combobox1.GetButtonPointer().Update(true);
      list_view.Update(true);
    }
  }
  return(true);
}

ドロップダウンリストでパスインデックスを選択すると、SetTimeRange()メソッドで削除された間隔が取得され、それらがグローバル配列に保存され、CTimeRanges型のグラフィカル要素に設定されます。

void CApp::SetTimeRange(void) {

  CListView *list_view = m_combobox1.GetListViewPointer();
  
  int   index       = list_view.SelectedItemIndex();
  ulong pass_number = (int)list_view.GetValue(index);
  
  string removed_intervals = GetFavoriteRemovedIntervalsByPassNumber(pass_number);
  
  ::ArrayFree(m_time_ranges_str);
  ::StringSplit(removed_intervals, ::StringGetCharacter("|", 0), m_time_ranges_str);
  
  int ranges_total = ::ArraySize(m_time_ranges_str);
  for(int i = 0; i < ranges_total; i++) {
    ::StringReplace(m_time_ranges_str[i], " - ", "-");
  }
  
  ::ArrayPrint(m_time_ranges_str);
  
  m_time_ranges1.SetTimeRanges(m_time_ranges_str);
  m_time_ranges1.Update();
}

次に、時間範囲を格納するための構造体が必要になります。EasyAndFastGUI 2.0ライブラリを使用する場合、そのような構造体(TimeRange)はCTimeRanges要素ファイルに既に存在します。

struct TimeRange {
  MqlDateTime start;
  MqlDateTime end;
};

このグラフィックライブラリを使用しない場合は、そのような構造体をコードで個別に宣言できます。

削除された時間範囲は既にSetTimeRange()メソッドで文字列形式で保存されているため、利便性を高めるためにそれらを構造体の配列に設定する必要があります。これをおこなうには、GetTimeRanges()メソッドを使用します。

void CApp::GetTimeRanges(TimeRange &ranges[]) {
  
  ::ArrayFree(ranges);
  
  int ranges_total = ::ArraySize(m_time_ranges_str);
  for(int i = 0; i < ranges_total; i++) {
    
    string tr[];
    ::StringSplit(m_time_ranges_str[i], ::StringGetCharacter("-", 0), tr);
  
    int size = ::ArraySize(ranges);
    ::ArrayResize(ranges, size + 1);
    
    MqlDateTime start, end;
    ::TimeToStruct(::StringToTime(tr[0]), start);
    ::TimeToStruct(::StringToTime(tr[1]), end);
    
    datetime time1 = HourSeconds(start.hour) + MinuteSeconds(start.min) + start.sec;
    datetime time2 = HourSeconds(end.hour) + MinuteSeconds(end.min) + end.sec;
    ::TimeToStruct(time1, ranges[size].start);
    ::TimeToStruct(time2, ranges[size].end);
  }
}

たとえば、これらのメソッドは、対応するイベント(アプリケーションクラスの短縮版)を処理するときに次のように使用できます。

class CApp : public CCoreCreate {
 private:
  TimeRange         m_time_ranges[];
  string            m_time_ranges_str[];
  
...

  virtual void      OnEvent(const int id, const long &lparam, const double &dparam, const string &sparam);

  void              SetTimeRange(void);
  void              GetTimeRanges(TimeRange &ranges[]);
  
  int               HourSeconds(const int hour)     { return(hour * 60 * 60); }
  int               MinuteSeconds(const int minute) { return(minute * 60);    }
};

void CApp::OnEvent(const int id, const long &lparam, const double &dparam, const string &sparam) {

  if(id == CHARTEVENT_CUSTOM + ON_CLICK_BUTTON) {
    if(OnClickOpenDB((int)lparam)) {
      SetTimeRange();
      GetTimeRanges(m_time_ranges);
      return;
    }
    return;
  }
  
  if(id == CHARTEVENT_CUSTOM + ON_CLICK_COMBOBOX_ITEM) {
    if(OnSelectPass((int)lparam)) {
      SetTimeRange();
      GetTimeRanges(m_time_ranges);
      return;
    }
    return;
  }
}

これで、CheckTradeTime()メソッドを実装して、許可された時間に取引がおこなわれたかどうかを確認できます。

bool CApp::CheckTradeTime(void) {

  bool     is_trade_time = true;
  datetime current_time  = ::TimeCurrent();
  
  MqlDateTime time;
  ::TimeToStruct(current_time, time);
  
  int ranges_total = ::ArraySize(m_time_ranges);
  for(int i = 0; i < ranges_total; i++) {
  
    MqlDateTime start = m_time_ranges[i].start;
    MqlDateTime end   = m_time_ranges[i].end;
    
    datetime time_c = HourSeconds(time.hour) + MinuteSeconds(time.min) + time.sec;
    datetime time_s = HourSeconds(start.hour) + MinuteSeconds(start.min) + start.sec;
    datetime time_e = HourSeconds(end.hour) + MinuteSeconds(end.min) + end.sec;
    
    if(time_c >= time_s && time_c <= time_e) {
      is_trade_time = false;
      break;
    }
  }
  return(is_trade_time);
}

ここでおこなう必要があるのは、たとえばOnTick()関数でCheckTradeTime()メソッドの呼び出しを設定することだけです。

  if(CheckTradeTime()) {
    Print(__FUNCTION__, " > trade time!");
  }

既製のアプリケーションは、記事の最後に添付されています。

取引から受信期間を削除する

取引から受信期間を削除する


結論

ストラテジーテスターでパラメータを最適化した後、単一のテストを実行してそれぞれの結果を表示する必要があります。これには非常に時間がかかり、非効率的です。

Frames Analyzerとは何でしょうか。これは、パラメータ最適化の直後に作成されたMQDファイルまたはデータベースを読み取ることにより、ストラテジーテスター内外でパラメータ最適化中に最適化フレームを分析するためのエキスパートアドバイザー(EA)のプラグインモジュールです。これらの最適化の結果はFrames Analyzerツールを使用している他のユーザーと共有して、結果について話し合うことができます。

Frames Analyzerを使用すると、上位100の最適化結果を同時にグラフ形式で表示できます。これらの上位100件の結果は、さまざまな基準(利益取引ドローダウンプロフィットファクターリカバリーファクター)を適用して取得できます。さらに、Frame Analyzerツールには、組み込みのBest Intervalsモジュールが搭載されており、不採算の期間が特定されます。取引履歴からそれらが削除され、これらの期間中に取引がおこなわれなかった場合に結果がどうなるかを確認できます。

好きな結果をデータベースに保存したり、EA外部パラメータを含む既製の設定ファイルの形式で保存したりできます。削除された期間もデータベースに保存されます。したがって、それらを取引に適用して利益を最大化することができます。Frame Analyzerで残されるのは、統計的に最も安全であることが証明された期間のみです。


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

添付されたファイル |
MQL5.zip (5545.43 KB)
DoEasy - コントロール(第22部):SplitContainer - 作成したオブジェクトのプロパティを変更する DoEasy - コントロール(第22部):SplitContainer - 作成したオブジェクトのプロパティを変更する
今回は、新しく作成したSplitContainerコントロールのプロパティと外観を変更する機能を実装します。
DoEasy-コントロール(第21部):SplitContainerコントロール。パネルセパレータ DoEasy-コントロール(第21部):SplitContainerコントロール。パネルセパレータ
この記事では、SplitContainerコントロールの補助パネルセパレータオブジェクトのクラスを作成します。
マウンテンチャートとアイスバーグチャート マウンテンチャートとアイスバーグチャート
MetaTrader 5プラットフォームに新しいチャートタイプを追加するというアイデアはいかがでしょうか。このプラットフォームには他のプラットフォームにあるものがいくつかないという声もあります。しかし、実際のところ、MetaTrader 5は他の多くのプラットフォームではできないこと(少なくとも簡単にはできないこと)ができる、非常に実用的なプラットフォームです。
アリゲーターによる取引システムの設計方法を学ぶ アリゲーターによる取引システムの設計方法を学ぶ
最も人気のあるテクニカル指標に基づいて取引システムを設計する方法についての連載は今回で完結します。アリゲーター指標を基にした取引システムの作り方を学びます。