記事「多通貨エキスパートアドバイザーの開発(第13回):第2段階の自動化 - グループへの選択」についてのディスカッション

 

新しい記事「多通貨エキスパートアドバイザーの開発(第13回):第2段階の自動化 - グループへの選択」はパブリッシュされました:

自動最適化の第1段階はすでに実装されています。いくつかの基準に従ってさまざま銘柄と時間枠の最適化を実行し、各パスの結果に関する情報をデータベースに保存します。ここで、最初の段階で見つかったものから最適なパラメータセットのグループを選択します。

次の段階は、取引戦略の単一インスタンスの優れたグループを選択し、それらを連携させることです。これにより、ドローダウンの削減、残高曲線の成長の直線性の向上など、取引パラメータが向上します。この段階は手動で実行する方法について、本連載第6部で説明しました。まず、単一取引戦略インスタンスのパラメータを最適化した結果から、注目に値するものを選択しました。これはさまざまな基準を使用して実行できますが、当時は利益がマイナスの結果のみを除外することに限定していました。その後、さまざまな方法を使用して、取引戦略の8つのインスタンスのさまざまな組み合わせを取得し、それらを1つのEAに組み合わせてテスターで実行し、共同作業のパラメータを評価しました。

手動選択から始めて、CSVファイルに保存されているパラメータのリストから選択された単一の取引戦略インスタンスの入力組み合わせの自動選択も実装しました。最も単純なケースでも、8つの組み合わせを選択する遺伝的最適化を実行するだけで、目的の結果が得られることが分かっています。

次に、グループ選択の最適化を実行したEAを変更し、第1段階の結果をデータベースから利用できるようにします。また、その結果をデータベースに保存する必要があります。また、データベースに必要なエントリを追加して、第2段階の最適化を実行するためのタスクを作成することも検討します。


作者: Yuriy Bykov

 
興味深い記事をありがとうございました!static修飾子について、あなたの状況を理解しています。私も最初は、この修飾子の助けを借りて、メモリの同じ部分にアクセスするためのプラスのような独自のシングルトンを作ることができると考えていました。しかし、この修飾子はExpert Advisorが動作しているシンボルのみに適用されることがわかりました。
 
素晴らしい記事をありがとう!
 

フィードバックをありがとう。

Alexanderさん、staticの使い方がまだよくわかっていないようですね。その助けを借りれば、MQL5でもC++でもシングルトン設計パターンを簡単に実装できます。例えば、私は第3 部のCVirtualReceiver クラスでこれを使いました。この修飾子はExpert Advisorが実行されるチャートとは一切関係ありません。この修飾子で宣言された変数やプロパティは、例えばSymbol()関数の呼び出しの結果などを代入すれば関連するかもしれません。しかし、これはそのような変数の値を後から変更できないという意味ではありません。

 
ユーリさん、こんにちは!どのプログラムでデータベースを開いて編集しているのか教えてください。私はmql5エディタで開いていますが、そこでは編集ができません(灰色のボタンとメニュー項目)。
 

Victorさん、こんにちは。

私はSQLiteStudioを使って います。このフリーのプログラムは最近機能が大幅に拡張されたので、必要なものが欠けているということはありません。MetaEditorでは、SQLクエリを実行することによってのみデータベースを編集することができます。もちろん、これはあまり便利ではありません。

 

ユーリ、プログラムをありがとう。データベースを開いて編集できるようになったよ。第一段階の計算は終わったのですが、第二段階に問題があります。まず第1段階を実行し、スクリーンショットにあるように第2段階の行を手動で追加し、記事に ある2つのクエリを実行しました。タスクとジョブはデータベースに表示され、Expert Advisorは第2ステージを実行しようとします。しかし、何らかの理由で、第1ステージのパスがデータベースにあるにもかかわらず表示されません。何か間違って理解しているかもしれません(私は誰のベースも扱ったことがありません)。

これがスクリーンショットのエラーです。どうすれば実行できますか?

ファイル:
37yepqooe5.png  129 kb
7339o8y4fn1.png  21 kb
 

また、私の理解では、これらのパラメーターは

input int      count_         = 16;                   // - グループ内の戦略数 (1 ... 16)

input int   i1_ = 1;       // - 戦略インデックス #1
input int   i2_ = 2;       // - 戦略インデックス#2
input int   i3_ = 3;       // 戦略インデックス#3
input int   i4_ = 4;       // - ストラテジー・インデックス第4位
input int   i5_ = 5;       // - ストラテジー・インデックス #5
input int   i6_ = 6;       // - ストラテジー・インデックス #6
input int   i7_ = 7;       // - ストラテジー・インデックス #7
input int   i8_ = 8;       // - ストラテジー・インデックス #8
input int   i9_ = 9;       // - ストラテジー・インデックス #9
input int   i10_ = 10;     // - ストラテジー・インデックス #10
input int   i12_ = 11;     // - ストラテジー・インデックス #11
input int   i11_ = 12;     // - ストラテジー・インデックス #12
input int   i13_ = 13;     // - ストラテジー・インデックス #13
input int   i14_ = 14;     // - ストラテジー・インデックス 第14位
input int   i15_ = 15;     // - ストラテジー・インデックス #15
input int   i16_ = 16;     // - ストラテジー・インデックス 第16回

は第2ステージの各タスク内で検索されるはずです。しかし、どの範囲で、どのステップで検索されるべきでしょうか?また、count_パラメーター自体は、検索されるべきではないのでしょうか?

 

第二段階では、第二データベースを自動的に作成し、テストエージェントに 送信する。その名前は

#define  PARAMS_FILE "database892.stage2.sqlite"

メインデータベースの名前とは異なるものでなければなりません。スクリーンショットでは、pass テーブルがこのデータベースにはないことが示されています。最初のデータベースから2番目のデータベースを作成するCreateTaskDB()関数の動作を理解してください。

i{N}_ 型のパラメータの検索のステップと限界は、2 番目のデータベースからの情報に基づいて Optimisation.mq5 Expert Advisor によって自動的に設定されます。

count_ パラメーターは検索する必要はありません。16個のインスタンスからではなく、より少ない数のインスタンスからグループを選択したい場合は、より小さい値に変更できます。例えば、12からとか8からとか。しかし、私の場合は常に16と同じにしています。

 

ユーリ、うまくいかないんだ...。私の持っている共通データベースのファイルは、アドバイザーdatabase892.sqliteであなたが持っているように指定され、私はそれを変更していないし、それは本当にディスク上にあり、アドバイザーOptimisation.mq5はそれに接続してタスクを実行します。Expert Advisor SimpleVolumesStage2.mq5にも指定されています。そして、タスクのデータベースファイルはdatabase892.stage2.sqliteと指定されている。 私の理解では、これらは異なるファイルである。共通データベースファイルはCommonFiles フォルダに ある

GetParamsTotal関数にチェックを入れ、DB::Connect関数でfileName変数を指定してみた:

//+------------------------------------------------------------------+
//| タスクデータベース内のストラテジーパラメータセットの数
//+------------------------------------------------------------------+
int GetParamsTotal(const string fileName) {
   int paramsTotal = 0;
         PrintFormat(__FUNCTION__" 1 ");

// タスク・データベースがオープンされている場合
   if(DB::Connect(fileName, 0)) {
         PrintFormat(__FUNCTION__" 2 ");

      // このタスクのパス数を取得するクエリーを作成する。
      string query = "SELECT COUNT(*) FROM passes p";
         PrintFormat(__FUNCTION__" 3 ");

      int request = DatabasePrepare(DB::Id(), query);
         PrintFormat(__FUNCTION__" 4 ");
      

      if(request != INVALID_HANDLE) {
         // クエリー結果のデータ構造
         PrintFormat(__FUNCTION__" 5 ");

         struct Row {
            int      total;
         } row;
         PrintFormat(__FUNCTION__" 6 ");
         
         // 最初の行からクエリの結果を取得する
         if (DatabaseReadBind(request, row)) {
            paramsTotal = row.total;
         }
      } else {
         PrintFormat(__FUNCTION__" | ERROR: request \n%s\nfailed with code %d", query, GetLastError());
      }
      DB::Close();
   }
         PrintFormat(__FUNCTION__" 7 ");

   return paramsTotal;
}

ログで実行するとこのように出力されます:

2024.08.21 22:05:27.964 Optimization (EURUSD,M5)        idTask_=124||0||0||0||N
2024.08.21 22:05:27.964 Optimization (EURUSD,M5)        idParentJob_=7||0||1||10||N
2024.08.21 22:05:27.964 Optimization (EURUSD,M5)        
2024.08.21 22:05:29.096 SimpleVolumesStage2 (GBPUSD,H1) GetParamsTotal 1 
2024.08.21 22:05:29.097 SimpleVolumesStage2 (GBPUSD,H1) GetParamsTotal 2 
2024.08.21 22:05:29.097 SimpleVolumesStage2 (GBPUSD,H1) GetParamsTotal 3 
2024.08.21 22:05:29.097 SimpleVolumesStage2 (GBPUSD,H1) database error, no such table: passes
2024.08.21 22:05:29.097 SimpleVolumesStage2 (GBPUSD,H1) GetParamsTotal 4 
2024.08.21 22:05:29.097 SimpleVolumesStage2 (GBPUSD,H1) GetParamsTotal | ERROR: request 
2024.08.21 22:05:29.097 SimpleVolumesStage2 (GBPUSD,H1) SELECT COUNT(*) FROM passes p
2024.08.21 22:05:29.097 SimpleVolumesStage2 (GBPUSD,H1) failed with code 5039
2024.08.21 22:05:29.098 SimpleVolumesStage2 (GBPUSD,H1) GetParamsTotal 7 
2024.08.21 22:05:29.098 SimpleVolumesStage2 (GBPUSD,H1) OnTesterInit | ERROR: Can't load data from file database892.sqlite.
2024.08.21 22:05:29.098 SimpleVolumesStage2 (GBPUSD,H1) Check that it exists in data folder or in common data folder.
2024.08.21 22:05:32.900 Optimization (EURUSD,M5)        OnTimer | Current Task ID = 124
2024.08.21 22:05:33.008 Optimization (EURUSD,M5)        FinishTask | Task ID = 124
2024.08.21 22:05:33.022 Optimization (EURUSD,M5)        StartTask | Task ID = 125
2024.08.21 22:05:33.022 Optimization (EURUSD,M5)        [Tester]

エラー番号はまだ5602を書くことができる場所。私の理解では、DatabasePrepare 関数でつまずきます。

私はあなたが記事11にファイルに投稿したようにデータベースを取り、私はdatabase.sqliteからdatabase892.sqliteに ファイル名を変更 し、データベース内の最初のステージアドバイザーの名前をこの部分の実際のものに変更し、私は最初のステージを実行した後、私はステージテーブルに第二ステージの行を追加し、あなたの記事からコマンドの2つのセットを実行 した唯一のもの。 他には何も変更していない。passテーブルには約388,000行のpassがあります。

 

エラーの発生はそれ以前であり、プログラム実行の 観点からはすべて正常であるため、報告されないだけである。

このメッセージは

2024.08.21 22:05:29.097 SimpleVolumesStage2 (GBPUSD,H1) database error, no such table: passes

は、2番目のデータベースにパス・ テーブルが存在せず、そこからデータを取得しようとしていることを直接示しています。そのため、それを作成する関数であるCreateTaskDB() に対処する必要があります。