Discussing the article: "Developing a multi-currency Expert Advisor (Part 13): Automating the second stage — selection into groups"

 

Check out the new article: Developing a multi-currency Expert Advisor (Part 13): Automating the second stage — selection into groups.

We have already implemented the first stage of the automated optimization. We perform optimization for different symbols and timeframes according to several criteria and store information about the results of each pass in the database. Now we are going to select the best groups of parameter sets from those found at the first stage.

The next stage is a selection of good groups of single instances of trading strategies that, when working together, will improve trading parameters reduce drawdown, increase the linearity of the balance curve growth, and so on. We already looked at how to carry out this stage manually in the sixth part of the series. First, we selected from the results of optimizing the parameters of single trading strategy instances those that deserved attention. This could have been done using various criteria, but at that time we limited ourselves to simply removing results with negative profit. Then, using different methods, we tried to take different combinations of eight instances of trading strategies, combine them in one EA and run them in the tester to evaluate the parameters of their joint work.

Starting with manual selection, we also implemented auto selection of input combinations of single trading strategies instances selected from the list of parameters stored in a CSV file. It turns out that even in the simplest case, the desired result is achieved when we simply run genetic optimization that selects eight combinations.

Let's now modify the EA that performed the group selection optimization so that it can use the results of the first stage from the database. It should also save its results in the database. We will also consider creating tasks for conducting second-stage optimizations by adding the necessary entries to our database.

Author: Yuriy Bykov

 
Thank you very much for the interesting article! About the modifier static I understand your situation, I also thought at first that with the help of this modifier you can make your own singleton like on pluses to access the same part of memory. But practice has shown that this modifier extends to the scope of only the symbol where the Expert Advisor itself is running.
 
Thank you for the super article!
 

Thanks for the feedback, we will move on.

Alexander, I guess you have not quite figured out how to use static. With its help, the Singleton design pattern can be easily implemented in MQL5 as well as in C++. I used it, for example, for the CVirtualReceiver class in the third part. This modifier is in no way related to the chart on which the Expert Advisor will be run. A variable or a property declared with this modifier may be related if we assign them, for example, the result of the Symbol() function call. But this does not mean that we cannot change the value of such variables afterwards

 
Yuri hello! Can you tell me, in which programme do you open and edit the database? I have it open in mql5 editor, but editing is not available there (grey buttons and menu items) and the sem interface looks a bit different?
 

Hello Victor.

I use SQLiteStudio. This free programme has recently expanded its functionality a lot, so I haven't encountered the lack of something necessary in it. In MetaEditor you can edit the database only by executing SQL queries. This is less convenient, of course.

 

Yuri, thanks for the programme, now I can open the database and edit it. And I have done the first stage of calculations, but the second stage has a problem - it won't start. I first ran the first stage, then added manually the line of the second stage as you have on the screenshot and executed two queries from your article. Tasks and jobs appeared in the database and the Expert Advisor tries to run the second stage. But for some reason it does not see the passes of the first stage, although they are in the database. I may understand something wrong (I have not worked with bases of anyone).

Here are the errors on the screenshots. How to run it?

Files:
37yepqooe5.png  129 kb
7339o8y4fn1.png  21 kb
 

Also, as I understand these parameters:

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

should be searched within each task of the second stage. But in what ranges should they be searched and with what step? And the count_ parameter itself, as I understand, should not be searched?

 

For the second stage, a second database should be automatically created and sent to the testing agents. Its name is specified in the directive

#define  PARAMS_FILE "database892.stage2.sqlite"

It must be different from the name of the main database. On the screenshot you are informed that the passes table is not in this database, although it was expected to be there. Try to understand the work of the CreateTaskDB() function, which creates the second database from the initial one.

The step and limits of the search of parameters of the i{N}_ type are set automatically by the Optimisation.mq5 Expert Advisor based on the information from the second database.

The count_ parameter does not need to be searched. It can be changed to a smaller value, if we want to select groups not from 16, but from a smaller number of instances. For example, from 12 or from 8. But for me it has always been equal to 16.

 

Yuri, I can't get it to work.... The file of the common database I have is specified as you have in the advisor database892.sqlite, I have not changed it and it is on the disc really, and the advisor Optimisation.mq5 connects to it and runs tasks. In the Expert Advisor SimpleVolumesStage2.mq5 it is also specified. And the database file of the task is specified database892.stage2.sqlite. As I understand they are different files. The common database file is located in the Common\Files folder.

I tried to insert checks into the GetParamsTotal function and specify the fileName variable in the DB::Connect function, here is the code:

//+------------------------------------------------------------------+
//| Количество наборов параметров стратегий в базе данных задачи     |
//+------------------------------------------------------------------+
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;
}

When executing in the log, it outputs like this:

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]

Where the error number can still write 5602 . As I understand it stumbles on the DatabasePrepare function.

I took the database as you posted in the file to the article 11 The only thing I changed the file name from database.sqlite to database892.sqlite and changed the name of the first stage advisor in the database to the actual one in this part and after I executed the first stage I added the line of the second stage to the stages table and executed 2 sets of commands from your article. I did not change anything else. There are about 388,000 rows with passes in the passes table.

 

The error occurs earlier, it is just not reported there, as everything is fine from the point of view of programme execution.

This message

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

directly says that there is no passes table in the second database, and we are trying to get data from it. That's why we should deal with the function that should create it - CreateTaskDB().