207 lines
		
	
	
	
		
			8.6 KiB
		
	
	
	
		
			MQL5
		
	
	
	
	
	
			
		
		
	
	
			207 lines
		
	
	
	
		
			8.6 KiB
		
	
	
	
		
			MQL5
		
	
	
	
	
	
//+------------------------------------------------------------------+
 | 
						|
//|                                                    Optimizer.mqh |
 | 
						|
//|                                      Copyright 2024, Yuriy Bykov |
 | 
						|
//|                            https://www.mql5.com/ru/users/antekov |
 | 
						|
//+------------------------------------------------------------------+
 | 
						|
#property copyright "Copyright 2024, Yuriy Bykov"
 | 
						|
#property link      "https://www.mql5.com/ru/users/antekov"
 | 
						|
#property version   "1.03"
 | 
						|
 | 
						|
#include "OptimizerTask.mqh"
 | 
						|
 | 
						|
//+------------------------------------------------------------------+
 | 
						|
//| Класс для менеджера автоматической оптимизации проектов          |
 | 
						|
//+------------------------------------------------------------------+
 | 
						|
class COptimizer {
 | 
						|
   string            m_fileName;
 | 
						|
   // Текущая задача оптимизации
 | 
						|
   COptimizerTask    *m_task;
 | 
						|
 | 
						|
   // Получение количества задач в очереди
 | 
						|
   int               TotalTasks();
 | 
						|
 | 
						|
   // Получение идентификатора следующей задачи оптимизации из очереди
 | 
						|
   ulong             GetNextTaskId();
 | 
						|
 | 
						|
public:
 | 
						|
                     COptimizer(string p_fileName, string p_pythonPath = NULL);   // Конструктор
 | 
						|
                     ~COptimizer();
 | 
						|
   void              Process();                           // Основной метод обработки
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
//+------------------------------------------------------------------+
 | 
						|
//| Конструктор                                                      |
 | 
						|
//+------------------------------------------------------------------+
 | 
						|
COptimizer::COptimizer(string p_fileName, string p_pythonPath = NULL) :
 | 
						|
   m_fileName(p_fileName) {
 | 
						|
// Передаём путь к интерпретатору объекту задачи оптимизации
 | 
						|
   m_task = new COptimizerTask(p_fileName, p_pythonPath);
 | 
						|
}
 | 
						|
 | 
						|
//+------------------------------------------------------------------+
 | 
						|
//| Конструктор                                                      |
 | 
						|
//+------------------------------------------------------------------+
 | 
						|
COptimizer::~COptimizer() {
 | 
						|
// Передаём путь к интерпретатору объекту задачи оптимизации
 | 
						|
   if (!!m_task) delete m_task;
 | 
						|
   Comment("");
 | 
						|
}
 | 
						|
 | 
						|
//+------------------------------------------------------------------+
 | 
						|
//| Получение количества задач с заданным статусом                   |
 | 
						|
//+------------------------------------------------------------------+
 | 
						|
int COptimizer::TotalTasks() {
 | 
						|
// Результат
 | 
						|
   int res = 0;
 | 
						|
 | 
						|
// Запрос на получение количества задач с заданным статусом
 | 
						|
   string query = "SELECT COUNT(*)"
 | 
						|
                  "  FROM tasks t"
 | 
						|
                  "       JOIN"
 | 
						|
                  "       jobs j ON t.id_job = j.id_job"
 | 
						|
                  "       JOIN"
 | 
						|
                  "       stages s ON j.id_stage = s.id_stage"
 | 
						|
                  " WHERE t.status IN ('Queued', 'Process') "
 | 
						|
                  " ORDER BY s.id_stage, j.id_job, t.status LIMIT 1;";
 | 
						|
 | 
						|
// Открываем базу данных
 | 
						|
   if(DB::Connect(m_fileName)) {
 | 
						|
      // Выполняем запрос
 | 
						|
      int request = DatabasePrepare(DB::Id(), query);
 | 
						|
 | 
						|
      // Если нет ошибки
 | 
						|
      if(request != INVALID_HANDLE) {
 | 
						|
         // Структура данных для чтения одной строки результата запроса
 | 
						|
         struct Row {
 | 
						|
            int      count;
 | 
						|
         } row;
 | 
						|
 | 
						|
         // Читаем данные из первой строки результата
 | 
						|
         if(DatabaseReadBind(request, row)) {
 | 
						|
            res = row.count;
 | 
						|
         } else {
 | 
						|
            // Сообщаем об ошибке при необходимости
 | 
						|
            PrintFormat(__FUNCTION__" | ERROR: Reading row for request \n%s\nfailed with code %d",
 | 
						|
                        query, GetLastError());
 | 
						|
         }
 | 
						|
      } else {
 | 
						|
         // Сообщаем об ошибке при необходимости
 | 
						|
         PrintFormat(__FUNCTION__" | ERROR: Request \n%s\nfailed with code %d", query, GetLastError());
 | 
						|
      }
 | 
						|
 | 
						|
      // Закрываем базу данных
 | 
						|
      DB::Close();
 | 
						|
   }
 | 
						|
 | 
						|
   return res;
 | 
						|
}
 | 
						|
 | 
						|
//+------------------------------------------------------------------+
 | 
						|
//| Получение идентификатора следующей задачи оптимизации из очереди |
 | 
						|
//+------------------------------------------------------------------+
 | 
						|
ulong COptimizer::GetNextTaskId() {
 | 
						|
// Результат
 | 
						|
   ulong res = 0;
 | 
						|
 | 
						|
// Запрос на получение очередной задачи оптимизации из очереди
 | 
						|
   string query = "SELECT t.id_task"
 | 
						|
                  "  FROM tasks t "
 | 
						|
                  "       JOIN "
 | 
						|
                  "       jobs j ON j.id_job = t.id_job "
 | 
						|
                  "       JOIN "
 | 
						|
                  "       stages s ON s.id_stage = j.id_stage "
 | 
						|
                  "       LEFT JOIN "
 | 
						|
                  "       stages ps ON ps.id_stage = s.id_parent_stage "
 | 
						|
                  "       JOIN "
 | 
						|
                  "       projects p ON p.id_project = s.id_project "
 | 
						|
                  " WHERE t.id_task > 0 AND "
 | 
						|
                  "       t.status IN ('Queued', 'Process') AND "
 | 
						|
                  "       (ps.id_stage IS NULL OR "
 | 
						|
                  "        ps.status = 'Done') "
 | 
						|
                  " ORDER BY j.id_stage, "
 | 
						|
                  "          j.id_job, "
 | 
						|
                  "          t.status, "
 | 
						|
                  "          t.id_task"
 | 
						|
                  " LIMIT 1;";
 | 
						|
 | 
						|
// Открываем базу данных
 | 
						|
   if(DB::Connect(m_fileName)) {
 | 
						|
      // Выполняем запрос
 | 
						|
      int request = DatabasePrepare(DB::Id(), query);
 | 
						|
 | 
						|
      // Если нет ошибки
 | 
						|
      if(request != INVALID_HANDLE) {
 | 
						|
         // Структура данных для чтения одной строки результата запроса
 | 
						|
         struct Row {
 | 
						|
            ulong    id_task;
 | 
						|
         } row;
 | 
						|
 | 
						|
         // Читаем данные из первой строки результата
 | 
						|
         if(DatabaseReadBind(request, row)) {
 | 
						|
            res = row.id_task;
 | 
						|
         } else {
 | 
						|
            // Сообщаем об ошибке при необходимости
 | 
						|
            PrintFormat(__FUNCTION__" | ERROR: Reading row for request \n%s\nfailed with code %d",
 | 
						|
                        query, GetLastError());
 | 
						|
         }
 | 
						|
      } else {
 | 
						|
         // Сообщаем об ошибке при необходимости
 | 
						|
         PrintFormat(__FUNCTION__" | ERROR: request \n%s\nfailed with code %d", query, GetLastError());
 | 
						|
      }
 | 
						|
 | 
						|
      // Закрываем базу данных
 | 
						|
      DB::Close();
 | 
						|
   }
 | 
						|
 | 
						|
   return res;
 | 
						|
}
 | 
						|
 | 
						|
//+------------------------------------------------------------------+
 | 
						|
//| Основной метод обработки                                         |
 | 
						|
//+------------------------------------------------------------------+
 | 
						|
void COptimizer::Process() {
 | 
						|
   PrintFormat(__FUNCTION__" | Current Task ID = %d", m_task.Id());
 | 
						|
 | 
						|
// Если советник остановлен, то удаляем таймер и самого советника с графика
 | 
						|
   if (IsStopped()) {
 | 
						|
      EventKillTimer();
 | 
						|
      ExpertRemove();
 | 
						|
      return;
 | 
						|
   }
 | 
						|
 | 
						|
// Если текущая задача завершена, то
 | 
						|
   if (m_task.IsDone()) {
 | 
						|
      // Если текущая задача не пустая, то
 | 
						|
      if(m_task.Id()) {
 | 
						|
         // Звершаем текущую задачу
 | 
						|
         m_task.Finish();
 | 
						|
      }
 | 
						|
 | 
						|
      // Получаем количество задач в очереди
 | 
						|
      int totalTasks = TotalTasks();
 | 
						|
 | 
						|
      // Если задачи есть, то
 | 
						|
      if(totalTasks) {
 | 
						|
         // Получаем идентификатор очередной текущей задачи
 | 
						|
         ulong taskId = GetNextTaskId();
 | 
						|
 | 
						|
         // Загружаем параметры задачи оптимизации из базы данных
 | 
						|
         m_task.Load(taskId);
 | 
						|
 | 
						|
         // Запускаем текущую задачу
 | 
						|
         m_task.Start();
 | 
						|
 | 
						|
         // Выводим на график количество оставшихся задач и текущую задачу
 | 
						|
         Comment(StringFormat(
 | 
						|
                    "Total tasks in queue: %d\n"
 | 
						|
                    "Current Task ID: %d",
 | 
						|
                    totalTasks, m_task.Id()));
 | 
						|
      } else {
 | 
						|
         // Если задач нет, то удаляем советник с графика
 | 
						|
         PrintFormat(__FUNCTION__" | Finish.", 0);
 | 
						|
         ExpertRemove();
 | 
						|
      }
 | 
						|
   }
 | 
						|
}
 | 
						|
//+------------------------------------------------------------------+
 |